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