xref: /csrg-svn/sys/vax/uba/lp.c (revision 7411)
1 /*	lp.c	4.26	82/07/15	*/
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 #ifndef CAD
31 #define MAXCOL	132
32 #else
33 #define	MAXCOL	512
34 #endif
35 #define CAP	1
36 
37 #define LPUNIT(dev) (minor(dev) >> 3)
38 
39 struct lpdevice {
40 	short	lpsr;
41 	short	lpbuf;
42 };
43 
44 struct lp_softc {
45 	struct	clist sc_outq;
46 	int	sc_state;
47 	int	sc_physcol;
48 	int	sc_logcol;
49 	int	sc_physline;
50 	char	sc_flags;
51 	int	sc_lpchar;
52 	struct	buf *sc_inbuf;
53 } lp_softc[NLP];
54 
55 struct uba_device *lpinfo[NLP];
56 
57 int lpprobe(), lpattach(), lptout();
58 u_short lpstd[] = { 0177514 };
59 struct uba_driver lpdriver =
60 	{ lpprobe, 0, lpattach, 0, lpstd, "lp", lpinfo };
61 
62 /* bits for state */
63 #define	OPEN		1	/* device is open */
64 #define	TOUT		2	/* timeout is active */
65 #define	MOD		4	/* device state has been modified */
66 #define	ASLP		8	/* awaiting draining of printer */
67 
68 extern	lbolt;
69 int	lptout();
70 
71 lpattach(ui)
72 	struct uba_device *ui;
73 {
74 	register struct lp_softc *sc;
75 
76 	sc = &lp_softc[ui->ui_unit];
77 	sc->sc_lpchar = -1;
78 }
79 
80 lpprobe(reg)
81 	caddr_t reg;
82 {
83 	register int br, cvec;			/* value-result */
84 	register struct lpdevice *lpaddr = (struct lpdevice *)reg;
85 #ifdef lint
86 	br = 0; cvec = br; br = cvec;
87 	lpintr(0);
88 #endif
89 
90 #ifdef INGVAX
91 	br = 0x14;
92 	cvec = 0200;
93 #else
94 	lpaddr->lpsr = IENABLE;
95 	DELAY(5);
96 	lpaddr->lpsr = 0;
97 #endif
98 	return (sizeof (struct lpdevice));
99 }
100 
101 /*ARGSUSED*/
102 lpopen(dev, flag)
103 	dev_t dev;
104 	int flag;
105 {
106 	register int unit;
107 	register struct lpdevice *lpaddr;
108 	register struct lp_softc *sc;
109 	register struct uba_device *ui;
110 
111 	if ((unit = LPUNIT(dev)) >= NLP ||
112 	    (sc = &lp_softc[unit])->sc_state&OPEN ||
113 	    (ui = lpinfo[unit]) == 0 || ui->ui_alive == 0) {
114 		u.u_error = ENXIO;
115 		return;
116 	}
117 	lpaddr = (struct lpdevice *)ui->ui_addr;
118 	if (lpaddr->lpsr&ERROR) {
119 		u.u_error = EIO;
120 		return;
121 	}
122 	sc->sc_state |= OPEN;
123 	sc->sc_inbuf = geteblk(512);
124 	sc->sc_flags = minor(dev) & 07;
125 	(void) spl4();
126 	if ((sc->sc_state&TOUT) == 0) {
127 		sc->sc_state |= TOUT;
128 		timeout(lptout, (caddr_t)dev, 10*hz);
129 	}
130 	(void) spl0();
131 	lpcanon(dev, '\f');
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)
147 	dev_t dev;
148 {
149 	register unsigned n;
150 	register char *cp;
151 	register struct lp_softc *sc = &lp_softc[LPUNIT(dev)];
152 
153 	while (n = min(512, u.u_count)) {
154 		cp = sc->sc_inbuf->b_un.b_addr;
155 		iomove(cp, n, B_WRITE);
156 		do
157 			lpcanon(dev, *cp++);
158 		while (--n);
159 	}
160 }
161 
162 lpcanon(dev, c)
163 	dev_t dev;
164 	register int c;
165 {
166 	register int logcol, physcol;
167 	register struct lp_softc *sc = &lp_softc[LPUNIT(dev)];
168 
169 	if (sc->sc_flags&CAP) {
170 		register c2;
171 
172 		if (c>='a' && c<='z')
173 			c += 'A'-'a'; else
174 		switch (c) {
175 
176 		case '{':
177 			c2 = '(';
178 			goto esc;
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 
195 		esc:
196 			lpcanon(dev, c2);
197 			sc->sc_logcol--;
198 			c = '-';
199 		}
200 	}
201 	logcol = sc->sc_logcol;
202 	physcol = sc->sc_physcol;
203 	if (c == ' ')
204 		logcol++;
205 	else switch(c) {
206 
207 	case '\t':
208 		logcol = (logcol+8) & ~7;
209 		break;
210 
211 	case '\f':
212 		if (sc->sc_physline == 0 && physcol == 0)
213 			break;
214 		/* fall into ... */
215 
216 	case '\n':
217 		lpoutput(dev, c);
218 		if (c == '\f')
219 			sc->sc_physline = 0;
220 		else
221 			sc->sc_physline++;
222 		physcol = 0;
223 		/* fall into ... */
224 
225 	case '\r':
226 		logcol = 0;
227 		(void) spl4();
228 		lpintr(LPUNIT(dev));
229 		(void) spl0();
230 		break;
231 
232 	case '\b':
233 		if (logcol > 0)
234 			logcol--;
235 		break;
236 
237 	default:
238 		if (logcol < physcol) {
239 			lpoutput(dev, '\r');
240 			physcol = 0;
241 		}
242 		if (logcol < MAXCOL) {
243 			while (logcol > physcol) {
244 				lpoutput(dev, ' ');
245 				physcol++;
246 			}
247 			lpoutput(dev, c);
248 			physcol++;
249 		}
250 		logcol++;
251 	}
252 	if (logcol > 1000)	/* ignore long lines  */
253 		logcol = 1000;
254 	sc->sc_logcol = logcol;
255 	sc->sc_physcol = physcol;
256 }
257 
258 lpoutput(dev, c)
259 	dev_t dev;
260 	int c;
261 {
262 	register struct lp_softc *sc = &lp_softc[LPUNIT(dev)];
263 
264 	if (sc->sc_outq.c_cc >= LPHWAT) {
265 		(void) 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 		(void) spl0();
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) {
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