xref: /csrg-svn/sys/vax/uba/lp.c (revision 4935)
1 /*	lp.c	4.21	81/11/18	*/
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  * TODO:
12  *	Test driver on multiple printers
13  */
14 
15 #include "../h/param.h"
16 #include "../h/dir.h"
17 #include "../h/user.h"
18 #include "../h/buf.h"
19 #include "../h/systm.h"
20 #include "../h/map.h"
21 #include "../h/pte.h"
22 #include "../h/ubavar.h"
23 #include "../h/ioctl.h"
24 #include "../h/tty.h"
25 
26 #define	LPPRI	(PZERO+8)
27 #define	IENABLE	0100
28 #define	DONE	0200
29 #define	ERROR	0100000
30 #define	LPLWAT	650
31 #define	LPHWAT	800
32 
33 #define MAXCOL	132
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 	lpaddr->lpsr = IENABLE;
90 	DELAY(5);
91 	lpaddr->lpsr = 0;
92 	return (1);
93 }
94 
95 /*ARGSUSED*/
96 lpopen(dev, flag)
97 	dev_t dev;
98 	int flag;
99 {
100 	register int unit;
101 	register struct lpdevice *lpaddr;
102 	register struct lp_softc *sc;
103 	register struct uba_device *ui;
104 
105 	if ((unit = LPUNIT(dev)) >= NLP ||
106 	    (sc = &lp_softc[unit])->sc_state&OPEN ||
107 	    (ui = lpinfo[unit]) == 0 || ui->ui_alive == 0) {
108 		u.u_error = ENXIO;
109 		return;
110 	}
111 	lpaddr = (struct lpdevice *)ui->ui_addr;
112 	if (lpaddr->lpsr&ERROR) {
113 		u.u_error = EIO;
114 		return;
115 	}
116 	sc->sc_state |= OPEN;
117 	sc->sc_inbuf = geteblk();
118 	sc->sc_flags = minor(dev) & 07;
119 	(void) spl4();
120 	if ((sc->sc_state&TOUT) == 0) {
121 		sc->sc_state |= TOUT;
122 		timeout(lptout, (caddr_t)dev, 10*hz);
123 	}
124 	(void) spl0();
125 	lpcanon(dev, '\f');
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)
141 	dev_t dev;
142 {
143 	register unsigned n;
144 	register char *cp;
145 	register struct lp_softc *sc = &lp_softc[LPUNIT(dev)];
146 
147 	while (n = min(BSIZE, u.u_count)) {
148 		cp = sc->sc_inbuf->b_un.b_addr;
149 		iomove(cp, n, B_WRITE);
150 		do
151 			lpcanon(dev, *cp++);
152 		while (--n);
153 	}
154 }
155 
156 lpcanon(dev, c)
157 	dev_t dev;
158 	register int c;
159 {
160 	register int logcol, physcol;
161 	register struct lp_softc *sc = &lp_softc[LPUNIT(dev)];
162 
163 	if (sc->sc_flags&CAP) {
164 		register c2;
165 
166 		if (c>='a' && c<='z')
167 			c += 'A'-'a'; else
168 		switch (c) {
169 
170 		case '{':
171 			c2 = '(';
172 			goto esc;
173 
174 		case '}':
175 			c2 = ')';
176 			goto esc;
177 
178 		case '`':
179 			c2 = '\'';
180 			goto esc;
181 
182 		case '|':
183 			c2 = '!';
184 			goto esc;
185 
186 		case '~':
187 			c2 = '^';
188 
189 		esc:
190 			lpcanon(dev, c2);
191 			sc->sc_logcol--;
192 			c = '-';
193 		}
194 	}
195 	logcol = sc->sc_logcol;
196 	physcol = sc->sc_physcol;
197 	if (c == ' ')
198 		logcol++;
199 	else switch(c) {
200 
201 	case '\t':
202 		logcol = (logcol+8) & ~7;
203 		break;
204 
205 	case '\f':
206 		if (sc->sc_physline == 0 && physcol == 0)
207 			break;
208 		/* fall into ... */
209 
210 	case '\n':
211 		lpoutput(dev, c);
212 		if (c == '\f')
213 			sc->sc_physline = 0;
214 		else
215 			sc->sc_physline++;
216 		physcol = 0;
217 		/* fall into ... */
218 
219 	case '\r':
220 		logcol = 0;
221 		(void) spl4();
222 		lpintr(LPUNIT(dev));
223 		(void) spl0();
224 		break;
225 
226 	case '\b':
227 		if (logcol > 0)
228 			logcol--;
229 		break;
230 
231 	default:
232 		if (logcol < physcol) {
233 			lpoutput(dev, '\r');
234 			physcol = 0;
235 		}
236 		if (logcol < MAXCOL) {
237 			while (logcol > physcol) {
238 				lpoutput(dev, ' ');
239 				physcol++;
240 			}
241 			lpoutput(dev, c);
242 			physcol++;
243 		}
244 		logcol++;
245 	}
246 	if (logcol > 1000)	/* ignore long lines  */
247 		logcol = 1000;
248 	sc->sc_logcol = logcol;
249 	sc->sc_physcol = physcol;
250 }
251 
252 lpoutput(dev, c)
253 	dev_t dev;
254 	int c;
255 {
256 	register struct lp_softc *sc = &lp_softc[LPUNIT(dev)];
257 
258 	if (sc->sc_outq.c_cc >= LPHWAT) {
259 		(void) spl4();
260 		lpintr(LPUNIT(dev));				/* unchoke */
261 		while (sc->sc_outq.c_cc >= LPHWAT) {
262 			sc->sc_state |= ASLP;		/* must be ERROR */
263 			sleep((caddr_t)sc, LPPRI);
264 		}
265 		(void) spl0();
266 	}
267 	while (putc(c, &sc->sc_outq))
268 		sleep((caddr_t)&lbolt, LPPRI);
269 }
270 
271 lpintr(lp11)
272 	int lp11;
273 {
274 	register int n;
275 	register struct lp_softc *sc = &lp_softc[lp11];
276 	register struct uba_device *ui = lpinfo[lp11];
277 	register struct lpdevice *lpaddr = (struct lpdevice *)ui->ui_addr;
278 
279 	lpaddr->lpsr &= ~IENABLE;
280 	n = sc->sc_outq.c_cc;
281 	if (sc->sc_lpchar < 0)
282 		sc->sc_lpchar = getc(&sc->sc_outq);
283 	while ((lpaddr->lpsr&DONE) && sc->sc_lpchar >= 0) {
284 		lpaddr->lpbuf = sc->sc_lpchar;
285 		sc->sc_lpchar = getc(&sc->sc_outq);
286 	}
287 	sc->sc_state |= MOD;
288 	if (sc->sc_outq.c_cc > 0 && (lpaddr->lpsr&ERROR)==0)
289 		lpaddr->lpsr |= IENABLE;	/* ok and more to do later */
290 	if (n>LPLWAT && sc->sc_outq.c_cc<=LPLWAT && sc->sc_state&ASLP) {
291 		sc->sc_state &= ~ASLP;
292 		wakeup((caddr_t)sc);		/* top half should go on */
293 	}
294 }
295 
296 lptout(dev)
297 	dev_t dev;
298 {
299 	register struct lp_softc *sc;
300 	register struct uba_device *ui;
301 	register struct lpdevice *lpaddr;
302 
303 	sc = &lp_softc[LPUNIT(dev)];
304 	ui = lpinfo[LPUNIT(dev)];
305 	lpaddr = (struct lpdevice *) ui->ui_addr;
306 	if ((sc->sc_state&MOD) != 0) {
307 		sc->sc_state &= ~MOD;		/* something happened */
308 		timeout(lptout, (caddr_t)dev, 2*hz);	/* so don't sweat */
309 		return;
310 	}
311 	if ((sc->sc_state&OPEN) == 0) {
312 		sc->sc_state &= ~TOUT;		/* no longer open */
313 		lpaddr->lpsr = 0;
314 		return;
315 	}
316 	if (sc->sc_outq.c_cc && (lpaddr->lpsr&DONE) && (lpaddr->lpsr&ERROR)==0)
317 		lpintr(LPUNIT(dev));			/* ready to go */
318 	timeout(lptout, (caddr_t)dev, 10*hz);
319 }
320 
321 lpreset(uban)
322 	int uban;
323 {
324 	register struct uba_device *ui;
325 	register struct lpdevice *lpaddr;
326 	register int unit;
327 
328 	for (unit = 0; unit < NLP; unit++) {
329 		if ((ui = lpinfo[unit]) == 0 || ui->ui_ubanum != uban ||
330 		    ui->ui_alive == 0)
331 			continue;
332 		printf(" lp%d", unit);
333 		lpaddr = (struct lpdevice *)ui->ui_addr;
334 		lpaddr->lpsr |= IENABLE;
335 	}
336 }
337