123331Smckusick /*
229224Smckusick * Copyright (c) 1982, 1986 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*45804Sbostic * @(#)lp.c 7.8 (Berkeley) 12/16/90
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 */
17*45804Sbostic #include "../include/pte.h"
181921Swnj
19*45804Sbostic #include "sys/param.h"
20*45804Sbostic #include "sys/user.h"
21*45804Sbostic #include "sys/buf.h"
22*45804Sbostic #include "sys/conf.h"
23*45804Sbostic #include "sys/systm.h"
24*45804Sbostic #include "sys/map.h"
25*45804Sbostic #include "sys/uio.h"
26*45804Sbostic #include "sys/ioctl.h"
27*45804Sbostic #include "sys/tty.h"
28*45804Sbostic #include "sys/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
3926367Skarels #define LPBUFSIZE 1024
4026367Skarels #define MAXCOL 132
4126367Skarels #define CAP 1
422963Stoy
4326367Skarels #define LPUNIT(dev) (minor(dev) >> 3)
442963Stoy
452963Stoy struct lpdevice {
461921Swnj short lpsr;
471921Swnj short lpbuf;
481921Swnj };
491921Swnj
502963Stoy struct lp_softc {
512963Stoy struct clist sc_outq;
522963Stoy int sc_state;
532963Stoy int sc_physcol;
542963Stoy int sc_logcol;
552963Stoy int sc_physline;
562963Stoy char sc_flags;
5710112Ssam short sc_maxcol;
582963Stoy int sc_lpchar;
592963Stoy struct buf *sc_inbuf;
602963Stoy } lp_softc[NLP];
611921Swnj
622963Stoy struct uba_device *lpinfo[NLP];
632963Stoy
642963Stoy int lpprobe(), lpattach(), lptout();
6525521Stef u_short lpstd[] = { 0177514, 0 };
662963Stoy struct uba_driver lpdriver =
672963Stoy { lpprobe, 0, lpattach, 0, lpstd, "lp", lpinfo };
682963Stoy
691921Swnj /* bits for state */
701921Swnj #define OPEN 1 /* device is open */
711921Swnj #define TOUT 2 /* timeout is active */
721921Swnj #define MOD 4 /* device state has been modified */
731921Swnj #define ASLP 8 /* awaiting draining of printer */
741921Swnj
753205Swnj lpattach(ui)
763205Swnj struct uba_device *ui;
773205Swnj {
783205Swnj register struct lp_softc *sc;
793205Swnj
803205Swnj sc = &lp_softc[ui->ui_unit];
813205Swnj sc->sc_lpchar = -1;
8210112Ssam if (ui->ui_flags)
8310112Ssam sc->sc_maxcol = ui->ui_flags;
8410112Ssam else
8510112Ssam sc->sc_maxcol = MAXCOL;
863205Swnj }
873205Swnj
lpprobe(reg)883205Swnj lpprobe(reg)
893205Swnj caddr_t reg;
903205Swnj {
913250Swnj register int br, cvec; /* value-result */
923205Swnj register struct lpdevice *lpaddr = (struct lpdevice *)reg;
933986Sroot #ifdef lint
943986Sroot br = 0; cvec = br; br = cvec;
954935Swnj lpintr(0);
963986Sroot #endif
973205Swnj
983205Swnj lpaddr->lpsr = IENABLE;
993250Swnj DELAY(5);
1003205Swnj lpaddr->lpsr = 0;
1017411Skre return (sizeof (struct lpdevice));
1023205Swnj }
1033205Swnj
1041921Swnj /*ARGSUSED*/
lpopen(dev,flag)1051921Swnj lpopen(dev, flag)
1063205Swnj dev_t dev;
1073205Swnj int flag;
1081921Swnj {
1092963Stoy register struct lpdevice *lpaddr;
1102963Stoy register struct lp_softc *sc;
1112963Stoy register struct uba_device *ui;
11217002Smckusick register int unit, s;
1131921Swnj
1143205Swnj if ((unit = LPUNIT(dev)) >= NLP ||
1153205Swnj (sc = &lp_softc[unit])->sc_state&OPEN ||
1168570Sroot (ui = lpinfo[unit]) == 0 || ui->ui_alive == 0)
1178570Sroot return (ENXIO);
1183205Swnj lpaddr = (struct lpdevice *)ui->ui_addr;
1198570Sroot if (lpaddr->lpsr&ERROR)
1208570Sroot return (EIO);
1212963Stoy sc->sc_state |= OPEN;
12226367Skarels sc->sc_inbuf = geteblk(LPBUFSIZE);
1232963Stoy sc->sc_flags = minor(dev) & 07;
12417002Smckusick s = spl4();
1252963Stoy if ((sc->sc_state&TOUT) == 0) {
1262963Stoy sc->sc_state |= TOUT;
1273986Sroot timeout(lptout, (caddr_t)dev, 10*hz);
1281921Swnj }
12917002Smckusick splx(s);
1303205Swnj lpcanon(dev, '\f');
1318570Sroot return (0);
1321921Swnj }
1331921Swnj
1341921Swnj /*ARGSUSED*/
lpclose(dev,flag)1351921Swnj lpclose(dev, flag)
1363205Swnj dev_t dev;
1373205Swnj int flag;
1381921Swnj {
1393205Swnj register struct lp_softc *sc = &lp_softc[LPUNIT(dev)];
1401921Swnj
1413205Swnj lpcanon(dev, '\f');
1422963Stoy brelse(sc->sc_inbuf);
1432963Stoy sc->sc_state &= ~OPEN;
14440728Skarels return (0);
1451921Swnj }
1461921Swnj
lpwrite(dev,uio)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
15626367Skarels while (n = MIN(LPBUFSIZE, (unsigned)uio->uio_resid)) {
1572963Stoy cp = sc->sc_inbuf->b_un.b_addr;
15837763Smckusick error = uiomove(cp, (int)n, uio);
1598491Sroot if (error)
1608491Sroot return (error);
1611921Swnj do
1623205Swnj lpcanon(dev, *cp++);
1631921Swnj while (--n);
1641921Swnj }
1658491Sroot return (0);
1661921Swnj }
1671921Swnj
lpcanon(dev,c)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
lpoutput(dev,c)2643205Swnj lpoutput(dev, c)
2653205Swnj dev_t dev;
2663205Swnj int c;
2671921Swnj {
2683205Swnj register struct lp_softc *sc = &lp_softc[LPUNIT(dev)];
26940728Skarels int s, error = 0;
2701921Swnj
2712963Stoy if (sc->sc_outq.c_cc >= LPHWAT) {
27217002Smckusick s = spl4();
2733205Swnj lpintr(LPUNIT(dev)); /* unchoke */
27440728Skarels while (sc->sc_outq.c_cc >= LPHWAT && error == 0) {
2752963Stoy sc->sc_state |= ASLP; /* must be ERROR */
27640728Skarels error = tsleep((caddr_t)sc, LPPRI | PCATCH,
27740728Skarels devout, 0);
2781921Swnj }
27917002Smckusick splx(s);
2801921Swnj }
28140728Skarels while (error == 0 && putc(c, &sc->sc_outq))
28240728Skarels error = tsleep((caddr_t)&lbolt, LPPRI | PCATCH,
28340728Skarels ttybuf, 0);
28440728Skarels return (error);
2851921Swnj }
2861921Swnj
lpintr(lp11)2873205Swnj lpintr(lp11)
2883205Swnj int lp11;
2891921Swnj {
2901921Swnj register int n;
2913205Swnj register struct lp_softc *sc = &lp_softc[lp11];
2923205Swnj register struct uba_device *ui = lpinfo[lp11];
2933205Swnj register struct lpdevice *lpaddr = (struct lpdevice *)ui->ui_addr;
2941921Swnj
2952963Stoy lpaddr->lpsr &= ~IENABLE;
2962963Stoy n = sc->sc_outq.c_cc;
2972963Stoy if (sc->sc_lpchar < 0)
2982963Stoy sc->sc_lpchar = getc(&sc->sc_outq);
2992963Stoy while ((lpaddr->lpsr&DONE) && sc->sc_lpchar >= 0) {
3002963Stoy lpaddr->lpbuf = sc->sc_lpchar;
3012963Stoy sc->sc_lpchar = getc(&sc->sc_outq);
3021921Swnj }
3032963Stoy sc->sc_state |= MOD;
3042963Stoy if (sc->sc_outq.c_cc > 0 && (lpaddr->lpsr&ERROR)==0)
3052963Stoy lpaddr->lpsr |= IENABLE; /* ok and more to do later */
3062963Stoy if (n>LPLWAT && sc->sc_outq.c_cc<=LPLWAT && sc->sc_state&ASLP) {
3072963Stoy sc->sc_state &= ~ASLP;
3082963Stoy wakeup((caddr_t)sc); /* top half should go on */
3091921Swnj }
3101921Swnj }
3111921Swnj
lptout(dev)3122963Stoy lptout(dev)
3133205Swnj dev_t dev;
3141921Swnj {
3152963Stoy register struct lp_softc *sc;
3162963Stoy register struct uba_device *ui;
3172963Stoy register struct lpdevice *lpaddr;
3181921Swnj
3192963Stoy sc = &lp_softc[LPUNIT(dev)];
3202963Stoy ui = lpinfo[LPUNIT(dev)];
3212963Stoy lpaddr = (struct lpdevice *) ui->ui_addr;
3222963Stoy if ((sc->sc_state&MOD) != 0) {
3232963Stoy sc->sc_state &= ~MOD; /* something happened */
3243986Sroot timeout(lptout, (caddr_t)dev, 2*hz); /* so don't sweat */
3251921Swnj return;
3261921Swnj }
32716835Smckusick if ((sc->sc_state&OPEN) == 0 && sc->sc_outq.c_cc == 0) {
3282963Stoy sc->sc_state &= ~TOUT; /* no longer open */
3292963Stoy lpaddr->lpsr = 0;
3301921Swnj return;
3311921Swnj }
3322963Stoy if (sc->sc_outq.c_cc && (lpaddr->lpsr&DONE) && (lpaddr->lpsr&ERROR)==0)
3333205Swnj lpintr(LPUNIT(dev)); /* ready to go */
3343986Sroot timeout(lptout, (caddr_t)dev, 10*hz);
3351921Swnj }
3361921Swnj
lpreset(uban)3372963Stoy lpreset(uban)
3383205Swnj int uban;
3391921Swnj {
3402963Stoy register struct uba_device *ui;
3412963Stoy register struct lpdevice *lpaddr;
3422963Stoy register int unit;
3431921Swnj
3443205Swnj for (unit = 0; unit < NLP; unit++) {
3453205Swnj if ((ui = lpinfo[unit]) == 0 || ui->ui_ubanum != uban ||
3463205Swnj ui->ui_alive == 0)
3472963Stoy continue;
3482963Stoy printf(" lp%d", unit);
3493205Swnj lpaddr = (struct lpdevice *)ui->ui_addr;
3502963Stoy lpaddr->lpsr |= IENABLE;
3511921Swnj }
3521921Swnj }
35313091Ssam #endif
354