xref: /csrg-svn/sys/vax/uba/lp.c (revision 3986)
1*3986Sroot /*	lp.c	4.19	81/07/09	*/
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.
102964Stoy  *
112964Stoy  * TODO:
122964Stoy  *	Test driver on multiple printers
131921Swnj  */
141921Swnj 
151921Swnj #include "../h/param.h"
161921Swnj #include "../h/dir.h"
171921Swnj #include "../h/user.h"
181921Swnj #include "../h/buf.h"
191921Swnj #include "../h/systm.h"
201921Swnj #include "../h/map.h"
211921Swnj #include "../h/pte.h"
222963Stoy #include "../h/ubavar.h"
231921Swnj #include "../h/ioctl.h"
241921Swnj #include "../h/tty.h"
251921Swnj 
261921Swnj #define	LPPRI	(PZERO+8)
271921Swnj #define	IENABLE	0100
281921Swnj #define	DONE	0200
291921Swnj #define	ERROR	0100000
301921Swnj #define	LPLWAT	650
311921Swnj #define	LPHWAT	800
321921Swnj 
332963Stoy #define MAXCOL	132
342963Stoy #define CAP	1
352963Stoy 
362963Stoy #define LPUNIT(dev) (minor(dev) >> 3)
372963Stoy 
382963Stoy struct lpdevice {
391921Swnj 	short	lpsr;
401921Swnj 	short	lpbuf;
411921Swnj };
421921Swnj 
432963Stoy struct lp_softc {
442963Stoy 	struct	clist sc_outq;
452963Stoy 	int	sc_state;
462963Stoy 	int	sc_physcol;
472963Stoy 	int	sc_logcol;
482963Stoy 	int	sc_physline;
492963Stoy 	char	sc_flags;
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 extern	lbolt;
681921Swnj int	lptout();
691921Swnj 
703205Swnj lpattach(ui)
713205Swnj 	struct uba_device *ui;
723205Swnj {
733205Swnj 	register struct lp_softc *sc;
743205Swnj 
753205Swnj 	sc = &lp_softc[ui->ui_unit];
763205Swnj 	sc->sc_lpchar = -1;
773205Swnj }
783205Swnj 
793205Swnj lpprobe(reg)
803205Swnj 	caddr_t reg;
813205Swnj {
823250Swnj 	register int br, cvec;			/* value-result */
833205Swnj 	register struct lpdevice *lpaddr = (struct lpdevice *)reg;
84*3986Sroot #ifdef lint
85*3986Sroot 	br = 0; cvec = br; br = cvec;
86*3986Sroot #endif
873205Swnj 
883205Swnj 	lpaddr->lpsr = IENABLE;
893250Swnj 	DELAY(5);
903205Swnj 	lpaddr->lpsr = 0;
913205Swnj }
923205Swnj 
931921Swnj /*ARGSUSED*/
941921Swnj lpopen(dev, flag)
953205Swnj 	dev_t dev;
963205Swnj 	int flag;
971921Swnj {
982963Stoy 	register int unit;
992963Stoy 	register struct lpdevice *lpaddr;
1002963Stoy 	register struct lp_softc *sc;
1012963Stoy 	register struct uba_device *ui;
1021921Swnj 
1033205Swnj 	if ((unit = LPUNIT(dev)) >= NLP ||
1043205Swnj 	    (sc = &lp_softc[unit])->sc_state&OPEN ||
1053205Swnj 	    (ui = lpinfo[unit]) == 0 || ui->ui_alive == 0) {
1062963Stoy 		u.u_error = ENXIO;
1072963Stoy 		return;
1082963Stoy 	}
1093205Swnj 	lpaddr = (struct lpdevice *)ui->ui_addr;
1103205Swnj 	if (lpaddr->lpsr&ERROR) {
1111921Swnj 		u.u_error = EIO;
1121921Swnj 		return;
1131921Swnj 	}
1142963Stoy 	sc->sc_state |= OPEN;
1152963Stoy 	sc->sc_inbuf = geteblk();
1162963Stoy 	sc->sc_flags = minor(dev) & 07;
1173104Swnj 	(void) spl4();
1182963Stoy 	if ((sc->sc_state&TOUT) == 0) {
1192963Stoy 		sc->sc_state |= TOUT;
120*3986Sroot 		timeout(lptout, (caddr_t)dev, 10*hz);
1211921Swnj 	}
1223104Swnj 	(void) spl0();
1233205Swnj 	lpcanon(dev, '\f');
1241921Swnj }
1251921Swnj 
1261921Swnj /*ARGSUSED*/
1271921Swnj lpclose(dev, flag)
1283205Swnj 	dev_t dev;
1293205Swnj 	int flag;
1301921Swnj {
1313205Swnj 	register struct lp_softc *sc = &lp_softc[LPUNIT(dev)];
1321921Swnj 
1333205Swnj 	lpcanon(dev, '\f');
1342963Stoy 	brelse(sc->sc_inbuf);
1352963Stoy 	sc->sc_state &= ~OPEN;
1361921Swnj }
1371921Swnj 
1382963Stoy lpwrite(dev)
1393205Swnj 	dev_t dev;
1401921Swnj {
141*3986Sroot 	register unsigned n;
1421921Swnj 	register char *cp;
1433205Swnj 	register struct lp_softc *sc = &lp_softc[LPUNIT(dev)];
1441921Swnj 
1451921Swnj 	while (n = min(BSIZE, u.u_count)) {
1462963Stoy 		cp = sc->sc_inbuf->b_un.b_addr;
1471921Swnj 		iomove(cp, n, B_WRITE);
1481921Swnj 		do
1493205Swnj 			lpcanon(dev, *cp++);
1501921Swnj 		while (--n);
1511921Swnj 	}
1521921Swnj }
1531921Swnj 
1543205Swnj lpcanon(dev, c)
1553205Swnj 	dev_t dev;
1563205Swnj 	register int c;
1571921Swnj {
1581921Swnj 	register int logcol, physcol;
1593205Swnj 	register struct lp_softc *sc = &lp_softc[LPUNIT(dev)];
1601921Swnj 
1612963Stoy 	if (sc->sc_flags&CAP) {
1621921Swnj 		register c2;
1631921Swnj 
1641921Swnj 		if (c>='a' && c<='z')
1651921Swnj 			c += 'A'-'a'; else
1661921Swnj 		switch (c) {
1671921Swnj 
1681921Swnj 		case '{':
1691921Swnj 			c2 = '(';
1701921Swnj 			goto esc;
1711921Swnj 
1721921Swnj 		case '}':
1731921Swnj 			c2 = ')';
1741921Swnj 			goto esc;
1751921Swnj 
1761921Swnj 		case '`':
1771921Swnj 			c2 = '\'';
1781921Swnj 			goto esc;
1791921Swnj 
1801921Swnj 		case '|':
1811921Swnj 			c2 = '!';
1821921Swnj 			goto esc;
1831921Swnj 
1841921Swnj 		case '~':
1851921Swnj 			c2 = '^';
1861921Swnj 
1871921Swnj 		esc:
1883205Swnj 			lpcanon(dev, c2);
1892963Stoy 			sc->sc_logcol--;
1901921Swnj 			c = '-';
1911921Swnj 		}
1921921Swnj 	}
1932963Stoy 	logcol = sc->sc_logcol;
1942963Stoy 	physcol = sc->sc_physcol;
1951921Swnj 	if (c == ' ')
1961921Swnj 		logcol++;
1971921Swnj 	else switch(c) {
1981921Swnj 
1991921Swnj 	case '\t':
2003328Swnj 		logcol = (logcol+8) & ~7;
2011921Swnj 		break;
2021921Swnj 
2031921Swnj 	case '\f':
2042963Stoy 		if (sc->sc_physline == 0 && physcol == 0)
2052044Swnj 			break;
2062206Stoy 		/* fall into ... */
2072206Stoy 
2082206Stoy 	case '\n':
2093205Swnj 		lpoutput(dev, c);
2102044Swnj 		if (c == '\f')
2112963Stoy 			sc->sc_physline = 0;
2122044Swnj 		else
2132963Stoy 			sc->sc_physline++;
2142206Stoy 		physcol = 0;
2151921Swnj 		/* fall into ... */
2161921Swnj 
2171921Swnj 	case '\r':
2182963Stoy 		logcol = 0;
2193104Swnj 		(void) spl4();
2203205Swnj 		lpintr(LPUNIT(dev));
2213104Swnj 		(void) spl0();
2221921Swnj 		break;
2231921Swnj 
2241921Swnj 	case '\b':
2251921Swnj 		if (logcol > 0)
2261921Swnj 			logcol--;
2271921Swnj 		break;
2281921Swnj 
2291921Swnj 	default:
2301921Swnj 		if (logcol < physcol) {
2313205Swnj 			lpoutput(dev, '\r');
2321921Swnj 			physcol = 0;
2331921Swnj 		}
2342963Stoy 		if (logcol < MAXCOL) {
2351921Swnj 			while (logcol > physcol) {
2363205Swnj 				lpoutput(dev, ' ');
2371921Swnj 				physcol++;
2381921Swnj 			}
2393205Swnj 			lpoutput(dev, c);
2401921Swnj 			physcol++;
2411921Swnj 		}
2421921Swnj 		logcol++;
2431921Swnj 	}
2441921Swnj 	if (logcol > 1000)	/* ignore long lines  */
2451921Swnj 		logcol = 1000;
2462963Stoy 	sc->sc_logcol = logcol;
2472963Stoy 	sc->sc_physcol = physcol;
2481921Swnj }
2491921Swnj 
2503205Swnj lpoutput(dev, c)
2513205Swnj 	dev_t dev;
2523205Swnj 	int c;
2531921Swnj {
2543205Swnj 	register struct lp_softc *sc = &lp_softc[LPUNIT(dev)];
2551921Swnj 
2562963Stoy 	if (sc->sc_outq.c_cc >= LPHWAT) {
2573104Swnj 		(void) spl4();
2583205Swnj 		lpintr(LPUNIT(dev));				/* unchoke */
2592963Stoy 		while (sc->sc_outq.c_cc >= LPHWAT) {
2602963Stoy 			sc->sc_state |= ASLP;		/* must be ERROR */
2612963Stoy 			sleep((caddr_t)sc, LPPRI);
2621921Swnj 		}
2633104Swnj 		(void) spl0();
2641921Swnj 	}
2652963Stoy 	while (putc(c, &sc->sc_outq))
2661921Swnj 		sleep((caddr_t)&lbolt, LPPRI);
2671921Swnj }
2681921Swnj 
2693205Swnj lpintr(lp11)
2703205Swnj 	int lp11;
2711921Swnj {
2721921Swnj 	register int n;
2733205Swnj 	register struct lp_softc *sc = &lp_softc[lp11];
2743205Swnj 	register struct uba_device *ui = lpinfo[lp11];
2753205Swnj 	register struct lpdevice *lpaddr = (struct lpdevice *)ui->ui_addr;
2761921Swnj 
2772963Stoy 	lpaddr->lpsr &= ~IENABLE;
2782963Stoy 	n = sc->sc_outq.c_cc;
2792963Stoy 	if (sc->sc_lpchar < 0)
2802963Stoy 		sc->sc_lpchar = getc(&sc->sc_outq);
2812963Stoy 	while ((lpaddr->lpsr&DONE) && sc->sc_lpchar >= 0) {
2822963Stoy 		lpaddr->lpbuf = sc->sc_lpchar;
2832963Stoy 		sc->sc_lpchar = getc(&sc->sc_outq);
2841921Swnj 	}
2852963Stoy 	sc->sc_state |= MOD;
2862963Stoy 	if (sc->sc_outq.c_cc > 0 && (lpaddr->lpsr&ERROR)==0)
2872963Stoy 		lpaddr->lpsr |= IENABLE;	/* ok and more to do later */
2882963Stoy 	if (n>LPLWAT && sc->sc_outq.c_cc<=LPLWAT && sc->sc_state&ASLP) {
2892963Stoy 		sc->sc_state &= ~ASLP;
2902963Stoy 		wakeup((caddr_t)sc);		/* top half should go on */
2911921Swnj 	}
2921921Swnj }
2931921Swnj 
2942963Stoy lptout(dev)
2953205Swnj 	dev_t dev;
2961921Swnj {
2972963Stoy 	register struct lp_softc *sc;
2982963Stoy 	register struct uba_device *ui;
2992963Stoy 	register struct lpdevice *lpaddr;
3001921Swnj 
3012963Stoy 	sc = &lp_softc[LPUNIT(dev)];
3022963Stoy 	ui = lpinfo[LPUNIT(dev)];
3032963Stoy 	lpaddr = (struct lpdevice *) ui->ui_addr;
3042963Stoy 	if ((sc->sc_state&MOD) != 0) {
3052963Stoy 		sc->sc_state &= ~MOD;		/* something happened */
306*3986Sroot 		timeout(lptout, (caddr_t)dev, 2*hz);	/* so don't sweat */
3071921Swnj 		return;
3081921Swnj 	}
3092963Stoy 	if ((sc->sc_state&OPEN) == 0) {
3102963Stoy 		sc->sc_state &= ~TOUT;		/* no longer open */
3112963Stoy 		lpaddr->lpsr = 0;
3121921Swnj 		return;
3131921Swnj 	}
3142963Stoy 	if (sc->sc_outq.c_cc && (lpaddr->lpsr&DONE) && (lpaddr->lpsr&ERROR)==0)
3153205Swnj 		lpintr(LPUNIT(dev));			/* ready to go */
316*3986Sroot 	timeout(lptout, (caddr_t)dev, 10*hz);
3171921Swnj }
3181921Swnj 
3192963Stoy lpreset(uban)
3203205Swnj 	int uban;
3211921Swnj {
3222963Stoy 	register struct uba_device *ui;
3232963Stoy 	register struct lpdevice *lpaddr;
3242963Stoy 	register int unit;
3251921Swnj 
3263205Swnj 	for (unit = 0; unit < NLP; unit++) {
3273205Swnj 		if ((ui = lpinfo[unit]) == 0 || ui->ui_ubanum != uban ||
3283205Swnj 		    ui->ui_alive == 0)
3292963Stoy 			continue;
3302963Stoy 		printf(" lp%d", unit);
3313205Swnj 		lpaddr = (struct lpdevice *)ui->ui_addr;
3322963Stoy 		lpaddr->lpsr |= IENABLE;
3331921Swnj 	}
3341921Swnj }
335