1 /* lp.c 4.28 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 155 while (n = min(512, uio->uio_resid)) { 156 cp = sc->sc_inbuf->b_un.b_addr; 157 u.u_error = uiomove(cp, n, UIO_WRITE, uio); 158 if (u.u_error) 159 break; 160 do 161 lpcanon(dev, *cp++); 162 while (--n); 163 } 164 } 165 166 lpcanon(dev, c) 167 dev_t dev; 168 register int c; 169 { 170 register int logcol, physcol; 171 register struct lp_softc *sc = &lp_softc[LPUNIT(dev)]; 172 173 if (sc->sc_flags&CAP) { 174 register c2; 175 176 if (c>='a' && c<='z') 177 c += 'A'-'a'; else 178 switch (c) { 179 180 case '{': 181 c2 = '('; 182 goto esc; 183 184 case '}': 185 c2 = ')'; 186 goto esc; 187 188 case '`': 189 c2 = '\''; 190 goto esc; 191 192 case '|': 193 c2 = '!'; 194 goto esc; 195 196 case '~': 197 c2 = '^'; 198 199 esc: 200 lpcanon(dev, c2); 201 sc->sc_logcol--; 202 c = '-'; 203 } 204 } 205 logcol = sc->sc_logcol; 206 physcol = sc->sc_physcol; 207 if (c == ' ') 208 logcol++; 209 else switch(c) { 210 211 case '\t': 212 logcol = (logcol+8) & ~7; 213 break; 214 215 case '\f': 216 if (sc->sc_physline == 0 && physcol == 0) 217 break; 218 /* fall into ... */ 219 220 case '\n': 221 lpoutput(dev, c); 222 if (c == '\f') 223 sc->sc_physline = 0; 224 else 225 sc->sc_physline++; 226 physcol = 0; 227 /* fall into ... */ 228 229 case '\r': 230 logcol = 0; 231 (void) spl4(); 232 lpintr(LPUNIT(dev)); 233 (void) spl0(); 234 break; 235 236 case '\b': 237 if (logcol > 0) 238 logcol--; 239 break; 240 241 default: 242 if (logcol < physcol) { 243 lpoutput(dev, '\r'); 244 physcol = 0; 245 } 246 if (logcol < MAXCOL) { 247 while (logcol > physcol) { 248 lpoutput(dev, ' '); 249 physcol++; 250 } 251 lpoutput(dev, c); 252 physcol++; 253 } 254 logcol++; 255 } 256 if (logcol > 1000) /* ignore long lines */ 257 logcol = 1000; 258 sc->sc_logcol = logcol; 259 sc->sc_physcol = physcol; 260 } 261 262 lpoutput(dev, c) 263 dev_t dev; 264 int c; 265 { 266 register struct lp_softc *sc = &lp_softc[LPUNIT(dev)]; 267 268 if (sc->sc_outq.c_cc >= LPHWAT) { 269 (void) spl4(); 270 lpintr(LPUNIT(dev)); /* unchoke */ 271 while (sc->sc_outq.c_cc >= LPHWAT) { 272 sc->sc_state |= ASLP; /* must be ERROR */ 273 sleep((caddr_t)sc, LPPRI); 274 } 275 (void) spl0(); 276 } 277 while (putc(c, &sc->sc_outq)) 278 sleep((caddr_t)&lbolt, LPPRI); 279 } 280 281 lpintr(lp11) 282 int lp11; 283 { 284 register int n; 285 register struct lp_softc *sc = &lp_softc[lp11]; 286 register struct uba_device *ui = lpinfo[lp11]; 287 register struct lpdevice *lpaddr = (struct lpdevice *)ui->ui_addr; 288 289 lpaddr->lpsr &= ~IENABLE; 290 n = sc->sc_outq.c_cc; 291 if (sc->sc_lpchar < 0) 292 sc->sc_lpchar = getc(&sc->sc_outq); 293 while ((lpaddr->lpsr&DONE) && sc->sc_lpchar >= 0) { 294 lpaddr->lpbuf = sc->sc_lpchar; 295 sc->sc_lpchar = getc(&sc->sc_outq); 296 } 297 sc->sc_state |= MOD; 298 if (sc->sc_outq.c_cc > 0 && (lpaddr->lpsr&ERROR)==0) 299 lpaddr->lpsr |= IENABLE; /* ok and more to do later */ 300 if (n>LPLWAT && sc->sc_outq.c_cc<=LPLWAT && sc->sc_state&ASLP) { 301 sc->sc_state &= ~ASLP; 302 wakeup((caddr_t)sc); /* top half should go on */ 303 } 304 } 305 306 lptout(dev) 307 dev_t dev; 308 { 309 register struct lp_softc *sc; 310 register struct uba_device *ui; 311 register struct lpdevice *lpaddr; 312 313 sc = &lp_softc[LPUNIT(dev)]; 314 ui = lpinfo[LPUNIT(dev)]; 315 lpaddr = (struct lpdevice *) ui->ui_addr; 316 if ((sc->sc_state&MOD) != 0) { 317 sc->sc_state &= ~MOD; /* something happened */ 318 timeout(lptout, (caddr_t)dev, 2*hz); /* so don't sweat */ 319 return; 320 } 321 if ((sc->sc_state&OPEN) == 0) { 322 sc->sc_state &= ~TOUT; /* no longer open */ 323 lpaddr->lpsr = 0; 324 return; 325 } 326 if (sc->sc_outq.c_cc && (lpaddr->lpsr&DONE) && (lpaddr->lpsr&ERROR)==0) 327 lpintr(LPUNIT(dev)); /* ready to go */ 328 timeout(lptout, (caddr_t)dev, 10*hz); 329 } 330 331 lpreset(uban) 332 int uban; 333 { 334 register struct uba_device *ui; 335 register struct lpdevice *lpaddr; 336 register int unit; 337 338 for (unit = 0; unit < NLP; unit++) { 339 if ((ui = lpinfo[unit]) == 0 || ui->ui_ubanum != uban || 340 ui->ui_alive == 0) 341 continue; 342 printf(" lp%d", unit); 343 lpaddr = (struct lpdevice *)ui->ui_addr; 344 lpaddr->lpsr |= IENABLE; 345 } 346 } 347