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