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