lpt.c revision 1.7.4.5 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.5 1993/10/01 00:38:54 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_SEL|LPS_NERR|LPS_NBSY|LPS_NACK)
122 #define LPS_MASK (LPS_SEL|LPS_NERR|LPS_NBSY|LPS_NACK|LPS_OUT)
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 delay;
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 /* XXXX mask or unmask interrupt */
281
282 #ifdef DIAGNOSTIC
283 if (sc->sc_state)
284 printf("lpt%d: state=0x%x not zero\n", unit, sc->sc_state);
285 #endif
286
287 sc->sc_state = LPT_INIT;
288
289 sc->sc_flags = flags;
290 lprintf("lpt%d: open flags=0x%x\n", unit, flags);
291 iobase = sc->sc_iobase;
292
293 if ((flags & LPT_NOPRIME) == 0)
294 outb(iobase + lpt_control, 0);
295
296 outb(iobase + lpt_control, LPC_SEL|LPC_NINIT);
297
298 /* wait till ready (printer running diagnostics) */
299 for (delay = 0; NOT_READY(); delay += STEP) {
300 if (delay >= TIMEOUT) {
301 sc->sc_state = 0;
302 return EBUSY;
303 }
304
305 /* wait 1/4 second, give up if we get a signal */
306 if (error = tsleep((caddr_t)sc,
307 LPTPRI|PCATCH, "lptopen", STEP) != EWOULDBLOCK) {
308 sc->sc_state = 0;
309 return error;
310 }
311 }
312
313 control = LPC_SEL|LPC_NINIT|LPC_ENA;
314 if (sc->sc_flags & LPT_AUTOLF)
315 control |= LPC_AUTOL;
316 sc->sc_control = control;
317 outb(iobase + lpt_control, control);
318
319 sc->sc_state = LPT_OPEN;
320 sc->sc_inbuf = geteblk(LPT_BSIZE);
321 sc->sc_count = 0;
322 lptout(sc);
323
324 lprintf("lpt%d: opened\n", unit);
325 return 0;
326 }
327
328 static void
329 lptout(sc)
330 struct lpt_softc *sc;
331 {
332 int s;
333
334 if ((sc->sc_state & LPT_OPEN) == 0)
335 return;
336 if (sc->sc_flags & LPT_NOINTR)
337 return;
338
339 /*
340 * Avoid possible hangs due to missed interrupts
341 */
342 if (sc->sc_count) {
343 s = spltty();
344 lptintr(sc);
345 splx(s);
346 } else {
347 sc->sc_state &= ~LPT_OBUSY;
348 wakeup((caddr_t)sc);
349 }
350
351 timeout((timeout_t)lptout, (caddr_t)sc, STEP);
352 }
353
354 /*
355 * lptclose -- close the device, free the local line buffer.
356 */
357 int
358 lptclose(dev, flag)
359 dev_t dev;
360 int flag;
361 {
362 int unit = LPTUNIT(minor(dev));
363 struct lpt_softc *sc = lptcd.cd_devs[unit];
364 u_short iobase = sc->sc_iobase;
365 int error;
366
367 if (error = pushbytes(sc))
368 return error;
369
370 outb(iobase + lpt_control, LPC_NINIT);
371 brelse(sc->sc_inbuf);
372 sc->sc_state = 0;
373
374 lprintf("lpt%d: closed\n", unit);
375 return 0;
376 }
377
378 static int
379 pushbytes(sc)
380 struct lpt_softc *sc;
381 {
382 u_short iobase = sc->sc_iobase;
383 int error;
384
385 if (sc->sc_flags & LPT_NOINTR) {
386 int spin, tic;
387 u_char control = sc->sc_control;
388 u_char ch;
389
390 while (sc->sc_count > 0) {
391 spin = tic = 0;
392 while (NOT_READY())
393 if (++spin >= sc->sc_smax) {
394 /* exponential backoff */
395 tic = tic + tic + 1;
396 if (error = tsleep((caddr_t)sc,
397 LPTPRI|PCATCH, "lptwrite1", tic))
398 return error;
399 }
400
401 outb(iobase + lpt_data, *sc->sc_cp++);
402 outb(iobase + lpt_control, control|LPC_STB);
403 outb(iobase + lpt_control, control);
404 sc->sc_count--;
405
406 /* adapt busy-wait algorithm */
407 if (spin >= sc->sc_smax && sc->sc_smax < MAX_SPIN)
408 sc->sc_smax++;
409 if (spin*2 < sc->sc_smax)
410 sc->sc_smax--;
411 }
412 } else {
413 int s;
414
415 while (sc->sc_count > 0) {
416 /* if the printer is ready for a char, give it one */
417 if ((sc->sc_state & LPT_OBUSY) == 0) {
418 lprintf("lpt%d: write %d\n", sc->sc_count);
419 s = spltty();
420 lptintr(sc);
421 splx(s);
422 }
423 if (error = tsleep((caddr_t)sc,
424 LPTPRI|PCATCH, "lptwrite2", 0))
425 return error;
426 }
427 }
428 }
429
430 /*
431 * copy a line from user space to a local buffer, then call
432 * putc to get the chars moved to the output queue.
433 */
434 int
435 lptwrite(dev, uio)
436 dev_t dev;
437 struct uio *uio;
438 {
439 int unit = LPTUNIT(minor(dev));
440 struct lpt_softc *sc = lptcd.cd_devs[unit];
441 size_t n;
442 int error = 0;
443
444 while (n = MIN(LPT_BSIZE, uio->uio_resid)) {
445 uiomove(sc->sc_cp = sc->sc_inbuf->b_un.b_addr, n, uio);
446 sc->sc_count = n;
447 error = pushbytes(sc);
448 if (error) {
449 /* return accurate residual if interrupted or
450 timed out */
451 uio->uio_resid += sc->sc_count;
452 sc->sc_count = 0;
453 return error;
454 }
455 }
456 return 0;
457 }
458
459 /*
460 * lptintr -- handle printer interrupts which occur when the printer is
461 * ready to accept another char.
462 */
463 static int
464 lptintr(arg)
465 void *arg;
466 {
467 struct lpt_softc *sc = (struct lpt_softc *)arg;
468 u_short iobase = sc->sc_iobase;
469 u_char control = sc->sc_control;
470 u_char status;
471
472 if ((sc->sc_state & LPT_OPEN) == 0)
473 return 0;
474
475 /* is printer online and ready for output */
476 if (!NOT_READY()) {
477 if (sc->sc_count) {
478 /* send char */
479 sc->sc_state |= LPT_OBUSY;
480 outb(iobase + lpt_data, *sc->sc_cp++);
481 outb(iobase + lpt_control, control|LPC_STB);
482 outb(iobase + lpt_control, control);
483 sc->sc_count--;
484 } else {
485 /* none, wake up the top half to get more */
486 sc->sc_state &= ~LPT_OBUSY;
487 wakeup((caddr_t)sc);
488 }
489 }
490
491 /* XXX possibly a more useful return value */
492 return 1;
493 }
494
495 int
496 lptioctl(dev, cmd, data, flag)
497 dev_t dev;
498 int cmd;
499 caddr_t data;
500 int flag;
501 {
502 int error = 0;
503
504 switch (cmd) {
505 default:
506 error = ENODEV;
507 }
508
509 return error;
510 }
511