|
|
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: * lpa.c,v 1.4 1993/06/05 22:58:29 cgd Exp
49: */
50:
51: /*
52: * Device Driver for AT parallel printer port
53: * Written by William Jolitz 12/18/90
54: * Modified to run without interrupts
55: * 92-08-19 Wolfgang Stanglmeier <[email protected]>
56: * Slight cleanup and reorganization, try to handle restarted syscalls
57: * 92-09-08 Andy Valencia <[email protected]>
58: * 93-04-08 Rodney W. Grimes <[email protected]>
59: * Converted to driver name lpa, shares lptreg.h with lpt.c, fixed probe
60: * so that it returns IO_LPTSIZE. Added dummy lpaioctl. Added my new
61: * probe code from lpt.c, as the one in here was crud.
62: */
63:
64: #include "lpa.h"
65: #if NLPA > 0
66:
67: #include "param.h"
68: #include "buf.h"
69: #include "systm.h"
70: #include "ioctl.h"
71: #include "tty.h"
72: #include "proc.h"
73: #include "user.h"
74: #include "uio.h"
75: #include "kernel.h"
76: #include "malloc.h"
77:
78: #include "i386/isa/isa.h"
79: #include "i386/isa/isa_device.h"
80: #include "i386/isa/lptreg.h"
81:
82: /* internal used flags */
83: #define OPEN (0x01) /* device is open */
84: #define INIT (0x02) /* device in open procedure */
85:
86: /* flags from minor device */
87: #define LPA_PRIME (0x20) /* prime printer on open */
88: #define LPA_ERROR (0x10) /* log error conditions */
89:
90: #define LPA_FLAG(x) ((x) & 0xfc)
91: #define LPA_UNIT(x) ((x) & 0x03)
92:
93: /* Printer Ready condition */
94: #define LPS_INVERT (LPS_NBSY | LPS_NACK | LPS_SEL | LPS_NERR)
95: #define LPS_MASK (LPS_NBSY | LPS_NACK | LPS_OUT | LPS_SEL | LPS_NERR)
96: #define NOT_READY() ((inb(sc->sc_stat)^LPS_INVERT)&LPS_MASK)
97:
98: /* tsleep priority */
99: #define LPPRI ((PZERO+8) | PCATCH)
100:
101: /* debug flags */
102: #ifndef DEBUG
103: #define lprintf
104: #else
105: #define lprintf if (lpaflag) printf
106: int lpaflag = 1;
107: #endif
108:
109: int lpaprobe(), lpaattach();
110: struct isa_driver lpadriver = {lpaprobe, lpaattach, "lpa"};
111:
112: /*
113: * copy usermode data into sysmode buffer
114: */
115: #define BUFSIZE 1024
116:
117: /*
118: ** Waittimes
119: */
120: #define TIMEOUT (hz*16) /* Timeout while open device */
121: #define LONG (hz* 1) /* Timesteps while open */
122:
123: #define MAX_SPIN 255 /* max loop counter for busy wait */
124:
125: struct lpa_softc {
126: char *sc_cp; /* current data to print */
127: int sc_count; /* bytes queued in sc_inbuf */
128: short sc_data; /* printer data port */
129: short sc_stat; /* printer control port */
130: short sc_ctrl; /* printer status port */
131: u_char sc_flags; /* flags (open and internal) */
132: u_char sc_unit; /* unit-number */
133: u_char sc_smax; /* current max busy loop cnt */
134: char /* buffer for data */
135: *sc_inbuf;
136: } lpa_sc[NLPA];
137:
138: /*
139: * Internal routine to lpaprobe to do port tests of one byte value
140: */
141: int
142: lpa_port_test(short port, u_char data, u_char mask)
143: {
144: int temp, timeout;
145:
146: data = data & mask;
147: outb(port, data);
148: timeout = 100;
149: do
150: temp = inb(port) & mask;
151: while (temp != data && --timeout);
152: lprintf("Port 0x%x\tout=%x\tin=%x\n", port, data, temp);
153: return (temp == data);
154: }
155:
156: /*
157: * New lpaprobe routine written by Rodney W. Grimes, 3/25/1993
158: *
159: * Logic:
160: * 1) You should be able to write to and read back the same value
161: * to the data port. Do an alternating zeros, alternating ones,
162: * walking zero, and walking one test to check for stuck bits.
163: *
164: * 2) You should be able to write to and read back the same value
165: * to the control port lower 5 bits, the upper 3 bits are reserved
166: * per the IBM PC technical reference manauls and different boards
167: * do different things with them. Do an alternating zeros, alternating
168: * ones, walking zero, and walking one test to check for stuck bits.
169: *
170: * Some printers drag the strobe line down when the are powered off
171: * so this bit has been masked out of the control port test.
172: *
173: * XXX Some printers may not like a fast pulse on init or strobe, I
174: * don't know at this point, if that becomes a problem these bits
175: * should be turned off in the mask byte for the control port test.
176: *
177: * 3) Set the data and control ports to a value of 0
178: */
179:
180: int
181: lpaprobe(struct isa_device *dvp)
182: {
183: int status;
184: short port;
185: u_char data;
186: u_char mask;
187: int i;
188:
189: status = IO_LPTSIZE;
190:
191: port = dvp->id_iobase + lpt_data;
192: mask = 0xff;
193: while (mask != 0)
194: {
195: data = 0x55; /* Alternating zeros */
196: if (!lpa_port_test(port, data, mask)) status = 0;
197:
198: data = 0xaa; /* Alternating ones */
199: if (!lpa_port_test(port, data, mask)) status = 0;
200:
201: for (i = 0; i < 8; i++) /* Walking zero */
202: {
203: data = ~(1 << i);
204: if (!lpa_port_test(port, data, mask)) status = 0;
205: }
206:
207: for (i = 0; i < 8; i++) /* Walking one */
208: {
209: data = (1 << i);
210: if (!lpa_port_test(port, data, mask)) status = 0;
211: }
212:
213: if (port == dvp->id_iobase + lpt_data)
214: {
215: port = dvp->id_iobase + lpt_control;
216: mask = 0x1e;
217: }
218: else
219: mask = 0;
220: }
221: outb(dvp->id_iobase+lpt_data, 0);
222: outb(dvp->id_iobase+lpt_control, 0);
223: return (status);
224: }
225:
226: /*
227: * lpaattach()
228: * Install device
229: */
230: lpaattach(isdp)
231: struct isa_device *isdp;
232: {
233: struct lpa_softc *sc;
234:
235: sc = lpa_sc + isdp->id_unit;
236: sc->sc_unit = isdp->id_unit;
237: sc->sc_data = isdp->id_iobase + lpt_data;
238: sc->sc_stat = isdp->id_iobase + lpt_status;
239: sc->sc_ctrl = isdp->id_iobase + lpt_control;
240: outb(sc->sc_ctrl, LPC_NINIT);
241: return (1);
242: }
243:
244: /*
245: * lpaopen()
246: * New open on device.
247: *
248: * We forbid all but first open
249: */
250: lpaopen(dev, flag)
251: dev_t dev;
252: int flag;
253: {
254: struct lpa_softc *sc;
255: int delay; /* slept time in 1/hz seconds of tsleep */
256: int err;
257: u_char sta, unit;
258:
259: unit= LPA_UNIT(minor(dev));
260: sta = LPA_FLAG(minor(dev));
261:
262: /* minor number out of limits ? */
263: if (unit >= NLPA)
264: return (ENXIO);
265: sc = lpa_sc + unit;
266:
267: /* Attached ? */
268: if (!sc->sc_ctrl) { /* not attached */
269: return(ENXIO);
270: }
271:
272: /* Printer busy ? */
273: if (sc->sc_flags) { /* too late .. */
274: return(EBUSY);
275: }
276:
277: /* Have memory for buffer? */
278: sc->sc_inbuf = malloc(BUFSIZE, M_DEVBUF, M_WAITOK);
279: if (sc->sc_inbuf == 0)
280: return(ENOMEM);
281:
282: /* Init printer */
283: sc->sc_flags = sta | INIT;
284: if (sc->sc_flags & LPA_PRIME) {
285: outb(sc->sc_ctrl, 0);
286: }
287:
288: /* Select printer */
289: outb(sc->sc_ctrl, LPC_SEL|LPC_NINIT);
290:
291: /* and wait for ready .. */
292: for (delay=0; NOT_READY(); delay+= LONG) {
293: if (delay >= TIMEOUT) { /* too long waited .. */
294: sc->sc_flags = 0;
295: return (EBUSY);
296: }
297:
298: /* sleep a moment */
299: if ((err = tsleep (sc, LPPRI, "lpa: open", LONG)) !=
300: EWOULDBLOCK) {
301: sc->sc_flags = 0;
302: return (EBUSY);
303: }
304: }
305:
306: /* Printer ready .. set variables */
307: sc->sc_flags |= OPEN;
308: sc->sc_count = 0;
309:
310: return(0);
311: }
312:
313: /*
314: * pushbytes()
315: * Workhorse for actually spinning and writing bytes to printer
316: */
317: static
318: pushbytes(sc)
319: struct lpa_softc *sc;
320: {
321: int spin, err, tic;
322: char ch;
323:
324: /* loop for every character .. */
325: while (sc->sc_count > 0) {
326: /* printer data */
327: ch = *(sc->sc_cp);
328: sc->sc_cp += 1;
329: sc->sc_count -= 1;
330: outb(sc->sc_data, ch);
331:
332: /* Busy wait for printer ready .. */
333: spin = tic = 0;
334: while (NOT_READY()) {
335: if (++spin >= sc->sc_smax) {
336: /*
337: * Now sleep, every cycle a
338: * little longer ..
339: */
340: tic = tic + tic + 1;
341: err = tsleep(sc, LPPRI, "lpa: write", tic);
342: if (err != EWOULDBLOCK) {
343: return (err);
344: }
345: }
346: }
347:
348: /* strobe */
349: outb(sc->sc_ctrl, LPC_NINIT|LPC_SEL|LPC_STB);
350: outb(sc->sc_ctrl, LPC_NINIT|LPC_SEL);
351:
352: /* Adapt busy-wait length... */
353: if (spin >= sc->sc_smax) { /* was sleep wait */
354: if (sc->sc_smax<MAX_SPIN)
355: sc->sc_smax++;
356: }
357: if (spin*2 < sc->sc_smax) {
358: sc->sc_smax--;
359: }
360: }
361: return(0);
362: }
363:
364: /*
365: * lpaclose()
366: * Close on lp. Try to flush data in buffer out.
367: */
368: lpaclose(dev, flag)
369: dev_t dev;
370: int flag;
371: {
372: struct lpa_softc *sc = lpa_sc + LPA_UNIT(minor(dev));
373:
374: /* If there's queued data, try to flush it */
375: (void)pushbytes(sc);
376:
377: /* really close .. quite simple :-) */
378: outb(sc->sc_ctrl, LPC_NINIT);
379: sc->sc_flags = 0;
380: free(sc->sc_inbuf, M_DEVBUF);
381: sc->sc_inbuf = 0; /* Sanity */
382: return(0);
383: }
384:
385: /*
386: * lpawrite()
387: * Copy from user's buffer, then print
388: */
389: lpawrite(dev, uio)
390: dev_t dev;
391: struct uio *uio;
392: {
393: struct lpa_softc *sc = lpa_sc + LPA_UNIT(minor(dev));
394: int err;
395:
396: /* Write out old bytes from interrupted syscall */
397: if (sc->sc_count > 0) {
398: err = pushbytes(sc);
399: if (err)
400: return(err);
401: }
402:
403: /* main loop */
404: while ((sc->sc_count = MIN(BUFSIZE, uio->uio_resid)) > 0) {
405: /* get from user-space */
406: sc->sc_cp = sc->sc_inbuf;
407: uiomove(sc->sc_inbuf, sc->sc_count, uio);
408: err = pushbytes(sc);
409: if (err)
410: return(err);
411: }
412: return(0);
413: }
414:
415: int
416: lpaioctl(dev_t dev, int cmd, caddr_t data, int flag)
417: {
418: int error;
419:
420: error = 0;
421: switch (cmd) {
422: #ifdef THISISASAMPLE
423: case XXX:
424: dothis; andthis; andthat;
425: error=x;
426: break;
427: #endif /* THISISASAMPLE */
428: default:
429: error = ENODEV;
430: }
431:
432: return(error);
433: }
434:
435: #endif /* NLPA > 0 */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.