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