lpt.c revision 1.35 1 /* $NetBSD: lpt.c,v 1.35 1996/03/18 09:14:32 cgd 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 lptclose(dev, flag)
397 dev_t dev;
398 int flag;
399 {
400 int unit = LPTUNIT(dev);
401 struct lpt_softc *sc = lpt_cd.cd_devs[unit];
402 bus_chipset_tag_t bc = sc->sc_bc;
403 bus_io_handle_t ioh = sc->sc_ioh;
404
405 if (sc->sc_count)
406 (void) pushbytes(sc);
407
408 if ((sc->sc_flags & LPT_NOINTR) == 0)
409 untimeout(lptwakeup, sc);
410
411 bus_io_write_1(bc, ioh, lpt_control, LPC_NINIT);
412 sc->sc_state = 0;
413 bus_io_write_1(bc, ioh, lpt_control, LPC_NINIT);
414 brelse(sc->sc_inbuf);
415
416 lprintf("%s: closed\n", sc->sc_dev.dv_xname);
417 return 0;
418 }
419
420 int
421 pushbytes(sc)
422 struct lpt_softc *sc;
423 {
424 bus_chipset_tag_t bc = sc->sc_bc;
425 bus_io_handle_t ioh = sc->sc_ioh;
426 int error;
427
428 if (sc->sc_flags & LPT_NOINTR) {
429 int spin, tic;
430 u_char control = sc->sc_control;
431
432 while (sc->sc_count > 0) {
433 spin = 0;
434 while (NOT_READY()) {
435 if (++spin < sc->sc_spinmax)
436 continue;
437 tic = 0;
438 /* adapt busy-wait algorithm */
439 sc->sc_spinmax++;
440 while (NOT_READY_ERR()) {
441 /* exponential backoff */
442 tic = tic + tic + 1;
443 if (tic > TIMEOUT)
444 tic = TIMEOUT;
445 error = tsleep((caddr_t)sc,
446 LPTPRI | PCATCH, "lptpsh", tic);
447 if (error != EWOULDBLOCK)
448 return error;
449 }
450 break;
451 }
452
453 bus_io_write_1(bc, ioh, lpt_data, *sc->sc_cp++);
454 bus_io_write_1(bc, ioh, lpt_control, control | LPC_STROBE);
455 sc->sc_count--;
456 bus_io_write_1(bc, ioh, lpt_control, control);
457
458 /* adapt busy-wait algorithm */
459 if (spin*2 + 16 < sc->sc_spinmax)
460 sc->sc_spinmax--;
461 }
462 } else {
463 int s;
464
465 while (sc->sc_count > 0) {
466 /* if the printer is ready for a char, give it one */
467 if ((sc->sc_state & LPT_OBUSY) == 0) {
468 lprintf("%s: write %d\n", sc->sc_dev.dv_xname,
469 sc->sc_count);
470 s = spltty();
471 (void) lptintr(sc);
472 splx(s);
473 }
474 if (error = tsleep((caddr_t)sc, LPTPRI | PCATCH,
475 "lptwrite2", 0))
476 return error;
477 }
478 }
479 return 0;
480 }
481
482 /*
483 * Copy a line from user space to a local buffer, then call putc to get the
484 * chars moved to the output queue.
485 */
486 lptwrite(dev, uio)
487 dev_t dev;
488 struct uio *uio;
489 {
490 struct lpt_softc *sc = lpt_cd.cd_devs[LPTUNIT(dev)];
491 size_t n;
492 int error = 0;
493
494 while (n = min(LPT_BSIZE, uio->uio_resid)) {
495 uiomove(sc->sc_cp = sc->sc_inbuf->b_data, n, uio);
496 sc->sc_count = n;
497 error = pushbytes(sc);
498 if (error) {
499 /*
500 * Return accurate residual if interrupted or timed
501 * out.
502 */
503 uio->uio_resid += sc->sc_count;
504 sc->sc_count = 0;
505 return error;
506 }
507 }
508 return 0;
509 }
510
511 /*
512 * Handle printer interrupts which occur when the printer is ready to accept
513 * another char.
514 */
515 int
516 lptintr(arg)
517 void *arg;
518 {
519 struct lpt_softc *sc = arg;
520 bus_chipset_tag_t bc = sc->sc_bc;
521 bus_io_handle_t ioh = sc->sc_ioh;
522
523 #if 0
524 if ((sc->sc_state & LPT_OPEN) == 0)
525 return 0;
526 #endif
527
528 /* is printer online and ready for output */
529 if (NOT_READY() && NOT_READY_ERR())
530 return 0;
531
532 if (sc->sc_count) {
533 u_char control = sc->sc_control;
534 /* send char */
535 bus_io_write_1(bc, ioh, lpt_data, *sc->sc_cp++);
536 bus_io_write_1(bc, ioh, lpt_control, control | LPC_STROBE);
537 sc->sc_count--;
538 bus_io_write_1(bc, ioh, lpt_control, control);
539 sc->sc_state |= LPT_OBUSY;
540 } else
541 sc->sc_state &= ~LPT_OBUSY;
542
543 if (sc->sc_count == 0) {
544 /* none, wake up the top half to get more */
545 wakeup((caddr_t)sc);
546 }
547
548 return 1;
549 }
550
551 int
552 lptioctl(dev, cmd, data, flag)
553 dev_t dev;
554 u_long cmd;
555 caddr_t data;
556 int flag;
557 {
558 int error = 0;
559
560 switch (cmd) {
561 default:
562 error = ENODEV;
563 }
564
565 return error;
566 }
567