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