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