1 /*
2 * Copyright (c) 1982, 1986 Regents of the University of California.
3 * All rights reserved. The Berkeley software License Agreement
4 * specifies the terms and conditions for redistribution.
5 *
6 * @(#)lp.c 7.8 (Berkeley) 12/16/90
7 */
8
9 #include "lp.h"
10 #if NLP > 0
11 /*
12 * LP-11 Line printer driver
13 *
14 * This driver has been modified to work on printers where
15 * leaving IENABLE set would cause continuous interrupts.
16 */
17 #include "../include/pte.h"
18
19 #include "sys/param.h"
20 #include "sys/user.h"
21 #include "sys/buf.h"
22 #include "sys/conf.h"
23 #include "sys/systm.h"
24 #include "sys/map.h"
25 #include "sys/uio.h"
26 #include "sys/ioctl.h"
27 #include "sys/tty.h"
28 #include "sys/kernel.h"
29
30 #include "ubavar.h"
31
32 #define LPPRI (PZERO+8)
33 #define IENABLE 0100
34 #define DONE 0200
35 #define ERROR 0100000
36 #define LPLWAT 650
37 #define LPHWAT 800
38
39 #define LPBUFSIZE 1024
40 #define MAXCOL 132
41 #define CAP 1
42
43 #define LPUNIT(dev) (minor(dev) >> 3)
44
45 struct lpdevice {
46 short lpsr;
47 short lpbuf;
48 };
49
50 struct lp_softc {
51 struct clist sc_outq;
52 int sc_state;
53 int sc_physcol;
54 int sc_logcol;
55 int sc_physline;
56 char sc_flags;
57 short sc_maxcol;
58 int sc_lpchar;
59 struct buf *sc_inbuf;
60 } lp_softc[NLP];
61
62 struct uba_device *lpinfo[NLP];
63
64 int lpprobe(), lpattach(), lptout();
65 u_short lpstd[] = { 0177514, 0 };
66 struct uba_driver lpdriver =
67 { lpprobe, 0, lpattach, 0, lpstd, "lp", lpinfo };
68
69 /* bits for state */
70 #define OPEN 1 /* device is open */
71 #define TOUT 2 /* timeout is active */
72 #define MOD 4 /* device state has been modified */
73 #define ASLP 8 /* awaiting draining of printer */
74
75 lpattach(ui)
76 struct uba_device *ui;
77 {
78 register struct lp_softc *sc;
79
80 sc = &lp_softc[ui->ui_unit];
81 sc->sc_lpchar = -1;
82 if (ui->ui_flags)
83 sc->sc_maxcol = ui->ui_flags;
84 else
85 sc->sc_maxcol = MAXCOL;
86 }
87
lpprobe(reg)88 lpprobe(reg)
89 caddr_t reg;
90 {
91 register int br, cvec; /* value-result */
92 register struct lpdevice *lpaddr = (struct lpdevice *)reg;
93 #ifdef lint
94 br = 0; cvec = br; br = cvec;
95 lpintr(0);
96 #endif
97
98 lpaddr->lpsr = IENABLE;
99 DELAY(5);
100 lpaddr->lpsr = 0;
101 return (sizeof (struct lpdevice));
102 }
103
104 /*ARGSUSED*/
lpopen(dev,flag)105 lpopen(dev, flag)
106 dev_t dev;
107 int flag;
108 {
109 register struct lpdevice *lpaddr;
110 register struct lp_softc *sc;
111 register struct uba_device *ui;
112 register int unit, s;
113
114 if ((unit = LPUNIT(dev)) >= NLP ||
115 (sc = &lp_softc[unit])->sc_state&OPEN ||
116 (ui = lpinfo[unit]) == 0 || ui->ui_alive == 0)
117 return (ENXIO);
118 lpaddr = (struct lpdevice *)ui->ui_addr;
119 if (lpaddr->lpsr&ERROR)
120 return (EIO);
121 sc->sc_state |= OPEN;
122 sc->sc_inbuf = geteblk(LPBUFSIZE);
123 sc->sc_flags = minor(dev) & 07;
124 s = spl4();
125 if ((sc->sc_state&TOUT) == 0) {
126 sc->sc_state |= TOUT;
127 timeout(lptout, (caddr_t)dev, 10*hz);
128 }
129 splx(s);
130 lpcanon(dev, '\f');
131 return (0);
132 }
133
134 /*ARGSUSED*/
lpclose(dev,flag)135 lpclose(dev, flag)
136 dev_t dev;
137 int flag;
138 {
139 register struct lp_softc *sc = &lp_softc[LPUNIT(dev)];
140
141 lpcanon(dev, '\f');
142 brelse(sc->sc_inbuf);
143 sc->sc_state &= ~OPEN;
144 return (0);
145 }
146
lpwrite(dev,uio)147 lpwrite(dev, uio)
148 dev_t dev;
149 struct uio *uio;
150 {
151 register unsigned n;
152 register char *cp;
153 register struct lp_softc *sc = &lp_softc[LPUNIT(dev)];
154 int error;
155
156 while (n = MIN(LPBUFSIZE, (unsigned)uio->uio_resid)) {
157 cp = sc->sc_inbuf->b_un.b_addr;
158 error = uiomove(cp, (int)n, uio);
159 if (error)
160 return (error);
161 do
162 lpcanon(dev, *cp++);
163 while (--n);
164 }
165 return (0);
166 }
167
lpcanon(dev,c)168 lpcanon(dev, c)
169 dev_t dev;
170 register int c;
171 {
172 register struct lp_softc *sc = &lp_softc[LPUNIT(dev)];
173 register int logcol, physcol, s;
174
175 if (sc->sc_flags&CAP) {
176 register c2;
177
178 if (c>='a' && c<='z')
179 c += 'A'-'a'; else
180 switch (c) {
181
182 case '{':
183 c2 = '(';
184 goto esc;
185
186 case '}':
187 c2 = ')';
188 goto esc;
189
190 case '`':
191 c2 = '\'';
192 goto esc;
193
194 case '|':
195 c2 = '!';
196 goto esc;
197
198 case '~':
199 c2 = '^';
200
201 esc:
202 lpcanon(dev, c2);
203 sc->sc_logcol--;
204 c = '-';
205 }
206 }
207 logcol = sc->sc_logcol;
208 physcol = sc->sc_physcol;
209 if (c == ' ')
210 logcol++;
211 else switch(c) {
212
213 case '\t':
214 logcol = (logcol+8) & ~7;
215 break;
216
217 case '\f':
218 if (sc->sc_physline == 0 && physcol == 0)
219 break;
220 /* fall into ... */
221
222 case '\n':
223 lpoutput(dev, c);
224 if (c == '\f')
225 sc->sc_physline = 0;
226 else
227 sc->sc_physline++;
228 physcol = 0;
229 /* fall into ... */
230
231 case '\r':
232 s = spl4();
233 logcol = 0;
234 lpintr(LPUNIT(dev));
235 splx(s);
236 break;
237
238 case '\b':
239 if (logcol > 0)
240 logcol--;
241 break;
242
243 default:
244 if (logcol < physcol) {
245 lpoutput(dev, '\r');
246 physcol = 0;
247 }
248 if (logcol < sc->sc_maxcol) {
249 while (logcol > physcol) {
250 lpoutput(dev, ' ');
251 physcol++;
252 }
253 lpoutput(dev, c);
254 physcol++;
255 }
256 logcol++;
257 }
258 if (logcol > 1000) /* ignore long lines */
259 logcol = 1000;
260 sc->sc_logcol = logcol;
261 sc->sc_physcol = physcol;
262 }
263
lpoutput(dev,c)264 lpoutput(dev, c)
265 dev_t dev;
266 int c;
267 {
268 register struct lp_softc *sc = &lp_softc[LPUNIT(dev)];
269 int s, error = 0;
270
271 if (sc->sc_outq.c_cc >= LPHWAT) {
272 s = spl4();
273 lpintr(LPUNIT(dev)); /* unchoke */
274 while (sc->sc_outq.c_cc >= LPHWAT && error == 0) {
275 sc->sc_state |= ASLP; /* must be ERROR */
276 error = tsleep((caddr_t)sc, LPPRI | PCATCH,
277 devout, 0);
278 }
279 splx(s);
280 }
281 while (error == 0 && putc(c, &sc->sc_outq))
282 error = tsleep((caddr_t)&lbolt, LPPRI | PCATCH,
283 ttybuf, 0);
284 return (error);
285 }
286
lpintr(lp11)287 lpintr(lp11)
288 int lp11;
289 {
290 register int n;
291 register struct lp_softc *sc = &lp_softc[lp11];
292 register struct uba_device *ui = lpinfo[lp11];
293 register struct lpdevice *lpaddr = (struct lpdevice *)ui->ui_addr;
294
295 lpaddr->lpsr &= ~IENABLE;
296 n = sc->sc_outq.c_cc;
297 if (sc->sc_lpchar < 0)
298 sc->sc_lpchar = getc(&sc->sc_outq);
299 while ((lpaddr->lpsr&DONE) && sc->sc_lpchar >= 0) {
300 lpaddr->lpbuf = sc->sc_lpchar;
301 sc->sc_lpchar = getc(&sc->sc_outq);
302 }
303 sc->sc_state |= MOD;
304 if (sc->sc_outq.c_cc > 0 && (lpaddr->lpsr&ERROR)==0)
305 lpaddr->lpsr |= IENABLE; /* ok and more to do later */
306 if (n>LPLWAT && sc->sc_outq.c_cc<=LPLWAT && sc->sc_state&ASLP) {
307 sc->sc_state &= ~ASLP;
308 wakeup((caddr_t)sc); /* top half should go on */
309 }
310 }
311
lptout(dev)312 lptout(dev)
313 dev_t dev;
314 {
315 register struct lp_softc *sc;
316 register struct uba_device *ui;
317 register struct lpdevice *lpaddr;
318
319 sc = &lp_softc[LPUNIT(dev)];
320 ui = lpinfo[LPUNIT(dev)];
321 lpaddr = (struct lpdevice *) ui->ui_addr;
322 if ((sc->sc_state&MOD) != 0) {
323 sc->sc_state &= ~MOD; /* something happened */
324 timeout(lptout, (caddr_t)dev, 2*hz); /* so don't sweat */
325 return;
326 }
327 if ((sc->sc_state&OPEN) == 0 && sc->sc_outq.c_cc == 0) {
328 sc->sc_state &= ~TOUT; /* no longer open */
329 lpaddr->lpsr = 0;
330 return;
331 }
332 if (sc->sc_outq.c_cc && (lpaddr->lpsr&DONE) && (lpaddr->lpsr&ERROR)==0)
333 lpintr(LPUNIT(dev)); /* ready to go */
334 timeout(lptout, (caddr_t)dev, 10*hz);
335 }
336
lpreset(uban)337 lpreset(uban)
338 int uban;
339 {
340 register struct uba_device *ui;
341 register struct lpdevice *lpaddr;
342 register int unit;
343
344 for (unit = 0; unit < NLP; unit++) {
345 if ((ui = lpinfo[unit]) == 0 || ui->ui_ubanum != uban ||
346 ui->ui_alive == 0)
347 continue;
348 printf(" lp%d", unit);
349 lpaddr = (struct lpdevice *)ui->ui_addr;
350 lpaddr->lpsr |= IENABLE;
351 }
352 }
353 #endif
354