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