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