1*23331Smckusick /* 2*23331Smckusick * Copyright (c) 1982 Regents of the University of California. 3*23331Smckusick * All rights reserved. The Berkeley software License Agreement 4*23331Smckusick * specifies the terms and conditions for redistribution. 5*23331Smckusick * 6*23331Smckusick * @(#)lp.c 6.6 (Berkeley) 06/08/85 7*23331Smckusick */ 81921Swnj 91941Swnj #include "lp.h" 102963Stoy #if NLP > 0 111921Swnj /* 121921Swnj * LP-11 Line printer driver 131921Swnj * 141921Swnj * This driver has been modified to work on printers where 151921Swnj * leaving IENABLE set would cause continuous interrupts. 161921Swnj */ 179775Ssam #include "../machine/pte.h" 181921Swnj 1917074Sbloom #include "param.h" 2017074Sbloom #include "dir.h" 2117074Sbloom #include "user.h" 2217074Sbloom #include "buf.h" 2317074Sbloom #include "systm.h" 2417074Sbloom #include "map.h" 2517074Sbloom #include "uio.h" 2617935Skupfer #include "ioctl.h" 2717074Sbloom #include "tty.h" 2817074Sbloom #include "kernel.h" 291921Swnj 3017074Sbloom #include "ubavar.h" 318476Sroot 321921Swnj #define LPPRI (PZERO+8) 331921Swnj #define IENABLE 0100 341921Swnj #define DONE 0200 351921Swnj #define ERROR 0100000 361921Swnj #define LPLWAT 650 371921Swnj #define LPHWAT 800 381921Swnj 392963Stoy #define MAXCOL 132 402963Stoy #define CAP 1 412963Stoy 422963Stoy #define LPUNIT(dev) (minor(dev) >> 3) 432963Stoy 442963Stoy struct lpdevice { 451921Swnj short lpsr; 461921Swnj short lpbuf; 471921Swnj }; 481921Swnj 492963Stoy struct lp_softc { 502963Stoy struct clist sc_outq; 512963Stoy int sc_state; 522963Stoy int sc_physcol; 532963Stoy int sc_logcol; 542963Stoy int sc_physline; 552963Stoy char sc_flags; 5610112Ssam short sc_maxcol; 572963Stoy int sc_lpchar; 582963Stoy struct buf *sc_inbuf; 592963Stoy } lp_softc[NLP]; 601921Swnj 612963Stoy struct uba_device *lpinfo[NLP]; 622963Stoy 632963Stoy int lpprobe(), lpattach(), lptout(); 642963Stoy u_short lpstd[] = { 0177514 }; 652963Stoy struct uba_driver lpdriver = 662963Stoy { lpprobe, 0, lpattach, 0, lpstd, "lp", lpinfo }; 672963Stoy 681921Swnj /* bits for state */ 691921Swnj #define OPEN 1 /* device is open */ 701921Swnj #define TOUT 2 /* timeout is active */ 711921Swnj #define MOD 4 /* device state has been modified */ 721921Swnj #define ASLP 8 /* awaiting draining of printer */ 731921Swnj 741921Swnj int lptout(); 751921Swnj 763205Swnj lpattach(ui) 773205Swnj struct uba_device *ui; 783205Swnj { 793205Swnj register struct lp_softc *sc; 803205Swnj 813205Swnj sc = &lp_softc[ui->ui_unit]; 823205Swnj sc->sc_lpchar = -1; 8310112Ssam if (ui->ui_flags) 8410112Ssam sc->sc_maxcol = ui->ui_flags; 8510112Ssam else 8610112Ssam sc->sc_maxcol = MAXCOL; 873205Swnj } 883205Swnj 893205Swnj lpprobe(reg) 903205Swnj caddr_t reg; 913205Swnj { 923250Swnj register int br, cvec; /* value-result */ 933205Swnj register struct lpdevice *lpaddr = (struct lpdevice *)reg; 943986Sroot #ifdef lint 953986Sroot br = 0; cvec = br; br = cvec; 964935Swnj lpintr(0); 973986Sroot #endif 983205Swnj 993205Swnj lpaddr->lpsr = IENABLE; 1003250Swnj DELAY(5); 1013205Swnj lpaddr->lpsr = 0; 1027411Skre return (sizeof (struct lpdevice)); 1033205Swnj } 1043205Swnj 1051921Swnj /*ARGSUSED*/ 1061921Swnj lpopen(dev, flag) 1073205Swnj dev_t dev; 1083205Swnj int flag; 1091921Swnj { 1102963Stoy register struct lpdevice *lpaddr; 1112963Stoy register struct lp_softc *sc; 1122963Stoy register struct uba_device *ui; 11317002Smckusick register int unit, s; 1141921Swnj 1153205Swnj if ((unit = LPUNIT(dev)) >= NLP || 1163205Swnj (sc = &lp_softc[unit])->sc_state&OPEN || 1178570Sroot (ui = lpinfo[unit]) == 0 || ui->ui_alive == 0) 1188570Sroot return (ENXIO); 1193205Swnj lpaddr = (struct lpdevice *)ui->ui_addr; 1208570Sroot if (lpaddr->lpsr&ERROR) 1218570Sroot return (EIO); 1222963Stoy sc->sc_state |= OPEN; 1237184Sroot sc->sc_inbuf = geteblk(512); 1242963Stoy sc->sc_flags = minor(dev) & 07; 12517002Smckusick s = spl4(); 1262963Stoy if ((sc->sc_state&TOUT) == 0) { 1272963Stoy sc->sc_state |= TOUT; 1283986Sroot timeout(lptout, (caddr_t)dev, 10*hz); 1291921Swnj } 13017002Smckusick splx(s); 1313205Swnj lpcanon(dev, '\f'); 1328570Sroot return (0); 1331921Swnj } 1341921Swnj 1351921Swnj /*ARGSUSED*/ 1361921Swnj lpclose(dev, flag) 1373205Swnj dev_t dev; 1383205Swnj int flag; 1391921Swnj { 1403205Swnj register struct lp_softc *sc = &lp_softc[LPUNIT(dev)]; 1411921Swnj 1423205Swnj lpcanon(dev, '\f'); 1432963Stoy brelse(sc->sc_inbuf); 1442963Stoy sc->sc_state &= ~OPEN; 1451921Swnj } 1461921Swnj 1477835Sroot lpwrite(dev, uio) 1483205Swnj dev_t dev; 1497835Sroot struct uio *uio; 1501921Swnj { 1513986Sroot register unsigned n; 1521921Swnj register char *cp; 1533205Swnj register struct lp_softc *sc = &lp_softc[LPUNIT(dev)]; 1548491Sroot int error; 1551921Swnj 15613091Ssam while (n = min(512, (unsigned)uio->uio_resid)) { 1572963Stoy cp = sc->sc_inbuf->b_un.b_addr; 15813091Ssam error = uiomove(cp, (int)n, UIO_WRITE, uio); 1598491Sroot if (error) 1608491Sroot return (error); 1611921Swnj do 1623205Swnj lpcanon(dev, *cp++); 1631921Swnj while (--n); 1641921Swnj } 1658491Sroot return (0); 1661921Swnj } 1671921Swnj 1683205Swnj lpcanon(dev, c) 1693205Swnj dev_t dev; 1703205Swnj register int c; 1711921Swnj { 1723205Swnj register struct lp_softc *sc = &lp_softc[LPUNIT(dev)]; 17317002Smckusick register int logcol, physcol, s; 1741921Swnj 1752963Stoy if (sc->sc_flags&CAP) { 1761921Swnj register c2; 1771921Swnj 1781921Swnj if (c>='a' && c<='z') 1791921Swnj c += 'A'-'a'; else 1801921Swnj switch (c) { 1811921Swnj 1821921Swnj case '{': 1831921Swnj c2 = '('; 1841921Swnj goto esc; 1851921Swnj 1861921Swnj case '}': 1871921Swnj c2 = ')'; 1881921Swnj goto esc; 1891921Swnj 1901921Swnj case '`': 1911921Swnj c2 = '\''; 1921921Swnj goto esc; 1931921Swnj 1941921Swnj case '|': 1951921Swnj c2 = '!'; 1961921Swnj goto esc; 1971921Swnj 1981921Swnj case '~': 1991921Swnj c2 = '^'; 2001921Swnj 2011921Swnj esc: 2023205Swnj lpcanon(dev, c2); 2032963Stoy sc->sc_logcol--; 2041921Swnj c = '-'; 2051921Swnj } 2061921Swnj } 2072963Stoy logcol = sc->sc_logcol; 2082963Stoy physcol = sc->sc_physcol; 2091921Swnj if (c == ' ') 2101921Swnj logcol++; 2111921Swnj else switch(c) { 2121921Swnj 2131921Swnj case '\t': 2143328Swnj logcol = (logcol+8) & ~7; 2151921Swnj break; 2161921Swnj 2171921Swnj case '\f': 2182963Stoy if (sc->sc_physline == 0 && physcol == 0) 2192044Swnj break; 2202206Stoy /* fall into ... */ 2212206Stoy 2222206Stoy case '\n': 2233205Swnj lpoutput(dev, c); 2242044Swnj if (c == '\f') 2252963Stoy sc->sc_physline = 0; 2262044Swnj else 2272963Stoy sc->sc_physline++; 2282206Stoy physcol = 0; 2291921Swnj /* fall into ... */ 2301921Swnj 2311921Swnj case '\r': 23217002Smckusick s = spl4(); 2332963Stoy logcol = 0; 2343205Swnj lpintr(LPUNIT(dev)); 23517002Smckusick splx(s); 2361921Swnj break; 2371921Swnj 2381921Swnj case '\b': 2391921Swnj if (logcol > 0) 2401921Swnj logcol--; 2411921Swnj break; 2421921Swnj 2431921Swnj default: 2441921Swnj if (logcol < physcol) { 2453205Swnj lpoutput(dev, '\r'); 2461921Swnj physcol = 0; 2471921Swnj } 24810112Ssam if (logcol < sc->sc_maxcol) { 2491921Swnj while (logcol > physcol) { 2503205Swnj lpoutput(dev, ' '); 2511921Swnj physcol++; 2521921Swnj } 2533205Swnj lpoutput(dev, c); 2541921Swnj physcol++; 2551921Swnj } 2561921Swnj logcol++; 2571921Swnj } 2581921Swnj if (logcol > 1000) /* ignore long lines */ 2591921Swnj logcol = 1000; 2602963Stoy sc->sc_logcol = logcol; 2612963Stoy sc->sc_physcol = physcol; 2621921Swnj } 2631921Swnj 2643205Swnj lpoutput(dev, c) 2653205Swnj dev_t dev; 2663205Swnj int c; 2671921Swnj { 2683205Swnj register struct lp_softc *sc = &lp_softc[LPUNIT(dev)]; 26917002Smckusick int s; 2701921Swnj 2712963Stoy if (sc->sc_outq.c_cc >= LPHWAT) { 27217002Smckusick s = spl4(); 2733205Swnj lpintr(LPUNIT(dev)); /* unchoke */ 2742963Stoy while (sc->sc_outq.c_cc >= LPHWAT) { 2752963Stoy sc->sc_state |= ASLP; /* must be ERROR */ 2762963Stoy sleep((caddr_t)sc, LPPRI); 2771921Swnj } 27817002Smckusick splx(s); 2791921Swnj } 2802963Stoy while (putc(c, &sc->sc_outq)) 2811921Swnj sleep((caddr_t)&lbolt, LPPRI); 2821921Swnj } 2831921Swnj 2843205Swnj lpintr(lp11) 2853205Swnj int lp11; 2861921Swnj { 2871921Swnj register int n; 2883205Swnj register struct lp_softc *sc = &lp_softc[lp11]; 2893205Swnj register struct uba_device *ui = lpinfo[lp11]; 2903205Swnj register struct lpdevice *lpaddr = (struct lpdevice *)ui->ui_addr; 2911921Swnj 2922963Stoy lpaddr->lpsr &= ~IENABLE; 2932963Stoy n = sc->sc_outq.c_cc; 2942963Stoy if (sc->sc_lpchar < 0) 2952963Stoy sc->sc_lpchar = getc(&sc->sc_outq); 2962963Stoy while ((lpaddr->lpsr&DONE) && sc->sc_lpchar >= 0) { 2972963Stoy lpaddr->lpbuf = sc->sc_lpchar; 2982963Stoy sc->sc_lpchar = getc(&sc->sc_outq); 2991921Swnj } 3002963Stoy sc->sc_state |= MOD; 3012963Stoy if (sc->sc_outq.c_cc > 0 && (lpaddr->lpsr&ERROR)==0) 3022963Stoy lpaddr->lpsr |= IENABLE; /* ok and more to do later */ 3032963Stoy if (n>LPLWAT && sc->sc_outq.c_cc<=LPLWAT && sc->sc_state&ASLP) { 3042963Stoy sc->sc_state &= ~ASLP; 3052963Stoy wakeup((caddr_t)sc); /* top half should go on */ 3061921Swnj } 3071921Swnj } 3081921Swnj 3092963Stoy lptout(dev) 3103205Swnj dev_t dev; 3111921Swnj { 3122963Stoy register struct lp_softc *sc; 3132963Stoy register struct uba_device *ui; 3142963Stoy register struct lpdevice *lpaddr; 3151921Swnj 3162963Stoy sc = &lp_softc[LPUNIT(dev)]; 3172963Stoy ui = lpinfo[LPUNIT(dev)]; 3182963Stoy lpaddr = (struct lpdevice *) ui->ui_addr; 3192963Stoy if ((sc->sc_state&MOD) != 0) { 3202963Stoy sc->sc_state &= ~MOD; /* something happened */ 3213986Sroot timeout(lptout, (caddr_t)dev, 2*hz); /* so don't sweat */ 3221921Swnj return; 3231921Swnj } 32416835Smckusick if ((sc->sc_state&OPEN) == 0 && sc->sc_outq.c_cc == 0) { 3252963Stoy sc->sc_state &= ~TOUT; /* no longer open */ 3262963Stoy lpaddr->lpsr = 0; 3271921Swnj return; 3281921Swnj } 3292963Stoy if (sc->sc_outq.c_cc && (lpaddr->lpsr&DONE) && (lpaddr->lpsr&ERROR)==0) 3303205Swnj lpintr(LPUNIT(dev)); /* ready to go */ 3313986Sroot timeout(lptout, (caddr_t)dev, 10*hz); 3321921Swnj } 3331921Swnj 3342963Stoy lpreset(uban) 3353205Swnj int uban; 3361921Swnj { 3372963Stoy register struct uba_device *ui; 3382963Stoy register struct lpdevice *lpaddr; 3392963Stoy register int unit; 3401921Swnj 3413205Swnj for (unit = 0; unit < NLP; unit++) { 3423205Swnj if ((ui = lpinfo[unit]) == 0 || ui->ui_ubanum != uban || 3433205Swnj ui->ui_alive == 0) 3442963Stoy continue; 3452963Stoy printf(" lp%d", unit); 3463205Swnj lpaddr = (struct lpdevice *)ui->ui_addr; 3472963Stoy lpaddr->lpsr |= IENABLE; 3481921Swnj } 3491921Swnj } 35013091Ssam #endif 351