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