xref: /csrg-svn/sys/vax/uba/lp.c (revision 17074)
1*17074Sbloom /*	lp.c	6.4	84/08/29	*/
21921Swnj 
31941Swnj #include "lp.h"
42963Stoy #if NLP > 0
51921Swnj /*
61921Swnj  * LP-11 Line printer driver
71921Swnj  *
81921Swnj  * This driver has been modified to work on printers where
91921Swnj  * leaving IENABLE set would cause continuous interrupts.
101921Swnj  */
119775Ssam #include "../machine/pte.h"
121921Swnj 
13*17074Sbloom #include "param.h"
14*17074Sbloom #include "dir.h"
15*17074Sbloom #include "user.h"
16*17074Sbloom #include "buf.h"
17*17074Sbloom #include "systm.h"
18*17074Sbloom #include "map.h"
19*17074Sbloom #include "uio.h"
20*17074Sbloom #include "tty.h"
21*17074Sbloom #include "kernel.h"
221921Swnj 
23*17074Sbloom #include "ubavar.h"
248476Sroot 
251921Swnj #define	LPPRI	(PZERO+8)
261921Swnj #define	IENABLE	0100
271921Swnj #define	DONE	0200
281921Swnj #define	ERROR	0100000
291921Swnj #define	LPLWAT	650
301921Swnj #define	LPHWAT	800
311921Swnj 
322963Stoy #define MAXCOL	132
332963Stoy #define CAP	1
342963Stoy 
352963Stoy #define LPUNIT(dev) (minor(dev) >> 3)
362963Stoy 
372963Stoy struct lpdevice {
381921Swnj 	short	lpsr;
391921Swnj 	short	lpbuf;
401921Swnj };
411921Swnj 
422963Stoy struct lp_softc {
432963Stoy 	struct	clist sc_outq;
442963Stoy 	int	sc_state;
452963Stoy 	int	sc_physcol;
462963Stoy 	int	sc_logcol;
472963Stoy 	int	sc_physline;
482963Stoy 	char	sc_flags;
4910112Ssam 	short	sc_maxcol;
502963Stoy 	int	sc_lpchar;
512963Stoy 	struct	buf *sc_inbuf;
522963Stoy } lp_softc[NLP];
531921Swnj 
542963Stoy struct uba_device *lpinfo[NLP];
552963Stoy 
562963Stoy int lpprobe(), lpattach(), lptout();
572963Stoy u_short lpstd[] = { 0177514 };
582963Stoy struct uba_driver lpdriver =
592963Stoy 	{ lpprobe, 0, lpattach, 0, lpstd, "lp", lpinfo };
602963Stoy 
611921Swnj /* bits for state */
621921Swnj #define	OPEN		1	/* device is open */
631921Swnj #define	TOUT		2	/* timeout is active */
641921Swnj #define	MOD		4	/* device state has been modified */
651921Swnj #define	ASLP		8	/* awaiting draining of printer */
661921Swnj 
671921Swnj int	lptout();
681921Swnj 
693205Swnj lpattach(ui)
703205Swnj 	struct uba_device *ui;
713205Swnj {
723205Swnj 	register struct lp_softc *sc;
733205Swnj 
743205Swnj 	sc = &lp_softc[ui->ui_unit];
753205Swnj 	sc->sc_lpchar = -1;
7610112Ssam 	if (ui->ui_flags)
7710112Ssam 		sc->sc_maxcol = ui->ui_flags;
7810112Ssam 	else
7910112Ssam 		sc->sc_maxcol = MAXCOL;
803205Swnj }
813205Swnj 
823205Swnj lpprobe(reg)
833205Swnj 	caddr_t reg;
843205Swnj {
853250Swnj 	register int br, cvec;			/* value-result */
863205Swnj 	register struct lpdevice *lpaddr = (struct lpdevice *)reg;
873986Sroot #ifdef lint
883986Sroot 	br = 0; cvec = br; br = cvec;
894935Swnj 	lpintr(0);
903986Sroot #endif
913205Swnj 
923205Swnj 	lpaddr->lpsr = IENABLE;
933250Swnj 	DELAY(5);
943205Swnj 	lpaddr->lpsr = 0;
957411Skre 	return (sizeof (struct lpdevice));
963205Swnj }
973205Swnj 
981921Swnj /*ARGSUSED*/
991921Swnj lpopen(dev, flag)
1003205Swnj 	dev_t dev;
1013205Swnj 	int flag;
1021921Swnj {
1032963Stoy 	register struct lpdevice *lpaddr;
1042963Stoy 	register struct lp_softc *sc;
1052963Stoy 	register struct uba_device *ui;
10617002Smckusick 	register int unit, s;
1071921Swnj 
1083205Swnj 	if ((unit = LPUNIT(dev)) >= NLP ||
1093205Swnj 	    (sc = &lp_softc[unit])->sc_state&OPEN ||
1108570Sroot 	    (ui = lpinfo[unit]) == 0 || ui->ui_alive == 0)
1118570Sroot 		return (ENXIO);
1123205Swnj 	lpaddr = (struct lpdevice *)ui->ui_addr;
1138570Sroot 	if (lpaddr->lpsr&ERROR)
1148570Sroot 		return (EIO);
1152963Stoy 	sc->sc_state |= OPEN;
1167184Sroot 	sc->sc_inbuf = geteblk(512);
1172963Stoy 	sc->sc_flags = minor(dev) & 07;
11817002Smckusick 	s = spl4();
1192963Stoy 	if ((sc->sc_state&TOUT) == 0) {
1202963Stoy 		sc->sc_state |= TOUT;
1213986Sroot 		timeout(lptout, (caddr_t)dev, 10*hz);
1221921Swnj 	}
12317002Smckusick 	splx(s);
1243205Swnj 	lpcanon(dev, '\f');
1258570Sroot 	return (0);
1261921Swnj }
1271921Swnj 
1281921Swnj /*ARGSUSED*/
1291921Swnj lpclose(dev, flag)
1303205Swnj 	dev_t dev;
1313205Swnj 	int flag;
1321921Swnj {
1333205Swnj 	register struct lp_softc *sc = &lp_softc[LPUNIT(dev)];
1341921Swnj 
1353205Swnj 	lpcanon(dev, '\f');
1362963Stoy 	brelse(sc->sc_inbuf);
1372963Stoy 	sc->sc_state &= ~OPEN;
1381921Swnj }
1391921Swnj 
1407835Sroot lpwrite(dev, uio)
1413205Swnj 	dev_t dev;
1427835Sroot 	struct uio *uio;
1431921Swnj {
1443986Sroot 	register unsigned n;
1451921Swnj 	register char *cp;
1463205Swnj 	register struct lp_softc *sc = &lp_softc[LPUNIT(dev)];
1478491Sroot 	int error;
1481921Swnj 
14913091Ssam 	while (n = min(512, (unsigned)uio->uio_resid)) {
1502963Stoy 		cp = sc->sc_inbuf->b_un.b_addr;
15113091Ssam 		error = uiomove(cp, (int)n, UIO_WRITE, uio);
1528491Sroot 		if (error)
1538491Sroot 			return (error);
1541921Swnj 		do
1553205Swnj 			lpcanon(dev, *cp++);
1561921Swnj 		while (--n);
1571921Swnj 	}
1588491Sroot 	return (0);
1591921Swnj }
1601921Swnj 
1613205Swnj lpcanon(dev, c)
1623205Swnj 	dev_t dev;
1633205Swnj 	register int c;
1641921Swnj {
1653205Swnj 	register struct lp_softc *sc = &lp_softc[LPUNIT(dev)];
16617002Smckusick 	register int logcol, physcol, s;
1671921Swnj 
1682963Stoy 	if (sc->sc_flags&CAP) {
1691921Swnj 		register c2;
1701921Swnj 
1711921Swnj 		if (c>='a' && c<='z')
1721921Swnj 			c += 'A'-'a'; else
1731921Swnj 		switch (c) {
1741921Swnj 
1751921Swnj 		case '{':
1761921Swnj 			c2 = '(';
1771921Swnj 			goto esc;
1781921Swnj 
1791921Swnj 		case '}':
1801921Swnj 			c2 = ')';
1811921Swnj 			goto esc;
1821921Swnj 
1831921Swnj 		case '`':
1841921Swnj 			c2 = '\'';
1851921Swnj 			goto esc;
1861921Swnj 
1871921Swnj 		case '|':
1881921Swnj 			c2 = '!';
1891921Swnj 			goto esc;
1901921Swnj 
1911921Swnj 		case '~':
1921921Swnj 			c2 = '^';
1931921Swnj 
1941921Swnj 		esc:
1953205Swnj 			lpcanon(dev, c2);
1962963Stoy 			sc->sc_logcol--;
1971921Swnj 			c = '-';
1981921Swnj 		}
1991921Swnj 	}
2002963Stoy 	logcol = sc->sc_logcol;
2012963Stoy 	physcol = sc->sc_physcol;
2021921Swnj 	if (c == ' ')
2031921Swnj 		logcol++;
2041921Swnj 	else switch(c) {
2051921Swnj 
2061921Swnj 	case '\t':
2073328Swnj 		logcol = (logcol+8) & ~7;
2081921Swnj 		break;
2091921Swnj 
2101921Swnj 	case '\f':
2112963Stoy 		if (sc->sc_physline == 0 && physcol == 0)
2122044Swnj 			break;
2132206Stoy 		/* fall into ... */
2142206Stoy 
2152206Stoy 	case '\n':
2163205Swnj 		lpoutput(dev, c);
2172044Swnj 		if (c == '\f')
2182963Stoy 			sc->sc_physline = 0;
2192044Swnj 		else
2202963Stoy 			sc->sc_physline++;
2212206Stoy 		physcol = 0;
2221921Swnj 		/* fall into ... */
2231921Swnj 
2241921Swnj 	case '\r':
22517002Smckusick 		s = spl4();
2262963Stoy 		logcol = 0;
2273205Swnj 		lpintr(LPUNIT(dev));
22817002Smckusick 		splx(s);
2291921Swnj 		break;
2301921Swnj 
2311921Swnj 	case '\b':
2321921Swnj 		if (logcol > 0)
2331921Swnj 			logcol--;
2341921Swnj 		break;
2351921Swnj 
2361921Swnj 	default:
2371921Swnj 		if (logcol < physcol) {
2383205Swnj 			lpoutput(dev, '\r');
2391921Swnj 			physcol = 0;
2401921Swnj 		}
24110112Ssam 		if (logcol < sc->sc_maxcol) {
2421921Swnj 			while (logcol > physcol) {
2433205Swnj 				lpoutput(dev, ' ');
2441921Swnj 				physcol++;
2451921Swnj 			}
2463205Swnj 			lpoutput(dev, c);
2471921Swnj 			physcol++;
2481921Swnj 		}
2491921Swnj 		logcol++;
2501921Swnj 	}
2511921Swnj 	if (logcol > 1000)	/* ignore long lines  */
2521921Swnj 		logcol = 1000;
2532963Stoy 	sc->sc_logcol = logcol;
2542963Stoy 	sc->sc_physcol = physcol;
2551921Swnj }
2561921Swnj 
2573205Swnj lpoutput(dev, c)
2583205Swnj 	dev_t dev;
2593205Swnj 	int c;
2601921Swnj {
2613205Swnj 	register struct lp_softc *sc = &lp_softc[LPUNIT(dev)];
26217002Smckusick 	int s;
2631921Swnj 
2642963Stoy 	if (sc->sc_outq.c_cc >= LPHWAT) {
26517002Smckusick 		s = spl4();
2663205Swnj 		lpintr(LPUNIT(dev));				/* unchoke */
2672963Stoy 		while (sc->sc_outq.c_cc >= LPHWAT) {
2682963Stoy 			sc->sc_state |= ASLP;		/* must be ERROR */
2692963Stoy 			sleep((caddr_t)sc, LPPRI);
2701921Swnj 		}
27117002Smckusick 		splx(s);
2721921Swnj 	}
2732963Stoy 	while (putc(c, &sc->sc_outq))
2741921Swnj 		sleep((caddr_t)&lbolt, LPPRI);
2751921Swnj }
2761921Swnj 
2773205Swnj lpintr(lp11)
2783205Swnj 	int lp11;
2791921Swnj {
2801921Swnj 	register int n;
2813205Swnj 	register struct lp_softc *sc = &lp_softc[lp11];
2823205Swnj 	register struct uba_device *ui = lpinfo[lp11];
2833205Swnj 	register struct lpdevice *lpaddr = (struct lpdevice *)ui->ui_addr;
2841921Swnj 
2852963Stoy 	lpaddr->lpsr &= ~IENABLE;
2862963Stoy 	n = sc->sc_outq.c_cc;
2872963Stoy 	if (sc->sc_lpchar < 0)
2882963Stoy 		sc->sc_lpchar = getc(&sc->sc_outq);
2892963Stoy 	while ((lpaddr->lpsr&DONE) && sc->sc_lpchar >= 0) {
2902963Stoy 		lpaddr->lpbuf = sc->sc_lpchar;
2912963Stoy 		sc->sc_lpchar = getc(&sc->sc_outq);
2921921Swnj 	}
2932963Stoy 	sc->sc_state |= MOD;
2942963Stoy 	if (sc->sc_outq.c_cc > 0 && (lpaddr->lpsr&ERROR)==0)
2952963Stoy 		lpaddr->lpsr |= IENABLE;	/* ok and more to do later */
2962963Stoy 	if (n>LPLWAT && sc->sc_outq.c_cc<=LPLWAT && sc->sc_state&ASLP) {
2972963Stoy 		sc->sc_state &= ~ASLP;
2982963Stoy 		wakeup((caddr_t)sc);		/* top half should go on */
2991921Swnj 	}
3001921Swnj }
3011921Swnj 
3022963Stoy lptout(dev)
3033205Swnj 	dev_t dev;
3041921Swnj {
3052963Stoy 	register struct lp_softc *sc;
3062963Stoy 	register struct uba_device *ui;
3072963Stoy 	register struct lpdevice *lpaddr;
3081921Swnj 
3092963Stoy 	sc = &lp_softc[LPUNIT(dev)];
3102963Stoy 	ui = lpinfo[LPUNIT(dev)];
3112963Stoy 	lpaddr = (struct lpdevice *) ui->ui_addr;
3122963Stoy 	if ((sc->sc_state&MOD) != 0) {
3132963Stoy 		sc->sc_state &= ~MOD;		/* something happened */
3143986Sroot 		timeout(lptout, (caddr_t)dev, 2*hz);	/* so don't sweat */
3151921Swnj 		return;
3161921Swnj 	}
31716835Smckusick 	if ((sc->sc_state&OPEN) == 0 && sc->sc_outq.c_cc == 0) {
3182963Stoy 		sc->sc_state &= ~TOUT;		/* no longer open */
3192963Stoy 		lpaddr->lpsr = 0;
3201921Swnj 		return;
3211921Swnj 	}
3222963Stoy 	if (sc->sc_outq.c_cc && (lpaddr->lpsr&DONE) && (lpaddr->lpsr&ERROR)==0)
3233205Swnj 		lpintr(LPUNIT(dev));			/* ready to go */
3243986Sroot 	timeout(lptout, (caddr_t)dev, 10*hz);
3251921Swnj }
3261921Swnj 
3272963Stoy lpreset(uban)
3283205Swnj 	int uban;
3291921Swnj {
3302963Stoy 	register struct uba_device *ui;
3312963Stoy 	register struct lpdevice *lpaddr;
3322963Stoy 	register int unit;
3331921Swnj 
3343205Swnj 	for (unit = 0; unit < NLP; unit++) {
3353205Swnj 		if ((ui = lpinfo[unit]) == 0 || ui->ui_ubanum != uban ||
3363205Swnj 		    ui->ui_alive == 0)
3372963Stoy 			continue;
3382963Stoy 		printf(" lp%d", unit);
3393205Swnj 		lpaddr = (struct lpdevice *)ui->ui_addr;
3402963Stoy 		lpaddr->lpsr |= IENABLE;
3411921Swnj 	}
3421921Swnj }
34313091Ssam #endif
344