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