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