1 /* lp.c 4.6 81/02/16 */ 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 #ifdef HALFASCII 112 if (lp11.flags&CAP) { 113 register c2; 114 115 if (c>='a' && c<='z') 116 c += 'A'-'a'; else 117 switch (c) { 118 119 case '{': 120 c2 = '('; 121 goto esc; 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 138 esc: 139 lpcanon(c2); 140 lp11.logcol--; 141 c = '-'; 142 } 143 } 144 #endif HALFASCII 145 logcol = lp11.logcol; 146 physcol = lp11.physcol; 147 if (c == ' ') 148 logcol++; 149 else switch(c) { 150 151 case '\t': 152 logcol = lp11.indent + ((logcol-lp11.indent+8) & ~7); 153 break; 154 155 case '\f': 156 if (lp11.physline == 0 && physcol == 0) 157 break; 158 /* fall into ... */ 159 160 case '\n': 161 lpoutput(c); 162 if (c == '\f') 163 lp11.physline = 0; 164 else 165 lp11.physline++; 166 physcol = 0; 167 /* fall into ... */ 168 169 case '\r': 170 logcol = lp11.indent; 171 spl4(); 172 lpintr(); 173 spl0(); 174 break; 175 176 case '\b': 177 if (logcol > 0) 178 logcol--; 179 break; 180 181 default: 182 if (logcol < physcol) { 183 lpoutput('\r'); 184 physcol = 0; 185 } 186 if (logcol < lp11.maxcol) { 187 while (logcol > physcol) { 188 lpoutput(' '); 189 physcol++; 190 } 191 lpoutput(c); 192 physcol++; 193 } 194 logcol++; 195 } 196 if (logcol > 1000) /* ignore long lines */ 197 logcol = 1000; 198 lp11.logcol = logcol; 199 lp11.physcol = physcol; 200 } 201 202 lpoutput(c) 203 { 204 205 if (lp11.outq.c_cc >= LPHWAT) { 206 spl4(); 207 lpintr(); /* unchoke */ 208 while (lp11.outq.c_cc >= LPHWAT) { 209 lp11.state |= ASLP; /* must be ERROR */ 210 sleep((caddr_t)&lp11, LPPRI); 211 } 212 spl0(); 213 } 214 while (putc(c, &lp11.outq)) 215 sleep((caddr_t)&lbolt, LPPRI); 216 } 217 218 int lpchar = -1; 219 220 lpintr() 221 { 222 register int n; 223 int i; 224 225 LPADDR->lpsr &= ~IENABLE; 226 n = lp11.outq.c_cc; 227 if (lpchar < 0) 228 lpchar = getc(&lp11); 229 while ((LPADDR->lpsr&DONE) && lpchar >= 0) { 230 LPADDR->lpbuf = lpchar; 231 lpchar = getc(&lp11); 232 } 233 lp11.state |= MOD; 234 if (lp11.outq.c_cc > 0 && (LPADDR->lpsr&ERROR)==0) 235 LPADDR->lpsr |= IENABLE; /* ok and more to do later */ 236 if (n>LPLWAT && lp11.outq.c_cc<=LPLWAT && lp11.state&ASLP) { 237 lp11.state &= ~ASLP; 238 wakeup((caddr_t)&lp11); /* top half should go on */ 239 } 240 } 241 242 lptout() 243 { 244 register short *sr; 245 246 if ((lp11.state&MOD) != 0) { 247 lp11.state &= ~MOD; /* something happened */ 248 timeout(lptout, 0, 2*HZ); /* so don't sweat */ 249 return; 250 } 251 sr = &LPADDR->lpsr; 252 if ((lp11.state&OPEN) == 0) { 253 lp11.state &= ~TOUT; /* no longer open */ 254 *sr = 0; 255 return; 256 } 257 if (lp11.outq.c_cc && (*sr&DONE) && (*sr&ERROR)==0) 258 lpintr(); /* ready to go */ 259 timeout(lptout, 0, 10*HZ); 260 } 261 262 /*ARGSUSED*/ 263 lpioctl(dev, cmd, addr, flag) 264 dev_t dev; 265 caddr_t addr; 266 { 267 register int m; 268 struct lpioctl lpio; 269 270 switch (cmd) { 271 272 case LGETSTATE: 273 copyout((caddr_t)&lp11.lpio, addr, sizeof (lp11.lpio)); 274 return; 275 276 case LSETSTATE: 277 m = copyin(addr, (caddr_t)&lpio, sizeof (lpio)); 278 if (m < 0) { 279 u.u_error = EFAULT; 280 return; 281 } 282 if (lpio.lp_indent <= 0 || lpio.lp_indent >= lpio.lp_maxcol || 283 lpio.lp_ejline <= 2 || lpio.lp_ejline <= lpio.lp_skpline || 284 lpio.lp_skpline < 0 || lpio.lp_maxcol <= 10) 285 u.u_error = EINVAL; 286 else 287 lp11.lpio = lpio; 288 return; 289 290 default: 291 u.u_error = ENOTTY; 292 return; 293 } 294 } 295 296 lpreset() 297 { 298 299 printf("lp "); 300 LPADDR->lpsr |= IENABLE; 301 } 302 303