|
|
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.