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