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