lpt.c revision 1.7.4.2 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.2 1993/09/29 05:20:26 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 size_t sc_count;
87 struct buf *sc_inbuf;
88 u_char *sc_cp ;
89 u_short sc_iobase;
90 u_short sc_irq;
91 u_char sc_state;
92 /* bits for state */
93 #define LPT_OPEN 0x01 /* device is open */
94 #define LPT_OBUSY 0x02 /* printer is busy doing output */
95 #define LPT_INIT 0x04 /* waiting to initialize for open */
96 u_char sc_flags;
97 #define LPT_AUTOLF 0x20 /* automatic LF on CR */
98 #define LPT_NOPRIME 0x40 /* don't prime on open */
99 #define LPT_NOINTR 0x80 /* do not use interrupt */
100 u_char sc_control;
101 u_char sc_smax;
102 };
103
104 static int lptprobe __P((struct device *, struct cfdata *, void *));
105 static void lptforceintr __P((void *));
106 static void lptattach __P((struct device *, struct device *, void *));
107 static int lptintr __P((void *));
108
109 struct cfdriver lptcd =
110 { NULL, "lpt", lptprobe, lptattach, sizeof(struct lpt_softc) };
111
112 #define LPTUNIT(s) ((s)&0x1f)
113 #define LPTFLAGS(s) ((s)&0xe0)
114
115 #define LPS_INVERT (LPS_SEL|LPS_NERR|LPS_NBSY|LPS_NACK)
116 #define LPS_MASK (LPS_SEL|LPS_NERR|LPS_NBSY|LPS_NACK|LPS_OUT)
117 #define NOT_READY() ((inb(iobase + lpt_status) ^ LPS_INVERT) & LPS_MASK)
118
119 static void lptout __P((struct lpt_softc *));
120 static int pushbytes __P((struct lpt_softc *));
121
122 /*
123 * Internal routine to lptprobe to do port tests of one byte value
124 */
125 int
126 lpt_port_test(port, data, mask)
127 u_short port;
128 u_char data, mask;
129 {
130 int timeout;
131 u_char temp;
132
133 data &= mask;
134 outb(port, data);
135 timeout = 100;
136 do {
137 temp = inb(port) & mask;
138 } while (temp != data && --timeout);
139 lprintf("lpt: port=0x%x out=0x%x in=0x%x\n", port, data, temp);
140 return (temp == data);
141 }
142
143 /*
144 * Logic:
145 * 1) You should be able to write to and read back the same value
146 * to the data port. Do an alternating zeros, alternating ones,
147 * walking zero, and walking one test to check for stuck bits.
148 *
149 * 2) You should be able to write to and read back the same value
150 * to the control port lower 5 bits, the upper 3 bits are reserved
151 * per the IBM PC technical reference manauls and different boards
152 * do different things with them. Do an alternating zeros, alternating
153 * ones, walking zero, and walking one test to check for stuck bits.
154 *
155 * Some printers drag the strobe line down when the are powered off
156 * so this bit has been masked out of the control port test.
157 *
158 * XXX Some printers may not like a fast pulse on init or strobe, I
159 * don't know at this point, if that becomes a problem these bits
160 * should be turned off in the mask byte for the control port test.
161 *
162 * 3) Set the data and control ports to a value of 0
163 */
164
165 static int
166 lptprobe(parent, cf, aux)
167 struct device *parent;
168 struct cfdata *cf;
169 void *aux;
170 {
171 struct isa_attach_args *ia = aux;
172 u_short iobase = ia->ia_iobase;
173 u_short port = iobase + lpt_data;
174 u_char mask = 0xff;
175 u_char data;
176 int i;
177
178 for (;;) {
179 data = 0x55; /* Alternating zeros */
180 if (!lpt_port_test(port, data, mask))
181 return 0;
182
183 data = 0xaa; /* Alternating ones */
184 if (!lpt_port_test(port, data, mask))
185 return 0;
186
187 for (i = 0; i < CHAR_BIT; i++) { /* Walking zero */
188 data = ~(1 << i);
189 if (!lpt_port_test(port, data, mask))
190 return 0;
191 }
192
193 for (i = 0; i < CHAR_BIT; i++) { /* Walking one */
194 data = (1 << i);
195 if (!lpt_port_test(port, data, mask))
196 return 0;
197 }
198
199 if (port == iobase + lpt_data) {
200 port = iobase + lpt_control;
201 mask = 0x1e;
202 } else
203 break;
204 }
205 outb(iobase + lpt_data, 0);
206 outb(iobase + lpt_control, 0);
207
208 /* XXXX isa_discoverintr */
209
210 ia->ia_iosize = LPT_NPORTS;
211 ia->ia_drq = DRQUNK;
212 ia->ia_msize = 0;
213 return 1;
214 }
215
216 static void
217 lptattach(parent, self, aux)
218 struct device *parent, *self;
219 void *aux;
220 {
221 struct isa_attach_args *ia = aux;
222 struct lpt_softc *sc = (struct lpt_softc *)self;
223 u_short iobase = ia->ia_iobase;
224 u_short irq = ia->ia_irq;
225
226 sc->sc_iobase = iobase;
227 sc->sc_irq = irq;
228 sc->sc_state = 0;
229 outb(iobase + lpt_control, LPC_NINIT);
230
231 /* XXXX isa_establishintr */
232 }
233
234 /*
235 * lptopen -- reset the printer, then wait until it's selected and not busy.
236 */
237 int
238 lptopen(dev, flag)
239 dev_t dev;
240 int flag;
241 {
242 int unit = LPTUNIT(minor(dev));
243 u_char flags = LPTFLAGS(minor(dev));
244 struct lpt_softc *sc;
245 u_short iobase;
246 u_char control;
247 int error;
248 int delay;
249
250 if (unit >= lptcd.cd_ndevs)
251 return ENXIO;
252 sc = (struct lpt_softc *)lptcd.cd_devs[unit];
253 if (!sc)
254 return ENXIO;
255
256 if (sc->sc_irq == IRQUNK && (flags & LPT_NOINTR) == 0)
257 return ENXIO;
258
259 if (sc->sc_state)
260 return EBUSY;
261
262 /* XXXX mask or unmask interrupt */
263
264 #ifdef DIAGNOSTIC
265 if (sc->sc_state)
266 printf("lpt%d: state=0x%x not zero\n", unit, sc->sc_state);
267 #endif
268
269 sc->sc_state = LPT_INIT;
270
271 sc->sc_flags = flags;
272 lprintf("lpt%d: open flags=0x%x\n", unit, flags);
273 iobase = sc->sc_iobase;
274
275 if ((flags & LPT_NOPRIME) == 0)
276 outb(iobase + lpt_control, 0);
277
278 outb(iobase + lpt_control, LPC_SEL|LPC_NINIT);
279
280 /* wait till ready (printer running diagnostics) */
281 for (delay = 0; NOT_READY(); delay += STEP) {
282 if (delay >= TIMEOUT) {
283 sc->sc_state = 0;
284 return EBUSY;
285 }
286
287 /* wait 1/4 second, give up if we get a signal */
288 if (error = tsleep((caddr_t)sc,
289 LPTPRI|PCATCH, "lptopen", STEP) != EWOULDBLOCK) {
290 sc->sc_state = 0;
291 return error;
292 }
293 }
294
295 control = LPC_SEL|LPC_NINIT|LPC_ENA;
296 if (sc->sc_flags & LPT_AUTOLF)
297 control |= LPC_AUTOL;
298 sc->sc_control = control;
299 outb(iobase + lpt_control, control);
300
301 sc->sc_state = LPT_OPEN;
302 sc->sc_inbuf = geteblk(LPT_BSIZE);
303 sc->sc_count = 0;
304 lptout(sc);
305
306 lprintf("lpt%d: opened\n", unit);
307 return 0;
308 }
309
310 static void
311 lptout(sc)
312 struct lpt_softc *sc;
313 {
314 int s;
315
316 if ((sc->sc_state & LPT_OPEN) == 0)
317 return;
318 if (sc->sc_flags & LPT_NOINTR)
319 return;
320
321 /*
322 * Avoid possible hangs due to missed interrupts
323 */
324 if (sc->sc_count) {
325 s = spltty();
326 lptintr(sc);
327 splx(s);
328 } else {
329 sc->sc_state &= ~LPT_OBUSY;
330 wakeup((caddr_t)sc);
331 }
332
333 timeout((timeout_t)lptout, (caddr_t)sc, STEP);
334 }
335
336 /*
337 * lptclose -- close the device, free the local line buffer.
338 */
339 int
340 lptclose(dev, flag)
341 dev_t dev;
342 int flag;
343 {
344 int unit = LPTUNIT(minor(dev));
345 struct lpt_softc *sc = (struct lpt_softc *)lptcd.cd_devs[unit];
346 u_short iobase = sc->sc_iobase;
347 int error;
348
349 if (error = pushbytes(sc))
350 return error;
351
352 outb(iobase + lpt_control, LPC_NINIT);
353 brelse(sc->sc_inbuf);
354 sc->sc_state = 0;
355
356 lprintf("lpt%d: closed\n", unit);
357 return 0;
358 }
359
360 static int
361 pushbytes(sc)
362 struct lpt_softc *sc;
363 {
364 u_short iobase = sc->sc_iobase;
365 int error;
366
367 if (sc->sc_flags & LPT_NOINTR) {
368 int spin, tic;
369 u_char control = sc->sc_control;
370 u_char ch;
371
372 while (sc->sc_count > 0) {
373 spin = tic = 0;
374 while (NOT_READY())
375 if (++spin >= sc->sc_smax) {
376 /* exponential backoff */
377 tic = tic + tic + 1;
378 if (error = tsleep((caddr_t)sc,
379 LPTPRI|PCATCH, "lptwrite1", tic))
380 return error;
381 }
382
383 outb(iobase + lpt_data, *sc->sc_cp++);
384 outb(iobase + lpt_control, control|LPC_STB);
385 outb(iobase + lpt_control, control);
386 sc->sc_count--;
387
388 /* adapt busy-wait algorithm */
389 if (spin >= sc->sc_smax && sc->sc_smax < MAX_SPIN)
390 sc->sc_smax++;
391 if (spin*2 < sc->sc_smax)
392 sc->sc_smax--;
393 }
394 } else {
395 int s;
396
397 while (sc->sc_count > 0) {
398 /* if the printer is ready for a char, give it one */
399 if ((sc->sc_state & LPT_OBUSY) == 0) {
400 lprintf("lpt%d: write %d\n", sc->sc_count);
401 s = spltty();
402 lptintr(sc);
403 splx(s);
404 }
405 if (error = tsleep((caddr_t)sc,
406 LPTPRI|PCATCH, "lptwrite2", 0))
407 return error;
408 }
409 }
410 }
411
412 /*
413 * copy a line from user space to a local buffer, then call
414 * putc to get the chars moved to the output queue.
415 */
416 int
417 lptwrite(dev, uio)
418 dev_t dev;
419 struct uio *uio;
420 {
421 int unit = LPTUNIT(minor(dev));
422 struct lpt_softc *sc = (struct lpt_softc *)lptcd.cd_devs[unit];
423 size_t n;
424 int error = 0;
425
426 while (n = MIN(LPT_BSIZE, uio->uio_resid)) {
427 uiomove(sc->sc_cp = sc->sc_inbuf->b_un.b_addr, n, uio);
428 sc->sc_count = n;
429 error = pushbytes(sc);
430 if (error) {
431 /* return accurate residual if interrupted or
432 timed out */
433 uio->uio_resid += sc->sc_count;
434 sc->sc_count = 0;
435 return error;
436 }
437 }
438 return 0;
439 }
440
441 /*
442 * lptintr -- handle printer interrupts which occur when the printer is
443 * ready to accept another char.
444 */
445 static int
446 lptintr(arg)
447 void *arg;
448 {
449 struct lpt_softc *sc = (struct lpt_softc *)arg;
450 u_short iobase = sc->sc_iobase;
451 u_char control = sc->sc_control;
452 u_char status;
453
454 if ((sc->sc_state & LPT_OPEN) == 0)
455 return 0;
456
457 /* is printer online and ready for output */
458 if (!NOT_READY()) {
459 if (sc->sc_count) {
460 /* send char */
461 sc->sc_state |= LPT_OBUSY;
462 outb(iobase + lpt_data, *sc->sc_cp++);
463 outb(iobase + lpt_control, control|LPC_STB);
464 outb(iobase + lpt_control, control);
465 sc->sc_count--;
466 } else {
467 /* none, wake up the top half to get more */
468 sc->sc_state &= ~LPT_OBUSY;
469 wakeup((caddr_t)sc);
470 }
471 }
472
473 /* XXX possibly a more useful return value */
474 return 1;
475 }
476
477 int
478 lptioctl(dev, cmd, data, flag)
479 dev_t dev;
480 int cmd;
481 caddr_t data;
482 int flag;
483 {
484 int error = 0;
485
486 switch (cmd) {
487 default:
488 error = ENODEV;
489 }
490
491 return error;
492 }
493