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