xref: /csrg-svn/sys/vax/uba/lp.c (revision 45804)
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