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