1 /* 2 * Copyright (c) 1982 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 6.6 (Berkeley) 06/08/85 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 "../machine/pte.h" 18 19 #include "param.h" 20 #include "dir.h" 21 #include "user.h" 22 #include "buf.h" 23 #include "systm.h" 24 #include "map.h" 25 #include "uio.h" 26 #include "ioctl.h" 27 #include "tty.h" 28 #include "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 MAXCOL 132 40 #define CAP 1 41 42 #define LPUNIT(dev) (minor(dev) >> 3) 43 44 struct lpdevice { 45 short lpsr; 46 short lpbuf; 47 }; 48 49 struct lp_softc { 50 struct clist sc_outq; 51 int sc_state; 52 int sc_physcol; 53 int sc_logcol; 54 int sc_physline; 55 char sc_flags; 56 short sc_maxcol; 57 int sc_lpchar; 58 struct buf *sc_inbuf; 59 } lp_softc[NLP]; 60 61 struct uba_device *lpinfo[NLP]; 62 63 int lpprobe(), lpattach(), lptout(); 64 u_short lpstd[] = { 0177514 }; 65 struct uba_driver lpdriver = 66 { lpprobe, 0, lpattach, 0, lpstd, "lp", lpinfo }; 67 68 /* bits for state */ 69 #define OPEN 1 /* device is open */ 70 #define TOUT 2 /* timeout is active */ 71 #define MOD 4 /* device state has been modified */ 72 #define ASLP 8 /* awaiting draining of printer */ 73 74 int lptout(); 75 76 lpattach(ui) 77 struct uba_device *ui; 78 { 79 register struct lp_softc *sc; 80 81 sc = &lp_softc[ui->ui_unit]; 82 sc->sc_lpchar = -1; 83 if (ui->ui_flags) 84 sc->sc_maxcol = ui->ui_flags; 85 else 86 sc->sc_maxcol = MAXCOL; 87 } 88 89 lpprobe(reg) 90 caddr_t reg; 91 { 92 register int br, cvec; /* value-result */ 93 register struct lpdevice *lpaddr = (struct lpdevice *)reg; 94 #ifdef lint 95 br = 0; cvec = br; br = cvec; 96 lpintr(0); 97 #endif 98 99 lpaddr->lpsr = IENABLE; 100 DELAY(5); 101 lpaddr->lpsr = 0; 102 return (sizeof (struct lpdevice)); 103 } 104 105 /*ARGSUSED*/ 106 lpopen(dev, flag) 107 dev_t dev; 108 int flag; 109 { 110 register struct lpdevice *lpaddr; 111 register struct lp_softc *sc; 112 register struct uba_device *ui; 113 register int unit, s; 114 115 if ((unit = LPUNIT(dev)) >= NLP || 116 (sc = &lp_softc[unit])->sc_state&OPEN || 117 (ui = lpinfo[unit]) == 0 || ui->ui_alive == 0) 118 return (ENXIO); 119 lpaddr = (struct lpdevice *)ui->ui_addr; 120 if (lpaddr->lpsr&ERROR) 121 return (EIO); 122 sc->sc_state |= OPEN; 123 sc->sc_inbuf = geteblk(512); 124 sc->sc_flags = minor(dev) & 07; 125 s = spl4(); 126 if ((sc->sc_state&TOUT) == 0) { 127 sc->sc_state |= TOUT; 128 timeout(lptout, (caddr_t)dev, 10*hz); 129 } 130 splx(s); 131 lpcanon(dev, '\f'); 132 return (0); 133 } 134 135 /*ARGSUSED*/ 136 lpclose(dev, flag) 137 dev_t dev; 138 int flag; 139 { 140 register struct lp_softc *sc = &lp_softc[LPUNIT(dev)]; 141 142 lpcanon(dev, '\f'); 143 brelse(sc->sc_inbuf); 144 sc->sc_state &= ~OPEN; 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(512, (unsigned)uio->uio_resid)) { 157 cp = sc->sc_inbuf->b_un.b_addr; 158 error = uiomove(cp, (int)n, UIO_WRITE, 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; 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) { 275 sc->sc_state |= ASLP; /* must be ERROR */ 276 sleep((caddr_t)sc, LPPRI); 277 } 278 splx(s); 279 } 280 while (putc(c, &sc->sc_outq)) 281 sleep((caddr_t)&lbolt, LPPRI); 282 } 283 284 lpintr(lp11) 285 int lp11; 286 { 287 register int n; 288 register struct lp_softc *sc = &lp_softc[lp11]; 289 register struct uba_device *ui = lpinfo[lp11]; 290 register struct lpdevice *lpaddr = (struct lpdevice *)ui->ui_addr; 291 292 lpaddr->lpsr &= ~IENABLE; 293 n = sc->sc_outq.c_cc; 294 if (sc->sc_lpchar < 0) 295 sc->sc_lpchar = getc(&sc->sc_outq); 296 while ((lpaddr->lpsr&DONE) && sc->sc_lpchar >= 0) { 297 lpaddr->lpbuf = sc->sc_lpchar; 298 sc->sc_lpchar = getc(&sc->sc_outq); 299 } 300 sc->sc_state |= MOD; 301 if (sc->sc_outq.c_cc > 0 && (lpaddr->lpsr&ERROR)==0) 302 lpaddr->lpsr |= IENABLE; /* ok and more to do later */ 303 if (n>LPLWAT && sc->sc_outq.c_cc<=LPLWAT && sc->sc_state&ASLP) { 304 sc->sc_state &= ~ASLP; 305 wakeup((caddr_t)sc); /* top half should go on */ 306 } 307 } 308 309 lptout(dev) 310 dev_t dev; 311 { 312 register struct lp_softc *sc; 313 register struct uba_device *ui; 314 register struct lpdevice *lpaddr; 315 316 sc = &lp_softc[LPUNIT(dev)]; 317 ui = lpinfo[LPUNIT(dev)]; 318 lpaddr = (struct lpdevice *) ui->ui_addr; 319 if ((sc->sc_state&MOD) != 0) { 320 sc->sc_state &= ~MOD; /* something happened */ 321 timeout(lptout, (caddr_t)dev, 2*hz); /* so don't sweat */ 322 return; 323 } 324 if ((sc->sc_state&OPEN) == 0 && sc->sc_outq.c_cc == 0) { 325 sc->sc_state &= ~TOUT; /* no longer open */ 326 lpaddr->lpsr = 0; 327 return; 328 } 329 if (sc->sc_outq.c_cc && (lpaddr->lpsr&DONE) && (lpaddr->lpsr&ERROR)==0) 330 lpintr(LPUNIT(dev)); /* ready to go */ 331 timeout(lptout, (caddr_t)dev, 10*hz); 332 } 333 334 lpreset(uban) 335 int uban; 336 { 337 register struct uba_device *ui; 338 register struct lpdevice *lpaddr; 339 register int unit; 340 341 for (unit = 0; unit < NLP; unit++) { 342 if ((ui = lpinfo[unit]) == 0 || ui->ui_ubanum != uban || 343 ui->ui_alive == 0) 344 continue; 345 printf(" lp%d", unit); 346 lpaddr = (struct lpdevice *)ui->ui_addr; 347 lpaddr->lpsr |= IENABLE; 348 } 349 } 350 #endif 351