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