131b944ffSmckusick /*
271e40568Smckusick * Copyright (c) 1982, 1986 Regents of the University of California.
331b944ffSmckusick * All rights reserved. The Berkeley software License Agreement
431b944ffSmckusick * specifies the terms and conditions for redistribution.
531b944ffSmckusick *
6*39bdaf89Sbostic * @(#)lp.c 7.8 (Berkeley) 12/16/90
731b944ffSmckusick */
88ad6c293Swnj
99826bf71Swnj #include "lp.h"
1019dc5c79Stoy #if NLP > 0
118ad6c293Swnj /*
128ad6c293Swnj * LP-11 Line printer driver
138ad6c293Swnj *
148ad6c293Swnj * This driver has been modified to work on printers where
158ad6c293Swnj * leaving IENABLE set would cause continuous interrupts.
168ad6c293Swnj */
17*39bdaf89Sbostic #include "../include/pte.h"
188ad6c293Swnj
19*39bdaf89Sbostic #include "sys/param.h"
20*39bdaf89Sbostic #include "sys/user.h"
21*39bdaf89Sbostic #include "sys/buf.h"
22*39bdaf89Sbostic #include "sys/conf.h"
23*39bdaf89Sbostic #include "sys/systm.h"
24*39bdaf89Sbostic #include "sys/map.h"
25*39bdaf89Sbostic #include "sys/uio.h"
26*39bdaf89Sbostic #include "sys/ioctl.h"
27*39bdaf89Sbostic #include "sys/tty.h"
28*39bdaf89Sbostic #include "sys/kernel.h"
298ad6c293Swnj
3071445730Sbloom #include "ubavar.h"
3142b8bd9bSroot
328ad6c293Swnj #define LPPRI (PZERO+8)
338ad6c293Swnj #define IENABLE 0100
348ad6c293Swnj #define DONE 0200
358ad6c293Swnj #define ERROR 0100000
368ad6c293Swnj #define LPLWAT 650
378ad6c293Swnj #define LPHWAT 800
388ad6c293Swnj
39395e3743Skarels #define LPBUFSIZE 1024
4019dc5c79Stoy #define MAXCOL 132
4119dc5c79Stoy #define CAP 1
4219dc5c79Stoy
4319dc5c79Stoy #define LPUNIT(dev) (minor(dev) >> 3)
4419dc5c79Stoy
4519dc5c79Stoy struct lpdevice {
468ad6c293Swnj short lpsr;
478ad6c293Swnj short lpbuf;
488ad6c293Swnj };
498ad6c293Swnj
5019dc5c79Stoy struct lp_softc {
5119dc5c79Stoy struct clist sc_outq;
5219dc5c79Stoy int sc_state;
5319dc5c79Stoy int sc_physcol;
5419dc5c79Stoy int sc_logcol;
5519dc5c79Stoy int sc_physline;
5619dc5c79Stoy char sc_flags;
57767a234cSsam short sc_maxcol;
5819dc5c79Stoy int sc_lpchar;
5919dc5c79Stoy struct buf *sc_inbuf;
6019dc5c79Stoy } lp_softc[NLP];
6119dc5c79Stoy
6219dc5c79Stoy struct uba_device *lpinfo[NLP];
6319dc5c79Stoy
6419dc5c79Stoy int lpprobe(), lpattach(), lptout();
653c68c3f4Stef u_short lpstd[] = { 0177514, 0 };
6619dc5c79Stoy struct uba_driver lpdriver =
6719dc5c79Stoy { lpprobe, 0, lpattach, 0, lpstd, "lp", lpinfo };
688ad6c293Swnj
698ad6c293Swnj /* bits for state */
708ad6c293Swnj #define OPEN 1 /* device is open */
718ad6c293Swnj #define TOUT 2 /* timeout is active */
728ad6c293Swnj #define MOD 4 /* device state has been modified */
738ad6c293Swnj #define ASLP 8 /* awaiting draining of printer */
748ad6c293Swnj
7584e24a43Swnj lpattach(ui)
7684e24a43Swnj struct uba_device *ui;
7784e24a43Swnj {
7884e24a43Swnj register struct lp_softc *sc;
7984e24a43Swnj
8084e24a43Swnj sc = &lp_softc[ui->ui_unit];
8184e24a43Swnj sc->sc_lpchar = -1;
82767a234cSsam if (ui->ui_flags)
83767a234cSsam sc->sc_maxcol = ui->ui_flags;
84767a234cSsam else
85767a234cSsam sc->sc_maxcol = MAXCOL;
8684e24a43Swnj }
8784e24a43Swnj
lpprobe(reg)8884e24a43Swnj lpprobe(reg)
8984e24a43Swnj caddr_t reg;
9084e24a43Swnj {
913bca611eSwnj register int br, cvec; /* value-result */
9284e24a43Swnj register struct lpdevice *lpaddr = (struct lpdevice *)reg;
93573260eeSroot #ifdef lint
94573260eeSroot br = 0; cvec = br; br = cvec;
95a0f3106dSwnj lpintr(0);
96573260eeSroot #endif
9784e24a43Swnj
9884e24a43Swnj lpaddr->lpsr = IENABLE;
993bca611eSwnj DELAY(5);
10084e24a43Swnj lpaddr->lpsr = 0;
1018b4ceed8Skre return (sizeof (struct lpdevice));
10284e24a43Swnj }
10384e24a43Swnj
1048ad6c293Swnj /*ARGSUSED*/
lpopen(dev,flag)1058ad6c293Swnj lpopen(dev, flag)
10619dc5c79Stoy dev_t dev;
10784e24a43Swnj int flag;
1088ad6c293Swnj {
10919dc5c79Stoy register struct lpdevice *lpaddr;
11019dc5c79Stoy register struct lp_softc *sc;
11119dc5c79Stoy register struct uba_device *ui;
1121d999883Smckusick register int unit, s;
1138ad6c293Swnj
11484e24a43Swnj if ((unit = LPUNIT(dev)) >= NLP ||
11584e24a43Swnj (sc = &lp_softc[unit])->sc_state&OPEN ||
1163536053eSroot (ui = lpinfo[unit]) == 0 || ui->ui_alive == 0)
1173536053eSroot return (ENXIO);
11819dc5c79Stoy lpaddr = (struct lpdevice *)ui->ui_addr;
1193536053eSroot if (lpaddr->lpsr&ERROR)
1203536053eSroot return (EIO);
12119dc5c79Stoy sc->sc_state |= OPEN;
122395e3743Skarels sc->sc_inbuf = geteblk(LPBUFSIZE);
12319dc5c79Stoy sc->sc_flags = minor(dev) & 07;
1241d999883Smckusick s = spl4();
12519dc5c79Stoy if ((sc->sc_state&TOUT) == 0) {
12619dc5c79Stoy sc->sc_state |= TOUT;
127573260eeSroot timeout(lptout, (caddr_t)dev, 10*hz);
1288ad6c293Swnj }
1291d999883Smckusick splx(s);
13084e24a43Swnj lpcanon(dev, '\f');
1313536053eSroot return (0);
1328ad6c293Swnj }
1338ad6c293Swnj
1348ad6c293Swnj /*ARGSUSED*/
lpclose(dev,flag)1358ad6c293Swnj lpclose(dev, flag)
13619dc5c79Stoy dev_t dev;
13784e24a43Swnj int flag;
1388ad6c293Swnj {
13984e24a43Swnj register struct lp_softc *sc = &lp_softc[LPUNIT(dev)];
1408ad6c293Swnj
14184e24a43Swnj lpcanon(dev, '\f');
14219dc5c79Stoy brelse(sc->sc_inbuf);
14319dc5c79Stoy sc->sc_state &= ~OPEN;
1441db00297Skarels return (0);
1458ad6c293Swnj }
1468ad6c293Swnj
lpwrite(dev,uio)14725aace65Sroot lpwrite(dev, uio)
14884e24a43Swnj dev_t dev;
14925aace65Sroot struct uio *uio;
1508ad6c293Swnj {
151573260eeSroot register unsigned n;
1528ad6c293Swnj register char *cp;
15384e24a43Swnj register struct lp_softc *sc = &lp_softc[LPUNIT(dev)];
1540d901dbeSroot int error;
1558ad6c293Swnj
156395e3743Skarels while (n = MIN(LPBUFSIZE, (unsigned)uio->uio_resid)) {
15719dc5c79Stoy cp = sc->sc_inbuf->b_un.b_addr;
15823898f75Smckusick error = uiomove(cp, (int)n, uio);
1590d901dbeSroot if (error)
1600d901dbeSroot return (error);
1618ad6c293Swnj do
16284e24a43Swnj lpcanon(dev, *cp++);
1638ad6c293Swnj while (--n);
1648ad6c293Swnj }
1650d901dbeSroot return (0);
1668ad6c293Swnj }
1678ad6c293Swnj
lpcanon(dev,c)16884e24a43Swnj lpcanon(dev, c)
16984e24a43Swnj dev_t dev;
17019dc5c79Stoy register int c;
1718ad6c293Swnj {
17284e24a43Swnj register struct lp_softc *sc = &lp_softc[LPUNIT(dev)];
1731d999883Smckusick register int logcol, physcol, s;
1748ad6c293Swnj
17519dc5c79Stoy if (sc->sc_flags&CAP) {
1768ad6c293Swnj register c2;
1778ad6c293Swnj
1788ad6c293Swnj if (c>='a' && c<='z')
1798ad6c293Swnj c += 'A'-'a'; else
1808ad6c293Swnj switch (c) {
1818ad6c293Swnj
1828ad6c293Swnj case '{':
1838ad6c293Swnj c2 = '(';
1848ad6c293Swnj goto esc;
1858ad6c293Swnj
1868ad6c293Swnj case '}':
1878ad6c293Swnj c2 = ')';
1888ad6c293Swnj goto esc;
1898ad6c293Swnj
1908ad6c293Swnj case '`':
1918ad6c293Swnj c2 = '\'';
1928ad6c293Swnj goto esc;
1938ad6c293Swnj
1948ad6c293Swnj case '|':
1958ad6c293Swnj c2 = '!';
1968ad6c293Swnj goto esc;
1978ad6c293Swnj
1988ad6c293Swnj case '~':
1998ad6c293Swnj c2 = '^';
2008ad6c293Swnj
2018ad6c293Swnj esc:
20284e24a43Swnj lpcanon(dev, c2);
20319dc5c79Stoy sc->sc_logcol--;
2048ad6c293Swnj c = '-';
2058ad6c293Swnj }
2068ad6c293Swnj }
20719dc5c79Stoy logcol = sc->sc_logcol;
20819dc5c79Stoy physcol = sc->sc_physcol;
2098ad6c293Swnj if (c == ' ')
2108ad6c293Swnj logcol++;
2118ad6c293Swnj else switch(c) {
2128ad6c293Swnj
2138ad6c293Swnj case '\t':
21470b581cfSwnj logcol = (logcol+8) & ~7;
2158ad6c293Swnj break;
2168ad6c293Swnj
2178ad6c293Swnj case '\f':
21819dc5c79Stoy if (sc->sc_physline == 0 && physcol == 0)
219f0b42318Swnj break;
220c2e62a0eStoy /* fall into ... */
221c2e62a0eStoy
222c2e62a0eStoy case '\n':
22384e24a43Swnj lpoutput(dev, c);
224f0b42318Swnj if (c == '\f')
22519dc5c79Stoy sc->sc_physline = 0;
226f0b42318Swnj else
22719dc5c79Stoy sc->sc_physline++;
228c2e62a0eStoy physcol = 0;
2298ad6c293Swnj /* fall into ... */
2308ad6c293Swnj
2318ad6c293Swnj case '\r':
2321d999883Smckusick s = spl4();
23319dc5c79Stoy logcol = 0;
23484e24a43Swnj lpintr(LPUNIT(dev));
2351d999883Smckusick splx(s);
2368ad6c293Swnj break;
2378ad6c293Swnj
2388ad6c293Swnj case '\b':
2398ad6c293Swnj if (logcol > 0)
2408ad6c293Swnj logcol--;
2418ad6c293Swnj break;
2428ad6c293Swnj
2438ad6c293Swnj default:
2448ad6c293Swnj if (logcol < physcol) {
24584e24a43Swnj lpoutput(dev, '\r');
2468ad6c293Swnj physcol = 0;
2478ad6c293Swnj }
248767a234cSsam if (logcol < sc->sc_maxcol) {
2498ad6c293Swnj while (logcol > physcol) {
25084e24a43Swnj lpoutput(dev, ' ');
2518ad6c293Swnj physcol++;
2528ad6c293Swnj }
25384e24a43Swnj lpoutput(dev, c);
2548ad6c293Swnj physcol++;
2558ad6c293Swnj }
2568ad6c293Swnj logcol++;
2578ad6c293Swnj }
2588ad6c293Swnj if (logcol > 1000) /* ignore long lines */
2598ad6c293Swnj logcol = 1000;
26019dc5c79Stoy sc->sc_logcol = logcol;
26119dc5c79Stoy sc->sc_physcol = physcol;
2628ad6c293Swnj }
2638ad6c293Swnj
lpoutput(dev,c)26484e24a43Swnj lpoutput(dev, c)
26519dc5c79Stoy dev_t dev;
26684e24a43Swnj int c;
2678ad6c293Swnj {
26884e24a43Swnj register struct lp_softc *sc = &lp_softc[LPUNIT(dev)];
2691db00297Skarels int s, error = 0;
2708ad6c293Swnj
27119dc5c79Stoy if (sc->sc_outq.c_cc >= LPHWAT) {
2721d999883Smckusick s = spl4();
27384e24a43Swnj lpintr(LPUNIT(dev)); /* unchoke */
2741db00297Skarels while (sc->sc_outq.c_cc >= LPHWAT && error == 0) {
27519dc5c79Stoy sc->sc_state |= ASLP; /* must be ERROR */
2761db00297Skarels error = tsleep((caddr_t)sc, LPPRI | PCATCH,
2771db00297Skarels devout, 0);
2788ad6c293Swnj }
2791d999883Smckusick splx(s);
2808ad6c293Swnj }
2811db00297Skarels while (error == 0 && putc(c, &sc->sc_outq))
2821db00297Skarels error = tsleep((caddr_t)&lbolt, LPPRI | PCATCH,
2831db00297Skarels ttybuf, 0);
2841db00297Skarels return (error);
2858ad6c293Swnj }
2868ad6c293Swnj
lpintr(lp11)28784e24a43Swnj lpintr(lp11)
28884e24a43Swnj int lp11;
2898ad6c293Swnj {
2908ad6c293Swnj register int n;
29184e24a43Swnj register struct lp_softc *sc = &lp_softc[lp11];
29284e24a43Swnj register struct uba_device *ui = lpinfo[lp11];
29384e24a43Swnj register struct lpdevice *lpaddr = (struct lpdevice *)ui->ui_addr;
2948ad6c293Swnj
29519dc5c79Stoy lpaddr->lpsr &= ~IENABLE;
29619dc5c79Stoy n = sc->sc_outq.c_cc;
29719dc5c79Stoy if (sc->sc_lpchar < 0)
29819dc5c79Stoy sc->sc_lpchar = getc(&sc->sc_outq);
29919dc5c79Stoy while ((lpaddr->lpsr&DONE) && sc->sc_lpchar >= 0) {
30019dc5c79Stoy lpaddr->lpbuf = sc->sc_lpchar;
30119dc5c79Stoy sc->sc_lpchar = getc(&sc->sc_outq);
3028ad6c293Swnj }
30319dc5c79Stoy sc->sc_state |= MOD;
30419dc5c79Stoy if (sc->sc_outq.c_cc > 0 && (lpaddr->lpsr&ERROR)==0)
30519dc5c79Stoy lpaddr->lpsr |= IENABLE; /* ok and more to do later */
30619dc5c79Stoy if (n>LPLWAT && sc->sc_outq.c_cc<=LPLWAT && sc->sc_state&ASLP) {
30719dc5c79Stoy sc->sc_state &= ~ASLP;
30819dc5c79Stoy wakeup((caddr_t)sc); /* top half should go on */
3098ad6c293Swnj }
3108ad6c293Swnj }
3118ad6c293Swnj
lptout(dev)31219dc5c79Stoy lptout(dev)
31384e24a43Swnj dev_t dev;
3148ad6c293Swnj {
31519dc5c79Stoy register struct lp_softc *sc;
31619dc5c79Stoy register struct uba_device *ui;
31719dc5c79Stoy register struct lpdevice *lpaddr;
3188ad6c293Swnj
31919dc5c79Stoy sc = &lp_softc[LPUNIT(dev)];
32019dc5c79Stoy ui = lpinfo[LPUNIT(dev)];
32119dc5c79Stoy lpaddr = (struct lpdevice *) ui->ui_addr;
32219dc5c79Stoy if ((sc->sc_state&MOD) != 0) {
32319dc5c79Stoy sc->sc_state &= ~MOD; /* something happened */
324573260eeSroot timeout(lptout, (caddr_t)dev, 2*hz); /* so don't sweat */
3258ad6c293Swnj return;
3268ad6c293Swnj }
3277cda3700Smckusick if ((sc->sc_state&OPEN) == 0 && sc->sc_outq.c_cc == 0) {
32819dc5c79Stoy sc->sc_state &= ~TOUT; /* no longer open */
32919dc5c79Stoy lpaddr->lpsr = 0;
3308ad6c293Swnj return;
3318ad6c293Swnj }
33219dc5c79Stoy if (sc->sc_outq.c_cc && (lpaddr->lpsr&DONE) && (lpaddr->lpsr&ERROR)==0)
33384e24a43Swnj lpintr(LPUNIT(dev)); /* ready to go */
334573260eeSroot timeout(lptout, (caddr_t)dev, 10*hz);
3358ad6c293Swnj }
3368ad6c293Swnj
lpreset(uban)33719dc5c79Stoy lpreset(uban)
33819dc5c79Stoy int uban;
3398ad6c293Swnj {
34019dc5c79Stoy register struct uba_device *ui;
34119dc5c79Stoy register struct lpdevice *lpaddr;
34219dc5c79Stoy register int unit;
3438ad6c293Swnj
34484e24a43Swnj for (unit = 0; unit < NLP; unit++) {
34584e24a43Swnj if ((ui = lpinfo[unit]) == 0 || ui->ui_ubanum != uban ||
34684e24a43Swnj ui->ui_alive == 0)
34719dc5c79Stoy continue;
34819dc5c79Stoy printf(" lp%d", unit);
34919dc5c79Stoy lpaddr = (struct lpdevice *)ui->ui_addr;
35019dc5c79Stoy lpaddr->lpsr |= IENABLE;
35119dc5c79Stoy }
3528ad6c293Swnj }
353ffffdfffSsam #endif
354