xref: /csrg-svn/sys/vax/uba/lp.c (revision 2831)
1 /*	lp.c	4.8	81/03/02	*/
2 
3 #include "lp.h"
4 #if NLP11 > 0
5 /*
6  * LP-11 Line printer driver
7  *
8  * This driver is only set up to handle one printer;
9  * thats all our user-level spoolers can handle anyways right now.
10  *
11  * This driver has been modified to work on printers where
12  * leaving IENABLE set would cause continuous interrupts.
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/uba.h"
23 #include "../h/ioctl.h"
24 #include "../h/tty.h"
25 #include "../h/lpio.h"
26 
27 #define	LPPRI	(PZERO+8)
28 #define	IENABLE	0100
29 #define	DONE	0200
30 #define	ERROR	0100000
31 #define	LPLWAT	650
32 #define	LPHWAT	800
33 
34 struct lpregs {
35 	short	lpsr;
36 	short	lpbuf;
37 };
38 
39 struct {
40 	struct	clist outq;
41 	int	state;
42 	int	physcol;
43 	int	logcol;
44 	int	physline;
45 	struct	lpioctl lpio;
46 	struct	buf *inbuf;
47 } lp11;
48 #define	flags	lpio.lp_flags
49 #define	indent	lpio.lp_indent
50 #define	maxcol	lpio.lp_maxcol
51 
52 /* bits for state */
53 #define	OPEN		1	/* device is open */
54 #define	TOUT		2	/* timeout is active */
55 #define	MOD		4	/* device state has been modified */
56 #define	ASLP		8	/* awaiting draining of printer */
57 
58 extern	lbolt;
59 int	lptout();
60 
61 /*ARGSUSED*/
62 lpopen(dev, flag)
63 {
64 
65 	if (lp11.state&OPEN || LPADDR->lpsr&ERROR) {
66 		u.u_error = EIO;
67 		return;
68 	}
69 	lp11.state |= OPEN;
70 	lp11.inbuf = geteblk();
71 	lp11.flags = LPFLAGS;
72 	lp11.indent = INDENT;
73 	lp11.maxcol = MAXCOL;
74 	spl4();
75 	if ((lp11.state&TOUT) == 0) {
76 		lp11.state |= TOUT;
77 		timeout(lptout, 0, 10*hz);
78 	}
79 	spl0();
80 	lpcanon('\f');
81 }
82 
83 /*ARGSUSED*/
84 lpclose(dev, flag)
85 {
86 
87 	lpcanon('\f');
88 	brelse(lp11.inbuf);
89 	lp11.state &= ~OPEN;
90 }
91 
92 lpwrite()
93 {
94 	register c, n;
95 	register char *cp;
96 
97 	while (n = min(BSIZE, u.u_count)) {
98 		cp = lp11.inbuf->b_un.b_addr;
99 		iomove(cp, n, B_WRITE);
100 		do
101 			lpcanon(*cp++);
102 		while (--n);
103 	}
104 }
105 
106 lpcanon(c)
107 register c;
108 {
109 	register int logcol, physcol;
110 
111 	if (lp11.flags&CAP) {
112 		register c2;
113 
114 		if (c>='a' && c<='z')
115 			c += 'A'-'a'; else
116 		switch (c) {
117 
118 		case '{':
119 			c2 = '(';
120 			goto esc;
121 
122 		case '}':
123 			c2 = ')';
124 			goto esc;
125 
126 		case '`':
127 			c2 = '\'';
128 			goto esc;
129 
130 		case '|':
131 			c2 = '!';
132 			goto esc;
133 
134 		case '~':
135 			c2 = '^';
136 
137 		esc:
138 			lpcanon(c2);
139 			lp11.logcol--;
140 			c = '-';
141 		}
142 	}
143 	logcol = lp11.logcol;
144 	physcol = lp11.physcol;
145 	if (c == ' ')
146 		logcol++;
147 	else switch(c) {
148 
149 	case '\t':
150 		logcol = lp11.indent + ((logcol-lp11.indent+8) & ~7);
151 		break;
152 
153 	case '\f':
154 		if (lp11.physline == 0 && physcol == 0)
155 			break;
156 		/* fall into ... */
157 
158 	case '\n':
159 		lpoutput(c);
160 		if (c == '\f')
161 			lp11.physline = 0;
162 		else
163 			lp11.physline++;
164 		physcol = 0;
165 		/* fall into ... */
166 
167 	case '\r':
168 		logcol = lp11.indent;
169 		spl4();
170 		lpintr();
171 		spl0();
172 		break;
173 
174 	case '\b':
175 		if (logcol > 0)
176 			logcol--;
177 		break;
178 
179 	default:
180 		if (logcol < physcol) {
181 			lpoutput('\r');
182 			physcol = 0;
183 		}
184 		if (logcol < lp11.maxcol) {
185 			while (logcol > physcol) {
186 				lpoutput(' ');
187 				physcol++;
188 			}
189 			lpoutput(c);
190 			physcol++;
191 		}
192 		logcol++;
193 	}
194 	if (logcol > 1000)	/* ignore long lines  */
195 		logcol = 1000;
196 	lp11.logcol = logcol;
197 	lp11.physcol = physcol;
198 }
199 
200 lpoutput(c)
201 {
202 
203 	if (lp11.outq.c_cc >= LPHWAT) {
204 		spl4();
205 		lpintr();				/* unchoke */
206 		while (lp11.outq.c_cc >= LPHWAT) {
207 			lp11.state |= ASLP;		/* must be ERROR */
208 			sleep((caddr_t)&lp11, LPPRI);
209 		}
210 		spl0();
211 	}
212 	while (putc(c, &lp11.outq))
213 		sleep((caddr_t)&lbolt, LPPRI);
214 }
215 
216 int	lpchar = -1;
217 
218 lpintr()
219 {
220 	register int n;
221 	int i;
222 
223 	LPADDR->lpsr &= ~IENABLE;
224 	n = lp11.outq.c_cc;
225 	if (lpchar < 0)
226 		lpchar = getc(&lp11);
227 	while ((LPADDR->lpsr&DONE) && lpchar >= 0) {
228 		LPADDR->lpbuf = lpchar;
229 		lpchar = getc(&lp11);
230 	}
231 	lp11.state |= MOD;
232 	if (lp11.outq.c_cc > 0 && (LPADDR->lpsr&ERROR)==0)
233 		LPADDR->lpsr |= IENABLE;	/* ok and more to do later */
234 	if (n>LPLWAT && lp11.outq.c_cc<=LPLWAT && lp11.state&ASLP) {
235 		lp11.state &= ~ASLP;
236 		wakeup((caddr_t)&lp11);		/* top half should go on */
237 	}
238 }
239 
240 lptout()
241 {
242 	register short *sr;
243 
244 	if ((lp11.state&MOD) != 0) {
245 		lp11.state &= ~MOD;		/* something happened */
246 		timeout(lptout, 0, 2*hz);	/* so don't sweat */
247 		return;
248 	}
249 	sr = &LPADDR->lpsr;
250 	if ((lp11.state&OPEN) == 0) {
251 		lp11.state &= ~TOUT;		/* no longer open */
252 		*sr = 0;
253 		return;
254 	}
255 	if (lp11.outq.c_cc && (*sr&DONE) && (*sr&ERROR)==0)
256 		lpintr();			/* ready to go */
257 	timeout(lptout, 0, 10*hz);
258 }
259 
260 /*ARGSUSED*/
261 lpioctl(dev, cmd, addr, flag)
262 	dev_t dev;
263 	caddr_t addr;
264 {
265 	register int m;
266 	struct lpioctl lpio;
267 
268 	switch (cmd) {
269 
270 	case LGETSTATE:
271 		copyout((caddr_t)&lp11.lpio, addr, sizeof (lp11.lpio));
272 		return;
273 
274 	case LSETSTATE:
275 		m = copyin(addr, (caddr_t)&lpio, sizeof (lpio));
276 		if (m < 0) {
277 			u.u_error = EFAULT;
278 			return;
279 		}
280 		if (lpio.lp_indent <= 0 || lpio.lp_indent >= lpio.lp_maxcol ||
281 		    lpio.lp_ejline <= 2 || lpio.lp_ejline <= lpio.lp_skpline ||
282 		    lpio.lp_skpline < 0 || lpio.lp_maxcol <= 10)
283 			u.u_error = EINVAL;
284 		else
285 			lp11.lpio = lpio;
286 		return;
287 
288 	default:
289 		u.u_error = ENOTTY;
290 		return;
291 	}
292 }
293 
294 lpreset()
295 {
296 
297 	printf("lp ");
298 	LPADDR->lpsr |= IENABLE;
299 }
300 
301