xref: /csrg-svn/sys/vax/uba/lp.c (revision 1929)
1 /*	lp.c	4.2	12/18/80	*/
2 
3 #include "../conf/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('\f');
94 }
95 
96 lpwrite()
97 {
98 	register c, n;
99 	register char *cp;
100 
101 	while (n = min(BSIZE, u.u_count)) {
102 		cp = lp11.inbuf->b_un.b_addr;
103 		iomove(cp, n, B_WRITE);
104 		do
105 			lpcanon(*cp++);
106 		while (--n);
107 	}
108 }
109 
110 lpcanon(c)
111 register c;
112 {
113 	register int logcol, physcol;
114 
115 #ifdef HALFASCII
116 	if (lp11.flags&CAP) {
117 		register c2;
118 
119 		if (c>='a' && c<='z')
120 			c += 'A'-'a'; else
121 		switch (c) {
122 
123 		case '{':
124 			c2 = '(';
125 			goto esc;
126 
127 		case '}':
128 			c2 = ')';
129 			goto esc;
130 
131 		case '`':
132 			c2 = '\'';
133 			goto esc;
134 
135 		case '|':
136 			c2 = '!';
137 			goto esc;
138 
139 		case '~':
140 			c2 = '^';
141 
142 		esc:
143 			lpcanon(c2);
144 			lp11.logcol--;
145 			c = '-';
146 		}
147 	}
148 #endif HALFASCII
149 	logcol = lp11.logcol;
150 	physcol = lp11.physcol;
151 	if (c == ' ')
152 		logcol++;
153 	else switch(c) {
154 
155 	case '\t':
156 		logcol = lp11.indent + ((logcol-lp11.indent+8) & ~7);
157 		break;
158 
159 	case '\n':
160 		lp11.physline++;
161 		if (lp11.physline >= lp11.ejline)
162 			c = '\f';
163 		/* fall through */
164 
165 	case '\f':
166 		physcol = 0;
167 		if (lp11.physline == 0 && (lp11.flags&SAVEPAPER))
168 			;
169 		else {
170 			lpoutput(c);
171 			if (c == '\f') {
172 				lp11.physline = 0;
173 				if (lp11.flags & SKIPFOLD) {
174 					int i;
175 					for (i = 0; i < lp11.skpline; i++)
176 						lpoutput('\n');
177 				}
178 			}
179 		}
180 		/* fall into ... */
181 
182 	case '\r':
183 		logcol = lp11.indent;
184 		spl4();
185 		lpintr();
186 		spl0();
187 		break;
188 
189 	case '\b':
190 		if (logcol > 0)
191 			logcol--;
192 		break;
193 
194 	default:
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 nomore:
247 	lp11.state |= MOD;
248 	if (lp11.outq.c_cc > 0 && (LPADDR->lpsr&ERROR)==0)
249 		LPADDR->lpsr |= IENABLE;	/* ok and more to do later */
250 	if (n>LPLWAT && lp11.outq.c_cc<=LPLWAT && lp11.state&ASLP) {
251 		lp11.state &= ~ASLP;
252 		wakeup((caddr_t)&lp11);		/* top half should go on */
253 	}
254 }
255 
256 lptout()
257 {
258 	register short *sr;
259 
260 	if ((lp11.state&MOD) != 0) {
261 		lp11.state &= ~MOD;		/* something happened */
262 		timeout(lptout, 0, 2*HZ);	/* so don't sweat */
263 		return;
264 	}
265 	sr = &LPADDR->lpsr;
266 	if ((lp11.state&OPEN) == 0) {
267 		lp11.state &= ~TOUT;		/* no longer open */
268 		*sr = 0;
269 		return;
270 	}
271 	if (lp11.outq.c_cc && (*sr&DONE) && (*sr&ERROR)==0)
272 		lpintr();			/* ready to go */
273 	timeout(lptout, 0, 10*HZ);
274 }
275 
276 /*ARGSUSED*/
277 lpioctl(dev, cmd, addr, flag)
278 	dev_t dev;
279 	caddr_t addr;
280 {
281 	register int m;
282 	struct lpioctl lpio;
283 
284 	switch (cmd) {
285 
286 	case LGETSTATE:
287 		copyout((caddr_t)&lp11.lpio, addr, sizeof (lp11.lpio));
288 		return;
289 
290 	case LSETSTATE:
291 		m = copyin(addr, (caddr_t)&lpio, sizeof (lpio));
292 		if (m < 0) {
293 			u.u_error = EFAULT;
294 			return;
295 		}
296 		if (lpio.lp_indent <= 0 || lpio.lp_indent >= lpio.lp_maxcol ||
297 		    lpio.lp_ejline <= 2 || lpio.lp_ejline <= lpio.lp_skpline ||
298 		    lpio.lp_skpline < 0 || lpio.lp_maxcol <= 10)
299 			u.u_error = EINVAL;
300 		else
301 			lp11.lpio = lpio;
302 		return;
303 
304 	default:
305 		u.u_error = ENOTTY;
306 		return;
307 	}
308 }
309 
310 lpreset()
311 {
312 
313 	printf("lp ");
314 	LPADDR->lpsr |= IENABLE;
315 }
316