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