xref: /csrg-svn/sys/vax/uba/lp.c (revision 8476)
1 /*	lp.c	4.28	82/10/10	*/
2 
3 #include "lp.h"
4 #if NLP > 0
5 /*
6  * LP-11 Line printer driver
7  *
8  * This driver has been modified to work on printers where
9  * leaving IENABLE set would cause continuous interrupts.
10  */
11 
12 #include "../h/param.h"
13 #include "../h/dir.h"
14 #include "../h/user.h"
15 #include "../h/buf.h"
16 #include "../h/systm.h"
17 #include "../h/map.h"
18 #include "../h/pte.h"
19 #include "../h/ioctl.h"
20 #include "../h/tty.h"
21 
22 #include "../vaxuba/ubavar.h"
23 
24 #define	LPPRI	(PZERO+8)
25 #define	IENABLE	0100
26 #define	DONE	0200
27 #define	ERROR	0100000
28 #define	LPLWAT	650
29 #define	LPHWAT	800
30 
31 #ifndef CAD
32 #define MAXCOL	132
33 #else
34 #define	MAXCOL	512
35 #endif
36 #define CAP	1
37 
38 #define LPUNIT(dev) (minor(dev) >> 3)
39 
40 struct lpdevice {
41 	short	lpsr;
42 	short	lpbuf;
43 };
44 
45 struct lp_softc {
46 	struct	clist sc_outq;
47 	int	sc_state;
48 	int	sc_physcol;
49 	int	sc_logcol;
50 	int	sc_physline;
51 	char	sc_flags;
52 	int	sc_lpchar;
53 	struct	buf *sc_inbuf;
54 } lp_softc[NLP];
55 
56 struct uba_device *lpinfo[NLP];
57 
58 int lpprobe(), lpattach(), lptout();
59 u_short lpstd[] = { 0177514 };
60 struct uba_driver lpdriver =
61 	{ lpprobe, 0, lpattach, 0, lpstd, "lp", lpinfo };
62 
63 /* bits for state */
64 #define	OPEN		1	/* device is open */
65 #define	TOUT		2	/* timeout is active */
66 #define	MOD		4	/* device state has been modified */
67 #define	ASLP		8	/* awaiting draining of printer */
68 
69 extern	lbolt;
70 int	lptout();
71 
72 lpattach(ui)
73 	struct uba_device *ui;
74 {
75 	register struct lp_softc *sc;
76 
77 	sc = &lp_softc[ui->ui_unit];
78 	sc->sc_lpchar = -1;
79 }
80 
81 lpprobe(reg)
82 	caddr_t reg;
83 {
84 	register int br, cvec;			/* value-result */
85 	register struct lpdevice *lpaddr = (struct lpdevice *)reg;
86 #ifdef lint
87 	br = 0; cvec = br; br = cvec;
88 	lpintr(0);
89 #endif
90 
91 #ifdef INGVAX
92 	br = 0x14;
93 	cvec = 0200;
94 #else
95 	lpaddr->lpsr = IENABLE;
96 	DELAY(5);
97 	lpaddr->lpsr = 0;
98 #endif
99 	return (sizeof (struct lpdevice));
100 }
101 
102 /*ARGSUSED*/
103 lpopen(dev, flag)
104 	dev_t dev;
105 	int flag;
106 {
107 	register int unit;
108 	register struct lpdevice *lpaddr;
109 	register struct lp_softc *sc;
110 	register struct uba_device *ui;
111 
112 	if ((unit = LPUNIT(dev)) >= NLP ||
113 	    (sc = &lp_softc[unit])->sc_state&OPEN ||
114 	    (ui = lpinfo[unit]) == 0 || ui->ui_alive == 0) {
115 		u.u_error = ENXIO;
116 		return;
117 	}
118 	lpaddr = (struct lpdevice *)ui->ui_addr;
119 	if (lpaddr->lpsr&ERROR) {
120 		u.u_error = EIO;
121 		return;
122 	}
123 	sc->sc_state |= OPEN;
124 	sc->sc_inbuf = geteblk(512);
125 	sc->sc_flags = minor(dev) & 07;
126 	(void) spl4();
127 	if ((sc->sc_state&TOUT) == 0) {
128 		sc->sc_state |= TOUT;
129 		timeout(lptout, (caddr_t)dev, 10*hz);
130 	}
131 	(void) spl0();
132 	lpcanon(dev, '\f');
133 }
134 
135 /*ARGSUSED*/
136 lpclose(dev, flag)
137 	dev_t dev;
138 	int flag;
139 {
140 	register struct lp_softc *sc = &lp_softc[LPUNIT(dev)];
141 
142 	lpcanon(dev, '\f');
143 	brelse(sc->sc_inbuf);
144 	sc->sc_state &= ~OPEN;
145 }
146 
147 lpwrite(dev, uio)
148 	dev_t dev;
149 	struct uio *uio;
150 {
151 	register unsigned n;
152 	register char *cp;
153 	register struct lp_softc *sc = &lp_softc[LPUNIT(dev)];
154 
155 	while (n = min(512, uio->uio_resid)) {
156 		cp = sc->sc_inbuf->b_un.b_addr;
157 		u.u_error = uiomove(cp, n, UIO_WRITE, uio);
158 		if (u.u_error)
159 			break;
160 		do
161 			lpcanon(dev, *cp++);
162 		while (--n);
163 	}
164 }
165 
166 lpcanon(dev, c)
167 	dev_t dev;
168 	register int c;
169 {
170 	register int logcol, physcol;
171 	register struct lp_softc *sc = &lp_softc[LPUNIT(dev)];
172 
173 	if (sc->sc_flags&CAP) {
174 		register c2;
175 
176 		if (c>='a' && c<='z')
177 			c += 'A'-'a'; else
178 		switch (c) {
179 
180 		case '{':
181 			c2 = '(';
182 			goto esc;
183 
184 		case '}':
185 			c2 = ')';
186 			goto esc;
187 
188 		case '`':
189 			c2 = '\'';
190 			goto esc;
191 
192 		case '|':
193 			c2 = '!';
194 			goto esc;
195 
196 		case '~':
197 			c2 = '^';
198 
199 		esc:
200 			lpcanon(dev, c2);
201 			sc->sc_logcol--;
202 			c = '-';
203 		}
204 	}
205 	logcol = sc->sc_logcol;
206 	physcol = sc->sc_physcol;
207 	if (c == ' ')
208 		logcol++;
209 	else switch(c) {
210 
211 	case '\t':
212 		logcol = (logcol+8) & ~7;
213 		break;
214 
215 	case '\f':
216 		if (sc->sc_physline == 0 && physcol == 0)
217 			break;
218 		/* fall into ... */
219 
220 	case '\n':
221 		lpoutput(dev, c);
222 		if (c == '\f')
223 			sc->sc_physline = 0;
224 		else
225 			sc->sc_physline++;
226 		physcol = 0;
227 		/* fall into ... */
228 
229 	case '\r':
230 		logcol = 0;
231 		(void) spl4();
232 		lpintr(LPUNIT(dev));
233 		(void) spl0();
234 		break;
235 
236 	case '\b':
237 		if (logcol > 0)
238 			logcol--;
239 		break;
240 
241 	default:
242 		if (logcol < physcol) {
243 			lpoutput(dev, '\r');
244 			physcol = 0;
245 		}
246 		if (logcol < MAXCOL) {
247 			while (logcol > physcol) {
248 				lpoutput(dev, ' ');
249 				physcol++;
250 			}
251 			lpoutput(dev, c);
252 			physcol++;
253 		}
254 		logcol++;
255 	}
256 	if (logcol > 1000)	/* ignore long lines  */
257 		logcol = 1000;
258 	sc->sc_logcol = logcol;
259 	sc->sc_physcol = physcol;
260 }
261 
262 lpoutput(dev, c)
263 	dev_t dev;
264 	int c;
265 {
266 	register struct lp_softc *sc = &lp_softc[LPUNIT(dev)];
267 
268 	if (sc->sc_outq.c_cc >= LPHWAT) {
269 		(void) spl4();
270 		lpintr(LPUNIT(dev));				/* unchoke */
271 		while (sc->sc_outq.c_cc >= LPHWAT) {
272 			sc->sc_state |= ASLP;		/* must be ERROR */
273 			sleep((caddr_t)sc, LPPRI);
274 		}
275 		(void) spl0();
276 	}
277 	while (putc(c, &sc->sc_outq))
278 		sleep((caddr_t)&lbolt, LPPRI);
279 }
280 
281 lpintr(lp11)
282 	int lp11;
283 {
284 	register int n;
285 	register struct lp_softc *sc = &lp_softc[lp11];
286 	register struct uba_device *ui = lpinfo[lp11];
287 	register struct lpdevice *lpaddr = (struct lpdevice *)ui->ui_addr;
288 
289 	lpaddr->lpsr &= ~IENABLE;
290 	n = sc->sc_outq.c_cc;
291 	if (sc->sc_lpchar < 0)
292 		sc->sc_lpchar = getc(&sc->sc_outq);
293 	while ((lpaddr->lpsr&DONE) && sc->sc_lpchar >= 0) {
294 		lpaddr->lpbuf = sc->sc_lpchar;
295 		sc->sc_lpchar = getc(&sc->sc_outq);
296 	}
297 	sc->sc_state |= MOD;
298 	if (sc->sc_outq.c_cc > 0 && (lpaddr->lpsr&ERROR)==0)
299 		lpaddr->lpsr |= IENABLE;	/* ok and more to do later */
300 	if (n>LPLWAT && sc->sc_outq.c_cc<=LPLWAT && sc->sc_state&ASLP) {
301 		sc->sc_state &= ~ASLP;
302 		wakeup((caddr_t)sc);		/* top half should go on */
303 	}
304 }
305 
306 lptout(dev)
307 	dev_t dev;
308 {
309 	register struct lp_softc *sc;
310 	register struct uba_device *ui;
311 	register struct lpdevice *lpaddr;
312 
313 	sc = &lp_softc[LPUNIT(dev)];
314 	ui = lpinfo[LPUNIT(dev)];
315 	lpaddr = (struct lpdevice *) ui->ui_addr;
316 	if ((sc->sc_state&MOD) != 0) {
317 		sc->sc_state &= ~MOD;		/* something happened */
318 		timeout(lptout, (caddr_t)dev, 2*hz);	/* so don't sweat */
319 		return;
320 	}
321 	if ((sc->sc_state&OPEN) == 0) {
322 		sc->sc_state &= ~TOUT;		/* no longer open */
323 		lpaddr->lpsr = 0;
324 		return;
325 	}
326 	if (sc->sc_outq.c_cc && (lpaddr->lpsr&DONE) && (lpaddr->lpsr&ERROR)==0)
327 		lpintr(LPUNIT(dev));			/* ready to go */
328 	timeout(lptout, (caddr_t)dev, 10*hz);
329 }
330 
331 lpreset(uban)
332 	int uban;
333 {
334 	register struct uba_device *ui;
335 	register struct lpdevice *lpaddr;
336 	register int unit;
337 
338 	for (unit = 0; unit < NLP; unit++) {
339 		if ((ui = lpinfo[unit]) == 0 || ui->ui_ubanum != uban ||
340 		    ui->ui_alive == 0)
341 			continue;
342 		printf(" lp%d", unit);
343 		lpaddr = (struct lpdevice *)ui->ui_addr;
344 		lpaddr->lpsr |= IENABLE;
345 	}
346 }
347