xref: /csrg-svn/sys/vax/uba/lp.c (revision 25521)
123331Smckusick /*
223331Smckusick  * Copyright (c) 1982 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*25521Stef  *	@(#)lp.c	6.7 (Berkeley) 11/22/85
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  */
179775Ssam #include "../machine/pte.h"
181921Swnj 
1917074Sbloom #include "param.h"
2017074Sbloom #include "dir.h"
2117074Sbloom #include "user.h"
2217074Sbloom #include "buf.h"
2317074Sbloom #include "systm.h"
2417074Sbloom #include "map.h"
2517074Sbloom #include "uio.h"
2617935Skupfer #include "ioctl.h"
2717074Sbloom #include "tty.h"
2817074Sbloom #include "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 
392963Stoy #define MAXCOL	132
402963Stoy #define CAP	1
412963Stoy 
422963Stoy #define LPUNIT(dev) (minor(dev) >> 3)
432963Stoy 
442963Stoy struct lpdevice {
451921Swnj 	short	lpsr;
461921Swnj 	short	lpbuf;
471921Swnj };
481921Swnj 
492963Stoy struct lp_softc {
502963Stoy 	struct	clist sc_outq;
512963Stoy 	int	sc_state;
522963Stoy 	int	sc_physcol;
532963Stoy 	int	sc_logcol;
542963Stoy 	int	sc_physline;
552963Stoy 	char	sc_flags;
5610112Ssam 	short	sc_maxcol;
572963Stoy 	int	sc_lpchar;
582963Stoy 	struct	buf *sc_inbuf;
592963Stoy } lp_softc[NLP];
601921Swnj 
612963Stoy struct uba_device *lpinfo[NLP];
622963Stoy 
632963Stoy int lpprobe(), lpattach(), lptout();
64*25521Stef u_short lpstd[] = { 0177514, 0 };
652963Stoy struct uba_driver lpdriver =
662963Stoy 	{ lpprobe, 0, lpattach, 0, lpstd, "lp", lpinfo };
672963Stoy 
681921Swnj /* bits for state */
691921Swnj #define	OPEN		1	/* device is open */
701921Swnj #define	TOUT		2	/* timeout is active */
711921Swnj #define	MOD		4	/* device state has been modified */
721921Swnj #define	ASLP		8	/* awaiting draining of printer */
731921Swnj 
743205Swnj lpattach(ui)
753205Swnj 	struct uba_device *ui;
763205Swnj {
773205Swnj 	register struct lp_softc *sc;
783205Swnj 
793205Swnj 	sc = &lp_softc[ui->ui_unit];
803205Swnj 	sc->sc_lpchar = -1;
8110112Ssam 	if (ui->ui_flags)
8210112Ssam 		sc->sc_maxcol = ui->ui_flags;
8310112Ssam 	else
8410112Ssam 		sc->sc_maxcol = MAXCOL;
853205Swnj }
863205Swnj 
873205Swnj lpprobe(reg)
883205Swnj 	caddr_t reg;
893205Swnj {
903250Swnj 	register int br, cvec;			/* value-result */
913205Swnj 	register struct lpdevice *lpaddr = (struct lpdevice *)reg;
923986Sroot #ifdef lint
933986Sroot 	br = 0; cvec = br; br = cvec;
944935Swnj 	lpintr(0);
953986Sroot #endif
963205Swnj 
973205Swnj 	lpaddr->lpsr = IENABLE;
983250Swnj 	DELAY(5);
993205Swnj 	lpaddr->lpsr = 0;
1007411Skre 	return (sizeof (struct lpdevice));
1013205Swnj }
1023205Swnj 
1031921Swnj /*ARGSUSED*/
1041921Swnj lpopen(dev, flag)
1053205Swnj 	dev_t dev;
1063205Swnj 	int flag;
1071921Swnj {
1082963Stoy 	register struct lpdevice *lpaddr;
1092963Stoy 	register struct lp_softc *sc;
1102963Stoy 	register struct uba_device *ui;
11117002Smckusick 	register int unit, s;
1121921Swnj 
1133205Swnj 	if ((unit = LPUNIT(dev)) >= NLP ||
1143205Swnj 	    (sc = &lp_softc[unit])->sc_state&OPEN ||
1158570Sroot 	    (ui = lpinfo[unit]) == 0 || ui->ui_alive == 0)
1168570Sroot 		return (ENXIO);
1173205Swnj 	lpaddr = (struct lpdevice *)ui->ui_addr;
1188570Sroot 	if (lpaddr->lpsr&ERROR)
1198570Sroot 		return (EIO);
1202963Stoy 	sc->sc_state |= OPEN;
1217184Sroot 	sc->sc_inbuf = geteblk(512);
1222963Stoy 	sc->sc_flags = minor(dev) & 07;
12317002Smckusick 	s = spl4();
1242963Stoy 	if ((sc->sc_state&TOUT) == 0) {
1252963Stoy 		sc->sc_state |= TOUT;
1263986Sroot 		timeout(lptout, (caddr_t)dev, 10*hz);
1271921Swnj 	}
12817002Smckusick 	splx(s);
1293205Swnj 	lpcanon(dev, '\f');
1308570Sroot 	return (0);
1311921Swnj }
1321921Swnj 
1331921Swnj /*ARGSUSED*/
1341921Swnj lpclose(dev, flag)
1353205Swnj 	dev_t dev;
1363205Swnj 	int flag;
1371921Swnj {
1383205Swnj 	register struct lp_softc *sc = &lp_softc[LPUNIT(dev)];
1391921Swnj 
1403205Swnj 	lpcanon(dev, '\f');
1412963Stoy 	brelse(sc->sc_inbuf);
1422963Stoy 	sc->sc_state &= ~OPEN;
1431921Swnj }
1441921Swnj 
1457835Sroot lpwrite(dev, uio)
1463205Swnj 	dev_t dev;
1477835Sroot 	struct uio *uio;
1481921Swnj {
1493986Sroot 	register unsigned n;
1501921Swnj 	register char *cp;
1513205Swnj 	register struct lp_softc *sc = &lp_softc[LPUNIT(dev)];
1528491Sroot 	int error;
1531921Swnj 
15413091Ssam 	while (n = min(512, (unsigned)uio->uio_resid)) {
1552963Stoy 		cp = sc->sc_inbuf->b_un.b_addr;
15613091Ssam 		error = uiomove(cp, (int)n, UIO_WRITE, uio);
1578491Sroot 		if (error)
1588491Sroot 			return (error);
1591921Swnj 		do
1603205Swnj 			lpcanon(dev, *cp++);
1611921Swnj 		while (--n);
1621921Swnj 	}
1638491Sroot 	return (0);
1641921Swnj }
1651921Swnj 
1663205Swnj lpcanon(dev, c)
1673205Swnj 	dev_t dev;
1683205Swnj 	register int c;
1691921Swnj {
1703205Swnj 	register struct lp_softc *sc = &lp_softc[LPUNIT(dev)];
17117002Smckusick 	register int logcol, physcol, s;
1721921Swnj 
1732963Stoy 	if (sc->sc_flags&CAP) {
1741921Swnj 		register c2;
1751921Swnj 
1761921Swnj 		if (c>='a' && c<='z')
1771921Swnj 			c += 'A'-'a'; else
1781921Swnj 		switch (c) {
1791921Swnj 
1801921Swnj 		case '{':
1811921Swnj 			c2 = '(';
1821921Swnj 			goto esc;
1831921Swnj 
1841921Swnj 		case '}':
1851921Swnj 			c2 = ')';
1861921Swnj 			goto esc;
1871921Swnj 
1881921Swnj 		case '`':
1891921Swnj 			c2 = '\'';
1901921Swnj 			goto esc;
1911921Swnj 
1921921Swnj 		case '|':
1931921Swnj 			c2 = '!';
1941921Swnj 			goto esc;
1951921Swnj 
1961921Swnj 		case '~':
1971921Swnj 			c2 = '^';
1981921Swnj 
1991921Swnj 		esc:
2003205Swnj 			lpcanon(dev, c2);
2012963Stoy 			sc->sc_logcol--;
2021921Swnj 			c = '-';
2031921Swnj 		}
2041921Swnj 	}
2052963Stoy 	logcol = sc->sc_logcol;
2062963Stoy 	physcol = sc->sc_physcol;
2071921Swnj 	if (c == ' ')
2081921Swnj 		logcol++;
2091921Swnj 	else switch(c) {
2101921Swnj 
2111921Swnj 	case '\t':
2123328Swnj 		logcol = (logcol+8) & ~7;
2131921Swnj 		break;
2141921Swnj 
2151921Swnj 	case '\f':
2162963Stoy 		if (sc->sc_physline == 0 && physcol == 0)
2172044Swnj 			break;
2182206Stoy 		/* fall into ... */
2192206Stoy 
2202206Stoy 	case '\n':
2213205Swnj 		lpoutput(dev, c);
2222044Swnj 		if (c == '\f')
2232963Stoy 			sc->sc_physline = 0;
2242044Swnj 		else
2252963Stoy 			sc->sc_physline++;
2262206Stoy 		physcol = 0;
2271921Swnj 		/* fall into ... */
2281921Swnj 
2291921Swnj 	case '\r':
23017002Smckusick 		s = spl4();
2312963Stoy 		logcol = 0;
2323205Swnj 		lpintr(LPUNIT(dev));
23317002Smckusick 		splx(s);
2341921Swnj 		break;
2351921Swnj 
2361921Swnj 	case '\b':
2371921Swnj 		if (logcol > 0)
2381921Swnj 			logcol--;
2391921Swnj 		break;
2401921Swnj 
2411921Swnj 	default:
2421921Swnj 		if (logcol < physcol) {
2433205Swnj 			lpoutput(dev, '\r');
2441921Swnj 			physcol = 0;
2451921Swnj 		}
24610112Ssam 		if (logcol < sc->sc_maxcol) {
2471921Swnj 			while (logcol > physcol) {
2483205Swnj 				lpoutput(dev, ' ');
2491921Swnj 				physcol++;
2501921Swnj 			}
2513205Swnj 			lpoutput(dev, c);
2521921Swnj 			physcol++;
2531921Swnj 		}
2541921Swnj 		logcol++;
2551921Swnj 	}
2561921Swnj 	if (logcol > 1000)	/* ignore long lines  */
2571921Swnj 		logcol = 1000;
2582963Stoy 	sc->sc_logcol = logcol;
2592963Stoy 	sc->sc_physcol = physcol;
2601921Swnj }
2611921Swnj 
2623205Swnj lpoutput(dev, c)
2633205Swnj 	dev_t dev;
2643205Swnj 	int c;
2651921Swnj {
2663205Swnj 	register struct lp_softc *sc = &lp_softc[LPUNIT(dev)];
26717002Smckusick 	int s;
2681921Swnj 
2692963Stoy 	if (sc->sc_outq.c_cc >= LPHWAT) {
27017002Smckusick 		s = spl4();
2713205Swnj 		lpintr(LPUNIT(dev));				/* unchoke */
2722963Stoy 		while (sc->sc_outq.c_cc >= LPHWAT) {
2732963Stoy 			sc->sc_state |= ASLP;		/* must be ERROR */
2742963Stoy 			sleep((caddr_t)sc, LPPRI);
2751921Swnj 		}
27617002Smckusick 		splx(s);
2771921Swnj 	}
2782963Stoy 	while (putc(c, &sc->sc_outq))
2791921Swnj 		sleep((caddr_t)&lbolt, LPPRI);
2801921Swnj }
2811921Swnj 
2823205Swnj lpintr(lp11)
2833205Swnj 	int lp11;
2841921Swnj {
2851921Swnj 	register int n;
2863205Swnj 	register struct lp_softc *sc = &lp_softc[lp11];
2873205Swnj 	register struct uba_device *ui = lpinfo[lp11];
2883205Swnj 	register struct lpdevice *lpaddr = (struct lpdevice *)ui->ui_addr;
2891921Swnj 
2902963Stoy 	lpaddr->lpsr &= ~IENABLE;
2912963Stoy 	n = sc->sc_outq.c_cc;
2922963Stoy 	if (sc->sc_lpchar < 0)
2932963Stoy 		sc->sc_lpchar = getc(&sc->sc_outq);
2942963Stoy 	while ((lpaddr->lpsr&DONE) && sc->sc_lpchar >= 0) {
2952963Stoy 		lpaddr->lpbuf = sc->sc_lpchar;
2962963Stoy 		sc->sc_lpchar = getc(&sc->sc_outq);
2971921Swnj 	}
2982963Stoy 	sc->sc_state |= MOD;
2992963Stoy 	if (sc->sc_outq.c_cc > 0 && (lpaddr->lpsr&ERROR)==0)
3002963Stoy 		lpaddr->lpsr |= IENABLE;	/* ok and more to do later */
3012963Stoy 	if (n>LPLWAT && sc->sc_outq.c_cc<=LPLWAT && sc->sc_state&ASLP) {
3022963Stoy 		sc->sc_state &= ~ASLP;
3032963Stoy 		wakeup((caddr_t)sc);		/* top half should go on */
3041921Swnj 	}
3051921Swnj }
3061921Swnj 
3072963Stoy lptout(dev)
3083205Swnj 	dev_t dev;
3091921Swnj {
3102963Stoy 	register struct lp_softc *sc;
3112963Stoy 	register struct uba_device *ui;
3122963Stoy 	register struct lpdevice *lpaddr;
3131921Swnj 
3142963Stoy 	sc = &lp_softc[LPUNIT(dev)];
3152963Stoy 	ui = lpinfo[LPUNIT(dev)];
3162963Stoy 	lpaddr = (struct lpdevice *) ui->ui_addr;
3172963Stoy 	if ((sc->sc_state&MOD) != 0) {
3182963Stoy 		sc->sc_state &= ~MOD;		/* something happened */
3193986Sroot 		timeout(lptout, (caddr_t)dev, 2*hz);	/* so don't sweat */
3201921Swnj 		return;
3211921Swnj 	}
32216835Smckusick 	if ((sc->sc_state&OPEN) == 0 && sc->sc_outq.c_cc == 0) {
3232963Stoy 		sc->sc_state &= ~TOUT;		/* no longer open */
3242963Stoy 		lpaddr->lpsr = 0;
3251921Swnj 		return;
3261921Swnj 	}
3272963Stoy 	if (sc->sc_outq.c_cc && (lpaddr->lpsr&DONE) && (lpaddr->lpsr&ERROR)==0)
3283205Swnj 		lpintr(LPUNIT(dev));			/* ready to go */
3293986Sroot 	timeout(lptout, (caddr_t)dev, 10*hz);
3301921Swnj }
3311921Swnj 
3322963Stoy lpreset(uban)
3333205Swnj 	int uban;
3341921Swnj {
3352963Stoy 	register struct uba_device *ui;
3362963Stoy 	register struct lpdevice *lpaddr;
3372963Stoy 	register int unit;
3381921Swnj 
3393205Swnj 	for (unit = 0; unit < NLP; unit++) {
3403205Swnj 		if ((ui = lpinfo[unit]) == 0 || ui->ui_ubanum != uban ||
3413205Swnj 		    ui->ui_alive == 0)
3422963Stoy 			continue;
3432963Stoy 		printf(" lp%d", unit);
3443205Swnj 		lpaddr = (struct lpdevice *)ui->ui_addr;
3452963Stoy 		lpaddr->lpsr |= IENABLE;
3461921Swnj 	}
3471921Swnj }
34813091Ssam #endif
349