|
|
1.1 root 1: /*
2: * Copyright (c) 1990 William F. Jolitz, TeleMuse
3: * All rights reserved.
4: *
5: * Redistribution and use in source and binary forms, with or without
6: * modification, are permitted provided that the following conditions
7: * are met:
8: * 1. Redistributions of source code must retain the above copyright
9: * notice, this list of conditions and the following disclaimer.
10: * 2. Redistributions in binary form must reproduce the above copyright
11: * notice, this list of conditions and the following disclaimer in the
12: * documentation and/or other materials provided with the distribution.
13: * 3. All advertising materials mentioning features or use of this software
14: * must display the following acknowledgement:
15: * This software is a component of "386BSD" developed by
16: * William F. Jolitz, TeleMuse.
17: * 4. Neither the name of the developer nor the name "386BSD"
18: * may be used to endorse or promote products derived from this software
19: * without specific prior written permission.
20: *
21: * THIS SOFTWARE IS A COMPONENT OF 386BSD DEVELOPED BY WILLIAM F. JOLITZ
22: * AND IS INTENDED FOR RESEARCH AND EDUCATIONAL PURPOSES ONLY. THIS
23: * SOFTWARE SHOULD NOT BE CONSIDERED TO BE A COMMERCIAL PRODUCT.
24: * THE DEVELOPER URGES THAT USERS WHO REQUIRE A COMMERCIAL PRODUCT
25: * NOT MAKE USE OF THIS WORK.
26: *
27: * FOR USERS WHO WISH TO UNDERSTAND THE 386BSD SYSTEM DEVELOPED
28: * BY WILLIAM F. JOLITZ, WE RECOMMEND THE USER STUDY WRITTEN
29: * REFERENCES SUCH AS THE "PORTING UNIX TO THE 386" SERIES
30: * (BEGINNING JANUARY 1991 "DR. DOBBS JOURNAL", USA AND BEGINNING
31: * JUNE 1991 "UNIX MAGAZIN", GERMANY) BY WILLIAM F. JOLITZ AND
32: * LYNNE GREER JOLITZ, AS WELL AS OTHER BOOKS ON UNIX AND THE
33: * ON-LINE 386BSD USER MANUAL BEFORE USE. A BOOK DISCUSSING THE INTERNALS
34: * OF 386BSD ENTITLED "386BSD FROM THE INSIDE OUT" WILL BE AVAILABLE LATE 1992.
35: *
36: * THIS SOFTWARE IS PROVIDED BY THE DEVELOPER ``AS IS'' AND
37: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
38: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
39: * ARE DISCLAIMED. IN NO EVENT SHALL THE DEVELOPER BE LIABLE
40: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
41: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
42: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
43: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
44: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
45: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
46: * SUCH DAMAGE.
47: *
1.1.1.2 ! root 48: * lpt.c,v 1.7 1993/07/17 16:20:32 mycroft Exp
1.1 root 49: */
50:
51: /*
52: * Device Driver for AT parallel printer port
53: * Written by William Jolitz 12/18/90
1.1.1.2 ! root 54: *
! 55: * Hacked heavily by Rod Grimes and Eric Haug...
1.1 root 56: */
57:
58: #include "lpt.h"
59: #if NLPT > 0
60:
61: #include "param.h"
1.1.1.2 ! root 62: #include "systm.h"
! 63: #include "proc.h"
1.1 root 64: #include "user.h"
65: #include "buf.h"
66: #include "kernel.h"
67: #include "ioctl.h"
68: #include "tty.h"
69: #include "uio.h"
70:
1.1.1.2 ! root 71: #include "i386/isa/isa.h"
1.1 root 72: #include "i386/isa/isa_device.h"
73: #include "i386/isa/lptreg.h"
74:
75: #define LPINITRDY 4 /* wait up to 4 seconds for a ready */
76: #define LPTOUTTIME 4 /* wait up to 4 seconds for a ready */
77: #define LPPRI (PZERO+8)
78: #define BUFSIZE 1024
79:
80: #ifndef DEBUG
81: #define lprintf
82: #else
1.1.1.2 ! root 83: #define lprintf if (lptflag) printf
! 84: int lptflag = 1;
1.1 root 85: #endif
86:
87: int lptout();
88: #ifdef DEBUG
1.1.1.2 ! root 89: int lptflag = 1;
1.1 root 90: #endif
91:
92: int lptprobe(), lptattach(), lptintr();
93:
94: struct isa_driver lptdriver = {
95: lptprobe, lptattach, "lpt"
96: };
97:
98: #define LPTUNIT(s) (((s)>>6)&0x3)
99: #define LPTFLAGS(s) ((s)&0x3f)
100:
101: struct lpt_softc {
102: short sc_port;
103: short sc_state;
104: /* default case: negative prime, negative ack, handshake strobe,
105: prime once */
106: u_char sc_control;
107: char sc_flags;
108: #define LP_POS_INIT 0x01 /* if we are a postive init signal */
109: #define LP_POS_ACK 0x02 /* if we are a positive going ack */
110: #define LP_NO_PRIME 0x04 /* don't prime the printer at all */
111: #define LP_PRIMEOPEN 0x08 /* prime on every open */
112: #define LP_AUTOLF 0x10 /* tell printer to do an automatic lf */
113: #define LP_BYPASS 0x20 /* bypass printer ready checks */
114: struct buf *sc_inbuf;
115: short sc_xfercnt ;
116: char sc_primed;
117: char *sc_cp ;
118: } lpt_sc[NLPT] ;
119:
120: /* bits for state */
121: #define OPEN (1<<0) /* device is open */
122: #define ASLP (1<<1) /* awaiting draining of printer */
123: #define ERROR (1<<2) /* error was received from printer */
124: #define OBUSY (1<<3) /* printer is busy doing output */
125: #define LPTOUT (1<<4) /* timeout while not selected */
126: #define TOUT (1<<5) /* timeout while not selected */
127: #define INIT (1<<6) /* waiting to initialize for open */
128:
1.1.1.2 ! root 129: /*
! 130: * Internal routine to lptprobe to do port tests of one byte value
! 131: */
! 132: int
! 133: lpt_port_test(short port, u_char data, u_char mask)
! 134: {
! 135: int temp, timeout;
! 136:
! 137: data = data & mask;
! 138: outb(port, data);
! 139: timeout = 100;
! 140: do
! 141: temp = inb(port) & mask;
! 142: while (temp != data && --timeout);
! 143: lprintf("Port 0x%x\tout=%x\tin=%x\n", port, data, temp);
! 144: return (temp == data);
! 145: }
! 146:
! 147: /*
! 148: * New lptprobe routine written by Rodney W. Grimes, 3/25/1993
! 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: int
! 172: lptprobe(struct isa_device *dvp)
! 173: {
! 174: int status;
! 175: short port;
! 176: u_char data;
! 177: u_char mask;
! 178: int i;
! 179:
! 180: status = IO_LPTSIZE;
! 181:
! 182: port = dvp->id_iobase + lpt_data;
! 183: mask = 0xff;
! 184: while (mask != 0)
! 185: {
! 186: data = 0x55; /* Alternating zeros */
! 187: if (!lpt_port_test(port, data, mask)) status = 0;
! 188:
! 189: data = 0xaa; /* Alternating ones */
! 190: if (!lpt_port_test(port, data, mask)) status = 0;
! 191:
! 192: for (i = 0; i < 8; i++) /* Walking zero */
! 193: {
! 194: data = ~(1 << i);
! 195: if (!lpt_port_test(port, data, mask)) status = 0;
! 196: }
! 197:
! 198: for (i = 0; i < 8; i++) /* Walking one */
! 199: {
! 200: data = (1 << i);
! 201: if (!lpt_port_test(port, data, mask)) status = 0;
! 202: }
! 203:
! 204: if (port == dvp->id_iobase + lpt_data)
! 205: {
! 206: port = dvp->id_iobase + lpt_control;
! 207: mask = 0x1e;
! 208: }
! 209: else
! 210: mask = 0;
! 211: }
! 212: outb(dvp->id_iobase+lpt_data, 0);
! 213: outb(dvp->id_iobase+lpt_control, 0);
! 214: return (status);
1.1 root 215: }
216:
217: lptattach(isdp)
218: struct isa_device *isdp;
219: {
220: struct lpt_softc *sc;
221:
222: sc = lpt_sc + isdp->id_unit;
223: sc->sc_port = isdp->id_iobase;
1.1.1.2 ! root 224: sc->sc_state = 0;
1.1 root 225: outb(sc->sc_port+lpt_control, LPC_NINIT);
226: return (1);
227: }
228:
229: /*
230: * lptopen -- reset the printer, then wait until it's selected and not busy.
231: */
232:
233: lptopen(dev, flag)
234: dev_t dev;
235: int flag;
236: {
237: struct lpt_softc *sc = lpt_sc + LPTUNIT(minor(dev));
238: int s;
239: int trys, port;
240:
241: if (sc->sc_state) {
242: lprintf("lp: still open\n") ;
243: printf("still open %x\n", sc->sc_state);
244: return(EBUSY);
245: } else sc->sc_state |= INIT;
246:
247: s = spltty();
248: sc->sc_flags = LPTFLAGS(minor(dev));
249: lprintf("lp flags 0x%x\n", sc->sc_flags);
250: port = sc->sc_port;
251:
252: /* init printer */
253: if((sc->sc_flags & LP_NO_PRIME) == 0) {
254: if((sc->sc_flags & LP_PRIMEOPEN) || sc->sc_primed == 0) {
255: outb(port+lpt_control, 0);
256: sc->sc_primed++;
257: DELAY(500);
258: }
259: }
260: outb(port+lpt_control, LPC_SEL|LPC_NINIT);
261:
262: /* wait till ready (printer running diagnostics) */
263: trys = 0;
264: do {
265: /* ran out of waiting for the printer */
266: if (trys++ >= LPINITRDY*4) {
267: splx(s);
268: sc->sc_state = 0;
269: printf ("status %x\n", inb(port+lpt_status) );
270: return (EBUSY);
271: }
272:
273: /* wait 1/4 second, give up if we get a signal */
1.1.1.2 ! root 274: if (tsleep((caddr_t)sc,
! 275: LPPRI|PCATCH, "lptinit", hz/4) != EWOULDBLOCK) {
1.1 root 276: sc->sc_state = 0;
277: splx(s);
278: return (EBUSY);
279: }
280:
281: /* is printer online and ready for output */
282: } while ((inb(port+lpt_status) & (LPS_SEL|LPS_OUT|LPS_NBSY|LPS_NERR)) !=
283: (LPS_SEL|LPS_NBSY|LPS_NERR));
284:
285: if(sc->sc_flags&LP_AUTOLF) {
286: outb(port+lpt_control, LPC_SEL|LPC_NINIT|LPC_ENA|LPC_AUTOL);
287: sc->sc_control = LPC_SEL|LPC_NINIT|LPC_ENA|LPC_AUTOL;
288: } else {
289: outb(port+lpt_control, LPC_SEL|LPC_NINIT|LPC_ENA);
290: sc->sc_control = LPC_SEL|LPC_NINIT|LPC_ENA;
291: }
292:
293: sc->sc_state = OPEN | TOUT;
294: sc->sc_inbuf = geteblk(BUFSIZE);
295: sc->sc_xfercnt = 0;
296: splx(s);
1.1.1.2 ! root 297: timeout((timeout_t)lptout, (caddr_t)sc, hz/2);
1.1 root 298: lprintf("opened.\n");
299: return(0);
300: }
301:
302: lptout (sc)
303: struct lpt_softc *sc;
304: { int pl;
305:
306: lprintf ("T %x ", inb(sc->sc_port+lpt_status));
307: if (sc->sc_state&OPEN)
1.1.1.2 ! root 308: timeout((timeout_t)lptout, (caddr_t)sc, hz/2);
1.1 root 309: else sc->sc_state &= ~TOUT;
310:
311: if (sc->sc_state & ERROR)
312: sc->sc_state &= ~ERROR;
313:
314: /*
315: * Avoid possible hangs do to missed interrupts
316: */
317: if (sc->sc_xfercnt) {
318: pl = spltty();
319: lptintr(sc - lpt_sc);
320: splx(pl);
321: } else {
322: sc->sc_state &= ~OBUSY;
323: wakeup((caddr_t)sc);
324: }
325: }
326:
327: /*
328: * lptclose -- close the device, free the local line buffer.
329: */
330:
331: lptclose(dev, flag)
332: int flag;
333: {
334: struct lpt_softc *sc = lpt_sc + LPTUNIT(minor(dev));
335: int port = sc->sc_port;
336:
337: sc->sc_state &= ~OPEN;
338: while ((inb(port+lpt_status) & (LPS_SEL|LPS_OUT|LPS_NBSY|LPS_NERR)) !=
339: (LPS_SEL|LPS_NBSY|LPS_NERR) || sc->sc_xfercnt)
340: /* wait 1/4 second, give up if we get a signal */
1.1.1.2 ! root 341: if (tsleep((caddr_t)sc,
! 342: LPPRI|PCATCH, "lpclose", hz) != EWOULDBLOCK)
1.1 root 343: break;
344:
345: sc->sc_state = 0;
346: sc->sc_xfercnt = 0;
347: outb(sc->sc_port+lpt_control, LPC_NINIT);
348: brelse(sc->sc_inbuf);
349: lprintf("closed.\n");
350: return(0);
351: }
352:
353: /*
354: * lptwrite --copy a line from user space to a local buffer, then call
355: * putc to get the chars moved to the output queue.
356: */
357:
358: lptwrite(dev, uio)
359: dev_t dev;
360: struct uio *uio;
361: {
362: register unsigned n;
363: int pl, err;
364: struct lpt_softc *sc = lpt_sc + LPTUNIT(minor(dev));
365:
366: while (n = MIN(BUFSIZE, uio->uio_resid)) {
367: sc->sc_cp = sc->sc_inbuf->b_un.b_addr ;
368: uiomove(sc->sc_cp, n, uio);
369: sc->sc_xfercnt = n ;
370: while (sc->sc_xfercnt > 0) {
371: /* if the printer is ready for a char, give it one */
372: if ((sc->sc_state & OBUSY) == 0){
373: lprintf("\nC %d. ", sc->sc_xfercnt);
374: pl = spltty();
375: lptintr(sc - lpt_sc);
376: (void) splx(pl);
377: }
378: lprintf("W ");
1.1.1.2 ! root 379: if (err = tsleep((caddr_t)sc,
! 380: LPPRI|PCATCH, "lpwrite", 0))
1.1 root 381: return(err);
382: }
383: }
384: return(0);
385: }
386:
387: /*
388: * lptintr -- handle printer interrupts which occur when the printer is
389: * ready to accept another char.
390: */
391:
392: lptintr(unit)
393: {
394: struct lpt_softc *sc = lpt_sc + unit;
395: int port = sc->sc_port,sts;
396:
1.1.1.2 ! root 397: sts = inb(port+lpt_status);
! 398:
! 399: if (!sc->sc_state) {
! 400: printf ("lpt%d: stray interrupt sts=0x%02x\n", unit, sts);
! 401: return;
! 402: }
! 403:
1.1 root 404: /* is printer online and ready for output */
1.1.1.2 ! root 405: if ((sts & (LPS_SEL|LPS_OUT|LPS_NBSY|LPS_NERR/*|LPS_NACK*/)) ==
1.1 root 406: (LPS_SEL|LPS_NBSY|LPS_NERR)) {
407: /* is this a false interrupt ? */
408: if ((sc->sc_state & OBUSY)
409: && (sts & LPS_NACK) == 0) return;
410: sc->sc_state |= OBUSY; sc->sc_state &= ~ERROR;
411:
412: if (sc->sc_xfercnt) {
413: /* send char */
414: /*lprintf("%x ", *sc->sc_cp); */
415: outb(port+lpt_data, *sc->sc_cp++) ; sc->sc_xfercnt-- ;
416: outb(port+lpt_control, sc->sc_control|LPC_STB);
417: /* DELAY(X) */
418: outb(port+lpt_control, sc->sc_control);
419: }
420:
421: /* any more bytes for the printer? */
422: if (sc->sc_xfercnt > 0) return;
423:
424: /* none, wake up the top half to get more */
425: sc->sc_state &= ~OBUSY;
426: wakeup((caddr_t)sc);
427: lprintf("w ");
428: return;
429: } else sc->sc_state |= ERROR;
430: lprintf("sts %x ", sts);
431: }
432:
1.1.1.2 ! root 433: int
! 434: lptioctl(dev_t dev, int cmd, caddr_t data, int flag)
! 435: {
! 436: int error;
! 437:
! 438: error = 0;
! 439: switch (cmd) {
! 440: #ifdef THISISASAMPLE
! 441: case XXX:
! 442: dothis; andthis; andthat;
! 443: error=x;
! 444: break;
! 445: #endif /* THISISASAMPLE */
! 446: default:
! 447: error = ENODEV;
! 448: }
! 449:
! 450: return(error);
! 451: }
! 452:
! 453: #endif /* NLPT */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.