restore sccs line
[unix-history] / usr / src / sys / vax / uba / lp.c
CommitLineData
b620b354 1/* lp.c 4.19 81/07/09 */
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
BJ
90 lpaddr->lpsr = 0;
91}
92
3f431cc4
BJ
93/*ARGSUSED*/
94lpopen(dev, flag)
5ffed226
BJ
95 dev_t dev;
96 int flag;
3f431cc4 97{
ca063532
MT
98 register int unit;
99 register struct lpdevice *lpaddr;
100 register struct lp_softc *sc;
101 register struct uba_device *ui;
102
5ffed226
BJ
103 if ((unit = LPUNIT(dev)) >= NLP ||
104 (sc = &lp_softc[unit])->sc_state&OPEN ||
105 (ui = lpinfo[unit]) == 0 || ui->ui_alive == 0) {
ca063532
MT
106 u.u_error = ENXIO;
107 return;
108 }
5ffed226
BJ
109 lpaddr = (struct lpdevice *)ui->ui_addr;
110 if (lpaddr->lpsr&ERROR) {
3f431cc4
BJ
111 u.u_error = EIO;
112 return;
113 }
ca063532
MT
114 sc->sc_state |= OPEN;
115 sc->sc_inbuf = geteblk();
116 sc->sc_flags = minor(dev) & 07;
a0eab615 117 (void) spl4();
ca063532
MT
118 if ((sc->sc_state&TOUT) == 0) {
119 sc->sc_state |= TOUT;
b620b354 120 timeout(lptout, (caddr_t)dev, 10*hz);
3f431cc4 121 }
a0eab615 122 (void) spl0();
5ffed226 123 lpcanon(dev, '\f');
3f431cc4
BJ
124}
125
126/*ARGSUSED*/
127lpclose(dev, flag)
5ffed226
BJ
128 dev_t dev;
129 int flag;
3f431cc4 130{
5ffed226 131 register struct lp_softc *sc = &lp_softc[LPUNIT(dev)];
3f431cc4 132
5ffed226 133 lpcanon(dev, '\f');
ca063532
MT
134 brelse(sc->sc_inbuf);
135 sc->sc_state &= ~OPEN;
3f431cc4
BJ
136}
137
ca063532 138lpwrite(dev)
5ffed226 139 dev_t dev;
3f431cc4 140{
b620b354 141 register unsigned n;
3f431cc4 142 register char *cp;
5ffed226 143 register struct lp_softc *sc = &lp_softc[LPUNIT(dev)];
3f431cc4
BJ
144
145 while (n = min(BSIZE, u.u_count)) {
ca063532 146 cp = sc->sc_inbuf->b_un.b_addr;
3f431cc4
BJ
147 iomove(cp, n, B_WRITE);
148 do
5ffed226 149 lpcanon(dev, *cp++);
3f431cc4
BJ
150 while (--n);
151 }
152}
153
5ffed226
BJ
154lpcanon(dev, c)
155 dev_t dev;
156 register int c;
3f431cc4
BJ
157{
158 register int logcol, physcol;
5ffed226 159 register struct lp_softc *sc = &lp_softc[LPUNIT(dev)];
3f431cc4 160
ca063532 161 if (sc->sc_flags&CAP) {
3f431cc4
BJ
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:
5ffed226 188 lpcanon(dev, c2);
ca063532 189 sc->sc_logcol--;
3f431cc4
BJ
190 c = '-';
191 }
192 }
ca063532
MT
193 logcol = sc->sc_logcol;
194 physcol = sc->sc_physcol;
3f431cc4
BJ
195 if (c == ' ')
196 logcol++;
197 else switch(c) {
198
199 case '\t':
36abf8b6 200 logcol = (logcol+8) & ~7;
3f431cc4
BJ
201 break;
202
3f431cc4 203 case '\f':
ca063532 204 if (sc->sc_physline == 0 && physcol == 0)
ea588cf0 205 break;
fb5a911f
MT
206 /* fall into ... */
207
208 case '\n':
5ffed226 209 lpoutput(dev, c);
ea588cf0 210 if (c == '\f')
ca063532 211 sc->sc_physline = 0;
ea588cf0 212 else
ca063532 213 sc->sc_physline++;
fb5a911f 214 physcol = 0;
3f431cc4
BJ
215 /* fall into ... */
216
217 case '\r':
ca063532 218 logcol = 0;
a0eab615 219 (void) spl4();
5ffed226 220 lpintr(LPUNIT(dev));
a0eab615 221 (void) spl0();
3f431cc4
BJ
222 break;
223
224 case '\b':
225 if (logcol > 0)
226 logcol--;
227 break;
228
229 default:
230 if (logcol < physcol) {
5ffed226 231 lpoutput(dev, '\r');
3f431cc4
BJ
232 physcol = 0;
233 }
ca063532 234 if (logcol < MAXCOL) {
3f431cc4 235 while (logcol > physcol) {
5ffed226 236 lpoutput(dev, ' ');
3f431cc4
BJ
237 physcol++;
238 }
5ffed226 239 lpoutput(dev, c);
3f431cc4
BJ
240 physcol++;
241 }
242 logcol++;
243 }
244 if (logcol > 1000) /* ignore long lines */
245 logcol = 1000;
ca063532
MT
246 sc->sc_logcol = logcol;
247 sc->sc_physcol = physcol;
3f431cc4
BJ
248}
249
5ffed226
BJ
250lpoutput(dev, c)
251 dev_t dev;
252 int c;
3f431cc4 253{
5ffed226 254 register struct lp_softc *sc = &lp_softc[LPUNIT(dev)];
3f431cc4 255
ca063532 256 if (sc->sc_outq.c_cc >= LPHWAT) {
a0eab615 257 (void) spl4();
5ffed226 258 lpintr(LPUNIT(dev)); /* unchoke */
ca063532
MT
259 while (sc->sc_outq.c_cc >= LPHWAT) {
260 sc->sc_state |= ASLP; /* must be ERROR */
261 sleep((caddr_t)sc, LPPRI);
3f431cc4 262 }
a0eab615 263 (void) spl0();
3f431cc4 264 }
ca063532 265 while (putc(c, &sc->sc_outq))
3f431cc4
BJ
266 sleep((caddr_t)&lbolt, LPPRI);
267}
268
5ffed226
BJ
269lpintr(lp11)
270 int lp11;
3f431cc4
BJ
271{
272 register int n;
5ffed226
BJ
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;
ca063532 276
ca063532
MT
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);
3f431cc4 284 }
ca063532
MT
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 */
3f431cc4
BJ
291 }
292}
293
ca063532 294lptout(dev)
5ffed226 295 dev_t dev;
3f431cc4 296{
ca063532
MT
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 */
b620b354 306 timeout(lptout, (caddr_t)dev, 2*hz); /* so don't sweat */
3f431cc4
BJ
307 return;
308 }
ca063532
MT
309 if ((sc->sc_state&OPEN) == 0) {
310 sc->sc_state &= ~TOUT; /* no longer open */
311 lpaddr->lpsr = 0;
3f431cc4
BJ
312 return;
313 }
ca063532 314 if (sc->sc_outq.c_cc && (lpaddr->lpsr&DONE) && (lpaddr->lpsr&ERROR)==0)
5ffed226 315 lpintr(LPUNIT(dev)); /* ready to go */
b620b354 316 timeout(lptout, (caddr_t)dev, 10*hz);
3f431cc4
BJ
317}
318
ca063532 319lpreset(uban)
5ffed226 320 int uban;
3f431cc4 321{
ca063532
MT
322 register struct uba_device *ui;
323 register struct lpdevice *lpaddr;
324 register int unit;
325
5ffed226
BJ
326 for (unit = 0; unit < NLP; unit++) {
327 if ((ui = lpinfo[unit]) == 0 || ui->ui_ubanum != uban ||
328 ui->ui_alive == 0)
ca063532
MT
329 continue;
330 printf(" lp%d", unit);
5ffed226 331 lpaddr = (struct lpdevice *)ui->ui_addr;
ca063532 332 lpaddr->lpsr |= IENABLE;
3f431cc4
BJ
333 }
334}