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