|
|
1.1 root 1: /*
2: * This is a driver for PC parallel printers.
3: * It has been tested on an EPSON MX-80, Printronix P300, HP LaserJet II.
4: * Supports up to three line printers.
5: */
6: #include <sys/coherent.h>
7: #ifdef _I386
8: #include <sys/reg.h>
9: #else
10: #include <sys/i8086.h>
11: #endif
12: #include <sys/con.h>
13: #include <sys/devices.h>
14: #include <errno.h>
15: #include <sys/io.h>
16: #include <sys/proc.h>
17: #include <sys/stat.h>
18:
19: /*
20: * Patchable parameters.
21: *
22: * LP0_OK specifies whether LP0 is always THERE.
23: * LPTIME specifies number of ticks between polls.
24: * LPWAIT specifies loop counter to wait in poll.
25: * LPTEST specifies whether or not to test for on-line conditition.
26: */
27: int LP0_OK = 0;
28: int LPTIME = 4;
29: int LPWAIT = 400;
30: int LPTEST = 1;
31:
32: /*
33: * Driver configuration.
34: */
35: int lpload();
36: int lpunload();
37: int lpwrite();
38: int lpopen();
39: int lpclose();
40: int lpintr();
41: int nulldev();
42: int nonedev();
43:
44: CON lpcon = {
45: DFCHR, /* Flags */
46: LP_MAJOR, /* Major index */
47: lpopen, /* Open */
48: lpclose, /* Close */
49: nulldev, /* Block */
50: nonedev, /* Read */
51: lpwrite, /* Write */
52: nonedev, /* Ioctl */
53: nulldev, /* Powerfail */
54: nulldev, /* Timeout */
55: lpload, /* Load */
56: lpunload /* Unload */
57: };
58:
59: /*
60: * Line Printer Registers.
61: */
62: #define LPDAT (0) /* Data port, lpbase + 0 */
63: #define LPSTR (1) /* Status port, lpbase + 1 */
64: #define LPCSR (2) /* Control port, lpbase + 2 */
65:
66: /*
67: * LP Flag Bits.
68: */
69: #define LPTHERE 0x01 /* Interface actually there */
70: #define LPOPEN 0x02 /* Printer is open */
71: #define LPSLEEP 0x04 /* Sleeping on buffer event */
72: #define LPRAW 0x80 /* Raw mode */
73:
74: /*
75: * Printer database.
76: * Terminated by lpbase = 0.
77: * NLP = # entries - 1.
78: */
79: static struct lpinfo {
80: int lpbase; /* I/O Base address */
81: int lpflag; /* Flags */
82: int lpcol; /* Current horizontal position */
83: } lpinfo[] = {
84: { 0x3BC },
85: { 0x378 },
86: { 0x278 },
87: { 0x000 }
88: };
89: #define NLP (sizeof(lpinfo) / sizeof(lpinfo[0]) - 1)
90:
91: /*
92: * LP Status Register Bits.
93: */
94: #define ACK 0x80 /* Ack (active high) */
95: #define BUSY 0x40 /* Busy (active high) */
96: #define NOPAPER 0x20 /* No paper */
97: #define ONLINE 0x10 /* On line */
98: #define NERROR 0x08 /* Error (active low) */
99:
100: /* IBM cable */
101: #define IBMNBSY 0x80 /* Busy (active low) */
102: #define IBMNACK 0x40 /* Ack (active low) */
103:
104: /*
105: * LP Control Register Bits.
106: */
107: #define IENABLE 0x10 /* Interrupt enable */
108: #define SEL 0x08 /* Select input */
109: #define NINIT 0x04 /* Initialise printer (active low) */
110: #define AFEED 0x02 /* Auto line feed */
111: #define STROBE 0x01 /* Strobe */
112:
113: /*
114: * On load
115: * compute the port addresses,
116: * reset the printer, and select it.
117: */
118: static
119: lpload()
120: {
121: register struct lpinfo * p;
122: register int delay;
123: static int notfirst;
124:
125: /*
126: * Only initialize hardware on first invocation.
127: * Necessary if used as console device [condev].
128: */
129: if ( notfirst )
130: return;
131: notfirst = 1;
132:
133: /*
134: * Note: since some PC clones lp ports can't be read,
135: * their lpflag field has to be patched to 'LPTHERE'.
136: */
137: if ( LP0_OK & 1 )
138: lpinfo[0].lpflag |= LPTHERE;
139: if ( LP0_OK & 2 )
140: lpinfo[1].lpflag |= LPTHERE;
141: if ( LP0_OK & 4 )
142: lpinfo[2].lpflag |= LPTHERE;
143:
144: for ( p = lpinfo; p->lpbase ; ++p ) {
145:
146: /*
147: * Check printer port existence.
148: */
149: if ( (p->lpflag & LPTHERE) == 0 ) {
150: outb( p->lpbase+LPDAT, 0xA5 );
151: delay = LPWAIT; do {
152: } while (--delay);
153: if ( inb(p->lpbase+LPDAT) == 0xA5 )
154: p->lpflag |= LPTHERE;
155: }
156:
157: /*
158: * Initialize and select printer.
159: */
160: outb( p->lpbase+LPCSR, SEL );
161: delay = LPWAIT; do {
162: } while (--delay);
163: outb( p->lpbase+LPCSR, SEL|NINIT );
164: }
165: }
166:
167: /*
168: * On unload
169: * cancel any timed functions.
170: */
171: static
172: lpunload()
173: {
174: lptimer();
175: }
176:
177: /*
178: * The open routine makes sure that
179: * only one process has the printer open
180: * at one time, and not too much else.
181: */
182: static
183: lpopen(dev, mode)
184: dev_t dev;
185: {
186: register struct lpinfo * p;
187:
188: /*
189: * Illegal printer port.
190: */
191: if ( (minor(dev) & ~LPRAW) >= NLP ) {
192: u.u_error = ENXIO;
193: return;
194: }
195:
196: /*
197: * Access attributes.
198: */
199: p = &lpinfo[ minor(dev) & ~LPRAW ];
200:
201: /*
202: * Attempt initialization if printer port not found.
203: */
204: if ( (p->lpflag&LPTHERE) == 0 )
205: lpload();
206:
207: /*
208: * Printer port not found.
209: */
210: if ( (p->lpflag&LPTHERE) == 0 ) {
211: u.u_error = ENXIO;
212: return;
213: }
214:
215: /*
216: * Printer port already open.
217: */
218: if ( (p->lpflag&LPOPEN) != 0 ) {
219: #ifdef _I386
220: u.u_error = EBUSY;
221: #else
222: u.u_error = EDBUSY;
223: #endif
224: return;
225: }
226:
227: /*
228: * Printer powered off or off-line
229: */
230: if (LPTEST && !(inb(p->lpbase+LPSTR) & ONLINE)) {
231: #ifdef _I386
232: u.u_error = EIO;
233: #else
234: u.u_error = EDATTN;
235: #endif
236: return;
237: }
238:
239: /*
240: * Flag port as being open.
241: */
242: p->lpflag &= ~LPRAW;
243: p->lpflag |= LPOPEN | minor(dev) & LPRAW;
244:
245: /*
246: * Initiate periodic printer scan if user open.
247: */
248: if ( (SELF != NULL) && (SELF->p_pid != 0) )
249: lptimer();
250: }
251:
252: /*
253: * The close routine marks the device as no longer open.
254: */
255: static
256: lpclose(dev)
257: dev_t dev;
258: {
259: lpinfo[ minor(dev) & ~LPRAW ].lpflag &= ~LPOPEN;
260: }
261:
262: /*
263: * The write routine copies the
264: * characters from the user buffer to
265: * the printer buffer, expanding tabs and
266: * keeping track of the current horizontal
267: * position of the print head.
268: */
269: static
270: lpwrite( dev, iop )
271: dev_t dev;
272: IO *iop;
273: {
274: register struct lpinfo * p;
275: register int c;
276:
277: p = &lpinfo[ minor(dev) & ~LPRAW ];
278:
279: /*
280: * Writes from kernel are handled via busy-waits instead of timeouts.
281: */
282: if (iop->io_seg == IOSYS) {
283:
284: while ( (c=iogetc(iop)) >= 0 ) {
285:
286: while ( (inb(p->lpbase+LPSTR) & IBMNBSY) == 0 )
287: ;
288:
289: outb( p->lpbase+LPDAT, c );
290: outb( p->lpbase+LPCSR, SEL|NINIT|STROBE );
291: outb( p->lpbase+LPCSR, SEL|NINIT );
292: }
293: return;
294: }
295:
296: /*
297: * Writes from user are handled via lpchar() which uses timeouts.
298: */
299: while ( (c=iogetc(iop)) >= 0 ) {
300:
301: if ( (p->lpflag&LPRAW) == 0 ) {
302:
303: switch (c) {
304:
305: case '\t':
306: do {
307: lpchar( p, ' ');
308: } while ((++p->lpcol&07) != 0);
309: continue;
310:
311: case '\n':
312: lpchar( p, '\r');
313: /* no break */
314:
315: case '\r':
316: case '\f':
317: p->lpcol = 0;
318: break;
319:
320: case '\b':
321: --p->lpcol;
322: break;
323:
324: default:
325: ++p->lpcol;
326: }
327: }
328: lpchar( p, c );
329:
330: if ( SELF->p_ssig!=0 && nondsig() ) {
331: u.u_error = EINTR;
332: break;
333: }
334: }
335: }
336:
337: /*
338: * Put a character into the printer buffer.
339: * If the printer doesn't respond ready in a reasonable time
340: * sleep for a while.
341: */
342: static
343: lpchar( p, c )
344: register struct lpinfo *p;
345: int c;
346: {
347: register int s;
348:
349: s = LPWAIT;
350: while ( (inb(p->lpbase+LPSTR) & IBMNBSY) == 0 ) {
351: if ( --s == 0 ) {
352: s = sphi();
353: p->lpflag |= LPSLEEP;
354: sleep((char *)p, 0, 0, 0);
355: spl(s);
356: s = LPWAIT;
357: }
358: }
359:
360: outb( p->lpbase+LPDAT, c );
361: outb( p->lpbase+LPCSR, SEL|NINIT|STROBE );
362: outb( p->lpbase+LPCSR, SEL|NINIT );
363: }
364:
365: /*
366: * Poll the line printer interface from the clock.
367: * Turn it off when there is nothing left to do.
368: */
369: static
370: lptimer()
371: {
372: register struct lpinfo *p;
373: int isopen = 0;
374: static TIM tim;
375:
376: /*
377: * Scan all printers.
378: */
379: for ( p = lpinfo; p->lpbase; ++p ) {
380:
381: /*
382: * Ignore unopened printers.
383: */
384: if ( (p->lpflag & LPOPEN) == 0 )
385: continue;
386:
387: ++isopen;
388:
389: /*
390: * Check for sleeping process on ready printer.
391: */
392: if((p->lpflag & LPSLEEP) && (inb(p->lpbase+LPSTR) & IBMNBSY)){
393: p->lpflag &= ~LPSLEEP;
394: wakeup((char *)p);
395: }
396: }
397:
398: /*
399: * Reschedule timer function if at least 1 printer is still open.
400: */
401: if ( isopen )
402: timeout( &tim, LPTIME, lptimer, &tim );
403: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.