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