fix to silo and bk bug
[unix-history] / usr / src / sys / vax / uba / lp.c
CommitLineData
8c1a04e5 1/* lp.c 4.20 81/07/25 */
3f431cc4 2
66b4fb09 3#include "lp.h"
ca063532 4#if NLP > 0
3f431cc4
BJ
5/*
6 * LP-11 Line printer driver
7 *
3f431cc4
BJ
8 * This driver has been modified to work on printers where
9 * leaving IENABLE set would cause continuous interrupts.
683f0425
MT
10 *
11 * TODO:
683f0425 12 * Test driver on multiple printers
3f431cc4
BJ
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"
ca063532 22#include "../h/ubavar.h"
3f431cc4
BJ
23#include "../h/ioctl.h"
24#include "../h/tty.h"
3f431cc4
BJ
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
ca063532
MT
33#define MAXCOL 132
34#define CAP 1
35
36#define LPUNIT(dev) (minor(dev) >> 3)
37
38struct lpdevice {
3f431cc4
BJ
39 short lpsr;
40 short lpbuf;
41};
42
ca063532
MT
43struct 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
54struct uba_device *lpinfo[NLP];
55
56int lpprobe(), lpattach(), lptout();
57u_short lpstd[] = { 0177514 };
58struct uba_driver lpdriver =
59 { lpprobe, 0, lpattach, 0, lpstd, "lp", lpinfo };
3f431cc4
BJ
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
67extern lbolt;
68int lptout();
69
5ffed226
BJ
70lpattach(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
79lpprobe(reg)
80 caddr_t reg;
81{
c2213eb5 82 register int br, cvec; /* value-result */
5ffed226 83 register struct lpdevice *lpaddr = (struct lpdevice *)reg;
b620b354
BJ
84#ifdef lint
85 br = 0; cvec = br; br = cvec;
86#endif
5ffed226
BJ
87
88 lpaddr->lpsr = IENABLE;
c2213eb5 89 DELAY(5);
5ffed226 90 lpaddr->lpsr = 0;
8c1a04e5 91 return (1);
5ffed226
BJ
92}
93
3f431cc4
BJ
94/*ARGSUSED*/
95lpopen(dev, flag)
5ffed226
BJ
96 dev_t dev;
97 int flag;
3f431cc4 98{
ca063532
MT
99 register int unit;
100 register struct lpdevice *lpaddr;
101 register struct lp_softc *sc;
102 register struct uba_device *ui;
103
5ffed226
BJ
104 if ((unit = LPUNIT(dev)) >= NLP ||
105 (sc = &lp_softc[unit])->sc_state&OPEN ||
106 (ui = lpinfo[unit]) == 0 || ui->ui_alive == 0) {
ca063532
MT
107 u.u_error = ENXIO;
108 return;
109 }
5ffed226
BJ
110 lpaddr = (struct lpdevice *)ui->ui_addr;
111 if (lpaddr->lpsr&ERROR) {
3f431cc4
BJ
112 u.u_error = EIO;
113 return;
114 }
ca063532
MT
115 sc->sc_state |= OPEN;
116 sc->sc_inbuf = geteblk();
117 sc->sc_flags = minor(dev) & 07;
a0eab615 118 (void) spl4();
ca063532
MT
119 if ((sc->sc_state&TOUT) == 0) {
120 sc->sc_state |= TOUT;
b620b354 121 timeout(lptout, (caddr_t)dev, 10*hz);
3f431cc4 122 }
a0eab615 123 (void) spl0();
5ffed226 124 lpcanon(dev, '\f');
3f431cc4
BJ
125}
126
127/*ARGSUSED*/
128lpclose(dev, flag)
5ffed226
BJ
129 dev_t dev;
130 int flag;
3f431cc4 131{
5ffed226 132 register struct lp_softc *sc = &lp_softc[LPUNIT(dev)];
3f431cc4 133
5ffed226 134 lpcanon(dev, '\f');
ca063532
MT
135 brelse(sc->sc_inbuf);
136 sc->sc_state &= ~OPEN;
3f431cc4
BJ
137}
138
ca063532 139lpwrite(dev)
5ffed226 140 dev_t dev;
3f431cc4 141{
b620b354 142 register unsigned n;
3f431cc4 143 register char *cp;
5ffed226 144 register struct lp_softc *sc = &lp_softc[LPUNIT(dev)];
3f431cc4
BJ
145
146 while (n = min(BSIZE, u.u_count)) {
ca063532 147 cp = sc->sc_inbuf->b_un.b_addr;
3f431cc4
BJ
148 iomove(cp, n, B_WRITE);
149 do
5ffed226 150 lpcanon(dev, *cp++);
3f431cc4
BJ
151 while (--n);
152 }
153}
154
5ffed226
BJ
155lpcanon(dev, c)
156 dev_t dev;
157 register int c;
3f431cc4
BJ
158{
159 register int logcol, physcol;
5ffed226 160 register struct lp_softc *sc = &lp_softc[LPUNIT(dev)];
3f431cc4 161
ca063532 162 if (sc->sc_flags&CAP) {
3f431cc4
BJ
163 register c2;
164
165 if (c>='a' && c<='z')
166 c += 'A'-'a'; else
167 switch (c) {
168
169 case '{':
170 c2 = '(';
171 goto esc;
172
173 case '}':
174 c2 = ')';
175 goto esc;
176
177 case '`':
178 c2 = '\'';
179 goto esc;
180
181 case '|':
182 c2 = '!';
183 goto esc;
184
185 case '~':
186 c2 = '^';
187
188 esc:
5ffed226 189 lpcanon(dev, c2);
ca063532 190 sc->sc_logcol--;
3f431cc4
BJ
191 c = '-';
192 }
193 }
ca063532
MT
194 logcol = sc->sc_logcol;
195 physcol = sc->sc_physcol;
3f431cc4
BJ
196 if (c == ' ')
197 logcol++;
198 else switch(c) {
199
200 case '\t':
36abf8b6 201 logcol = (logcol+8) & ~7;
3f431cc4
BJ
202 break;
203
3f431cc4 204 case '\f':
ca063532 205 if (sc->sc_physline == 0 && physcol == 0)
ea588cf0 206 break;
fb5a911f
MT
207 /* fall into ... */
208
209 case '\n':
5ffed226 210 lpoutput(dev, c);
ea588cf0 211 if (c == '\f')
ca063532 212 sc->sc_physline = 0;
ea588cf0 213 else
ca063532 214 sc->sc_physline++;
fb5a911f 215 physcol = 0;
3f431cc4
BJ
216 /* fall into ... */
217
218 case '\r':
ca063532 219 logcol = 0;
a0eab615 220 (void) spl4();
5ffed226 221 lpintr(LPUNIT(dev));
a0eab615 222 (void) spl0();
3f431cc4
BJ
223 break;
224
225 case '\b':
226 if (logcol > 0)
227 logcol--;
228 break;
229
230 default:
231 if (logcol < physcol) {
5ffed226 232 lpoutput(dev, '\r');
3f431cc4
BJ
233 physcol = 0;
234 }
ca063532 235 if (logcol < MAXCOL) {
3f431cc4 236 while (logcol > physcol) {
5ffed226 237 lpoutput(dev, ' ');
3f431cc4
BJ
238 physcol++;
239 }
5ffed226 240 lpoutput(dev, c);
3f431cc4
BJ
241 physcol++;
242 }
243 logcol++;
244 }
245 if (logcol > 1000) /* ignore long lines */
246 logcol = 1000;
ca063532
MT
247 sc->sc_logcol = logcol;
248 sc->sc_physcol = physcol;
3f431cc4
BJ
249}
250
5ffed226
BJ
251lpoutput(dev, c)
252 dev_t dev;
253 int c;
3f431cc4 254{
5ffed226 255 register struct lp_softc *sc = &lp_softc[LPUNIT(dev)];
3f431cc4 256
ca063532 257 if (sc->sc_outq.c_cc >= LPHWAT) {
a0eab615 258 (void) spl4();
5ffed226 259 lpintr(LPUNIT(dev)); /* unchoke */
ca063532
MT
260 while (sc->sc_outq.c_cc >= LPHWAT) {
261 sc->sc_state |= ASLP; /* must be ERROR */
262 sleep((caddr_t)sc, LPPRI);
3f431cc4 263 }
a0eab615 264 (void) spl0();
3f431cc4 265 }
ca063532 266 while (putc(c, &sc->sc_outq))
3f431cc4
BJ
267 sleep((caddr_t)&lbolt, LPPRI);
268}
269
5ffed226
BJ
270lpintr(lp11)
271 int lp11;
3f431cc4
BJ
272{
273 register int n;
5ffed226
BJ
274 register struct lp_softc *sc = &lp_softc[lp11];
275 register struct uba_device *ui = lpinfo[lp11];
276 register struct lpdevice *lpaddr = (struct lpdevice *)ui->ui_addr;
ca063532 277
ca063532
MT
278 lpaddr->lpsr &= ~IENABLE;
279 n = sc->sc_outq.c_cc;
280 if (sc->sc_lpchar < 0)
281 sc->sc_lpchar = getc(&sc->sc_outq);
282 while ((lpaddr->lpsr&DONE) && sc->sc_lpchar >= 0) {
283 lpaddr->lpbuf = sc->sc_lpchar;
284 sc->sc_lpchar = getc(&sc->sc_outq);
3f431cc4 285 }
ca063532
MT
286 sc->sc_state |= MOD;
287 if (sc->sc_outq.c_cc > 0 && (lpaddr->lpsr&ERROR)==0)
288 lpaddr->lpsr |= IENABLE; /* ok and more to do later */
289 if (n>LPLWAT && sc->sc_outq.c_cc<=LPLWAT && sc->sc_state&ASLP) {
290 sc->sc_state &= ~ASLP;
291 wakeup((caddr_t)sc); /* top half should go on */
3f431cc4
BJ
292 }
293}
294
ca063532 295lptout(dev)
5ffed226 296 dev_t dev;
3f431cc4 297{
ca063532
MT
298 register struct lp_softc *sc;
299 register struct uba_device *ui;
300 register struct lpdevice *lpaddr;
301
302 sc = &lp_softc[LPUNIT(dev)];
303 ui = lpinfo[LPUNIT(dev)];
304 lpaddr = (struct lpdevice *) ui->ui_addr;
305 if ((sc->sc_state&MOD) != 0) {
306 sc->sc_state &= ~MOD; /* something happened */
b620b354 307 timeout(lptout, (caddr_t)dev, 2*hz); /* so don't sweat */
3f431cc4
BJ
308 return;
309 }
ca063532
MT
310 if ((sc->sc_state&OPEN) == 0) {
311 sc->sc_state &= ~TOUT; /* no longer open */
312 lpaddr->lpsr = 0;
3f431cc4
BJ
313 return;
314 }
ca063532 315 if (sc->sc_outq.c_cc && (lpaddr->lpsr&DONE) && (lpaddr->lpsr&ERROR)==0)
5ffed226 316 lpintr(LPUNIT(dev)); /* ready to go */
b620b354 317 timeout(lptout, (caddr_t)dev, 10*hz);
3f431cc4
BJ
318}
319
ca063532 320lpreset(uban)
5ffed226 321 int uban;
3f431cc4 322{
ca063532
MT
323 register struct uba_device *ui;
324 register struct lpdevice *lpaddr;
325 register int unit;
326
5ffed226
BJ
327 for (unit = 0; unit < NLP; unit++) {
328 if ((ui = lpinfo[unit]) == 0 || ui->ui_ubanum != uban ||
329 ui->ui_alive == 0)
ca063532
MT
330 continue;
331 printf(" lp%d", unit);
5ffed226 332 lpaddr = (struct lpdevice *)ui->ui_addr;
ca063532 333 lpaddr->lpsr |= IENABLE;
3f431cc4
BJ
334 }
335}