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