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