1 /* lp.c 4.29 82/10/10 */ 2 3 #include "lp.h" 4 #if NLP > 0 5 /* 6 * LP-11 Line printer driver 7 * 8 * This driver has been modified to work on printers where 9 * leaving IENABLE set would cause continuous interrupts. 10 */ 11 12 #include "../h/param.h" 13 #include "../h/dir.h" 14 #include "../h/user.h" 15 #include "../h/buf.h" 16 #include "../h/systm.h" 17 #include "../h/map.h" 18 #include "../h/pte.h" 19 #include "../h/ioctl.h" 20 #include "../h/tty.h" 21 22 #include "../vaxuba/ubavar.h" 23 24 #define LPPRI (PZERO+8) 25 #define IENABLE 0100 26 #define DONE 0200 27 #define ERROR 0100000 28 #define LPLWAT 650 29 #define LPHWAT 800 30 31 #ifndef CAD 32 #define MAXCOL 132 33 #else 34 #define MAXCOL 512 35 #endif 36 #define CAP 1 37 38 #define LPUNIT(dev) (minor(dev) >> 3) 39 40 struct lpdevice { 41 short lpsr; 42 short lpbuf; 43 }; 44 45 struct lp_softc { 46 struct clist sc_outq; 47 int sc_state; 48 int sc_physcol; 49 int sc_logcol; 50 int sc_physline; 51 char sc_flags; 52 int sc_lpchar; 53 struct buf *sc_inbuf; 54 } lp_softc[NLP]; 55 56 struct uba_device *lpinfo[NLP]; 57 58 int lpprobe(), lpattach(), lptout(); 59 u_short lpstd[] = { 0177514 }; 60 struct uba_driver lpdriver = 61 { lpprobe, 0, lpattach, 0, lpstd, "lp", lpinfo }; 62 63 /* bits for state */ 64 #define OPEN 1 /* device is open */ 65 #define TOUT 2 /* timeout is active */ 66 #define MOD 4 /* device state has been modified */ 67 #define ASLP 8 /* awaiting draining of printer */ 68 69 extern lbolt; 70 int lptout(); 71 72 lpattach(ui) 73 struct uba_device *ui; 74 { 75 register struct lp_softc *sc; 76 77 sc = &lp_softc[ui->ui_unit]; 78 sc->sc_lpchar = -1; 79 } 80 81 lpprobe(reg) 82 caddr_t reg; 83 { 84 register int br, cvec; /* value-result */ 85 register struct lpdevice *lpaddr = (struct lpdevice *)reg; 86 #ifdef lint 87 br = 0; cvec = br; br = cvec; 88 lpintr(0); 89 #endif 90 91 #ifdef INGVAX 92 br = 0x14; 93 cvec = 0200; 94 #else 95 lpaddr->lpsr = IENABLE; 96 DELAY(5); 97 lpaddr->lpsr = 0; 98 #endif 99 return (sizeof (struct lpdevice)); 100 } 101 102 /*ARGSUSED*/ 103 lpopen(dev, flag) 104 dev_t dev; 105 int flag; 106 { 107 register int unit; 108 register struct lpdevice *lpaddr; 109 register struct lp_softc *sc; 110 register struct uba_device *ui; 111 112 if ((unit = LPUNIT(dev)) >= NLP || 113 (sc = &lp_softc[unit])->sc_state&OPEN || 114 (ui = lpinfo[unit]) == 0 || ui->ui_alive == 0) { 115 u.u_error = ENXIO; 116 return; 117 } 118 lpaddr = (struct lpdevice *)ui->ui_addr; 119 if (lpaddr->lpsr&ERROR) { 120 u.u_error = EIO; 121 return; 122 } 123 sc->sc_state |= OPEN; 124 sc->sc_inbuf = geteblk(512); 125 sc->sc_flags = minor(dev) & 07; 126 (void) spl4(); 127 if ((sc->sc_state&TOUT) == 0) { 128 sc->sc_state |= TOUT; 129 timeout(lptout, (caddr_t)dev, 10*hz); 130 } 131 (void) spl0(); 132 lpcanon(dev, '\f'); 133 } 134 135 /*ARGSUSED*/ 136 lpclose(dev, flag) 137 dev_t dev; 138 int flag; 139 { 140 register struct lp_softc *sc = &lp_softc[LPUNIT(dev)]; 141 142 lpcanon(dev, '\f'); 143 brelse(sc->sc_inbuf); 144 sc->sc_state &= ~OPEN; 145 } 146 147 lpwrite(dev, uio) 148 dev_t dev; 149 struct uio *uio; 150 { 151 register unsigned n; 152 register char *cp; 153 register struct lp_softc *sc = &lp_softc[LPUNIT(dev)]; 154 int error; 155 156 while (n = min(512, uio->uio_resid)) { 157 cp = sc->sc_inbuf->b_un.b_addr; 158 error = uiomove(cp, n, UIO_WRITE, uio); 159 if (error) 160 return (error); 161 do 162 lpcanon(dev, *cp++); 163 while (--n); 164 } 165 return (0); 166 } 167 168 lpcanon(dev, c) 169 dev_t dev; 170 register int c; 171 { 172 register int logcol, physcol; 173 register struct lp_softc *sc = &lp_softc[LPUNIT(dev)]; 174 175 if (sc->sc_flags&CAP) { 176 register c2; 177 178 if (c>='a' && c<='z') 179 c += 'A'-'a'; else 180 switch (c) { 181 182 case '{': 183 c2 = '('; 184 goto esc; 185 186 case '}': 187 c2 = ')'; 188 goto esc; 189 190 case '`': 191 c2 = '\''; 192 goto esc; 193 194 case '|': 195 c2 = '!'; 196 goto esc; 197 198 case '~': 199 c2 = '^'; 200 201 esc: 202 lpcanon(dev, c2); 203 sc->sc_logcol--; 204 c = '-'; 205 } 206 } 207 logcol = sc->sc_logcol; 208 physcol = sc->sc_physcol; 209 if (c == ' ') 210 logcol++; 211 else switch(c) { 212 213 case '\t': 214 logcol = (logcol+8) & ~7; 215 break; 216 217 case '\f': 218 if (sc->sc_physline == 0 && physcol == 0) 219 break; 220 /* fall into ... */ 221 222 case '\n': 223 lpoutput(dev, c); 224 if (c == '\f') 225 sc->sc_physline = 0; 226 else 227 sc->sc_physline++; 228 physcol = 0; 229 /* fall into ... */ 230 231 case '\r': 232 logcol = 0; 233 (void) spl4(); 234 lpintr(LPUNIT(dev)); 235 (void) spl0(); 236 break; 237 238 case '\b': 239 if (logcol > 0) 240 logcol--; 241 break; 242 243 default: 244 if (logcol < physcol) { 245 lpoutput(dev, '\r'); 246 physcol = 0; 247 } 248 if (logcol < MAXCOL) { 249 while (logcol > physcol) { 250 lpoutput(dev, ' '); 251 physcol++; 252 } 253 lpoutput(dev, c); 254 physcol++; 255 } 256 logcol++; 257 } 258 if (logcol > 1000) /* ignore long lines */ 259 logcol = 1000; 260 sc->sc_logcol = logcol; 261 sc->sc_physcol = physcol; 262 } 263 264 lpoutput(dev, c) 265 dev_t dev; 266 int c; 267 { 268 register struct lp_softc *sc = &lp_softc[LPUNIT(dev)]; 269 270 if (sc->sc_outq.c_cc >= LPHWAT) { 271 (void) spl4(); 272 lpintr(LPUNIT(dev)); /* unchoke */ 273 while (sc->sc_outq.c_cc >= LPHWAT) { 274 sc->sc_state |= ASLP; /* must be ERROR */ 275 sleep((caddr_t)sc, LPPRI); 276 } 277 (void) spl0(); 278 } 279 while (putc(c, &sc->sc_outq)) 280 sleep((caddr_t)&lbolt, LPPRI); 281 } 282 283 lpintr(lp11) 284 int lp11; 285 { 286 register int n; 287 register struct lp_softc *sc = &lp_softc[lp11]; 288 register struct uba_device *ui = lpinfo[lp11]; 289 register struct lpdevice *lpaddr = (struct lpdevice *)ui->ui_addr; 290 291 lpaddr->lpsr &= ~IENABLE; 292 n = sc->sc_outq.c_cc; 293 if (sc->sc_lpchar < 0) 294 sc->sc_lpchar = getc(&sc->sc_outq); 295 while ((lpaddr->lpsr&DONE) && sc->sc_lpchar >= 0) { 296 lpaddr->lpbuf = sc->sc_lpchar; 297 sc->sc_lpchar = getc(&sc->sc_outq); 298 } 299 sc->sc_state |= MOD; 300 if (sc->sc_outq.c_cc > 0 && (lpaddr->lpsr&ERROR)==0) 301 lpaddr->lpsr |= IENABLE; /* ok and more to do later */ 302 if (n>LPLWAT && sc->sc_outq.c_cc<=LPLWAT && sc->sc_state&ASLP) { 303 sc->sc_state &= ~ASLP; 304 wakeup((caddr_t)sc); /* top half should go on */ 305 } 306 } 307 308 lptout(dev) 309 dev_t dev; 310 { 311 register struct lp_softc *sc; 312 register struct uba_device *ui; 313 register struct lpdevice *lpaddr; 314 315 sc = &lp_softc[LPUNIT(dev)]; 316 ui = lpinfo[LPUNIT(dev)]; 317 lpaddr = (struct lpdevice *) ui->ui_addr; 318 if ((sc->sc_state&MOD) != 0) { 319 sc->sc_state &= ~MOD; /* something happened */ 320 timeout(lptout, (caddr_t)dev, 2*hz); /* so don't sweat */ 321 return; 322 } 323 if ((sc->sc_state&OPEN) == 0) { 324 sc->sc_state &= ~TOUT; /* no longer open */ 325 lpaddr->lpsr = 0; 326 return; 327 } 328 if (sc->sc_outq.c_cc && (lpaddr->lpsr&DONE) && (lpaddr->lpsr&ERROR)==0) 329 lpintr(LPUNIT(dev)); /* ready to go */ 330 timeout(lptout, (caddr_t)dev, 10*hz); 331 } 332 333 lpreset(uban) 334 int uban; 335 { 336 register struct uba_device *ui; 337 register struct lpdevice *lpaddr; 338 register int unit; 339 340 for (unit = 0; unit < NLP; unit++) { 341 if ((ui = lpinfo[unit]) == 0 || ui->ui_ubanum != uban || 342 ui->ui_alive == 0) 343 continue; 344 printf(" lp%d", unit); 345 lpaddr = (struct lpdevice *)ui->ui_addr; 346 lpaddr->lpsr |= IENABLE; 347 } 348 } 349