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