xref: /original-bsd/sys/vax/uba/lp.c (revision 39bdaf89)
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