xref: /csrg-svn/sys/vax/uba/lp.c (revision 25521)
1 /*
2  * Copyright (c) 1982 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	6.7 (Berkeley) 11/22/85
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 "../machine/pte.h"
18 
19 #include "param.h"
20 #include "dir.h"
21 #include "user.h"
22 #include "buf.h"
23 #include "systm.h"
24 #include "map.h"
25 #include "uio.h"
26 #include "ioctl.h"
27 #include "tty.h"
28 #include "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 MAXCOL	132
40 #define CAP	1
41 
42 #define LPUNIT(dev) (minor(dev) >> 3)
43 
44 struct lpdevice {
45 	short	lpsr;
46 	short	lpbuf;
47 };
48 
49 struct lp_softc {
50 	struct	clist sc_outq;
51 	int	sc_state;
52 	int	sc_physcol;
53 	int	sc_logcol;
54 	int	sc_physline;
55 	char	sc_flags;
56 	short	sc_maxcol;
57 	int	sc_lpchar;
58 	struct	buf *sc_inbuf;
59 } lp_softc[NLP];
60 
61 struct uba_device *lpinfo[NLP];
62 
63 int lpprobe(), lpattach(), lptout();
64 u_short lpstd[] = { 0177514, 0 };
65 struct uba_driver lpdriver =
66 	{ lpprobe, 0, lpattach, 0, lpstd, "lp", lpinfo };
67 
68 /* bits for state */
69 #define	OPEN		1	/* device is open */
70 #define	TOUT		2	/* timeout is active */
71 #define	MOD		4	/* device state has been modified */
72 #define	ASLP		8	/* awaiting draining of printer */
73 
74 lpattach(ui)
75 	struct uba_device *ui;
76 {
77 	register struct lp_softc *sc;
78 
79 	sc = &lp_softc[ui->ui_unit];
80 	sc->sc_lpchar = -1;
81 	if (ui->ui_flags)
82 		sc->sc_maxcol = ui->ui_flags;
83 	else
84 		sc->sc_maxcol = MAXCOL;
85 }
86 
87 lpprobe(reg)
88 	caddr_t reg;
89 {
90 	register int br, cvec;			/* value-result */
91 	register struct lpdevice *lpaddr = (struct lpdevice *)reg;
92 #ifdef lint
93 	br = 0; cvec = br; br = cvec;
94 	lpintr(0);
95 #endif
96 
97 	lpaddr->lpsr = IENABLE;
98 	DELAY(5);
99 	lpaddr->lpsr = 0;
100 	return (sizeof (struct lpdevice));
101 }
102 
103 /*ARGSUSED*/
104 lpopen(dev, flag)
105 	dev_t dev;
106 	int flag;
107 {
108 	register struct lpdevice *lpaddr;
109 	register struct lp_softc *sc;
110 	register struct uba_device *ui;
111 	register int unit, s;
112 
113 	if ((unit = LPUNIT(dev)) >= NLP ||
114 	    (sc = &lp_softc[unit])->sc_state&OPEN ||
115 	    (ui = lpinfo[unit]) == 0 || ui->ui_alive == 0)
116 		return (ENXIO);
117 	lpaddr = (struct lpdevice *)ui->ui_addr;
118 	if (lpaddr->lpsr&ERROR)
119 		return (EIO);
120 	sc->sc_state |= OPEN;
121 	sc->sc_inbuf = geteblk(512);
122 	sc->sc_flags = minor(dev) & 07;
123 	s = spl4();
124 	if ((sc->sc_state&TOUT) == 0) {
125 		sc->sc_state |= TOUT;
126 		timeout(lptout, (caddr_t)dev, 10*hz);
127 	}
128 	splx(s);
129 	lpcanon(dev, '\f');
130 	return (0);
131 }
132 
133 /*ARGSUSED*/
134 lpclose(dev, flag)
135 	dev_t dev;
136 	int flag;
137 {
138 	register struct lp_softc *sc = &lp_softc[LPUNIT(dev)];
139 
140 	lpcanon(dev, '\f');
141 	brelse(sc->sc_inbuf);
142 	sc->sc_state &= ~OPEN;
143 }
144 
145 lpwrite(dev, uio)
146 	dev_t dev;
147 	struct uio *uio;
148 {
149 	register unsigned n;
150 	register char *cp;
151 	register struct lp_softc *sc = &lp_softc[LPUNIT(dev)];
152 	int error;
153 
154 	while (n = min(512, (unsigned)uio->uio_resid)) {
155 		cp = sc->sc_inbuf->b_un.b_addr;
156 		error = uiomove(cp, (int)n, UIO_WRITE, uio);
157 		if (error)
158 			return (error);
159 		do
160 			lpcanon(dev, *cp++);
161 		while (--n);
162 	}
163 	return (0);
164 }
165 
166 lpcanon(dev, c)
167 	dev_t dev;
168 	register int c;
169 {
170 	register struct lp_softc *sc = &lp_softc[LPUNIT(dev)];
171 	register int logcol, physcol, s;
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 		s = spl4();
231 		logcol = 0;
232 		lpintr(LPUNIT(dev));
233 		splx(s);
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 < sc->sc_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 	int s;
268 
269 	if (sc->sc_outq.c_cc >= LPHWAT) {
270 		s = spl4();
271 		lpintr(LPUNIT(dev));				/* unchoke */
272 		while (sc->sc_outq.c_cc >= LPHWAT) {
273 			sc->sc_state |= ASLP;		/* must be ERROR */
274 			sleep((caddr_t)sc, LPPRI);
275 		}
276 		splx(s);
277 	}
278 	while (putc(c, &sc->sc_outq))
279 		sleep((caddr_t)&lbolt, LPPRI);
280 }
281 
282 lpintr(lp11)
283 	int lp11;
284 {
285 	register int n;
286 	register struct lp_softc *sc = &lp_softc[lp11];
287 	register struct uba_device *ui = lpinfo[lp11];
288 	register struct lpdevice *lpaddr = (struct lpdevice *)ui->ui_addr;
289 
290 	lpaddr->lpsr &= ~IENABLE;
291 	n = sc->sc_outq.c_cc;
292 	if (sc->sc_lpchar < 0)
293 		sc->sc_lpchar = getc(&sc->sc_outq);
294 	while ((lpaddr->lpsr&DONE) && sc->sc_lpchar >= 0) {
295 		lpaddr->lpbuf = sc->sc_lpchar;
296 		sc->sc_lpchar = getc(&sc->sc_outq);
297 	}
298 	sc->sc_state |= MOD;
299 	if (sc->sc_outq.c_cc > 0 && (lpaddr->lpsr&ERROR)==0)
300 		lpaddr->lpsr |= IENABLE;	/* ok and more to do later */
301 	if (n>LPLWAT && sc->sc_outq.c_cc<=LPLWAT && sc->sc_state&ASLP) {
302 		sc->sc_state &= ~ASLP;
303 		wakeup((caddr_t)sc);		/* top half should go on */
304 	}
305 }
306 
307 lptout(dev)
308 	dev_t dev;
309 {
310 	register struct lp_softc *sc;
311 	register struct uba_device *ui;
312 	register struct lpdevice *lpaddr;
313 
314 	sc = &lp_softc[LPUNIT(dev)];
315 	ui = lpinfo[LPUNIT(dev)];
316 	lpaddr = (struct lpdevice *) ui->ui_addr;
317 	if ((sc->sc_state&MOD) != 0) {
318 		sc->sc_state &= ~MOD;		/* something happened */
319 		timeout(lptout, (caddr_t)dev, 2*hz);	/* so don't sweat */
320 		return;
321 	}
322 	if ((sc->sc_state&OPEN) == 0 && sc->sc_outq.c_cc == 0) {
323 		sc->sc_state &= ~TOUT;		/* no longer open */
324 		lpaddr->lpsr = 0;
325 		return;
326 	}
327 	if (sc->sc_outq.c_cc && (lpaddr->lpsr&DONE) && (lpaddr->lpsr&ERROR)==0)
328 		lpintr(LPUNIT(dev));			/* ready to go */
329 	timeout(lptout, (caddr_t)dev, 10*hz);
330 }
331 
332 lpreset(uban)
333 	int uban;
334 {
335 	register struct uba_device *ui;
336 	register struct lpdevice *lpaddr;
337 	register int unit;
338 
339 	for (unit = 0; unit < NLP; unit++) {
340 		if ((ui = lpinfo[unit]) == 0 || ui->ui_ubanum != uban ||
341 		    ui->ui_alive == 0)
342 			continue;
343 		printf(" lp%d", unit);
344 		lpaddr = (struct lpdevice *)ui->ui_addr;
345 		lpaddr->lpsr |= IENABLE;
346 	}
347 }
348 #endif
349