xref: /original-bsd/sys/vax/uba/lp.c (revision a76afa45)
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.3 (Berkeley) 05/09/89
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	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 }
145 
146 lpwrite(dev, uio)
147 	dev_t dev;
148 	struct uio *uio;
149 {
150 	register unsigned n;
151 	register char *cp;
152 	register struct lp_softc *sc = &lp_softc[LPUNIT(dev)];
153 	int error;
154 
155 	while (n = MIN(LPBUFSIZE, (unsigned)uio->uio_resid)) {
156 		cp = sc->sc_inbuf->b_un.b_addr;
157 		error = uiomove(cp, (int)n, uio);
158 		if (error)
159 			return (error);
160 		do
161 			lpcanon(dev, *cp++);
162 		while (--n);
163 	}
164 	return (0);
165 }
166 
167 lpcanon(dev, c)
168 	dev_t dev;
169 	register int c;
170 {
171 	register struct lp_softc *sc = &lp_softc[LPUNIT(dev)];
172 	register int logcol, physcol, s;
173 
174 	if (sc->sc_flags&CAP) {
175 		register c2;
176 
177 		if (c>='a' && c<='z')
178 			c += 'A'-'a'; else
179 		switch (c) {
180 
181 		case '{':
182 			c2 = '(';
183 			goto esc;
184 
185 		case '}':
186 			c2 = ')';
187 			goto esc;
188 
189 		case '`':
190 			c2 = '\'';
191 			goto esc;
192 
193 		case '|':
194 			c2 = '!';
195 			goto esc;
196 
197 		case '~':
198 			c2 = '^';
199 
200 		esc:
201 			lpcanon(dev, c2);
202 			sc->sc_logcol--;
203 			c = '-';
204 		}
205 	}
206 	logcol = sc->sc_logcol;
207 	physcol = sc->sc_physcol;
208 	if (c == ' ')
209 		logcol++;
210 	else switch(c) {
211 
212 	case '\t':
213 		logcol = (logcol+8) & ~7;
214 		break;
215 
216 	case '\f':
217 		if (sc->sc_physline == 0 && physcol == 0)
218 			break;
219 		/* fall into ... */
220 
221 	case '\n':
222 		lpoutput(dev, c);
223 		if (c == '\f')
224 			sc->sc_physline = 0;
225 		else
226 			sc->sc_physline++;
227 		physcol = 0;
228 		/* fall into ... */
229 
230 	case '\r':
231 		s = spl4();
232 		logcol = 0;
233 		lpintr(LPUNIT(dev));
234 		splx(s);
235 		break;
236 
237 	case '\b':
238 		if (logcol > 0)
239 			logcol--;
240 		break;
241 
242 	default:
243 		if (logcol < physcol) {
244 			lpoutput(dev, '\r');
245 			physcol = 0;
246 		}
247 		if (logcol < sc->sc_maxcol) {
248 			while (logcol > physcol) {
249 				lpoutput(dev, ' ');
250 				physcol++;
251 			}
252 			lpoutput(dev, c);
253 			physcol++;
254 		}
255 		logcol++;
256 	}
257 	if (logcol > 1000)	/* ignore long lines  */
258 		logcol = 1000;
259 	sc->sc_logcol = logcol;
260 	sc->sc_physcol = physcol;
261 }
262 
263 lpoutput(dev, c)
264 	dev_t dev;
265 	int c;
266 {
267 	register struct lp_softc *sc = &lp_softc[LPUNIT(dev)];
268 	int s;
269 
270 	if (sc->sc_outq.c_cc >= LPHWAT) {
271 		s = spl4();
272 		lpintr(LPUNIT(dev));				/* unchoke */
273 		while (sc->sc_outq.c_cc >= LPHWAT) {
274 			sc->sc_state |= ASLP;		/* must be ERROR */
275 			sleep((caddr_t)sc, LPPRI);
276 		}
277 		splx(s);
278 	}
279 	while (putc(c, &sc->sc_outq))
280 		sleep((caddr_t)&lbolt, LPPRI);
281 }
282 
283 lpintr(lp11)
284 	int lp11;
285 {
286 	register int n;
287 	register struct lp_softc *sc = &lp_softc[lp11];
288 	register struct uba_device *ui = lpinfo[lp11];
289 	register struct lpdevice *lpaddr = (struct lpdevice *)ui->ui_addr;
290 
291 	lpaddr->lpsr &= ~IENABLE;
292 	n = sc->sc_outq.c_cc;
293 	if (sc->sc_lpchar < 0)
294 		sc->sc_lpchar = getc(&sc->sc_outq);
295 	while ((lpaddr->lpsr&DONE) && sc->sc_lpchar >= 0) {
296 		lpaddr->lpbuf = sc->sc_lpchar;
297 		sc->sc_lpchar = getc(&sc->sc_outq);
298 	}
299 	sc->sc_state |= MOD;
300 	if (sc->sc_outq.c_cc > 0 && (lpaddr->lpsr&ERROR)==0)
301 		lpaddr->lpsr |= IENABLE;	/* ok and more to do later */
302 	if (n>LPLWAT && sc->sc_outq.c_cc<=LPLWAT && sc->sc_state&ASLP) {
303 		sc->sc_state &= ~ASLP;
304 		wakeup((caddr_t)sc);		/* top half should go on */
305 	}
306 }
307 
308 lptout(dev)
309 	dev_t dev;
310 {
311 	register struct lp_softc *sc;
312 	register struct uba_device *ui;
313 	register struct lpdevice *lpaddr;
314 
315 	sc = &lp_softc[LPUNIT(dev)];
316 	ui = lpinfo[LPUNIT(dev)];
317 	lpaddr = (struct lpdevice *) ui->ui_addr;
318 	if ((sc->sc_state&MOD) != 0) {
319 		sc->sc_state &= ~MOD;		/* something happened */
320 		timeout(lptout, (caddr_t)dev, 2*hz);	/* so don't sweat */
321 		return;
322 	}
323 	if ((sc->sc_state&OPEN) == 0 && sc->sc_outq.c_cc == 0) {
324 		sc->sc_state &= ~TOUT;		/* no longer open */
325 		lpaddr->lpsr = 0;
326 		return;
327 	}
328 	if (sc->sc_outq.c_cc && (lpaddr->lpsr&DONE) && (lpaddr->lpsr&ERROR)==0)
329 		lpintr(LPUNIT(dev));			/* ready to go */
330 	timeout(lptout, (caddr_t)dev, 10*hz);
331 }
332 
333 lpreset(uban)
334 	int uban;
335 {
336 	register struct uba_device *ui;
337 	register struct lpdevice *lpaddr;
338 	register int unit;
339 
340 	for (unit = 0; unit < NLP; unit++) {
341 		if ((ui = lpinfo[unit]) == 0 || ui->ui_ubanum != uban ||
342 		    ui->ui_alive == 0)
343 			continue;
344 		printf(" lp%d", unit);
345 		lpaddr = (struct lpdevice *)ui->ui_addr;
346 		lpaddr->lpsr |= IENABLE;
347 	}
348 }
349 #endif
350