1*767a234cSsam /* lp.c 4.32 83/01/03 */ 28ad6c293Swnj 39826bf71Swnj #include "lp.h" 419dc5c79Stoy #if NLP > 0 58ad6c293Swnj /* 68ad6c293Swnj * LP-11 Line printer driver 78ad6c293Swnj * 88ad6c293Swnj * This driver has been modified to work on printers where 98ad6c293Swnj * leaving IENABLE set would cause continuous interrupts. 108ad6c293Swnj */ 11df5e0e02Ssam #include "../machine/pte.h" 128ad6c293Swnj 138ad6c293Swnj #include "../h/param.h" 148ad6c293Swnj #include "../h/dir.h" 158ad6c293Swnj #include "../h/user.h" 168ad6c293Swnj #include "../h/buf.h" 178ad6c293Swnj #include "../h/systm.h" 188ad6c293Swnj #include "../h/map.h" 19*767a234cSsam #include "../h/uio.h" 20*767a234cSsam #include "../h/tty.h" 21*767a234cSsam #include "../h/kernel.h" 228ad6c293Swnj 2342b8bd9bSroot #include "../vaxuba/ubavar.h" 2442b8bd9bSroot 258ad6c293Swnj #define LPPRI (PZERO+8) 268ad6c293Swnj #define IENABLE 0100 278ad6c293Swnj #define DONE 0200 288ad6c293Swnj #define ERROR 0100000 298ad6c293Swnj #define LPLWAT 650 308ad6c293Swnj #define LPHWAT 800 318ad6c293Swnj 3219dc5c79Stoy #define MAXCOL 132 3319dc5c79Stoy #define CAP 1 3419dc5c79Stoy 3519dc5c79Stoy #define LPUNIT(dev) (minor(dev) >> 3) 3619dc5c79Stoy 3719dc5c79Stoy struct lpdevice { 388ad6c293Swnj short lpsr; 398ad6c293Swnj short lpbuf; 408ad6c293Swnj }; 418ad6c293Swnj 4219dc5c79Stoy struct lp_softc { 4319dc5c79Stoy struct clist sc_outq; 4419dc5c79Stoy int sc_state; 4519dc5c79Stoy int sc_physcol; 4619dc5c79Stoy int sc_logcol; 4719dc5c79Stoy int sc_physline; 4819dc5c79Stoy char sc_flags; 49*767a234cSsam short sc_maxcol; 5019dc5c79Stoy int sc_lpchar; 5119dc5c79Stoy struct buf *sc_inbuf; 5219dc5c79Stoy } lp_softc[NLP]; 5319dc5c79Stoy 5419dc5c79Stoy struct uba_device *lpinfo[NLP]; 5519dc5c79Stoy 5619dc5c79Stoy int lpprobe(), lpattach(), lptout(); 5719dc5c79Stoy u_short lpstd[] = { 0177514 }; 5819dc5c79Stoy struct uba_driver lpdriver = 5919dc5c79Stoy { lpprobe, 0, lpattach, 0, lpstd, "lp", lpinfo }; 608ad6c293Swnj 618ad6c293Swnj /* bits for state */ 628ad6c293Swnj #define OPEN 1 /* device is open */ 638ad6c293Swnj #define TOUT 2 /* timeout is active */ 648ad6c293Swnj #define MOD 4 /* device state has been modified */ 658ad6c293Swnj #define ASLP 8 /* awaiting draining of printer */ 668ad6c293Swnj 678ad6c293Swnj int lptout(); 688ad6c293Swnj 6984e24a43Swnj lpattach(ui) 7084e24a43Swnj struct uba_device *ui; 7184e24a43Swnj { 7284e24a43Swnj register struct lp_softc *sc; 7384e24a43Swnj 7484e24a43Swnj sc = &lp_softc[ui->ui_unit]; 7584e24a43Swnj sc->sc_lpchar = -1; 76*767a234cSsam if (ui->ui_flags) 77*767a234cSsam sc->sc_maxcol = ui->ui_flags; 78*767a234cSsam else 79*767a234cSsam sc->sc_maxcol = MAXCOL; 8084e24a43Swnj } 8184e24a43Swnj 8284e24a43Swnj lpprobe(reg) 8384e24a43Swnj caddr_t reg; 8484e24a43Swnj { 853bca611eSwnj register int br, cvec; /* value-result */ 8684e24a43Swnj register struct lpdevice *lpaddr = (struct lpdevice *)reg; 87573260eeSroot #ifdef lint 88573260eeSroot br = 0; cvec = br; br = cvec; 89a0f3106dSwnj lpintr(0); 90573260eeSroot #endif 9184e24a43Swnj 9284e24a43Swnj lpaddr->lpsr = IENABLE; 933bca611eSwnj DELAY(5); 9484e24a43Swnj lpaddr->lpsr = 0; 958b4ceed8Skre return (sizeof (struct lpdevice)); 9684e24a43Swnj } 9784e24a43Swnj 988ad6c293Swnj /*ARGSUSED*/ 998ad6c293Swnj lpopen(dev, flag) 10019dc5c79Stoy dev_t dev; 10184e24a43Swnj int flag; 1028ad6c293Swnj { 10319dc5c79Stoy register int unit; 10419dc5c79Stoy register struct lpdevice *lpaddr; 10519dc5c79Stoy register struct lp_softc *sc; 10619dc5c79Stoy register struct uba_device *ui; 1078ad6c293Swnj 10884e24a43Swnj if ((unit = LPUNIT(dev)) >= NLP || 10984e24a43Swnj (sc = &lp_softc[unit])->sc_state&OPEN || 1103536053eSroot (ui = lpinfo[unit]) == 0 || ui->ui_alive == 0) 1113536053eSroot return (ENXIO); 11219dc5c79Stoy lpaddr = (struct lpdevice *)ui->ui_addr; 1133536053eSroot if (lpaddr->lpsr&ERROR) 1143536053eSroot return (EIO); 11519dc5c79Stoy sc->sc_state |= OPEN; 11647d449d1Sroot sc->sc_inbuf = geteblk(512); 11719dc5c79Stoy sc->sc_flags = minor(dev) & 07; 118ee3fde7dSwnj (void) spl4(); 11919dc5c79Stoy if ((sc->sc_state&TOUT) == 0) { 12019dc5c79Stoy sc->sc_state |= TOUT; 121573260eeSroot timeout(lptout, (caddr_t)dev, 10*hz); 1228ad6c293Swnj } 123ee3fde7dSwnj (void) spl0(); 12484e24a43Swnj lpcanon(dev, '\f'); 1253536053eSroot return (0); 1268ad6c293Swnj } 1278ad6c293Swnj 1288ad6c293Swnj /*ARGSUSED*/ 1298ad6c293Swnj lpclose(dev, flag) 13019dc5c79Stoy dev_t dev; 13184e24a43Swnj int flag; 1328ad6c293Swnj { 13384e24a43Swnj register struct lp_softc *sc = &lp_softc[LPUNIT(dev)]; 1348ad6c293Swnj 13584e24a43Swnj lpcanon(dev, '\f'); 13619dc5c79Stoy brelse(sc->sc_inbuf); 13719dc5c79Stoy sc->sc_state &= ~OPEN; 1388ad6c293Swnj } 1398ad6c293Swnj 14025aace65Sroot lpwrite(dev, uio) 14184e24a43Swnj dev_t dev; 14225aace65Sroot struct uio *uio; 1438ad6c293Swnj { 144573260eeSroot register unsigned n; 1458ad6c293Swnj register char *cp; 14684e24a43Swnj register struct lp_softc *sc = &lp_softc[LPUNIT(dev)]; 1470d901dbeSroot int error; 1488ad6c293Swnj 14925aace65Sroot while (n = min(512, uio->uio_resid)) { 15019dc5c79Stoy cp = sc->sc_inbuf->b_un.b_addr; 1510d901dbeSroot error = uiomove(cp, n, UIO_WRITE, uio); 1520d901dbeSroot if (error) 1530d901dbeSroot return (error); 1548ad6c293Swnj do 15584e24a43Swnj lpcanon(dev, *cp++); 1568ad6c293Swnj while (--n); 1578ad6c293Swnj } 1580d901dbeSroot return (0); 1598ad6c293Swnj } 1608ad6c293Swnj 16184e24a43Swnj lpcanon(dev, c) 16284e24a43Swnj dev_t dev; 16319dc5c79Stoy register int c; 1648ad6c293Swnj { 1658ad6c293Swnj register int logcol, physcol; 16684e24a43Swnj register struct lp_softc *sc = &lp_softc[LPUNIT(dev)]; 1678ad6c293Swnj 16819dc5c79Stoy if (sc->sc_flags&CAP) { 1698ad6c293Swnj register c2; 1708ad6c293Swnj 1718ad6c293Swnj if (c>='a' && c<='z') 1728ad6c293Swnj c += 'A'-'a'; else 1738ad6c293Swnj switch (c) { 1748ad6c293Swnj 1758ad6c293Swnj case '{': 1768ad6c293Swnj c2 = '('; 1778ad6c293Swnj goto esc; 1788ad6c293Swnj 1798ad6c293Swnj case '}': 1808ad6c293Swnj c2 = ')'; 1818ad6c293Swnj goto esc; 1828ad6c293Swnj 1838ad6c293Swnj case '`': 1848ad6c293Swnj c2 = '\''; 1858ad6c293Swnj goto esc; 1868ad6c293Swnj 1878ad6c293Swnj case '|': 1888ad6c293Swnj c2 = '!'; 1898ad6c293Swnj goto esc; 1908ad6c293Swnj 1918ad6c293Swnj case '~': 1928ad6c293Swnj c2 = '^'; 1938ad6c293Swnj 1948ad6c293Swnj esc: 19584e24a43Swnj lpcanon(dev, c2); 19619dc5c79Stoy sc->sc_logcol--; 1978ad6c293Swnj c = '-'; 1988ad6c293Swnj } 1998ad6c293Swnj } 20019dc5c79Stoy logcol = sc->sc_logcol; 20119dc5c79Stoy physcol = sc->sc_physcol; 2028ad6c293Swnj if (c == ' ') 2038ad6c293Swnj logcol++; 2048ad6c293Swnj else switch(c) { 2058ad6c293Swnj 2068ad6c293Swnj case '\t': 20770b581cfSwnj logcol = (logcol+8) & ~7; 2088ad6c293Swnj break; 2098ad6c293Swnj 2108ad6c293Swnj case '\f': 21119dc5c79Stoy if (sc->sc_physline == 0 && physcol == 0) 212f0b42318Swnj break; 213c2e62a0eStoy /* fall into ... */ 214c2e62a0eStoy 215c2e62a0eStoy case '\n': 21684e24a43Swnj lpoutput(dev, c); 217f0b42318Swnj if (c == '\f') 21819dc5c79Stoy sc->sc_physline = 0; 219f0b42318Swnj else 22019dc5c79Stoy sc->sc_physline++; 221c2e62a0eStoy physcol = 0; 2228ad6c293Swnj /* fall into ... */ 2238ad6c293Swnj 2248ad6c293Swnj case '\r': 22519dc5c79Stoy logcol = 0; 226ee3fde7dSwnj (void) spl4(); 22784e24a43Swnj lpintr(LPUNIT(dev)); 228ee3fde7dSwnj (void) spl0(); 2298ad6c293Swnj break; 2308ad6c293Swnj 2318ad6c293Swnj case '\b': 2328ad6c293Swnj if (logcol > 0) 2338ad6c293Swnj logcol--; 2348ad6c293Swnj break; 2358ad6c293Swnj 2368ad6c293Swnj default: 2378ad6c293Swnj if (logcol < physcol) { 23884e24a43Swnj lpoutput(dev, '\r'); 2398ad6c293Swnj physcol = 0; 2408ad6c293Swnj } 241*767a234cSsam if (logcol < sc->sc_maxcol) { 2428ad6c293Swnj while (logcol > physcol) { 24384e24a43Swnj lpoutput(dev, ' '); 2448ad6c293Swnj physcol++; 2458ad6c293Swnj } 24684e24a43Swnj lpoutput(dev, c); 2478ad6c293Swnj physcol++; 2488ad6c293Swnj } 2498ad6c293Swnj logcol++; 2508ad6c293Swnj } 2518ad6c293Swnj if (logcol > 1000) /* ignore long lines */ 2528ad6c293Swnj logcol = 1000; 25319dc5c79Stoy sc->sc_logcol = logcol; 25419dc5c79Stoy sc->sc_physcol = physcol; 2558ad6c293Swnj } 2568ad6c293Swnj 25784e24a43Swnj lpoutput(dev, c) 25819dc5c79Stoy dev_t dev; 25984e24a43Swnj int c; 2608ad6c293Swnj { 26184e24a43Swnj register struct lp_softc *sc = &lp_softc[LPUNIT(dev)]; 2628ad6c293Swnj 26319dc5c79Stoy if (sc->sc_outq.c_cc >= LPHWAT) { 264ee3fde7dSwnj (void) spl4(); 26584e24a43Swnj lpintr(LPUNIT(dev)); /* unchoke */ 26619dc5c79Stoy while (sc->sc_outq.c_cc >= LPHWAT) { 26719dc5c79Stoy sc->sc_state |= ASLP; /* must be ERROR */ 26819dc5c79Stoy sleep((caddr_t)sc, LPPRI); 2698ad6c293Swnj } 270ee3fde7dSwnj (void) spl0(); 2718ad6c293Swnj } 27219dc5c79Stoy while (putc(c, &sc->sc_outq)) 2738ad6c293Swnj sleep((caddr_t)&lbolt, LPPRI); 2748ad6c293Swnj } 2758ad6c293Swnj 27684e24a43Swnj lpintr(lp11) 27784e24a43Swnj int lp11; 2788ad6c293Swnj { 2798ad6c293Swnj register int n; 28084e24a43Swnj register struct lp_softc *sc = &lp_softc[lp11]; 28184e24a43Swnj register struct uba_device *ui = lpinfo[lp11]; 28284e24a43Swnj register struct lpdevice *lpaddr = (struct lpdevice *)ui->ui_addr; 2838ad6c293Swnj 28419dc5c79Stoy lpaddr->lpsr &= ~IENABLE; 28519dc5c79Stoy n = sc->sc_outq.c_cc; 28619dc5c79Stoy if (sc->sc_lpchar < 0) 28719dc5c79Stoy sc->sc_lpchar = getc(&sc->sc_outq); 28819dc5c79Stoy while ((lpaddr->lpsr&DONE) && sc->sc_lpchar >= 0) { 28919dc5c79Stoy lpaddr->lpbuf = sc->sc_lpchar; 29019dc5c79Stoy sc->sc_lpchar = getc(&sc->sc_outq); 2918ad6c293Swnj } 29219dc5c79Stoy sc->sc_state |= MOD; 29319dc5c79Stoy if (sc->sc_outq.c_cc > 0 && (lpaddr->lpsr&ERROR)==0) 29419dc5c79Stoy lpaddr->lpsr |= IENABLE; /* ok and more to do later */ 29519dc5c79Stoy if (n>LPLWAT && sc->sc_outq.c_cc<=LPLWAT && sc->sc_state&ASLP) { 29619dc5c79Stoy sc->sc_state &= ~ASLP; 29719dc5c79Stoy wakeup((caddr_t)sc); /* top half should go on */ 2988ad6c293Swnj } 2998ad6c293Swnj } 3008ad6c293Swnj 30119dc5c79Stoy lptout(dev) 30284e24a43Swnj dev_t dev; 3038ad6c293Swnj { 30419dc5c79Stoy register struct lp_softc *sc; 30519dc5c79Stoy register struct uba_device *ui; 30619dc5c79Stoy register struct lpdevice *lpaddr; 3078ad6c293Swnj 30819dc5c79Stoy sc = &lp_softc[LPUNIT(dev)]; 30919dc5c79Stoy ui = lpinfo[LPUNIT(dev)]; 31019dc5c79Stoy lpaddr = (struct lpdevice *) ui->ui_addr; 31119dc5c79Stoy if ((sc->sc_state&MOD) != 0) { 31219dc5c79Stoy sc->sc_state &= ~MOD; /* something happened */ 313573260eeSroot timeout(lptout, (caddr_t)dev, 2*hz); /* so don't sweat */ 3148ad6c293Swnj return; 3158ad6c293Swnj } 31619dc5c79Stoy if ((sc->sc_state&OPEN) == 0) { 31719dc5c79Stoy sc->sc_state &= ~TOUT; /* no longer open */ 31819dc5c79Stoy lpaddr->lpsr = 0; 3198ad6c293Swnj return; 3208ad6c293Swnj } 32119dc5c79Stoy if (sc->sc_outq.c_cc && (lpaddr->lpsr&DONE) && (lpaddr->lpsr&ERROR)==0) 32284e24a43Swnj lpintr(LPUNIT(dev)); /* ready to go */ 323573260eeSroot timeout(lptout, (caddr_t)dev, 10*hz); 3248ad6c293Swnj } 3258ad6c293Swnj 32619dc5c79Stoy lpreset(uban) 32719dc5c79Stoy int uban; 3288ad6c293Swnj { 32919dc5c79Stoy register struct uba_device *ui; 33019dc5c79Stoy register struct lpdevice *lpaddr; 33119dc5c79Stoy register int unit; 3328ad6c293Swnj 33384e24a43Swnj for (unit = 0; unit < NLP; unit++) { 33484e24a43Swnj if ((ui = lpinfo[unit]) == 0 || ui->ui_ubanum != uban || 33584e24a43Swnj ui->ui_alive == 0) 33619dc5c79Stoy continue; 33719dc5c79Stoy printf(" lp%d", unit); 33819dc5c79Stoy lpaddr = (struct lpdevice *)ui->ui_addr; 33919dc5c79Stoy lpaddr->lpsr |= IENABLE; 34019dc5c79Stoy } 3418ad6c293Swnj } 342