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