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