1 /* $NetBSD: lpt_pcc.c,v 1.12 2008/04/28 20:23:29 martin Exp $ */
2
3 /*-
4 * Copyright (c) 1999 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Steve C. Woodford.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 /*
33 * Device Driver back-end for the MVME147's parallel printer port
34 */
35
36 #include <sys/cdefs.h>
37 __KERNEL_RCSID(0, "$NetBSD: lpt_pcc.c,v 1.12 2008/04/28 20:23:29 martin Exp $");
38
39 #include <sys/param.h>
40 #include <sys/systm.h>
41 #include <sys/kernel.h>
42 #include <sys/device.h>
43 #include <sys/syslog.h>
44
45 #include <machine/bus.h>
46
47 #include <dev/mvme/lptvar.h>
48
49 #include <mvme68k/dev/lpt_pccreg.h>
50 #include <mvme68k/dev/pccreg.h>
51 #include <mvme68k/dev/pccvar.h>
52
53 #include "ioconf.h"
54
55
56 static int lpt_pcc_intr(void *);
57 static void lpt_pcc_open(struct lpt_softc *, int);
58 static void lpt_pcc_close(struct lpt_softc *);
59 static void lpt_pcc_iprime(struct lpt_softc *);
60 static void lpt_pcc_speed(struct lpt_softc *, int);
61 static int lpt_pcc_notrdy(struct lpt_softc *, int);
62 static void lpt_pcc_wr_data(struct lpt_softc *, u_char);
63
64 struct lpt_funcs lpt_pcc_funcs = {
65 lpt_pcc_open,
66 lpt_pcc_close,
67 lpt_pcc_iprime,
68 lpt_pcc_speed,
69 lpt_pcc_notrdy,
70 lpt_pcc_wr_data
71 };
72
73 /*
74 * Autoconfig stuff
75 */
76 static int lpt_pcc_match(device_t, cfdata_t , void *);
77 static void lpt_pcc_attach(device_t, device_t, void *);
78
79 CFATTACH_DECL_NEW(lpt_pcc, sizeof(struct lpt_softc),
80 lpt_pcc_match, lpt_pcc_attach, NULL, NULL);
81
82
83 /*ARGSUSED*/
84 static int
lpt_pcc_match(device_t parent,cfdata_t cf,void * args)85 lpt_pcc_match(device_t parent, cfdata_t cf, void *args)
86 {
87 struct pcc_attach_args *pa;
88
89 pa = args;
90
91 if (strcmp(pa->pa_name, lpt_cd.cd_name))
92 return 0;
93
94 pa->pa_ipl = cf->pcccf_ipl;
95 return 1;
96 }
97
98 /*ARGSUSED*/
99 static void
lpt_pcc_attach(device_t parent,device_t self,void * args)100 lpt_pcc_attach(device_t parent, device_t self, void *args)
101 {
102 struct lpt_softc *sc;
103 struct pcc_attach_args *pa;
104
105 sc = device_private(self);
106 sc->sc_dev = self;
107 pa = args;
108
109 sc->sc_bust = pa->pa_bust;
110 bus_space_map(pa->pa_bust, pa->pa_offset, LPREG_SIZE, 0, &sc->sc_bush);
111
112 sc->sc_ipl = pa->pa_ipl & PCC_IMASK;
113 sc->sc_funcs = &lpt_pcc_funcs;
114 sc->sc_laststatus = 0;
115
116 aprint_normal(": PCC Parallel Printer\n");
117
118 /*
119 * Disable interrupts until device is opened
120 */
121 pcc_reg_write(sys_pcc, PCCREG_PRNT_INTR_CTRL, 0);
122
123 /*
124 * Main attachment code
125 */
126 lpt_attach_subr(sc);
127
128 /* Register the event counter */
129 evcnt_attach_dynamic(&sc->sc_evcnt, EVCNT_TYPE_INTR,
130 pccintr_evcnt(sc->sc_ipl), "printer", device_xname(sc->sc_dev));
131
132 /*
133 * Hook into the printer interrupt
134 */
135 pccintr_establish(PCCV_PRINTER, lpt_pcc_intr, sc->sc_ipl, sc,
136 &sc->sc_evcnt);
137 }
138
139 /*
140 * Handle printer interrupts which occur when the printer is ready to accept
141 * another char.
142 */
143 int
lpt_pcc_intr(void * arg)144 lpt_pcc_intr(void *arg)
145 {
146 struct lpt_softc *sc;
147 int i;
148
149 sc = arg;
150
151 /* is printer online and ready for output */
152 if (lpt_pcc_notrdy(sc, 0) && lpt_pcc_notrdy(sc, 1))
153 return 0;
154
155 i = lpt_intr(sc);
156
157 if (pcc_reg_read(sys_pcc, PCCREG_PRNT_INTR_CTRL) & LPI_ACKINT) {
158 pcc_reg_write(sys_pcc, PCCREG_PRNT_INTR_CTRL,
159 sc->sc_icr | LPI_ACKINT);
160 }
161
162 return i;
163 }
164
165
166 static void
lpt_pcc_open(struct lpt_softc * sc,int int_ena)167 lpt_pcc_open(struct lpt_softc *sc, int int_ena)
168 {
169 int sps;
170
171 pcc_reg_write(sys_pcc, PCCREG_PRNT_INTR_CTRL,
172 LPI_ACKINT | LPI_FAULTINT);
173
174 if (int_ena == 0) {
175 sps = splhigh();
176 sc->sc_icr = sc->sc_ipl | LPI_ENABLE;
177 pcc_reg_write(sys_pcc, PCCREG_PRNT_INTR_CTRL, sc->sc_icr);
178 splx(sps);
179 }
180 }
181
182 static void
lpt_pcc_close(struct lpt_softc * sc)183 lpt_pcc_close(struct lpt_softc *sc)
184 {
185
186 pcc_reg_write(sys_pcc, PCCREG_PRNT_INTR_CTRL, 0);
187 sc->sc_icr = sc->sc_ipl;
188 pcc_reg_write(sys_pcc, PCCREG_PRNT_INTR_CTRL, sc->sc_icr);
189 }
190
191 /* ARGSUSED */
192 static void
lpt_pcc_iprime(struct lpt_softc * sc)193 lpt_pcc_iprime(struct lpt_softc *sc)
194 {
195
196 lpt_control_write(LPC_INPUT_PRIME);
197 delay(100);
198 }
199
200 /* ARGSUSED */
201 static void
lpt_pcc_speed(struct lpt_softc * sc,int speed)202 lpt_pcc_speed(struct lpt_softc *sc, int speed)
203 {
204
205 if (speed == LPT_STROBE_FAST)
206 lpt_control_write(LPC_FAST_STROBE);
207 else
208 lpt_control_write(0);
209 }
210
211 static int
lpt_pcc_notrdy(struct lpt_softc * sc,int err)212 lpt_pcc_notrdy(struct lpt_softc *sc, int err)
213 {
214 u_char status;
215 u_char new;
216
217 #define LPS_INVERT (LPS_SELECT)
218 #define LPS_MASK (LPS_SELECT|LPS_FAULT|LPS_BUSY|LPS_PAPER_EMPTY)
219
220 status = (lpt_status_read(sc) ^ LPS_INVERT) & LPS_MASK;
221
222 if (err) {
223 new = status & ~sc->sc_laststatus;
224 sc->sc_laststatus = status;
225
226 if (new & LPS_SELECT)
227 log(LOG_NOTICE, "%s: offline\n",
228 device_xname(sc->sc_dev));
229 else if (new & LPS_PAPER_EMPTY)
230 log(LOG_NOTICE, "%s: out of paper\n",
231 device_xname(sc->sc_dev));
232 else if (new & LPS_FAULT)
233 log(LOG_NOTICE, "%s: output error\n",
234 device_xname(sc->sc_dev));
235 }
236
237 pcc_reg_write(sys_pcc, PCCREG_PRNT_INTR_CTRL,
238 sc->sc_icr | LPI_FAULTINT);
239
240 return status;
241 }
242
243 static void
lpt_pcc_wr_data(struct lpt_softc * sc,u_char data)244 lpt_pcc_wr_data(struct lpt_softc *sc, u_char data)
245 {
246
247 lpt_data_write(sc, data);
248 }
249