lpt.c revision 1.7.4.6 1 /*
2 * Copyright (c) 1993 Charles Hannum
3 * Copyright (c) 1990 William F. Jolitz, TeleMuse
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. All advertising materials mentioning features or use of this software
15 * must display the following acknowledgement:
16 * This software is a component of "386BSD" developed by
17 * William F. Jolitz, TeleMuse.
18 * 4. Neither the name of the developer nor the name "386BSD"
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
21 *
22 * THIS SOFTWARE IS A COMPONENT OF 386BSD DEVELOPED BY WILLIAM F. JOLITZ
23 * AND IS INTENDED FOR RESEARCH AND EDUCATIONAL PURPOSES ONLY. THIS
24 * SOFTWARE SHOULD NOT BE CONSIDERED TO BE A COMMERCIAL PRODUCT.
25 * THE DEVELOPER URGES THAT USERS WHO REQUIRE A COMMERCIAL PRODUCT
26 * NOT MAKE USE OF THIS WORK.
27 *
28 * FOR USERS WHO WISH TO UNDERSTAND THE 386BSD SYSTEM DEVELOPED
29 * BY WILLIAM F. JOLITZ, WE RECOMMEND THE USER STUDY WRITTEN
30 * REFERENCES SUCH AS THE "PORTING UNIX TO THE 386" SERIES
31 * (BEGINNING JANUARY 1991 "DR. DOBBS JOURNAL", USA AND BEGINNING
32 * JUNE 1991 "UNIX MAGAZIN", GERMANY) BY WILLIAM F. JOLITZ AND
33 * LYNNE GREER JOLITZ, AS WELL AS OTHER BOOKS ON UNIX AND THE
34 * ON-LINE 386BSD USER MANUAL BEFORE USE. A BOOK DISCUSSING THE INTERNALS
35 * OF 386BSD ENTITLED "386BSD FROM THE INSIDE OUT" WILL BE AVAILABLE LATE 1992.
36 *
37 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPER ``AS IS'' AND
38 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
39 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
40 * ARE DISCLAIMED. IN NO EVENT SHALL THE DEVELOPER BE LIABLE
41 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
42 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
43 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
44 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
45 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
46 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
47 * SUCH DAMAGE.
48 *
49 * $Id: lpt.c,v 1.7.4.6 1993/10/06 12:10:53 mycroft Exp $
50 */
51
52 /*
53 * Device Driver for AT parallel printer port
54 */
55
56 #include "param.h"
57 #include "systm.h"
58 #include "proc.h"
59 #include "user.h"
60 #include "buf.h"
61 #include "kernel.h"
62 #include "ioctl.h"
63 #include "uio.h"
64 #include "sys/device.h"
65 #include "machine/cpu.h"
66
67 #include "i386/isa/isavar.h"
68 #include "i386/isa/isa.h"
69 #include "i386/isa/icu.h"
70 #include "i386/isa/lptreg.h"
71
72 #define TIMEOUT hz*16 /* wait up to 4 seconds for a ready */
73 #define STEP hz/4
74
75 #define MAX_SPIN 255
76
77 #define LPTPRI (PZERO+8)
78 #define LPT_BSIZE 1024
79
80 #ifndef DEBUG
81 #define lprintf
82 #else
83 #define lprintf if (lptdebug) printf
84 int lptdebug = 1;
85 #endif
86
87 struct lpt_softc {
88 struct device sc_dev;
89 struct isadev sc_id;
90 struct intrhand sc_ih;
91
92 size_t sc_count;
93 struct buf *sc_inbuf;
94 u_char *sc_cp ;
95 u_short sc_iobase;
96 u_short sc_irq;
97 u_char sc_state;
98 /* bits for state */
99 #define LPT_OPEN 0x01 /* device is open */
100 #define LPT_OBUSY 0x02 /* printer is busy doing output */
101 #define LPT_INIT 0x04 /* waiting to initialize for open */
102 u_char sc_flags;
103 #define LPT_AUTOLF 0x20 /* automatic LF on CR */
104 #define LPT_NOPRIME 0x40 /* don't prime on open */
105 #define LPT_NOINTR 0x80 /* do not use interrupt */
106 u_char sc_control;
107 u_char sc_smax;
108 };
109
110 static int lptprobe __P((struct device *, struct cfdata *, void *));
111 static void lptforceintr __P((void *));
112 static void lptattach __P((struct device *, struct device *, void *));
113 static int lptintr __P((void *));
114
115 struct cfdriver lptcd =
116 { NULL, "lpt", lptprobe, lptattach, sizeof(struct lpt_softc) };
117
118 #define LPTUNIT(s) ((s)&0x1f)
119 #define LPTFLAGS(s) ((s)&0xe0)
120
121 #define LPS_INVERT (LPS_SELECT|LPS_NERR|LPS_NBSY|LPS_NACK)
122 #define LPS_MASK (LPS_SELECT|LPS_NERR|LPS_NBSY|LPS_NACK|LPS_NOPAPER)
123 #define NOT_READY() ((inb(iobase + lpt_status) ^ LPS_INVERT) & LPS_MASK)
124
125 static void lptout __P((struct lpt_softc *));
126 static int pushbytes __P((struct lpt_softc *));
127
128 /*
129 * Internal routine to lptprobe to do port tests of one byte value
130 */
131 int
132 lpt_port_test(port, data, mask)
133 u_short port;
134 u_char data, mask;
135 {
136 int timeout;
137 u_char temp;
138
139 data &= mask;
140 outb(port, data);
141 timeout = 100;
142 do {
143 temp = inb(port) & mask;
144 } while (temp != data && --timeout);
145 lprintf("lpt: port=0x%x out=0x%x in=0x%x\n", port, data, temp);
146 return (temp == data);
147 }
148
149 /*
150 * Logic:
151 * 1) You should be able to write to and read back the same value
152 * to the data port. Do an alternating zeros, alternating ones,
153 * walking zero, and walking one test to check for stuck bits.
154 *
155 * 2) You should be able to write to and read back the same value
156 * to the control port lower 5 bits, the upper 3 bits are reserved
157 * per the IBM PC technical reference manauls and different boards
158 * do different things with them. Do an alternating zeros, alternating
159 * ones, walking zero, and walking one test to check for stuck bits.
160 *
161 * Some printers drag the strobe line down when the are powered off
162 * so this bit has been masked out of the control port test.
163 *
164 * XXX Some printers may not like a fast pulse on init or strobe, I
165 * don't know at this point, if that becomes a problem these bits
166 * should be turned off in the mask byte for the control port test.
167 *
168 * 3) Set the data and control ports to a value of 0
169 */
170
171 static int
172 lptprobe(parent, cf, aux)
173 struct device *parent;
174 struct cfdata *cf;
175 void *aux;
176 {
177 struct isa_attach_args *ia = aux;
178 u_short iobase = ia->ia_iobase;
179 u_short port = iobase + lpt_data;
180 u_char mask = 0xff;
181 u_char data;
182 int i;
183
184 if (iobase == IOBASEUNK)
185 return 0;
186
187 for (;;) {
188 data = 0x55; /* Alternating zeros */
189 if (!lpt_port_test(port, data, mask))
190 return 0;
191
192 data = 0xaa; /* Alternating ones */
193 if (!lpt_port_test(port, data, mask))
194 return 0;
195
196 for (i = 0; i < CHAR_BIT; i++) { /* Walking zero */
197 data = ~(1 << i);
198 if (!lpt_port_test(port, data, mask))
199 return 0;
200 }
201
202 for (i = 0; i < CHAR_BIT; i++) { /* Walking one */
203 data = (1 << i);
204 if (!lpt_port_test(port, data, mask))
205 return 0;
206 }
207
208 if (port == iobase + lpt_data) {
209 port = iobase + lpt_control;
210 mask = 0x1e;
211 } else
212 break;
213 }
214 outb(iobase + lpt_data, 0);
215 outb(iobase + lpt_control, 0);
216
217 if (ia->ia_irq == IRQUNK)
218 ia->ia_irq = isa_discoverintr(lptforceintr, aux);
219 /* okay if we don't have an irq; will force polling */
220
221 ia->ia_iosize = LPT_NPORTS;
222 ia->ia_drq = DRQUNK;
223 ia->ia_msize = 0;
224 return 1;
225 }
226
227 static void
228 lptattach(parent, self, aux)
229 struct device *parent, *self;
230 void *aux;
231 {
232 struct isa_attach_args *ia = aux;
233 struct lpt_softc *sc = (struct lpt_softc *)self;
234 u_short iobase = ia->ia_iobase;
235 u_short irq = ia->ia_irq;
236
237 sc->sc_iobase = iobase;
238 sc->sc_irq = irq;
239 sc->sc_state = 0;
240 outb(iobase + lpt_control, LPC_NINIT);
241
242 printf(": %sparallel port\n", irq == IRQNONE ? "polled " : "");
243 isa_establish(&sc->sc_id, &sc->sc_dev);
244
245 if (irq != IRQNONE) {
246 sc->sc_ih.ih_fun = lptintr;
247 sc->sc_ih.ih_arg = sc;
248 intr_establish(ia->ia_irq, &sc->sc_ih, DV_TTY);
249 }
250 }
251
252 /*
253 * lptopen -- reset the printer, then wait until it's selected and not busy.
254 */
255 int
256 lptopen(dev, flag)
257 dev_t dev;
258 int flag;
259 {
260 int unit = LPTUNIT(minor(dev));
261 u_char flags = LPTFLAGS(minor(dev));
262 struct lpt_softc *sc;
263 u_short iobase;
264 u_char control;
265 int error;
266 int spin;
267
268 if (unit >= lptcd.cd_ndevs)
269 return ENXIO;
270 sc = lptcd.cd_devs[unit];
271 if (!sc)
272 return ENXIO;
273
274 if (sc->sc_irq == IRQNONE && (flags & LPT_NOINTR) == 0)
275 return ENXIO;
276
277 if (sc->sc_state)
278 return EBUSY;
279
280 #ifdef DIAGNOSTIC
281 if (sc->sc_state)
282 printf("lpt%d: state=0x%x not zero\n", unit, sc->sc_state);
283 #endif
284
285 sc->sc_state = LPT_INIT;
286
287 sc->sc_flags = flags;
288 lprintf("lpt%d: open flags=0x%x\n", unit, flags);
289 iobase = sc->sc_iobase;
290
291 if ((flags & LPT_NOPRIME) == 0) {
292 /* assert INIT for 100 usec to start up printer */
293 outb(iobase + lpt_control, LPC_SELECT);
294 delay(100);
295 }
296
297 control = LPC_SELECT | LPC_NINIT;
298 outb(iobase + lpt_control, control);
299
300 /* wait till ready (printer running diagnostics) */
301 for (spin = 0; NOT_READY(); spin += STEP) {
302 if (spin >= TIMEOUT) {
303 sc->sc_state = 0;
304 return EBUSY;
305 }
306
307 /* wait 1/4 second, give up if we get a signal */
308 if (error = tsleep((caddr_t)sc,
309 LPTPRI | PCATCH, "lptopen", STEP) != EWOULDBLOCK) {
310 sc->sc_state = 0;
311 return error;
312 }
313 }
314
315 if ((flags & LPT_NOINTR) == 0)
316 control |= LPC_IENABLE;
317 if (flags & LPT_AUTOLF)
318 control |= LPC_AUTOLF;
319 sc->sc_control = control;
320 outb(iobase + lpt_control, control);
321
322 sc->sc_state = LPT_OPEN;
323 sc->sc_inbuf = geteblk(LPT_BSIZE);
324 sc->sc_count = 0;
325 lptout(sc);
326
327 lprintf("lpt%d: opened\n", unit);
328 return 0;
329 }
330
331 static void
332 lptout(sc)
333 struct lpt_softc *sc;
334 {
335 int s;
336
337 if ((sc->sc_state & LPT_OPEN) == 0)
338 return;
339 if (sc->sc_flags & LPT_NOINTR)
340 return;
341
342 /*
343 * Avoid possible hangs due to missed interrupts
344 */
345 if (sc->sc_count) {
346 s = spltty();
347 lptintr(sc);
348 splx(s);
349 } else {
350 sc->sc_state &= ~LPT_OBUSY;
351 wakeup((caddr_t)sc);
352 }
353
354 timeout((timeout_t)lptout, (caddr_t)sc, STEP);
355 }
356
357 /*
358 * lptclose -- close the device, free the local line buffer.
359 */
360 int
361 lptclose(dev, flag)
362 dev_t dev;
363 int flag;
364 {
365 int unit = LPTUNIT(minor(dev));
366 struct lpt_softc *sc = lptcd.cd_devs[unit];
367 u_short iobase = sc->sc_iobase;
368 int error;
369
370 if (error = pushbytes(sc))
371 return error;
372
373 outb(iobase + lpt_control, LPC_NINIT);
374 brelse(sc->sc_inbuf);
375 sc->sc_state = 0;
376
377 lprintf("lpt%d: closed\n", unit);
378 return 0;
379 }
380
381 static int
382 pushbytes(sc)
383 struct lpt_softc *sc;
384 {
385 u_short iobase = sc->sc_iobase;
386 int error;
387
388 if (sc->sc_flags & LPT_NOINTR) {
389 int spin, tic;
390 u_char control = sc->sc_control;
391 u_char ch;
392
393 while (sc->sc_count > 0) {
394 spin = tic = 0;
395 while (NOT_READY())
396 if (++spin >= sc->sc_smax) {
397 /* exponential backoff */
398 tic = tic + tic + 1;
399 if (error = tsleep((caddr_t)sc,
400 LPTPRI | PCATCH, "lptwrite1", tic))
401 return error;
402 }
403
404 outb(iobase + lpt_data, *sc->sc_cp++);
405 outb(iobase + lpt_control, control | LPC_STROBE);
406 sc->sc_count--;
407 outb(iobase + lpt_control, control);
408
409 /* adapt busy-wait algorithm */
410 if (spin >= sc->sc_smax && sc->sc_smax < MAX_SPIN)
411 sc->sc_smax++;
412 if (spin*2 < sc->sc_smax)
413 sc->sc_smax--;
414 }
415 } else {
416 int s;
417
418 while (sc->sc_count > 0) {
419 /* if the printer is ready for a char, give it one */
420 if ((sc->sc_state & LPT_OBUSY) == 0) {
421 lprintf("lpt%d: write %d\n", sc->sc_count);
422 s = spltty();
423 lptintr(sc);
424 splx(s);
425 }
426 if (error = tsleep((caddr_t)sc,
427 LPTPRI | PCATCH, "lptwrite2", 0))
428 return error;
429 }
430 }
431 }
432
433 /*
434 * copy a line from user space to a local buffer, then call
435 * putc to get the chars moved to the output queue.
436 */
437 int
438 lptwrite(dev, uio)
439 dev_t dev;
440 struct uio *uio;
441 {
442 int unit = LPTUNIT(minor(dev));
443 struct lpt_softc *sc = lptcd.cd_devs[unit];
444 size_t n;
445 int error = 0;
446
447 while (n = MIN(LPT_BSIZE, uio->uio_resid)) {
448 uiomove(sc->sc_cp = sc->sc_inbuf->b_un.b_addr, n, uio);
449 sc->sc_count = n;
450 error = pushbytes(sc);
451 if (error) {
452 /* return accurate residual if interrupted or
453 timed out */
454 uio->uio_resid += sc->sc_count;
455 sc->sc_count = 0;
456 return error;
457 }
458 }
459 return 0;
460 }
461
462 /*
463 * lptintr -- handle printer interrupts which occur when the printer is
464 * ready to accept another char.
465 */
466 static int
467 lptintr(arg)
468 void *arg;
469 {
470 struct lpt_softc *sc = (struct lpt_softc *)arg;
471 u_short iobase = sc->sc_iobase;
472 u_char control = sc->sc_control;
473 u_char status;
474
475 if ((sc->sc_state & LPT_OPEN) == 0)
476 return 0;
477
478 /* is printer online and ready for output */
479 if (!NOT_READY()) {
480 if (sc->sc_count) {
481 /* send char */
482 sc->sc_state |= LPT_OBUSY;
483 while (sc->sc_count &&
484 (inb(iobase + lpt_status) & LPS_NBSY) == 0) {
485 outb(iobase + lpt_data, *sc->sc_cp++);
486 outb(iobase + lpt_control, control | LPC_STROBE);
487 sc->sc_count--;
488 outb(iobase + lpt_control, control);
489 }
490 } else {
491 /* none, wake up the top half to get more */
492 sc->sc_state &= ~LPT_OBUSY;
493 wakeup((caddr_t)sc);
494 }
495 }
496
497 return 1;
498 }
499
500 int
501 lptioctl(dev, cmd, data, flag)
502 dev_t dev;
503 int cmd;
504 caddr_t data;
505 int flag;
506 {
507 int error = 0;
508
509 switch (cmd) {
510 default:
511 error = ENODEV;
512 }
513
514 return error;
515 }
516