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