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