|
|
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: *
48: */
49: */
50:
51: /*
52: * Device Driver for AT parallel printer port
53: * Written by William Jolitz 12/18/90
54: */
55:
56: #include "lpt.h"
57: #if NLPT > 0
58:
59: #include "param.h"
60: #include "user.h"
61: #include "buf.h"
62: #include "systm.h"
63: #include "kernel.h"
64: #include "ioctl.h"
65: #include "tty.h"
66: #include "uio.h"
67:
68: #include "i386/isa/isa_device.h"
69: #include "i386/isa/lptreg.h"
70:
71: #define LPINITRDY 4 /* wait up to 4 seconds for a ready */
72: #define LPTOUTTIME 4 /* wait up to 4 seconds for a ready */
73: #define LPPRI (PZERO+8)
74: #define BUFSIZE 1024
75:
76: #ifndef DEBUG
77: #define lprintf
78: #else
79: #define lprintf if (lpflag) printf
80: #endif
81:
82: int lptout();
83: #ifdef DEBUG
84: int lpflag = 1;
85: #endif
86:
87: int lptprobe(), lptattach(), lptintr();
88:
89: struct isa_driver lptdriver = {
90: lptprobe, lptattach, "lpt"
91: };
92:
93: #define LPTUNIT(s) (((s)>>6)&0x3)
94: #define LPTFLAGS(s) ((s)&0x3f)
95:
96: struct lpt_softc {
97: short sc_port;
98: short sc_state;
99: /* default case: negative prime, negative ack, handshake strobe,
100: prime once */
101: u_char sc_control;
102: char sc_flags;
103: #define LP_POS_INIT 0x01 /* if we are a postive init signal */
104: #define LP_POS_ACK 0x02 /* if we are a positive going ack */
105: #define LP_NO_PRIME 0x04 /* don't prime the printer at all */
106: #define LP_PRIMEOPEN 0x08 /* prime on every open */
107: #define LP_AUTOLF 0x10 /* tell printer to do an automatic lf */
108: #define LP_BYPASS 0x20 /* bypass printer ready checks */
109: struct buf *sc_inbuf;
110: short sc_xfercnt ;
111: char sc_primed;
112: char *sc_cp ;
113: } lpt_sc[NLPT] ;
114:
115: /* bits for state */
116: #define OPEN (1<<0) /* device is open */
117: #define ASLP (1<<1) /* awaiting draining of printer */
118: #define ERROR (1<<2) /* error was received from printer */
119: #define OBUSY (1<<3) /* printer is busy doing output */
120: #define LPTOUT (1<<4) /* timeout while not selected */
121: #define TOUT (1<<5) /* timeout while not selected */
122: #define INIT (1<<6) /* waiting to initialize for open */
123:
124: lptprobe(idp)
125: struct isa_device *idp;
126: { unsigned v;
127:
128: outb(idp->id_iobase+lpt_status,0xf0);
129: v = inb(idp->id_iobase+lpt_status);
130: outb(idp->id_iobase+lpt_status,0);
131: if (inb(idp->id_iobase+lpt_status) == v) {
132: outb(idp->id_iobase+lpt_control,0xff);
133: DELAY(100);
134: if (inb(idp->id_iobase+lpt_control) != 0xff)
135: return(0);
136: outb(idp->id_iobase+lpt_control,0);
137: DELAY(100);
138: if (inb(idp->id_iobase+lpt_control) != 0xe0)
139: return(0);
140: return(1);
141: }
142: return(0);
143: }
144:
145: lptattach(isdp)
146: struct isa_device *isdp;
147: {
148: struct lpt_softc *sc;
149:
150: sc = lpt_sc + isdp->id_unit;
151: sc->sc_port = isdp->id_iobase;
152: outb(sc->sc_port+lpt_control, LPC_NINIT);
153: return (1);
154: }
155:
156: /*
157: * lptopen -- reset the printer, then wait until it's selected and not busy.
158: */
159:
160: lptopen(dev, flag)
161: dev_t dev;
162: int flag;
163: {
164: struct lpt_softc *sc = lpt_sc + LPTUNIT(minor(dev));
165: int s;
166: int trys, port;
167:
168: if (sc->sc_state) {
169: lprintf("lp: still open\n") ;
170: printf("still open %x\n", sc->sc_state);
171: return(EBUSY);
172: } else sc->sc_state |= INIT;
173:
174: s = spltty();
175: sc->sc_flags = LPTFLAGS(minor(dev));
176: lprintf("lp flags 0x%x\n", sc->sc_flags);
177: port = sc->sc_port;
178:
179: /* init printer */
180: if((sc->sc_flags & LP_NO_PRIME) == 0) {
181: if((sc->sc_flags & LP_PRIMEOPEN) || sc->sc_primed == 0) {
182: outb(port+lpt_control, 0);
183: sc->sc_primed++;
184: DELAY(500);
185: }
186: }
187: outb(port+lpt_control, LPC_SEL|LPC_NINIT);
188:
189: /* wait till ready (printer running diagnostics) */
190: trys = 0;
191: do {
192: /* ran out of waiting for the printer */
193: if (trys++ >= LPINITRDY*4) {
194: splx(s);
195: sc->sc_state = 0;
196: printf ("status %x\n", inb(port+lpt_status) );
197: return (EBUSY);
198: }
199:
200: /* wait 1/4 second, give up if we get a signal */
201: if (tsleep (sc, LPPRI|PCATCH, "lptinit", hz/4) != EWOULDBLOCK) {
202: sc->sc_state = 0;
203: splx(s);
204: return (EBUSY);
205: }
206:
207: /* is printer online and ready for output */
208: } while ((inb(port+lpt_status) & (LPS_SEL|LPS_OUT|LPS_NBSY|LPS_NERR)) !=
209: (LPS_SEL|LPS_NBSY|LPS_NERR));
210:
211: if(sc->sc_flags&LP_AUTOLF) {
212: outb(port+lpt_control, LPC_SEL|LPC_NINIT|LPC_ENA|LPC_AUTOL);
213: sc->sc_control = LPC_SEL|LPC_NINIT|LPC_ENA|LPC_AUTOL;
214: } else {
215: outb(port+lpt_control, LPC_SEL|LPC_NINIT|LPC_ENA);
216: sc->sc_control = LPC_SEL|LPC_NINIT|LPC_ENA;
217: }
218:
219: sc->sc_state = OPEN | TOUT;
220: sc->sc_inbuf = geteblk(BUFSIZE);
221: sc->sc_xfercnt = 0;
222: splx(s);
223: timeout (lptout, sc, hz/2);
224: lprintf("opened.\n");
225: return(0);
226: }
227:
228: lptout (sc)
229: struct lpt_softc *sc;
230: { int pl;
231:
232: lprintf ("T %x ", inb(sc->sc_port+lpt_status));
233: if (sc->sc_state&OPEN)
234: timeout (lptout, sc, hz/2);
235: else sc->sc_state &= ~TOUT;
236:
237: if (sc->sc_state & ERROR)
238: sc->sc_state &= ~ERROR;
239:
240: /*
241: * Avoid possible hangs do to missed interrupts
242: */
243: if (sc->sc_xfercnt) {
244: pl = spltty();
245: lptintr(sc - lpt_sc);
246: splx(pl);
247: } else {
248: sc->sc_state &= ~OBUSY;
249: wakeup((caddr_t)sc);
250: }
251: }
252:
253: /*
254: * lptclose -- close the device, free the local line buffer.
255: */
256:
257: lptclose(dev, flag)
258: int flag;
259: {
260: struct lpt_softc *sc = lpt_sc + LPTUNIT(minor(dev));
261: int port = sc->sc_port;
262:
263: sc->sc_state &= ~OPEN;
264: while ((inb(port+lpt_status) & (LPS_SEL|LPS_OUT|LPS_NBSY|LPS_NERR)) !=
265: (LPS_SEL|LPS_NBSY|LPS_NERR) || sc->sc_xfercnt)
266: /* wait 1/4 second, give up if we get a signal */
267: if (tsleep (sc, LPPRI|PCATCH, "lpclose", hz) != EWOULDBLOCK)
268: break;
269:
270: sc->sc_state = 0;
271: sc->sc_xfercnt = 0;
272: outb(sc->sc_port+lpt_control, LPC_NINIT);
273: brelse(sc->sc_inbuf);
274: lprintf("closed.\n");
275: return(0);
276: }
277:
278: /*
279: * lptwrite --copy a line from user space to a local buffer, then call
280: * putc to get the chars moved to the output queue.
281: */
282:
283: lptwrite(dev, uio)
284: dev_t dev;
285: struct uio *uio;
286: {
287: register unsigned n;
288: int pl, err;
289: struct lpt_softc *sc = lpt_sc + LPTUNIT(minor(dev));
290:
291: while (n = MIN(BUFSIZE, uio->uio_resid)) {
292: sc->sc_cp = sc->sc_inbuf->b_un.b_addr ;
293: uiomove(sc->sc_cp, n, uio);
294: sc->sc_xfercnt = n ;
295: while (sc->sc_xfercnt > 0) {
296: /* if the printer is ready for a char, give it one */
297: if ((sc->sc_state & OBUSY) == 0){
298: lprintf("\nC %d. ", sc->sc_xfercnt);
299: pl = spltty();
300: lptintr(sc - lpt_sc);
301: (void) splx(pl);
302: }
303: lprintf("W ");
304: if (err = tsleep (sc, LPPRI|PCATCH, "lpwrite", 0))
305: return(err);
306: }
307: }
308: return(0);
309: }
310:
311: /*
312: * lptintr -- handle printer interrupts which occur when the printer is
313: * ready to accept another char.
314: */
315:
316: lptintr(unit)
317: {
318: struct lpt_softc *sc = lpt_sc + unit;
319: int port = sc->sc_port,sts;
320:
321: /* is printer online and ready for output */
322: if (((sts=inb(port+lpt_status)) & (LPS_SEL|LPS_OUT|LPS_NBSY|LPS_NERR/*|LPS_NACK*/)) ==
323: (LPS_SEL|LPS_NBSY|LPS_NERR)) {
324: /* is this a false interrupt ? */
325: if ((sc->sc_state & OBUSY)
326: && (sts & LPS_NACK) == 0) return;
327: sc->sc_state |= OBUSY; sc->sc_state &= ~ERROR;
328:
329: if (sc->sc_xfercnt) {
330: /* send char */
331: /*lprintf("%x ", *sc->sc_cp); */
332: outb(port+lpt_data, *sc->sc_cp++) ; sc->sc_xfercnt-- ;
333: outb(port+lpt_control, sc->sc_control|LPC_STB);
334: /* DELAY(X) */
335: outb(port+lpt_control, sc->sc_control);
336: }
337:
338: /* any more bytes for the printer? */
339: if (sc->sc_xfercnt > 0) return;
340:
341: /* none, wake up the top half to get more */
342: sc->sc_state &= ~OBUSY;
343: wakeup((caddr_t)sc);
344: lprintf("w ");
345: return;
346: } else sc->sc_state |= ERROR;
347: lprintf("sts %x ", sts);
348: }
349:
350: #endif NLP
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.