1 /* $NetBSD: lpt_mvme.c,v 1.4 2003/07/14 15:47:19 lukem Exp $ */
2
3 /*-
4 * Copyright (c) 1999, 2002 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 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the NetBSD
21 * Foundation, Inc. and its contributors.
22 * 4. Neither the name of The NetBSD Foundation nor the names of its
23 * contributors may be used to endorse or promote products derived
24 * from this software without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
37 */
38
39 /*
40 * Copyright (c) 1993, 1994 Charles M. Hannum.
41 * Copyright (c) 1990 William F. Jolitz, TeleMuse
42 * All rights reserved.
43 *
44 * Redistribution and use in source and binary forms, with or without
45 * modification, are permitted provided that the following conditions
46 * are met:
47 * 1. Redistributions of source code must retain the above copyright
48 * notice, this list of conditions and the following disclaimer.
49 * 2. Redistributions in binary form must reproduce the above copyright
50 * notice, this list of conditions and the following disclaimer in the
51 * documentation and/or other materials provided with the distribution.
52 * 3. All advertising materials mentioning features or use of this software
53 * must display the following acknowledgement:
54 * This software is a component of "386BSD" developed by
55 * William F. Jolitz, TeleMuse.
56 * 4. Neither the name of the developer nor the name "386BSD"
57 * may be used to endorse or promote products derived from this software
58 * without specific prior written permission.
59 *
60 * THIS SOFTWARE IS A COMPONENT OF 386BSD DEVELOPED BY WILLIAM F. JOLITZ
61 * AND IS INTENDED FOR RESEARCH AND EDUCATIONAL PURPOSES ONLY. THIS
62 * SOFTWARE SHOULD NOT BE CONSIDERED TO BE A COMMERCIAL PRODUCT.
63 * THE DEVELOPER URGES THAT USERS WHO REQUIRE A COMMERCIAL PRODUCT
64 * NOT MAKE USE OF THIS WORK.
65 *
66 * FOR USERS WHO WISH TO UNDERSTAND THE 386BSD SYSTEM DEVELOPED
67 * BY WILLIAM F. JOLITZ, WE RECOMMEND THE USER STUDY WRITTEN
68 * REFERENCES SUCH AS THE "PORTING UNIX TO THE 386" SERIES
69 * (BEGINNING JANUARY 1991 "DR. DOBBS JOURNAL", USA AND BEGINNING
70 * JUNE 1991 "UNIX MAGAZIN", GERMANY) BY WILLIAM F. JOLITZ AND
71 * LYNNE GREER JOLITZ, AS WELL AS OTHER BOOKS ON UNIX AND THE
72 * ON-LINE 386BSD USER MANUAL BEFORE USE. A BOOK DISCUSSING THE INTERNALS
73 * OF 386BSD ENTITLED "386BSD FROM THE INSIDE OUT" WILL BE AVAILABLE LATE 1992.
74 *
75 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPER ``AS IS'' AND
76 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
77 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
78 * ARE DISCLAIMED. IN NO EVENT SHALL THE DEVELOPER BE LIABLE
79 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
80 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
81 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
82 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
83 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
84 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
85 * SUCH DAMAGE.
86 */
87
88 /*
89 * Device Driver for an MVME68K/MVME88K board's parallel printer port
90 * This driver attaches above the board-specific back-end.
91 */
92
93 #include <sys/cdefs.h>
94 __KERNEL_RCSID(0, "$NetBSD: lpt_mvme.c,v 1.4 2003/07/14 15:47:19 lukem Exp $");
95
96 #include <sys/param.h>
97 #include <sys/systm.h>
98 #include <sys/proc.h>
99 #include <sys/user.h>
100 #include <sys/buf.h>
101 #include <sys/kernel.h>
102 #include <sys/ioctl.h>
103 #include <sys/uio.h>
104 #include <sys/device.h>
105 #include <sys/conf.h>
106 #include <sys/syslog.h>
107
108 #include <machine/cpu.h>
109 #include <machine/bus.h>
110
111 #include <dev/mvme/lptvar.h>
112
113
114 #define TIMEOUT hz*16 /* wait up to 16 seconds for a ready */
115 #define STEP hz/4
116
117 #define LPTPRI (PZERO+8)
118 #define LPT_BSIZE 1024
119
120 #if !defined(DEBUG) || !defined(notdef)
121 #define LPRINTF(a)
122 #else
123 #define LPRINTF if (lptdebug) printf a
124 int lptdebug = 1;
125 #endif
126
127 #define LPTUNIT(s) (minor(s) & 0x0f)
128 #define LPTFLAGS(s) (minor(s) & 0xf0)
129
130 static void lpt_wakeup __P((void *arg));
131 static int pushbytes __P((struct lpt_softc *));
132
133 extern struct cfdriver lpt_cd;
134
135 dev_type_open(lptopen);
136 dev_type_close(lptclose);
137 dev_type_write(lptwrite);
138 dev_type_ioctl(lptioctl);
139
140 const struct cdevsw lpt_cdevsw = {
141 lptopen, lptclose, noread, lptwrite, lptioctl,
142 nostop, notty, nopoll, nommap, nokqfilter,
143 };
144
145 void
146 lpt_attach_subr(sc)
147 struct lpt_softc *sc;
148 {
149
150 sc->sc_state = 0;
151 callout_init(&sc->sc_wakeup_ch);
152 }
153
154 /*
155 * Reset the printer, then wait until it's selected and not busy.
156 */
157 int
158 lptopen(dev, flag, mode, p)
159 dev_t dev;
160 int flag;
161 int mode;
162 struct proc *p;
163 {
164 int unit;
165 u_char flags;
166 struct lpt_softc *sc;
167 int error;
168 int spin;
169
170 unit = LPTUNIT(dev);
171 flags = LPTFLAGS(dev);
172
173 if (unit >= lpt_cd.cd_ndevs)
174 return (ENXIO);
175 sc = lpt_cd.cd_devs[unit];
176 if (!sc)
177 return (ENXIO);
178
179 #ifdef DIAGNOSTIC
180 if (sc->sc_state)
181 printf("%s: stat=0x%x not zero\n", sc->sc_dev.dv_xname,
182 sc->sc_state);
183 #endif
184
185 if (sc->sc_state)
186 return (EBUSY);
187
188 sc->sc_state = LPT_INIT;
189 sc->sc_flags = flags;
190 LPRINTF(("%s: open: flags=0x%x\n", sc->sc_dev.dv_xname, flags));
191
192 if ((flags & LPT_NOPRIME) == 0) {
193 /* assert Input Prime for 100 usec to start up printer */
194 (sc->sc_funcs->lf_iprime) (sc);
195 }
196
197 /* select fast or slow strobe depending on minor device number */
198 if (flags & LPT_FAST_STROBE)
199 (sc->sc_funcs->lf_speed) (sc, LPT_STROBE_FAST);
200 else
201 (sc->sc_funcs->lf_speed) (sc, LPT_STROBE_SLOW);
202
203 /* wait till ready (printer running diagnostics) */
204 for (spin = 0; (sc->sc_funcs->lf_notrdy) (sc, 1); spin += STEP) {
205 if (spin >= TIMEOUT) {
206 sc->sc_state = 0;
207 return (EBUSY);
208 }
209 /* wait 1/4 second, give up if we get a signal */
210 error = tsleep((caddr_t) sc, LPTPRI | PCATCH, "lptopen", STEP);
211 if (error != EWOULDBLOCK) {
212 sc->sc_state = 0;
213 return (error);
214 }
215 }
216
217 sc->sc_inbuf = geteblk(LPT_BSIZE);
218 sc->sc_count = 0;
219 sc->sc_state = LPT_OPEN;
220
221 if ((sc->sc_flags & LPT_NOINTR) == 0)
222 lpt_wakeup(sc);
223
224 (sc->sc_funcs->lf_open) (sc, sc->sc_flags & LPT_NOINTR);
225
226 LPRINTF(("%s: opened\n", sc->sc_dev.dv_xname));
227 return (0);
228 }
229
230 void
231 lpt_wakeup(arg)
232 void *arg;
233 {
234 struct lpt_softc *sc;
235 int s;
236
237 sc = arg;
238
239 s = spltty();
240 lpt_intr(sc);
241 splx(s);
242
243 callout_reset(&sc->sc_wakeup_ch, STEP, lpt_wakeup, sc);
244 }
245
246 /*
247 * Close the device, and free the local line buffer.
248 */
249 int
250 lptclose(dev, flag, mode, p)
251 dev_t dev;
252 int flag;
253 int mode;
254 struct proc *p;
255 {
256 struct lpt_softc *sc;
257 int unit;
258
259 unit = LPTUNIT(dev);
260 sc = lpt_cd.cd_devs[unit];
261
262 if (sc->sc_count)
263 (void) pushbytes(sc);
264
265 if ((sc->sc_flags & LPT_NOINTR) == 0)
266 callout_stop(&sc->sc_wakeup_ch);
267
268 (sc->sc_funcs->lf_close) (sc);
269
270 sc->sc_state = 0;
271 brelse(sc->sc_inbuf);
272
273 LPRINTF(("%s: closed\n", sc->sc_dev.dv_xname));
274 return (0);
275 }
276
277 int
278 pushbytes(sc)
279 struct lpt_softc *sc;
280 {
281 int s, error, spin, tic;
282
283 if (sc->sc_flags & LPT_NOINTR) {
284 while (sc->sc_count > 0) {
285 spin = 0;
286 while ((sc->sc_funcs->lf_notrdy) (sc, 0)) {
287 if (++spin < sc->sc_spinmax)
288 continue;
289 tic = 0;
290 /* adapt busy-wait algorithm */
291 sc->sc_spinmax++;
292 while ((sc->sc_funcs->lf_notrdy) (sc, 1)) {
293 /* exponential backoff */
294 tic = tic + tic + 1;
295 if (tic > TIMEOUT)
296 tic = TIMEOUT;
297 error = tsleep((caddr_t) sc,
298 LPTPRI | PCATCH, "lptpsh", tic);
299 if (error != EWOULDBLOCK)
300 return (error);
301 }
302 break;
303 }
304
305 (sc->sc_funcs->lf_wrdata) (sc, *sc->sc_cp++);
306 sc->sc_count--;
307
308 /* adapt busy-wait algorithm */
309 if (spin * 2 + 16 < sc->sc_spinmax)
310 sc->sc_spinmax--;
311 }
312 } else {
313 while (sc->sc_count > 0) {
314 /* if the printer is ready for a char, give it one */
315 if ((sc->sc_state & LPT_OBUSY) == 0) {
316 LPRINTF(("%s: write %d\n", sc->sc_dev.dv_xname,
317 sc->sc_count));
318 s = spltty();
319 (void) lpt_intr(sc);
320 splx(s);
321 }
322 error = tsleep((caddr_t) sc, LPTPRI | PCATCH,
323 "lptwrite2", 0);
324 if (error)
325 return (error);
326 }
327 }
328 return (0);
329 }
330
331 /*
332 * Copy a line from user space to a local buffer, then call putc to get the
333 * chars moved to the output queue.
334 */
335 int
336 lptwrite(dev, uio, flags)
337 dev_t dev;
338 struct uio *uio;
339 int flags;
340 {
341 struct lpt_softc *sc;
342 size_t n;
343 int error;
344
345 sc = lpt_cd.cd_devs[LPTUNIT(dev)];
346 error = 0;
347
348 while ((n = min(LPT_BSIZE, uio->uio_resid)) != 0) {
349 uiomove(sc->sc_cp = sc->sc_inbuf->b_data, n, uio);
350 sc->sc_count = n;
351 error = pushbytes(sc);
352 if (error) {
353 /*
354 * Return accurate residual if interrupted or timed
355 * out.
356 */
357 uio->uio_resid += sc->sc_count;
358 sc->sc_count = 0;
359 return (error);
360 }
361 }
362 return (0);
363 }
364
365 /*
366 * Handle printer interrupts which occur when the printer is ready to accept
367 * another char.
368 */
369 int
370 lpt_intr(sc)
371 struct lpt_softc *sc;
372 {
373
374 if (sc->sc_count) {
375 /* send char */
376 (sc->sc_funcs->lf_wrdata) (sc, *sc->sc_cp++);
377 sc->sc_count--;
378 sc->sc_state |= LPT_OBUSY;
379 } else
380 sc->sc_state &= ~LPT_OBUSY;
381
382 if (sc->sc_count == 0) {
383 /* none, wake up the top half to get more */
384 wakeup((caddr_t) sc);
385 }
386
387 return (1);
388 }
389
390 /* ARGSUSED */
391 int
392 lptioctl(dev, cmd, data, flag, p)
393 dev_t dev;
394 u_long cmd;
395 caddr_t data;
396 int flag;
397 struct proc *p;
398 {
399
400 return (ENODEV);
401 }
Cache object: 6ed93fc7caca0a32088eed20e9bea36c
|