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