lptvar.h revision 1.2 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 * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE
49 * -------------------- ----- ----------------------
50 * CURRENT PATCH LEVEL: 1 00133
51 * -------------------- ----- ----------------------
52 *
53 * 06 Apr 93 Eric Haug Fixed comments and includes. [Ed: I did
54 * not include the unit-1 thing, that is a
55 * DOSism, fixed the config file instead]
56 * 06 Apr 93 Rodney W. Grimes A real probe routine, may even cause on
57 * interrupt if a printer is attached.
58 *
59 */
60
61 /*
62 * Device Driver for AT parallel printer port
63 * Written by William Jolitz 12/18/90
64 */
65
66 #include "lpt.h"
67 #if NLPT > 0
68
69 #include "param.h"
70 #include "systm.h"
71 #include "proc.h"
72 #include "user.h"
73 #include "buf.h"
74 #include "kernel.h"
75 #include "ioctl.h"
76 #include "tty.h"
77 #include "uio.h"
78
79 #include "i386/isa/isa.h"
80 #include "i386/isa/isa_device.h"
81 #include "i386/isa/lptreg.h"
82
83 #define LPINITRDY 4 /* wait up to 4 seconds for a ready */
84 #define LPTOUTTIME 4 /* wait up to 4 seconds for a ready */
85 #define LPPRI (PZERO+8)
86 #define BUFSIZE 1024
87
88 #ifndef DEBUG
89 #define lprintf
90 #else
91 #define lprintf if (lpflag) printf
92 #endif
93
94 int lptout();
95 #ifdef DEBUG
96 int lpflag = 1;
97 #endif
98
99 int lptprobe(), lptattach(), lptintr();
100
101 struct isa_driver lptdriver = {
102 lptprobe, lptattach, "lpt"
103 };
104
105 #define LPTUNIT(s) (((s)>>6)&0x3)
106 #define LPTFLAGS(s) ((s)&0x3f)
107
108 struct lpt_softc {
109 short sc_port;
110 short sc_state;
111 /* default case: negative prime, negative ack, handshake strobe,
112 prime once */
113 u_char sc_control;
114 char sc_flags;
115 #define LP_POS_INIT 0x01 /* if we are a postive init signal */
116 #define LP_POS_ACK 0x02 /* if we are a positive going ack */
117 #define LP_NO_PRIME 0x04 /* don't prime the printer at all */
118 #define LP_PRIMEOPEN 0x08 /* prime on every open */
119 #define LP_AUTOLF 0x10 /* tell printer to do an automatic lf */
120 #define LP_BYPASS 0x20 /* bypass printer ready checks */
121 struct buf *sc_inbuf;
122 short sc_xfercnt ;
123 char sc_primed;
124 char *sc_cp ;
125 } lpt_sc[NLPT] ;
126
127 /* bits for state */
128 #define OPEN (1<<0) /* device is open */
129 #define ASLP (1<<1) /* awaiting draining of printer */
130 #define ERROR (1<<2) /* error was received from printer */
131 #define OBUSY (1<<3) /* printer is busy doing output */
132 #define LPTOUT (1<<4) /* timeout while not selected */
133 #define TOUT (1<<5) /* timeout while not selected */
134 #define INIT (1<<6) /* waiting to initialize for open */
135
136 /*
137 * Internal routine to lptprobe to do port tests of one byte value
138 */
139 int
140 lpt_port_test(short port, u_char data, u_char mask)
141 {
142 int temp;
143
144 data = data & mask;
145 outb(port, data);
146 temp = inb(port) & mask;
147 lprintf("Port 0x%x\tout=%x\tin=%x\n", port, data, temp);
148 return (temp == data);
149 }
150
151 /*
152 * New lptprobe routine written by Rodney W. Grimes, 3/25/1993
153 *
154 * Logic:
155 * 1) You should be able to write to and read back the same value
156 * to the data port. Do an alternating zeros, alternating ones,
157 * walking zero, and walking one test to check for stuck bits.
158 *
159 * 2) You should be able to write to and read back the same value
160 * to the control port lower 5 bits, the upper 3 bits are reserved
161 * per the IBM PC technical reference manauls and different boards
162 * do different things with them. Do an alternating zeros, alternating
163 * ones, walking zero, and walking one test to check for stuck bits.
164 *
165 * Some printers drag the strobe line down when the are powered off
166 * so this bit has been masked out of the control port test.
167 *
168 * XXX Some printers may not like a fast pulse on init or strobe, I
169 * don't know at this point, if that becomes a problem these bits
170 * should be turned off in the mask byte for the control port test.
171 *
172 * 3) Set the data and control ports to a value of 0
173 */
174
175 int
176 lptprobe(struct isa_device *dvp)
177 {
178 int status;
179 short port;
180 u_char data;
181 u_char mask;
182 int i;
183
184 status = IO_LPTSIZE;
185
186 port = dvp->id_iobase + lpt_data;
187 mask = 0xff;
188 while (mask != 0)
189 {
190 data = 0x55; /* Alternating zeros */
191 if (!lpt_port_test(port, data, mask)) status = 0;
192
193 data = 0xaa; /* Alternating ones */
194 if (!lpt_port_test(port, data, mask)) status = 0;
195
196 for (i = 0; i < 8; i++) /* Walking zero */
197 {
198 data = ~(1 << i);
199 if (!lpt_port_test(port, data, mask)) status = 0;
200 }
201
202 for (i = 0; i < 8; i++) /* Walking one */
203 {
204 data = (1 << i);
205 if (!lpt_port_test(port, data, mask)) status = 0;
206 }
207
208 if (port == dvp->id_iobase + lpt_data)
209 {
210 port = dvp->id_iobase + lpt_control;
211 mask = 0x1e;
212 }
213 else
214 mask = 0;
215 }
216 outb(dvp->id_iobase+lpt_data, 0);
217 outb(dvp->id_iobase+lpt_control, 0);
218 return (status);
219 }
220
221 lptattach(isdp)
222 struct isa_device *isdp;
223 {
224 struct lpt_softc *sc;
225
226 sc = lpt_sc + isdp->id_unit;
227 sc->sc_port = isdp->id_iobase;
228 outb(sc->sc_port+lpt_control, LPC_NINIT);
229 return (1);
230 }
231
232 /*
233 * lptopen -- reset the printer, then wait until it's selected and not busy.
234 */
235
236 lptopen(dev, flag)
237 dev_t dev;
238 int flag;
239 {
240 struct lpt_softc *sc = lpt_sc + LPTUNIT(minor(dev));
241 int s;
242 int trys, port;
243
244 if (sc->sc_state) {
245 lprintf("lp: still open\n") ;
246 printf("still open %x\n", sc->sc_state);
247 return(EBUSY);
248 } else sc->sc_state |= INIT;
249
250 s = spltty();
251 sc->sc_flags = LPTFLAGS(minor(dev));
252 lprintf("lp flags 0x%x\n", sc->sc_flags);
253 port = sc->sc_port;
254
255 /* init printer */
256 if((sc->sc_flags & LP_NO_PRIME) == 0) {
257 if((sc->sc_flags & LP_PRIMEOPEN) || sc->sc_primed == 0) {
258 outb(port+lpt_control, 0);
259 sc->sc_primed++;
260 DELAY(500);
261 }
262 }
263 outb(port+lpt_control, LPC_SEL|LPC_NINIT);
264
265 /* wait till ready (printer running diagnostics) */
266 trys = 0;
267 do {
268 /* ran out of waiting for the printer */
269 if (trys++ >= LPINITRDY*4) {
270 splx(s);
271 sc->sc_state = 0;
272 printf ("status %x\n", inb(port+lpt_status) );
273 return (EBUSY);
274 }
275
276 /* wait 1/4 second, give up if we get a signal */
277 if (tsleep (sc, LPPRI|PCATCH, "lptinit", hz/4) != EWOULDBLOCK) {
278 sc->sc_state = 0;
279 splx(s);
280 return (EBUSY);
281 }
282
283 /* is printer online and ready for output */
284 } while ((inb(port+lpt_status) & (LPS_SEL|LPS_OUT|LPS_NBSY|LPS_NERR)) !=
285 (LPS_SEL|LPS_NBSY|LPS_NERR));
286
287 if(sc->sc_flags&LP_AUTOLF) {
288 outb(port+lpt_control, LPC_SEL|LPC_NINIT|LPC_ENA|LPC_AUTOL);
289 sc->sc_control = LPC_SEL|LPC_NINIT|LPC_ENA|LPC_AUTOL;
290 } else {
291 outb(port+lpt_control, LPC_SEL|LPC_NINIT|LPC_ENA);
292 sc->sc_control = LPC_SEL|LPC_NINIT|LPC_ENA;
293 }
294
295 sc->sc_state = OPEN | TOUT;
296 sc->sc_inbuf = geteblk(BUFSIZE);
297 sc->sc_xfercnt = 0;
298 splx(s);
299 timeout (lptout, sc, hz/2);
300 lprintf("opened.\n");
301 return(0);
302 }
303
304 lptout (sc)
305 struct lpt_softc *sc;
306 { int pl;
307
308 lprintf ("T %x ", inb(sc->sc_port+lpt_status));
309 if (sc->sc_state&OPEN)
310 timeout (lptout, sc, hz/2);
311 else sc->sc_state &= ~TOUT;
312
313 if (sc->sc_state & ERROR)
314 sc->sc_state &= ~ERROR;
315
316 /*
317 * Avoid possible hangs do to missed interrupts
318 */
319 if (sc->sc_xfercnt) {
320 pl = spltty();
321 lptintr(sc - lpt_sc);
322 splx(pl);
323 } else {
324 sc->sc_state &= ~OBUSY;
325 wakeup((caddr_t)sc);
326 }
327 }
328
329 /*
330 * lptclose -- close the device, free the local line buffer.
331 */
332
333 lptclose(dev, flag)
334 int flag;
335 {
336 struct lpt_softc *sc = lpt_sc + LPTUNIT(minor(dev));
337 int port = sc->sc_port;
338
339 sc->sc_state &= ~OPEN;
340 while ((inb(port+lpt_status) & (LPS_SEL|LPS_OUT|LPS_NBSY|LPS_NERR)) !=
341 (LPS_SEL|LPS_NBSY|LPS_NERR) || sc->sc_xfercnt)
342 /* wait 1/4 second, give up if we get a signal */
343 if (tsleep (sc, LPPRI|PCATCH, "lpclose", hz) != EWOULDBLOCK)
344 break;
345
346 sc->sc_state = 0;
347 sc->sc_xfercnt = 0;
348 outb(sc->sc_port+lpt_control, LPC_NINIT);
349 brelse(sc->sc_inbuf);
350 lprintf("closed.\n");
351 return(0);
352 }
353
354 /*
355 * lptwrite --copy a line from user space to a local buffer, then call
356 * putc to get the chars moved to the output queue.
357 */
358
359 lptwrite(dev, uio)
360 dev_t dev;
361 struct uio *uio;
362 {
363 register unsigned n;
364 int pl, err;
365 struct lpt_softc *sc = lpt_sc + LPTUNIT(minor(dev));
366
367 while (n = MIN(BUFSIZE, uio->uio_resid)) {
368 sc->sc_cp = sc->sc_inbuf->b_un.b_addr ;
369 uiomove(sc->sc_cp, n, uio);
370 sc->sc_xfercnt = n ;
371 while (sc->sc_xfercnt > 0) {
372 /* if the printer is ready for a char, give it one */
373 if ((sc->sc_state & OBUSY) == 0){
374 lprintf("\nC %d. ", sc->sc_xfercnt);
375 pl = spltty();
376 lptintr(sc - lpt_sc);
377 (void) splx(pl);
378 }
379 lprintf("W ");
380 if (err = tsleep (sc, LPPRI|PCATCH, "lpwrite", 0))
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
397 /* is printer online and ready for output */
398 if (((sts=inb(port+lpt_status)) & (LPS_SEL|LPS_OUT|LPS_NBSY|LPS_NERR/*|LPS_NACK*/)) ==
399 (LPS_SEL|LPS_NBSY|LPS_NERR)) {
400 /* is this a false interrupt ? */
401 if ((sc->sc_state & OBUSY)
402 && (sts & LPS_NACK) == 0) return;
403 sc->sc_state |= OBUSY; sc->sc_state &= ~ERROR;
404
405 if (sc->sc_xfercnt) {
406 /* send char */
407 /*lprintf("%x ", *sc->sc_cp); */
408 outb(port+lpt_data, *sc->sc_cp++) ; sc->sc_xfercnt-- ;
409 outb(port+lpt_control, sc->sc_control|LPC_STB);
410 /* DELAY(X) */
411 outb(port+lpt_control, sc->sc_control);
412 }
413
414 /* any more bytes for the printer? */
415 if (sc->sc_xfercnt > 0) return;
416
417 /* none, wake up the top half to get more */
418 sc->sc_state &= ~OBUSY;
419 wakeup((caddr_t)sc);
420 lprintf("w ");
421 return;
422 } else sc->sc_state |= ERROR;
423 lprintf("sts %x ", sts);
424 }
425
426 int
427 lptioctl(dev_t dev, int cmd, caddr_t data, int flag)
428 {
429 int error;
430
431 error = 0;
432 switch (cmd) {
433 #ifdef THISISASAMPLE
434 case XXX:
435 dothis; andthis; andthat;
436 error=x;
437 break;
438 #endif /* THISISASAMPLE */
439 default:
440 error = ENODEV;
441 }
442
443 return(error);
444 }
445
446 #endif /* NLPT */
447