123331Smckusick /* 223331Smckusick * Copyright (c) 1982 Regents of the University of California. 323331Smckusick * All rights reserved. The Berkeley software License Agreement 423331Smckusick * specifies the terms and conditions for redistribution. 523331Smckusick * 6*25521Stef * @(#)lp.c 6.7 (Berkeley) 11/22/85 723331Smckusick */ 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(); 64*25521Stef u_short lpstd[] = { 0177514, 0 }; 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 743205Swnj lpattach(ui) 753205Swnj struct uba_device *ui; 763205Swnj { 773205Swnj register struct lp_softc *sc; 783205Swnj 793205Swnj sc = &lp_softc[ui->ui_unit]; 803205Swnj sc->sc_lpchar = -1; 8110112Ssam if (ui->ui_flags) 8210112Ssam sc->sc_maxcol = ui->ui_flags; 8310112Ssam else 8410112Ssam sc->sc_maxcol = MAXCOL; 853205Swnj } 863205Swnj 873205Swnj lpprobe(reg) 883205Swnj caddr_t reg; 893205Swnj { 903250Swnj register int br, cvec; /* value-result */ 913205Swnj register struct lpdevice *lpaddr = (struct lpdevice *)reg; 923986Sroot #ifdef lint 933986Sroot br = 0; cvec = br; br = cvec; 944935Swnj lpintr(0); 953986Sroot #endif 963205Swnj 973205Swnj lpaddr->lpsr = IENABLE; 983250Swnj DELAY(5); 993205Swnj lpaddr->lpsr = 0; 1007411Skre return (sizeof (struct lpdevice)); 1013205Swnj } 1023205Swnj 1031921Swnj /*ARGSUSED*/ 1041921Swnj lpopen(dev, flag) 1053205Swnj dev_t dev; 1063205Swnj int flag; 1071921Swnj { 1082963Stoy register struct lpdevice *lpaddr; 1092963Stoy register struct lp_softc *sc; 1102963Stoy register struct uba_device *ui; 11117002Smckusick register int unit, s; 1121921Swnj 1133205Swnj if ((unit = LPUNIT(dev)) >= NLP || 1143205Swnj (sc = &lp_softc[unit])->sc_state&OPEN || 1158570Sroot (ui = lpinfo[unit]) == 0 || ui->ui_alive == 0) 1168570Sroot return (ENXIO); 1173205Swnj lpaddr = (struct lpdevice *)ui->ui_addr; 1188570Sroot if (lpaddr->lpsr&ERROR) 1198570Sroot return (EIO); 1202963Stoy sc->sc_state |= OPEN; 1217184Sroot sc->sc_inbuf = geteblk(512); 1222963Stoy sc->sc_flags = minor(dev) & 07; 12317002Smckusick s = spl4(); 1242963Stoy if ((sc->sc_state&TOUT) == 0) { 1252963Stoy sc->sc_state |= TOUT; 1263986Sroot timeout(lptout, (caddr_t)dev, 10*hz); 1271921Swnj } 12817002Smckusick splx(s); 1293205Swnj lpcanon(dev, '\f'); 1308570Sroot return (0); 1311921Swnj } 1321921Swnj 1331921Swnj /*ARGSUSED*/ 1341921Swnj lpclose(dev, flag) 1353205Swnj dev_t dev; 1363205Swnj int flag; 1371921Swnj { 1383205Swnj register struct lp_softc *sc = &lp_softc[LPUNIT(dev)]; 1391921Swnj 1403205Swnj lpcanon(dev, '\f'); 1412963Stoy brelse(sc->sc_inbuf); 1422963Stoy sc->sc_state &= ~OPEN; 1431921Swnj } 1441921Swnj 1457835Sroot lpwrite(dev, uio) 1463205Swnj dev_t dev; 1477835Sroot struct uio *uio; 1481921Swnj { 1493986Sroot register unsigned n; 1501921Swnj register char *cp; 1513205Swnj register struct lp_softc *sc = &lp_softc[LPUNIT(dev)]; 1528491Sroot int error; 1531921Swnj 15413091Ssam while (n = min(512, (unsigned)uio->uio_resid)) { 1552963Stoy cp = sc->sc_inbuf->b_un.b_addr; 15613091Ssam error = uiomove(cp, (int)n, UIO_WRITE, uio); 1578491Sroot if (error) 1588491Sroot return (error); 1591921Swnj do 1603205Swnj lpcanon(dev, *cp++); 1611921Swnj while (--n); 1621921Swnj } 1638491Sroot return (0); 1641921Swnj } 1651921Swnj 1663205Swnj lpcanon(dev, c) 1673205Swnj dev_t dev; 1683205Swnj register int c; 1691921Swnj { 1703205Swnj register struct lp_softc *sc = &lp_softc[LPUNIT(dev)]; 17117002Smckusick register int logcol, physcol, s; 1721921Swnj 1732963Stoy if (sc->sc_flags&CAP) { 1741921Swnj register c2; 1751921Swnj 1761921Swnj if (c>='a' && c<='z') 1771921Swnj c += 'A'-'a'; else 1781921Swnj switch (c) { 1791921Swnj 1801921Swnj case '{': 1811921Swnj c2 = '('; 1821921Swnj goto esc; 1831921Swnj 1841921Swnj case '}': 1851921Swnj c2 = ')'; 1861921Swnj goto esc; 1871921Swnj 1881921Swnj case '`': 1891921Swnj c2 = '\''; 1901921Swnj goto esc; 1911921Swnj 1921921Swnj case '|': 1931921Swnj c2 = '!'; 1941921Swnj goto esc; 1951921Swnj 1961921Swnj case '~': 1971921Swnj c2 = '^'; 1981921Swnj 1991921Swnj esc: 2003205Swnj lpcanon(dev, c2); 2012963Stoy sc->sc_logcol--; 2021921Swnj c = '-'; 2031921Swnj } 2041921Swnj } 2052963Stoy logcol = sc->sc_logcol; 2062963Stoy physcol = sc->sc_physcol; 2071921Swnj if (c == ' ') 2081921Swnj logcol++; 2091921Swnj else switch(c) { 2101921Swnj 2111921Swnj case '\t': 2123328Swnj logcol = (logcol+8) & ~7; 2131921Swnj break; 2141921Swnj 2151921Swnj case '\f': 2162963Stoy if (sc->sc_physline == 0 && physcol == 0) 2172044Swnj break; 2182206Stoy /* fall into ... */ 2192206Stoy 2202206Stoy case '\n': 2213205Swnj lpoutput(dev, c); 2222044Swnj if (c == '\f') 2232963Stoy sc->sc_physline = 0; 2242044Swnj else 2252963Stoy sc->sc_physline++; 2262206Stoy physcol = 0; 2271921Swnj /* fall into ... */ 2281921Swnj 2291921Swnj case '\r': 23017002Smckusick s = spl4(); 2312963Stoy logcol = 0; 2323205Swnj lpintr(LPUNIT(dev)); 23317002Smckusick splx(s); 2341921Swnj break; 2351921Swnj 2361921Swnj case '\b': 2371921Swnj if (logcol > 0) 2381921Swnj logcol--; 2391921Swnj break; 2401921Swnj 2411921Swnj default: 2421921Swnj if (logcol < physcol) { 2433205Swnj lpoutput(dev, '\r'); 2441921Swnj physcol = 0; 2451921Swnj } 24610112Ssam if (logcol < sc->sc_maxcol) { 2471921Swnj while (logcol > physcol) { 2483205Swnj lpoutput(dev, ' '); 2491921Swnj physcol++; 2501921Swnj } 2513205Swnj lpoutput(dev, c); 2521921Swnj physcol++; 2531921Swnj } 2541921Swnj logcol++; 2551921Swnj } 2561921Swnj if (logcol > 1000) /* ignore long lines */ 2571921Swnj logcol = 1000; 2582963Stoy sc->sc_logcol = logcol; 2592963Stoy sc->sc_physcol = physcol; 2601921Swnj } 2611921Swnj 2623205Swnj lpoutput(dev, c) 2633205Swnj dev_t dev; 2643205Swnj int c; 2651921Swnj { 2663205Swnj register struct lp_softc *sc = &lp_softc[LPUNIT(dev)]; 26717002Smckusick int s; 2681921Swnj 2692963Stoy if (sc->sc_outq.c_cc >= LPHWAT) { 27017002Smckusick s = spl4(); 2713205Swnj lpintr(LPUNIT(dev)); /* unchoke */ 2722963Stoy while (sc->sc_outq.c_cc >= LPHWAT) { 2732963Stoy sc->sc_state |= ASLP; /* must be ERROR */ 2742963Stoy sleep((caddr_t)sc, LPPRI); 2751921Swnj } 27617002Smckusick splx(s); 2771921Swnj } 2782963Stoy while (putc(c, &sc->sc_outq)) 2791921Swnj sleep((caddr_t)&lbolt, LPPRI); 2801921Swnj } 2811921Swnj 2823205Swnj lpintr(lp11) 2833205Swnj int lp11; 2841921Swnj { 2851921Swnj register int n; 2863205Swnj register struct lp_softc *sc = &lp_softc[lp11]; 2873205Swnj register struct uba_device *ui = lpinfo[lp11]; 2883205Swnj register struct lpdevice *lpaddr = (struct lpdevice *)ui->ui_addr; 2891921Swnj 2902963Stoy lpaddr->lpsr &= ~IENABLE; 2912963Stoy n = sc->sc_outq.c_cc; 2922963Stoy if (sc->sc_lpchar < 0) 2932963Stoy sc->sc_lpchar = getc(&sc->sc_outq); 2942963Stoy while ((lpaddr->lpsr&DONE) && sc->sc_lpchar >= 0) { 2952963Stoy lpaddr->lpbuf = sc->sc_lpchar; 2962963Stoy sc->sc_lpchar = getc(&sc->sc_outq); 2971921Swnj } 2982963Stoy sc->sc_state |= MOD; 2992963Stoy if (sc->sc_outq.c_cc > 0 && (lpaddr->lpsr&ERROR)==0) 3002963Stoy lpaddr->lpsr |= IENABLE; /* ok and more to do later */ 3012963Stoy if (n>LPLWAT && sc->sc_outq.c_cc<=LPLWAT && sc->sc_state&ASLP) { 3022963Stoy sc->sc_state &= ~ASLP; 3032963Stoy wakeup((caddr_t)sc); /* top half should go on */ 3041921Swnj } 3051921Swnj } 3061921Swnj 3072963Stoy lptout(dev) 3083205Swnj dev_t dev; 3091921Swnj { 3102963Stoy register struct lp_softc *sc; 3112963Stoy register struct uba_device *ui; 3122963Stoy register struct lpdevice *lpaddr; 3131921Swnj 3142963Stoy sc = &lp_softc[LPUNIT(dev)]; 3152963Stoy ui = lpinfo[LPUNIT(dev)]; 3162963Stoy lpaddr = (struct lpdevice *) ui->ui_addr; 3172963Stoy if ((sc->sc_state&MOD) != 0) { 3182963Stoy sc->sc_state &= ~MOD; /* something happened */ 3193986Sroot timeout(lptout, (caddr_t)dev, 2*hz); /* so don't sweat */ 3201921Swnj return; 3211921Swnj } 32216835Smckusick if ((sc->sc_state&OPEN) == 0 && sc->sc_outq.c_cc == 0) { 3232963Stoy sc->sc_state &= ~TOUT; /* no longer open */ 3242963Stoy lpaddr->lpsr = 0; 3251921Swnj return; 3261921Swnj } 3272963Stoy if (sc->sc_outq.c_cc && (lpaddr->lpsr&DONE) && (lpaddr->lpsr&ERROR)==0) 3283205Swnj lpintr(LPUNIT(dev)); /* ready to go */ 3293986Sroot timeout(lptout, (caddr_t)dev, 10*hz); 3301921Swnj } 3311921Swnj 3322963Stoy lpreset(uban) 3333205Swnj int uban; 3341921Swnj { 3352963Stoy register struct uba_device *ui; 3362963Stoy register struct lpdevice *lpaddr; 3372963Stoy register int unit; 3381921Swnj 3393205Swnj for (unit = 0; unit < NLP; unit++) { 3403205Swnj if ((ui = lpinfo[unit]) == 0 || ui->ui_ubanum != uban || 3413205Swnj ui->ui_alive == 0) 3422963Stoy continue; 3432963Stoy printf(" lp%d", unit); 3443205Swnj lpaddr = (struct lpdevice *)ui->ui_addr; 3452963Stoy lpaddr->lpsr |= IENABLE; 3461921Swnj } 3471921Swnj } 34813091Ssam #endif 349