1*10112Ssam /* lp.c 4.32 83/01/03 */ 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 131921Swnj #include "../h/param.h" 141921Swnj #include "../h/dir.h" 151921Swnj #include "../h/user.h" 161921Swnj #include "../h/buf.h" 171921Swnj #include "../h/systm.h" 181921Swnj #include "../h/map.h" 19*10112Ssam #include "../h/uio.h" 20*10112Ssam #include "../h/tty.h" 21*10112Ssam #include "../h/kernel.h" 221921Swnj 238476Sroot #include "../vaxuba/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; 49*10112Ssam 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; 76*10112Ssam if (ui->ui_flags) 77*10112Ssam sc->sc_maxcol = ui->ui_flags; 78*10112Ssam else 79*10112Ssam 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 int unit; 1042963Stoy register struct lpdevice *lpaddr; 1052963Stoy register struct lp_softc *sc; 1062963Stoy register struct uba_device *ui; 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; 1183104Swnj (void) spl4(); 1192963Stoy if ((sc->sc_state&TOUT) == 0) { 1202963Stoy sc->sc_state |= TOUT; 1213986Sroot timeout(lptout, (caddr_t)dev, 10*hz); 1221921Swnj } 1233104Swnj (void) spl0(); 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 1497835Sroot while (n = min(512, uio->uio_resid)) { 1502963Stoy cp = sc->sc_inbuf->b_un.b_addr; 1518491Sroot error = uiomove(cp, 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 { 1651921Swnj register int logcol, physcol; 1663205Swnj register struct lp_softc *sc = &lp_softc[LPUNIT(dev)]; 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': 2252963Stoy logcol = 0; 2263104Swnj (void) spl4(); 2273205Swnj lpintr(LPUNIT(dev)); 2283104Swnj (void) spl0(); 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 } 241*10112Ssam 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)]; 2621921Swnj 2632963Stoy if (sc->sc_outq.c_cc >= LPHWAT) { 2643104Swnj (void) spl4(); 2653205Swnj lpintr(LPUNIT(dev)); /* unchoke */ 2662963Stoy while (sc->sc_outq.c_cc >= LPHWAT) { 2672963Stoy sc->sc_state |= ASLP; /* must be ERROR */ 2682963Stoy sleep((caddr_t)sc, LPPRI); 2691921Swnj } 2703104Swnj (void) spl0(); 2711921Swnj } 2722963Stoy while (putc(c, &sc->sc_outq)) 2731921Swnj sleep((caddr_t)&lbolt, LPPRI); 2741921Swnj } 2751921Swnj 2763205Swnj lpintr(lp11) 2773205Swnj int lp11; 2781921Swnj { 2791921Swnj register int n; 2803205Swnj register struct lp_softc *sc = &lp_softc[lp11]; 2813205Swnj register struct uba_device *ui = lpinfo[lp11]; 2823205Swnj register struct lpdevice *lpaddr = (struct lpdevice *)ui->ui_addr; 2831921Swnj 2842963Stoy lpaddr->lpsr &= ~IENABLE; 2852963Stoy n = sc->sc_outq.c_cc; 2862963Stoy if (sc->sc_lpchar < 0) 2872963Stoy sc->sc_lpchar = getc(&sc->sc_outq); 2882963Stoy while ((lpaddr->lpsr&DONE) && sc->sc_lpchar >= 0) { 2892963Stoy lpaddr->lpbuf = sc->sc_lpchar; 2902963Stoy sc->sc_lpchar = getc(&sc->sc_outq); 2911921Swnj } 2922963Stoy sc->sc_state |= MOD; 2932963Stoy if (sc->sc_outq.c_cc > 0 && (lpaddr->lpsr&ERROR)==0) 2942963Stoy lpaddr->lpsr |= IENABLE; /* ok and more to do later */ 2952963Stoy if (n>LPLWAT && sc->sc_outq.c_cc<=LPLWAT && sc->sc_state&ASLP) { 2962963Stoy sc->sc_state &= ~ASLP; 2972963Stoy wakeup((caddr_t)sc); /* top half should go on */ 2981921Swnj } 2991921Swnj } 3001921Swnj 3012963Stoy lptout(dev) 3023205Swnj dev_t dev; 3031921Swnj { 3042963Stoy register struct lp_softc *sc; 3052963Stoy register struct uba_device *ui; 3062963Stoy register struct lpdevice *lpaddr; 3071921Swnj 3082963Stoy sc = &lp_softc[LPUNIT(dev)]; 3092963Stoy ui = lpinfo[LPUNIT(dev)]; 3102963Stoy lpaddr = (struct lpdevice *) ui->ui_addr; 3112963Stoy if ((sc->sc_state&MOD) != 0) { 3122963Stoy sc->sc_state &= ~MOD; /* something happened */ 3133986Sroot timeout(lptout, (caddr_t)dev, 2*hz); /* so don't sweat */ 3141921Swnj return; 3151921Swnj } 3162963Stoy if ((sc->sc_state&OPEN) == 0) { 3172963Stoy sc->sc_state &= ~TOUT; /* no longer open */ 3182963Stoy lpaddr->lpsr = 0; 3191921Swnj return; 3201921Swnj } 3212963Stoy if (sc->sc_outq.c_cc && (lpaddr->lpsr&DONE) && (lpaddr->lpsr&ERROR)==0) 3223205Swnj lpintr(LPUNIT(dev)); /* ready to go */ 3233986Sroot timeout(lptout, (caddr_t)dev, 10*hz); 3241921Swnj } 3251921Swnj 3262963Stoy lpreset(uban) 3273205Swnj int uban; 3281921Swnj { 3292963Stoy register struct uba_device *ui; 3302963Stoy register struct lpdevice *lpaddr; 3312963Stoy register int unit; 3321921Swnj 3333205Swnj for (unit = 0; unit < NLP; unit++) { 3343205Swnj if ((ui = lpinfo[unit]) == 0 || ui->ui_ubanum != uban || 3353205Swnj ui->ui_alive == 0) 3362963Stoy continue; 3372963Stoy printf(" lp%d", unit); 3383205Swnj lpaddr = (struct lpdevice *)ui->ui_addr; 3392963Stoy lpaddr->lpsr |= IENABLE; 3401921Swnj } 3411921Swnj } 342