1*17074Sbloom /* lp.c 6.4 84/08/29 */ 21921Swnj 31941Swnj #include "lp.h" 42963Stoy #if NLP > 0 51921Swnj /* 61921Swnj * LP-11 Line printer driver 71921Swnj * 81921Swnj * This driver has been modified to work on printers where 91921Swnj * leaving IENABLE set would cause continuous interrupts. 101921Swnj */ 119775Ssam #include "../machine/pte.h" 121921Swnj 13*17074Sbloom #include "param.h" 14*17074Sbloom #include "dir.h" 15*17074Sbloom #include "user.h" 16*17074Sbloom #include "buf.h" 17*17074Sbloom #include "systm.h" 18*17074Sbloom #include "map.h" 19*17074Sbloom #include "uio.h" 20*17074Sbloom #include "tty.h" 21*17074Sbloom #include "kernel.h" 221921Swnj 23*17074Sbloom #include "ubavar.h" 248476Sroot 251921Swnj #define LPPRI (PZERO+8) 261921Swnj #define IENABLE 0100 271921Swnj #define DONE 0200 281921Swnj #define ERROR 0100000 291921Swnj #define LPLWAT 650 301921Swnj #define LPHWAT 800 311921Swnj 322963Stoy #define MAXCOL 132 332963Stoy #define CAP 1 342963Stoy 352963Stoy #define LPUNIT(dev) (minor(dev) >> 3) 362963Stoy 372963Stoy struct lpdevice { 381921Swnj short lpsr; 391921Swnj short lpbuf; 401921Swnj }; 411921Swnj 422963Stoy struct lp_softc { 432963Stoy struct clist sc_outq; 442963Stoy int sc_state; 452963Stoy int sc_physcol; 462963Stoy int sc_logcol; 472963Stoy int sc_physline; 482963Stoy char sc_flags; 4910112Ssam short sc_maxcol; 502963Stoy int sc_lpchar; 512963Stoy struct buf *sc_inbuf; 522963Stoy } lp_softc[NLP]; 531921Swnj 542963Stoy struct uba_device *lpinfo[NLP]; 552963Stoy 562963Stoy int lpprobe(), lpattach(), lptout(); 572963Stoy u_short lpstd[] = { 0177514 }; 582963Stoy struct uba_driver lpdriver = 592963Stoy { lpprobe, 0, lpattach, 0, lpstd, "lp", lpinfo }; 602963Stoy 611921Swnj /* bits for state */ 621921Swnj #define OPEN 1 /* device is open */ 631921Swnj #define TOUT 2 /* timeout is active */ 641921Swnj #define MOD 4 /* device state has been modified */ 651921Swnj #define ASLP 8 /* awaiting draining of printer */ 661921Swnj 671921Swnj int lptout(); 681921Swnj 693205Swnj lpattach(ui) 703205Swnj struct uba_device *ui; 713205Swnj { 723205Swnj register struct lp_softc *sc; 733205Swnj 743205Swnj sc = &lp_softc[ui->ui_unit]; 753205Swnj sc->sc_lpchar = -1; 7610112Ssam if (ui->ui_flags) 7710112Ssam sc->sc_maxcol = ui->ui_flags; 7810112Ssam else 7910112Ssam sc->sc_maxcol = MAXCOL; 803205Swnj } 813205Swnj 823205Swnj lpprobe(reg) 833205Swnj caddr_t reg; 843205Swnj { 853250Swnj register int br, cvec; /* value-result */ 863205Swnj register struct lpdevice *lpaddr = (struct lpdevice *)reg; 873986Sroot #ifdef lint 883986Sroot br = 0; cvec = br; br = cvec; 894935Swnj lpintr(0); 903986Sroot #endif 913205Swnj 923205Swnj lpaddr->lpsr = IENABLE; 933250Swnj DELAY(5); 943205Swnj lpaddr->lpsr = 0; 957411Skre return (sizeof (struct lpdevice)); 963205Swnj } 973205Swnj 981921Swnj /*ARGSUSED*/ 991921Swnj lpopen(dev, flag) 1003205Swnj dev_t dev; 1013205Swnj int flag; 1021921Swnj { 1032963Stoy register struct lpdevice *lpaddr; 1042963Stoy register struct lp_softc *sc; 1052963Stoy register struct uba_device *ui; 10617002Smckusick register int unit, s; 1071921Swnj 1083205Swnj if ((unit = LPUNIT(dev)) >= NLP || 1093205Swnj (sc = &lp_softc[unit])->sc_state&OPEN || 1108570Sroot (ui = lpinfo[unit]) == 0 || ui->ui_alive == 0) 1118570Sroot return (ENXIO); 1123205Swnj lpaddr = (struct lpdevice *)ui->ui_addr; 1138570Sroot if (lpaddr->lpsr&ERROR) 1148570Sroot return (EIO); 1152963Stoy sc->sc_state |= OPEN; 1167184Sroot sc->sc_inbuf = geteblk(512); 1172963Stoy sc->sc_flags = minor(dev) & 07; 11817002Smckusick s = spl4(); 1192963Stoy if ((sc->sc_state&TOUT) == 0) { 1202963Stoy sc->sc_state |= TOUT; 1213986Sroot timeout(lptout, (caddr_t)dev, 10*hz); 1221921Swnj } 12317002Smckusick splx(s); 1243205Swnj lpcanon(dev, '\f'); 1258570Sroot return (0); 1261921Swnj } 1271921Swnj 1281921Swnj /*ARGSUSED*/ 1291921Swnj lpclose(dev, flag) 1303205Swnj dev_t dev; 1313205Swnj int flag; 1321921Swnj { 1333205Swnj register struct lp_softc *sc = &lp_softc[LPUNIT(dev)]; 1341921Swnj 1353205Swnj lpcanon(dev, '\f'); 1362963Stoy brelse(sc->sc_inbuf); 1372963Stoy sc->sc_state &= ~OPEN; 1381921Swnj } 1391921Swnj 1407835Sroot lpwrite(dev, uio) 1413205Swnj dev_t dev; 1427835Sroot struct uio *uio; 1431921Swnj { 1443986Sroot register unsigned n; 1451921Swnj register char *cp; 1463205Swnj register struct lp_softc *sc = &lp_softc[LPUNIT(dev)]; 1478491Sroot int error; 1481921Swnj 14913091Ssam while (n = min(512, (unsigned)uio->uio_resid)) { 1502963Stoy cp = sc->sc_inbuf->b_un.b_addr; 15113091Ssam error = uiomove(cp, (int)n, UIO_WRITE, uio); 1528491Sroot if (error) 1538491Sroot return (error); 1541921Swnj do 1553205Swnj lpcanon(dev, *cp++); 1561921Swnj while (--n); 1571921Swnj } 1588491Sroot return (0); 1591921Swnj } 1601921Swnj 1613205Swnj lpcanon(dev, c) 1623205Swnj dev_t dev; 1633205Swnj register int c; 1641921Swnj { 1653205Swnj register struct lp_softc *sc = &lp_softc[LPUNIT(dev)]; 16617002Smckusick register int logcol, physcol, s; 1671921Swnj 1682963Stoy if (sc->sc_flags&CAP) { 1691921Swnj register c2; 1701921Swnj 1711921Swnj if (c>='a' && c<='z') 1721921Swnj c += 'A'-'a'; else 1731921Swnj switch (c) { 1741921Swnj 1751921Swnj case '{': 1761921Swnj c2 = '('; 1771921Swnj goto esc; 1781921Swnj 1791921Swnj case '}': 1801921Swnj c2 = ')'; 1811921Swnj goto esc; 1821921Swnj 1831921Swnj case '`': 1841921Swnj c2 = '\''; 1851921Swnj goto esc; 1861921Swnj 1871921Swnj case '|': 1881921Swnj c2 = '!'; 1891921Swnj goto esc; 1901921Swnj 1911921Swnj case '~': 1921921Swnj c2 = '^'; 1931921Swnj 1941921Swnj esc: 1953205Swnj lpcanon(dev, c2); 1962963Stoy sc->sc_logcol--; 1971921Swnj c = '-'; 1981921Swnj } 1991921Swnj } 2002963Stoy logcol = sc->sc_logcol; 2012963Stoy physcol = sc->sc_physcol; 2021921Swnj if (c == ' ') 2031921Swnj logcol++; 2041921Swnj else switch(c) { 2051921Swnj 2061921Swnj case '\t': 2073328Swnj logcol = (logcol+8) & ~7; 2081921Swnj break; 2091921Swnj 2101921Swnj case '\f': 2112963Stoy if (sc->sc_physline == 0 && physcol == 0) 2122044Swnj break; 2132206Stoy /* fall into ... */ 2142206Stoy 2152206Stoy case '\n': 2163205Swnj lpoutput(dev, c); 2172044Swnj if (c == '\f') 2182963Stoy sc->sc_physline = 0; 2192044Swnj else 2202963Stoy sc->sc_physline++; 2212206Stoy physcol = 0; 2221921Swnj /* fall into ... */ 2231921Swnj 2241921Swnj case '\r': 22517002Smckusick s = spl4(); 2262963Stoy logcol = 0; 2273205Swnj lpintr(LPUNIT(dev)); 22817002Smckusick splx(s); 2291921Swnj break; 2301921Swnj 2311921Swnj case '\b': 2321921Swnj if (logcol > 0) 2331921Swnj logcol--; 2341921Swnj break; 2351921Swnj 2361921Swnj default: 2371921Swnj if (logcol < physcol) { 2383205Swnj lpoutput(dev, '\r'); 2391921Swnj physcol = 0; 2401921Swnj } 24110112Ssam if (logcol < sc->sc_maxcol) { 2421921Swnj while (logcol > physcol) { 2433205Swnj lpoutput(dev, ' '); 2441921Swnj physcol++; 2451921Swnj } 2463205Swnj lpoutput(dev, c); 2471921Swnj physcol++; 2481921Swnj } 2491921Swnj logcol++; 2501921Swnj } 2511921Swnj if (logcol > 1000) /* ignore long lines */ 2521921Swnj logcol = 1000; 2532963Stoy sc->sc_logcol = logcol; 2542963Stoy sc->sc_physcol = physcol; 2551921Swnj } 2561921Swnj 2573205Swnj lpoutput(dev, c) 2583205Swnj dev_t dev; 2593205Swnj int c; 2601921Swnj { 2613205Swnj register struct lp_softc *sc = &lp_softc[LPUNIT(dev)]; 26217002Smckusick int s; 2631921Swnj 2642963Stoy if (sc->sc_outq.c_cc >= LPHWAT) { 26517002Smckusick s = spl4(); 2663205Swnj lpintr(LPUNIT(dev)); /* unchoke */ 2672963Stoy while (sc->sc_outq.c_cc >= LPHWAT) { 2682963Stoy sc->sc_state |= ASLP; /* must be ERROR */ 2692963Stoy sleep((caddr_t)sc, LPPRI); 2701921Swnj } 27117002Smckusick splx(s); 2721921Swnj } 2732963Stoy while (putc(c, &sc->sc_outq)) 2741921Swnj sleep((caddr_t)&lbolt, LPPRI); 2751921Swnj } 2761921Swnj 2773205Swnj lpintr(lp11) 2783205Swnj int lp11; 2791921Swnj { 2801921Swnj register int n; 2813205Swnj register struct lp_softc *sc = &lp_softc[lp11]; 2823205Swnj register struct uba_device *ui = lpinfo[lp11]; 2833205Swnj register struct lpdevice *lpaddr = (struct lpdevice *)ui->ui_addr; 2841921Swnj 2852963Stoy lpaddr->lpsr &= ~IENABLE; 2862963Stoy n = sc->sc_outq.c_cc; 2872963Stoy if (sc->sc_lpchar < 0) 2882963Stoy sc->sc_lpchar = getc(&sc->sc_outq); 2892963Stoy while ((lpaddr->lpsr&DONE) && sc->sc_lpchar >= 0) { 2902963Stoy lpaddr->lpbuf = sc->sc_lpchar; 2912963Stoy sc->sc_lpchar = getc(&sc->sc_outq); 2921921Swnj } 2932963Stoy sc->sc_state |= MOD; 2942963Stoy if (sc->sc_outq.c_cc > 0 && (lpaddr->lpsr&ERROR)==0) 2952963Stoy lpaddr->lpsr |= IENABLE; /* ok and more to do later */ 2962963Stoy if (n>LPLWAT && sc->sc_outq.c_cc<=LPLWAT && sc->sc_state&ASLP) { 2972963Stoy sc->sc_state &= ~ASLP; 2982963Stoy wakeup((caddr_t)sc); /* top half should go on */ 2991921Swnj } 3001921Swnj } 3011921Swnj 3022963Stoy lptout(dev) 3033205Swnj dev_t dev; 3041921Swnj { 3052963Stoy register struct lp_softc *sc; 3062963Stoy register struct uba_device *ui; 3072963Stoy register struct lpdevice *lpaddr; 3081921Swnj 3092963Stoy sc = &lp_softc[LPUNIT(dev)]; 3102963Stoy ui = lpinfo[LPUNIT(dev)]; 3112963Stoy lpaddr = (struct lpdevice *) ui->ui_addr; 3122963Stoy if ((sc->sc_state&MOD) != 0) { 3132963Stoy sc->sc_state &= ~MOD; /* something happened */ 3143986Sroot timeout(lptout, (caddr_t)dev, 2*hz); /* so don't sweat */ 3151921Swnj return; 3161921Swnj } 31716835Smckusick if ((sc->sc_state&OPEN) == 0 && sc->sc_outq.c_cc == 0) { 3182963Stoy sc->sc_state &= ~TOUT; /* no longer open */ 3192963Stoy lpaddr->lpsr = 0; 3201921Swnj return; 3211921Swnj } 3222963Stoy if (sc->sc_outq.c_cc && (lpaddr->lpsr&DONE) && (lpaddr->lpsr&ERROR)==0) 3233205Swnj lpintr(LPUNIT(dev)); /* ready to go */ 3243986Sroot timeout(lptout, (caddr_t)dev, 10*hz); 3251921Swnj } 3261921Swnj 3272963Stoy lpreset(uban) 3283205Swnj int uban; 3291921Swnj { 3302963Stoy register struct uba_device *ui; 3312963Stoy register struct lpdevice *lpaddr; 3322963Stoy register int unit; 3331921Swnj 3343205Swnj for (unit = 0; unit < NLP; unit++) { 3353205Swnj if ((ui = lpinfo[unit]) == 0 || ui->ui_ubanum != uban || 3363205Swnj ui->ui_alive == 0) 3372963Stoy continue; 3382963Stoy printf(" lp%d", unit); 3393205Swnj lpaddr = (struct lpdevice *)ui->ui_addr; 3402963Stoy lpaddr->lpsr |= IENABLE; 3411921Swnj } 3421921Swnj } 34313091Ssam #endif 344