1 /* lp.c 4.26 82/07/15 */ 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 #else 94 lpaddr->lpsr = IENABLE; 95 DELAY(5); 96 lpaddr->lpsr = 0; 97 #endif 98 return (sizeof (struct lpdevice)); 99 } 100 101 /*ARGSUSED*/ 102 lpopen(dev, flag) 103 dev_t dev; 104 int flag; 105 { 106 register int unit; 107 register struct lpdevice *lpaddr; 108 register struct lp_softc *sc; 109 register struct uba_device *ui; 110 111 if ((unit = LPUNIT(dev)) >= NLP || 112 (sc = &lp_softc[unit])->sc_state&OPEN || 113 (ui = lpinfo[unit]) == 0 || ui->ui_alive == 0) { 114 u.u_error = ENXIO; 115 return; 116 } 117 lpaddr = (struct lpdevice *)ui->ui_addr; 118 if (lpaddr->lpsr&ERROR) { 119 u.u_error = EIO; 120 return; 121 } 122 sc->sc_state |= OPEN; 123 sc->sc_inbuf = geteblk(512); 124 sc->sc_flags = minor(dev) & 07; 125 (void) spl4(); 126 if ((sc->sc_state&TOUT) == 0) { 127 sc->sc_state |= TOUT; 128 timeout(lptout, (caddr_t)dev, 10*hz); 129 } 130 (void) spl0(); 131 lpcanon(dev, '\f'); 132 } 133 134 /*ARGSUSED*/ 135 lpclose(dev, flag) 136 dev_t dev; 137 int flag; 138 { 139 register struct lp_softc *sc = &lp_softc[LPUNIT(dev)]; 140 141 lpcanon(dev, '\f'); 142 brelse(sc->sc_inbuf); 143 sc->sc_state &= ~OPEN; 144 } 145 146 lpwrite(dev) 147 dev_t dev; 148 { 149 register unsigned n; 150 register char *cp; 151 register struct lp_softc *sc = &lp_softc[LPUNIT(dev)]; 152 153 while (n = min(512, u.u_count)) { 154 cp = sc->sc_inbuf->b_un.b_addr; 155 iomove(cp, n, B_WRITE); 156 do 157 lpcanon(dev, *cp++); 158 while (--n); 159 } 160 } 161 162 lpcanon(dev, c) 163 dev_t dev; 164 register int c; 165 { 166 register int logcol, physcol; 167 register struct lp_softc *sc = &lp_softc[LPUNIT(dev)]; 168 169 if (sc->sc_flags&CAP) { 170 register c2; 171 172 if (c>='a' && c<='z') 173 c += 'A'-'a'; else 174 switch (c) { 175 176 case '{': 177 c2 = '('; 178 goto esc; 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 195 esc: 196 lpcanon(dev, c2); 197 sc->sc_logcol--; 198 c = '-'; 199 } 200 } 201 logcol = sc->sc_logcol; 202 physcol = sc->sc_physcol; 203 if (c == ' ') 204 logcol++; 205 else switch(c) { 206 207 case '\t': 208 logcol = (logcol+8) & ~7; 209 break; 210 211 case '\f': 212 if (sc->sc_physline == 0 && physcol == 0) 213 break; 214 /* fall into ... */ 215 216 case '\n': 217 lpoutput(dev, c); 218 if (c == '\f') 219 sc->sc_physline = 0; 220 else 221 sc->sc_physline++; 222 physcol = 0; 223 /* fall into ... */ 224 225 case '\r': 226 logcol = 0; 227 (void) spl4(); 228 lpintr(LPUNIT(dev)); 229 (void) spl0(); 230 break; 231 232 case '\b': 233 if (logcol > 0) 234 logcol--; 235 break; 236 237 default: 238 if (logcol < physcol) { 239 lpoutput(dev, '\r'); 240 physcol = 0; 241 } 242 if (logcol < MAXCOL) { 243 while (logcol > physcol) { 244 lpoutput(dev, ' '); 245 physcol++; 246 } 247 lpoutput(dev, c); 248 physcol++; 249 } 250 logcol++; 251 } 252 if (logcol > 1000) /* ignore long lines */ 253 logcol = 1000; 254 sc->sc_logcol = logcol; 255 sc->sc_physcol = physcol; 256 } 257 258 lpoutput(dev, c) 259 dev_t dev; 260 int c; 261 { 262 register struct lp_softc *sc = &lp_softc[LPUNIT(dev)]; 263 264 if (sc->sc_outq.c_cc >= LPHWAT) { 265 (void) spl4(); 266 lpintr(LPUNIT(dev)); /* unchoke */ 267 while (sc->sc_outq.c_cc >= LPHWAT) { 268 sc->sc_state |= ASLP; /* must be ERROR */ 269 sleep((caddr_t)sc, LPPRI); 270 } 271 (void) spl0(); 272 } 273 while (putc(c, &sc->sc_outq)) 274 sleep((caddr_t)&lbolt, LPPRI); 275 } 276 277 lpintr(lp11) 278 int lp11; 279 { 280 register int n; 281 register struct lp_softc *sc = &lp_softc[lp11]; 282 register struct uba_device *ui = lpinfo[lp11]; 283 register struct lpdevice *lpaddr = (struct lpdevice *)ui->ui_addr; 284 285 lpaddr->lpsr &= ~IENABLE; 286 n = sc->sc_outq.c_cc; 287 if (sc->sc_lpchar < 0) 288 sc->sc_lpchar = getc(&sc->sc_outq); 289 while ((lpaddr->lpsr&DONE) && sc->sc_lpchar >= 0) { 290 lpaddr->lpbuf = sc->sc_lpchar; 291 sc->sc_lpchar = getc(&sc->sc_outq); 292 } 293 sc->sc_state |= MOD; 294 if (sc->sc_outq.c_cc > 0 && (lpaddr->lpsr&ERROR)==0) 295 lpaddr->lpsr |= IENABLE; /* ok and more to do later */ 296 if (n>LPLWAT && sc->sc_outq.c_cc<=LPLWAT && sc->sc_state&ASLP) { 297 sc->sc_state &= ~ASLP; 298 wakeup((caddr_t)sc); /* top half should go on */ 299 } 300 } 301 302 lptout(dev) 303 dev_t dev; 304 { 305 register struct lp_softc *sc; 306 register struct uba_device *ui; 307 register struct lpdevice *lpaddr; 308 309 sc = &lp_softc[LPUNIT(dev)]; 310 ui = lpinfo[LPUNIT(dev)]; 311 lpaddr = (struct lpdevice *) ui->ui_addr; 312 if ((sc->sc_state&MOD) != 0) { 313 sc->sc_state &= ~MOD; /* something happened */ 314 timeout(lptout, (caddr_t)dev, 2*hz); /* so don't sweat */ 315 return; 316 } 317 if ((sc->sc_state&OPEN) == 0) { 318 sc->sc_state &= ~TOUT; /* no longer open */ 319 lpaddr->lpsr = 0; 320 return; 321 } 322 if (sc->sc_outq.c_cc && (lpaddr->lpsr&DONE) && (lpaddr->lpsr&ERROR)==0) 323 lpintr(LPUNIT(dev)); /* ready to go */ 324 timeout(lptout, (caddr_t)dev, 10*hz); 325 } 326 327 lpreset(uban) 328 int uban; 329 { 330 register struct uba_device *ui; 331 register struct lpdevice *lpaddr; 332 register int unit; 333 334 for (unit = 0; unit < NLP; unit++) { 335 if ((ui = lpinfo[unit]) == 0 || ui->ui_ubanum != uban || 336 ui->ui_alive == 0) 337 continue; 338 printf(" lp%d", unit); 339 lpaddr = (struct lpdevice *)ui->ui_addr; 340 lpaddr->lpsr |= IENABLE; 341 } 342 } 343