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