Annotation of sys/dev/ic/lpt.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: lpt.c,v 1.5 2002/03/14 01:26:54 millert Exp $ */
2: /* $NetBSD: lpt.c,v 1.42 1996/10/21 22:41:14 thorpej Exp $ */
3:
4: /*
5: * Copyright (c) 1993, 1994 Charles Hannum.
6: * Copyright (c) 1990 William F. Jolitz, TeleMuse
7: * All rights reserved.
8: *
9: * Redistribution and use in source and binary forms, with or without
10: * modification, are permitted provided that the following conditions
11: * are met:
12: * 1. Redistributions of source code must retain the above copyright
13: * notice, this list of conditions and the following disclaimer.
14: * 2. Redistributions in binary form must reproduce the above copyright
15: * notice, this list of conditions and the following disclaimer in the
16: * documentation and/or other materials provided with the distribution.
17: * 3. All advertising materials mentioning features or use of this software
18: * must display the following acknowledgement:
19: * This software is a component of "386BSD" developed by
20: * William F. Jolitz, TeleMuse.
21: * 4. Neither the name of the developer nor the name "386BSD"
22: * may be used to endorse or promote products derived from this software
23: * without specific prior written permission.
24: *
25: * THIS SOFTWARE IS A COMPONENT OF 386BSD DEVELOPED BY WILLIAM F. JOLITZ
26: * AND IS INTENDED FOR RESEARCH AND EDUCATIONAL PURPOSES ONLY. THIS
27: * SOFTWARE SHOULD NOT BE CONSIDERED TO BE A COMMERCIAL PRODUCT.
28: * THE DEVELOPER URGES THAT USERS WHO REQUIRE A COMMERCIAL PRODUCT
29: * NOT MAKE USE OF THIS WORK.
30: *
31: * FOR USERS WHO WISH TO UNDERSTAND THE 386BSD SYSTEM DEVELOPED
32: * BY WILLIAM F. JOLITZ, WE RECOMMEND THE USER STUDY WRITTEN
33: * REFERENCES SUCH AS THE "PORTING UNIX TO THE 386" SERIES
34: * (BEGINNING JANUARY 1991 "DR. DOBBS JOURNAL", USA AND BEGINNING
35: * JUNE 1991 "UNIX MAGAZIN", GERMANY) BY WILLIAM F. JOLITZ AND
36: * LYNNE GREER JOLITZ, AS WELL AS OTHER BOOKS ON UNIX AND THE
37: * ON-LINE 386BSD USER MANUAL BEFORE USE. A BOOK DISCUSSING THE INTERNALS
38: * OF 386BSD ENTITLED "386BSD FROM THE INSIDE OUT" WILL BE AVAILABLE LATE 1992.
39: *
40: * THIS SOFTWARE IS PROVIDED BY THE DEVELOPER ``AS IS'' AND
41: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
42: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
43: * ARE DISCLAIMED. IN NO EVENT SHALL THE DEVELOPER BE LIABLE
44: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
45: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
46: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
47: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
48: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
49: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
50: * SUCH DAMAGE.
51: */
52:
53: /*
54: * Device Driver for AT parallel printer port
55: */
56:
57: #include <sys/param.h>
58: #include <sys/systm.h>
59: #include <sys/proc.h>
60: #include <sys/user.h>
61: #include <sys/buf.h>
62: #include <sys/kernel.h>
63: #include <sys/ioctl.h>
64: #include <sys/uio.h>
65: #include <sys/device.h>
66: #include <sys/conf.h>
67: #include <sys/syslog.h>
68:
69: #include <machine/bus.h>
70: #include <machine/intr.h>
71:
72: #include <dev/ic/lptreg.h>
73: #include <dev/ic/lptvar.h>
74:
75: #include "lpt.h"
76:
77: #define TIMEOUT hz*16 /* wait up to 16 seconds for a ready */
78: #define STEP hz/4
79:
80: #define LPTPRI (PZERO+8)
81: #define LPT_BSIZE 1024
82:
83: #if !defined(DEBUG) || !defined(notdef)
84: #define LPRINTF(a)
85: #else
86: #define LPRINTF(a) if (lptdebug) printf a
87: int lptdebug = 1;
88: #endif
89:
90: /* XXX does not belong here */
91: cdev_decl(lpt);
92:
93: struct cfdriver lpt_cd = {
94: NULL, "lpt", DV_TTY
95: };
96:
97: #define LPTUNIT(s) (minor(s) & 0x1f)
98: #define LPTFLAGS(s) (minor(s) & 0xe0)
99:
100: #define LPS_INVERT (LPS_SELECT|LPS_NERR|LPS_NBSY|LPS_NACK)
101: #define LPS_MASK (LPS_SELECT|LPS_NERR|LPS_NBSY|LPS_NACK|LPS_NOPAPER)
102: #define NOT_READY() \
103: ((bus_space_read_1(iot, ioh, lpt_status) ^ LPS_INVERT) & LPS_MASK)
104: #define NOT_READY_ERR() \
105: lpt_not_ready(bus_space_read_1(iot, ioh, lpt_status), sc)
106:
107: int lpt_not_ready(u_int8_t, struct lpt_softc *);
108: void lptwakeup(void *arg);
109: int lptpushbytes(struct lpt_softc *);
110:
111: /*
112: * Internal routine to lptprobe to do port tests of one byte value.
113: */
114: int
115: lpt_port_test(iot, ioh, base, off, data, mask)
116: bus_space_tag_t iot;
117: bus_space_handle_t ioh;
118: bus_addr_t base;
119: bus_size_t off;
120: u_int8_t data, mask;
121: {
122: int timeout;
123: u_int8_t temp;
124:
125: data &= mask;
126: bus_space_write_1(iot, ioh, off, data);
127: timeout = 1000;
128: do {
129: delay(10);
130: temp = bus_space_read_1(iot, ioh, off) & mask;
131: } while (temp != data && --timeout);
132: LPRINTF(("lpt: port=0x%x out=0x%x in=0x%x timeout=%d\n", base + off,
133: data, temp, timeout));
134: return (temp == data);
135: }
136:
137: void
138: lpt_attach_common(sc)
139: struct lpt_softc *sc;
140: {
141: printf("\n");
142:
143: bus_space_write_1(sc->sc_iot, sc->sc_ioh, lpt_control, LPC_NINIT);
144:
145: timeout_set(&sc->sc_wakeup_tmo, lptwakeup, sc);
146: }
147:
148: /*
149: * Reset the printer, then wait until it's selected and not busy.
150: */
151: int
152: lptopen(dev, flag, mode, p)
153: dev_t dev;
154: int flag;
155: int mode;
156: struct proc *p;
157: {
158: int unit = LPTUNIT(dev);
159: u_int8_t flags = LPTFLAGS(dev);
160: struct lpt_softc *sc;
161: bus_space_tag_t iot;
162: bus_space_handle_t ioh;
163: u_int8_t control;
164: int error;
165: int spin;
166:
167: if (unit >= lpt_cd.cd_ndevs)
168: return ENXIO;
169: sc = lpt_cd.cd_devs[unit];
170: if (!sc)
171: return ENXIO;
172:
173: sc->sc_flags = (sc->sc_flags & LPT_POLLED) | flags;
174: if ((sc->sc_flags & (LPT_POLLED|LPT_NOINTR)) == LPT_POLLED)
175: return ENXIO;
176:
177: #ifdef DIAGNOSTIC
178: if (sc->sc_state)
179: printf("%s: stat=0x%x not zero\n", sc->sc_dev.dv_xname,
180: sc->sc_state);
181: #endif
182:
183: if (sc->sc_state)
184: return EBUSY;
185:
186: sc->sc_state = LPT_INIT;
187: LPRINTF(("%s: open: flags=0x%x\n", sc->sc_dev.dv_xname, flags));
188: iot = sc->sc_iot;
189: ioh = sc->sc_ioh;
190:
191: if ((flags & LPT_NOPRIME) == 0) {
192: /* assert INIT for 100 usec to start up printer */
193: bus_space_write_1(iot, ioh, lpt_control, LPC_SELECT);
194: delay(100);
195: }
196:
197: control = LPC_SELECT | LPC_NINIT;
198: bus_space_write_1(iot, ioh, lpt_control, control);
199:
200: /* wait till ready (printer running diagnostics) */
201: for (spin = 0; NOT_READY_ERR(); spin += STEP) {
202: if (spin >= TIMEOUT) {
203: sc->sc_state = 0;
204: return EBUSY;
205: }
206:
207: /* wait 1/4 second, give up if we get a signal */
208: error = tsleep((caddr_t)sc, LPTPRI | PCATCH, "lptopen", STEP);
209: if (error != EWOULDBLOCK) {
210: sc->sc_state = 0;
211: return error;
212: }
213: }
214:
215: if ((flags & LPT_NOINTR) == 0)
216: control |= LPC_IENABLE;
217: if (flags & LPT_AUTOLF)
218: control |= LPC_AUTOLF;
219: sc->sc_control = control;
220: bus_space_write_1(iot, ioh, lpt_control, control);
221:
222: sc->sc_inbuf = geteblk(LPT_BSIZE);
223: sc->sc_count = 0;
224: sc->sc_state = LPT_OPEN;
225:
226: if ((sc->sc_flags & LPT_NOINTR) == 0)
227: lptwakeup(sc);
228:
229: LPRINTF(("%s: opened\n", sc->sc_dev.dv_xname));
230: return 0;
231: }
232:
233: int
234: lpt_not_ready(status, sc)
235: u_int8_t status;
236: struct lpt_softc *sc;
237: {
238: u_int8_t new;
239:
240: status = (status ^ LPS_INVERT) & LPS_MASK;
241: new = status & ~sc->sc_laststatus;
242: sc->sc_laststatus = status;
243:
244: if (new & LPS_SELECT)
245: log(LOG_NOTICE, "%s: offline\n", sc->sc_dev.dv_xname);
246: else if (new & LPS_NOPAPER)
247: log(LOG_NOTICE, "%s: out of paper\n", sc->sc_dev.dv_xname);
248: else if (new & LPS_NERR)
249: log(LOG_NOTICE, "%s: output error\n", sc->sc_dev.dv_xname);
250:
251: return status;
252: }
253:
254: void
255: lptwakeup(arg)
256: void *arg;
257: {
258: struct lpt_softc *sc = arg;
259: int s;
260:
261: s = spltty();
262: lptintr(sc);
263: splx(s);
264:
265: timeout_add(&sc->sc_wakeup_tmo, STEP);
266: }
267:
268: /*
269: * Close the device, and free the local line buffer.
270: */
271: int
272: lptclose(dev, flag, mode, p)
273: dev_t dev;
274: int flag;
275: int mode;
276: struct proc *p;
277: {
278: int unit = LPTUNIT(dev);
279: struct lpt_softc *sc = lpt_cd.cd_devs[unit];
280: bus_space_tag_t iot = sc->sc_iot;
281: bus_space_handle_t ioh = sc->sc_ioh;
282:
283: if (sc->sc_count)
284: (void) lptpushbytes(sc);
285:
286: if ((sc->sc_flags & LPT_NOINTR) == 0)
287: timeout_del(&sc->sc_wakeup_tmo);
288:
289: bus_space_write_1(iot, ioh, lpt_control, LPC_NINIT);
290: sc->sc_state = 0;
291: bus_space_write_1(iot, ioh, lpt_control, LPC_NINIT);
292: brelse(sc->sc_inbuf);
293:
294: LPRINTF(("%s: closed\n", sc->sc_dev.dv_xname));
295: return 0;
296: }
297:
298: int
299: lptpushbytes(sc)
300: struct lpt_softc *sc;
301: {
302: bus_space_tag_t iot = sc->sc_iot;
303: bus_space_handle_t ioh = sc->sc_ioh;
304: int error;
305:
306: if (sc->sc_flags & LPT_NOINTR) {
307: int spin, tic;
308: u_int8_t control = sc->sc_control;
309:
310: while (sc->sc_count > 0) {
311: spin = 0;
312: while (NOT_READY()) {
313: if (++spin < sc->sc_spinmax)
314: continue;
315: tic = 0;
316: /* adapt busy-wait algorithm */
317: sc->sc_spinmax++;
318: while (NOT_READY_ERR()) {
319: /* exponential backoff */
320: tic = tic + tic + 1;
321: if (tic > TIMEOUT)
322: tic = TIMEOUT;
323: error = tsleep((caddr_t)sc,
324: LPTPRI | PCATCH, "lptpsh", tic);
325: if (error != EWOULDBLOCK)
326: return error;
327: }
328: break;
329: }
330:
331: bus_space_write_1(iot, ioh, lpt_data, *sc->sc_cp++);
332: bus_space_write_1(iot, ioh, lpt_control,
333: control | LPC_STROBE);
334: sc->sc_count--;
335: bus_space_write_1(iot, ioh, lpt_control, control);
336:
337: /* adapt busy-wait algorithm */
338: if (spin*2 + 16 < sc->sc_spinmax)
339: sc->sc_spinmax--;
340: }
341: } else {
342: int s;
343:
344: while (sc->sc_count > 0) {
345: /* if the printer is ready for a char, give it one */
346: if ((sc->sc_state & LPT_OBUSY) == 0) {
347: LPRINTF(("%s: write %d\n", sc->sc_dev.dv_xname,
348: sc->sc_count));
349: s = spltty();
350: (void) lptintr(sc);
351: splx(s);
352: }
353: error = tsleep((caddr_t)sc, LPTPRI | PCATCH,
354: "lptwrite2", 0);
355: if (error)
356: return error;
357: }
358: }
359: return 0;
360: }
361:
362: /*
363: * Copy a line from user space to a local buffer, then call putc to get the
364: * chars moved to the output queue.
365: */
366: int
367: lptwrite(dev, uio, flags)
368: dev_t dev;
369: struct uio *uio;
370: int flags;
371: {
372: struct lpt_softc *sc = lpt_cd.cd_devs[LPTUNIT(dev)];
373: size_t n;
374: int error = 0;
375:
376: while ((n = min(LPT_BSIZE, uio->uio_resid)) != 0) {
377: uiomove(sc->sc_cp = sc->sc_inbuf->b_data, n, uio);
378: sc->sc_count = n;
379: error = lptpushbytes(sc);
380: if (error) {
381: /*
382: * Return accurate residual if interrupted or timed
383: * out.
384: */
385: uio->uio_resid += sc->sc_count;
386: sc->sc_count = 0;
387: return error;
388: }
389: }
390: return 0;
391: }
392:
393: /*
394: * Handle printer interrupts which occur when the printer is ready to accept
395: * another char.
396: */
397: int
398: lptintr(arg)
399: void *arg;
400: {
401: struct lpt_softc *sc = arg;
402: bus_space_tag_t iot = sc->sc_iot;
403: bus_space_handle_t ioh = sc->sc_ioh;
404:
405: if (((sc->sc_state & LPT_OPEN) == 0 && sc->sc_count == 0) ||
406: (sc->sc_flags & LPT_NOINTR))
407: return 0;
408:
409: /* is printer online and ready for output */
410: if (NOT_READY() && NOT_READY_ERR())
411: return -1;
412:
413: if (sc->sc_count) {
414: u_int8_t control = sc->sc_control;
415: /* send char */
416: bus_space_write_1(iot, ioh, lpt_data, *sc->sc_cp++);
417: delay (50);
418: bus_space_write_1(iot, ioh, lpt_control, control | LPC_STROBE);
419: sc->sc_count--;
420: bus_space_write_1(iot, ioh, lpt_control, control);
421: sc->sc_state |= LPT_OBUSY;
422: } else
423: sc->sc_state &= ~LPT_OBUSY;
424:
425: if (sc->sc_count == 0) {
426: /* none, wake up the top half to get more */
427: wakeup((caddr_t)sc);
428: }
429:
430: return 1;
431: }
432:
433: int
434: lptioctl(dev, cmd, data, flag, p)
435: dev_t dev;
436: u_long cmd;
437: caddr_t data;
438: int flag;
439: struct proc *p;
440: {
441: int error = 0;
442:
443: switch (cmd) {
444: default:
445: error = ENODEV;
446: }
447:
448: return error;
449: }
CVSweb