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