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