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