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