1*3986Sroot /* lp.c 4.19 81/07/09 */ 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. 102964Stoy * 112964Stoy * TODO: 122964Stoy * Test driver on multiple printers 131921Swnj */ 141921Swnj 151921Swnj #include "../h/param.h" 161921Swnj #include "../h/dir.h" 171921Swnj #include "../h/user.h" 181921Swnj #include "../h/buf.h" 191921Swnj #include "../h/systm.h" 201921Swnj #include "../h/map.h" 211921Swnj #include "../h/pte.h" 222963Stoy #include "../h/ubavar.h" 231921Swnj #include "../h/ioctl.h" 241921Swnj #include "../h/tty.h" 251921Swnj 261921Swnj #define LPPRI (PZERO+8) 271921Swnj #define IENABLE 0100 281921Swnj #define DONE 0200 291921Swnj #define ERROR 0100000 301921Swnj #define LPLWAT 650 311921Swnj #define LPHWAT 800 321921Swnj 332963Stoy #define MAXCOL 132 342963Stoy #define CAP 1 352963Stoy 362963Stoy #define LPUNIT(dev) (minor(dev) >> 3) 372963Stoy 382963Stoy struct lpdevice { 391921Swnj short lpsr; 401921Swnj short lpbuf; 411921Swnj }; 421921Swnj 432963Stoy struct lp_softc { 442963Stoy struct clist sc_outq; 452963Stoy int sc_state; 462963Stoy int sc_physcol; 472963Stoy int sc_logcol; 482963Stoy int sc_physline; 492963Stoy char sc_flags; 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 extern lbolt; 681921Swnj int lptout(); 691921Swnj 703205Swnj lpattach(ui) 713205Swnj struct uba_device *ui; 723205Swnj { 733205Swnj register struct lp_softc *sc; 743205Swnj 753205Swnj sc = &lp_softc[ui->ui_unit]; 763205Swnj sc->sc_lpchar = -1; 773205Swnj } 783205Swnj 793205Swnj lpprobe(reg) 803205Swnj caddr_t reg; 813205Swnj { 823250Swnj register int br, cvec; /* value-result */ 833205Swnj register struct lpdevice *lpaddr = (struct lpdevice *)reg; 84*3986Sroot #ifdef lint 85*3986Sroot br = 0; cvec = br; br = cvec; 86*3986Sroot #endif 873205Swnj 883205Swnj lpaddr->lpsr = IENABLE; 893250Swnj DELAY(5); 903205Swnj lpaddr->lpsr = 0; 913205Swnj } 923205Swnj 931921Swnj /*ARGSUSED*/ 941921Swnj lpopen(dev, flag) 953205Swnj dev_t dev; 963205Swnj int flag; 971921Swnj { 982963Stoy register int unit; 992963Stoy register struct lpdevice *lpaddr; 1002963Stoy register struct lp_softc *sc; 1012963Stoy register struct uba_device *ui; 1021921Swnj 1033205Swnj if ((unit = LPUNIT(dev)) >= NLP || 1043205Swnj (sc = &lp_softc[unit])->sc_state&OPEN || 1053205Swnj (ui = lpinfo[unit]) == 0 || ui->ui_alive == 0) { 1062963Stoy u.u_error = ENXIO; 1072963Stoy return; 1082963Stoy } 1093205Swnj lpaddr = (struct lpdevice *)ui->ui_addr; 1103205Swnj if (lpaddr->lpsr&ERROR) { 1111921Swnj u.u_error = EIO; 1121921Swnj return; 1131921Swnj } 1142963Stoy sc->sc_state |= OPEN; 1152963Stoy sc->sc_inbuf = geteblk(); 1162963Stoy sc->sc_flags = minor(dev) & 07; 1173104Swnj (void) spl4(); 1182963Stoy if ((sc->sc_state&TOUT) == 0) { 1192963Stoy sc->sc_state |= TOUT; 120*3986Sroot timeout(lptout, (caddr_t)dev, 10*hz); 1211921Swnj } 1223104Swnj (void) spl0(); 1233205Swnj lpcanon(dev, '\f'); 1241921Swnj } 1251921Swnj 1261921Swnj /*ARGSUSED*/ 1271921Swnj lpclose(dev, flag) 1283205Swnj dev_t dev; 1293205Swnj int flag; 1301921Swnj { 1313205Swnj register struct lp_softc *sc = &lp_softc[LPUNIT(dev)]; 1321921Swnj 1333205Swnj lpcanon(dev, '\f'); 1342963Stoy brelse(sc->sc_inbuf); 1352963Stoy sc->sc_state &= ~OPEN; 1361921Swnj } 1371921Swnj 1382963Stoy lpwrite(dev) 1393205Swnj dev_t dev; 1401921Swnj { 141*3986Sroot register unsigned n; 1421921Swnj register char *cp; 1433205Swnj register struct lp_softc *sc = &lp_softc[LPUNIT(dev)]; 1441921Swnj 1451921Swnj while (n = min(BSIZE, u.u_count)) { 1462963Stoy cp = sc->sc_inbuf->b_un.b_addr; 1471921Swnj iomove(cp, n, B_WRITE); 1481921Swnj do 1493205Swnj lpcanon(dev, *cp++); 1501921Swnj while (--n); 1511921Swnj } 1521921Swnj } 1531921Swnj 1543205Swnj lpcanon(dev, c) 1553205Swnj dev_t dev; 1563205Swnj register int c; 1571921Swnj { 1581921Swnj register int logcol, physcol; 1593205Swnj register struct lp_softc *sc = &lp_softc[LPUNIT(dev)]; 1601921Swnj 1612963Stoy if (sc->sc_flags&CAP) { 1621921Swnj register c2; 1631921Swnj 1641921Swnj if (c>='a' && c<='z') 1651921Swnj c += 'A'-'a'; else 1661921Swnj switch (c) { 1671921Swnj 1681921Swnj case '{': 1691921Swnj c2 = '('; 1701921Swnj goto esc; 1711921Swnj 1721921Swnj case '}': 1731921Swnj c2 = ')'; 1741921Swnj goto esc; 1751921Swnj 1761921Swnj case '`': 1771921Swnj c2 = '\''; 1781921Swnj goto esc; 1791921Swnj 1801921Swnj case '|': 1811921Swnj c2 = '!'; 1821921Swnj goto esc; 1831921Swnj 1841921Swnj case '~': 1851921Swnj c2 = '^'; 1861921Swnj 1871921Swnj esc: 1883205Swnj lpcanon(dev, c2); 1892963Stoy sc->sc_logcol--; 1901921Swnj c = '-'; 1911921Swnj } 1921921Swnj } 1932963Stoy logcol = sc->sc_logcol; 1942963Stoy physcol = sc->sc_physcol; 1951921Swnj if (c == ' ') 1961921Swnj logcol++; 1971921Swnj else switch(c) { 1981921Swnj 1991921Swnj case '\t': 2003328Swnj logcol = (logcol+8) & ~7; 2011921Swnj break; 2021921Swnj 2031921Swnj case '\f': 2042963Stoy if (sc->sc_physline == 0 && physcol == 0) 2052044Swnj break; 2062206Stoy /* fall into ... */ 2072206Stoy 2082206Stoy case '\n': 2093205Swnj lpoutput(dev, c); 2102044Swnj if (c == '\f') 2112963Stoy sc->sc_physline = 0; 2122044Swnj else 2132963Stoy sc->sc_physline++; 2142206Stoy physcol = 0; 2151921Swnj /* fall into ... */ 2161921Swnj 2171921Swnj case '\r': 2182963Stoy logcol = 0; 2193104Swnj (void) spl4(); 2203205Swnj lpintr(LPUNIT(dev)); 2213104Swnj (void) spl0(); 2221921Swnj break; 2231921Swnj 2241921Swnj case '\b': 2251921Swnj if (logcol > 0) 2261921Swnj logcol--; 2271921Swnj break; 2281921Swnj 2291921Swnj default: 2301921Swnj if (logcol < physcol) { 2313205Swnj lpoutput(dev, '\r'); 2321921Swnj physcol = 0; 2331921Swnj } 2342963Stoy if (logcol < MAXCOL) { 2351921Swnj while (logcol > physcol) { 2363205Swnj lpoutput(dev, ' '); 2371921Swnj physcol++; 2381921Swnj } 2393205Swnj lpoutput(dev, c); 2401921Swnj physcol++; 2411921Swnj } 2421921Swnj logcol++; 2431921Swnj } 2441921Swnj if (logcol > 1000) /* ignore long lines */ 2451921Swnj logcol = 1000; 2462963Stoy sc->sc_logcol = logcol; 2472963Stoy sc->sc_physcol = physcol; 2481921Swnj } 2491921Swnj 2503205Swnj lpoutput(dev, c) 2513205Swnj dev_t dev; 2523205Swnj int c; 2531921Swnj { 2543205Swnj register struct lp_softc *sc = &lp_softc[LPUNIT(dev)]; 2551921Swnj 2562963Stoy if (sc->sc_outq.c_cc >= LPHWAT) { 2573104Swnj (void) spl4(); 2583205Swnj lpintr(LPUNIT(dev)); /* unchoke */ 2592963Stoy while (sc->sc_outq.c_cc >= LPHWAT) { 2602963Stoy sc->sc_state |= ASLP; /* must be ERROR */ 2612963Stoy sleep((caddr_t)sc, LPPRI); 2621921Swnj } 2633104Swnj (void) spl0(); 2641921Swnj } 2652963Stoy while (putc(c, &sc->sc_outq)) 2661921Swnj sleep((caddr_t)&lbolt, LPPRI); 2671921Swnj } 2681921Swnj 2693205Swnj lpintr(lp11) 2703205Swnj int lp11; 2711921Swnj { 2721921Swnj register int n; 2733205Swnj register struct lp_softc *sc = &lp_softc[lp11]; 2743205Swnj register struct uba_device *ui = lpinfo[lp11]; 2753205Swnj register struct lpdevice *lpaddr = (struct lpdevice *)ui->ui_addr; 2761921Swnj 2772963Stoy lpaddr->lpsr &= ~IENABLE; 2782963Stoy n = sc->sc_outq.c_cc; 2792963Stoy if (sc->sc_lpchar < 0) 2802963Stoy sc->sc_lpchar = getc(&sc->sc_outq); 2812963Stoy while ((lpaddr->lpsr&DONE) && sc->sc_lpchar >= 0) { 2822963Stoy lpaddr->lpbuf = sc->sc_lpchar; 2832963Stoy sc->sc_lpchar = getc(&sc->sc_outq); 2841921Swnj } 2852963Stoy sc->sc_state |= MOD; 2862963Stoy if (sc->sc_outq.c_cc > 0 && (lpaddr->lpsr&ERROR)==0) 2872963Stoy lpaddr->lpsr |= IENABLE; /* ok and more to do later */ 2882963Stoy if (n>LPLWAT && sc->sc_outq.c_cc<=LPLWAT && sc->sc_state&ASLP) { 2892963Stoy sc->sc_state &= ~ASLP; 2902963Stoy wakeup((caddr_t)sc); /* top half should go on */ 2911921Swnj } 2921921Swnj } 2931921Swnj 2942963Stoy lptout(dev) 2953205Swnj dev_t dev; 2961921Swnj { 2972963Stoy register struct lp_softc *sc; 2982963Stoy register struct uba_device *ui; 2992963Stoy register struct lpdevice *lpaddr; 3001921Swnj 3012963Stoy sc = &lp_softc[LPUNIT(dev)]; 3022963Stoy ui = lpinfo[LPUNIT(dev)]; 3032963Stoy lpaddr = (struct lpdevice *) ui->ui_addr; 3042963Stoy if ((sc->sc_state&MOD) != 0) { 3052963Stoy sc->sc_state &= ~MOD; /* something happened */ 306*3986Sroot timeout(lptout, (caddr_t)dev, 2*hz); /* so don't sweat */ 3071921Swnj return; 3081921Swnj } 3092963Stoy if ((sc->sc_state&OPEN) == 0) { 3102963Stoy sc->sc_state &= ~TOUT; /* no longer open */ 3112963Stoy lpaddr->lpsr = 0; 3121921Swnj return; 3131921Swnj } 3142963Stoy if (sc->sc_outq.c_cc && (lpaddr->lpsr&DONE) && (lpaddr->lpsr&ERROR)==0) 3153205Swnj lpintr(LPUNIT(dev)); /* ready to go */ 316*3986Sroot timeout(lptout, (caddr_t)dev, 10*hz); 3171921Swnj } 3181921Swnj 3192963Stoy lpreset(uban) 3203205Swnj int uban; 3211921Swnj { 3222963Stoy register struct uba_device *ui; 3232963Stoy register struct lpdevice *lpaddr; 3242963Stoy register int unit; 3251921Swnj 3263205Swnj for (unit = 0; unit < NLP; unit++) { 3273205Swnj if ((ui = lpinfo[unit]) == 0 || ui->ui_ubanum != uban || 3283205Swnj ui->ui_alive == 0) 3292963Stoy continue; 3302963Stoy printf(" lp%d", unit); 3313205Swnj lpaddr = (struct lpdevice *)ui->ui_addr; 3322963Stoy lpaddr->lpsr |= IENABLE; 3331921Swnj } 3341921Swnj } 335