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