1 /* $NetBSD: lpt.c,v 1.43 1996/12/05 01:25:42 cgd Exp $ */ 2 3 /* 4 * Copyright (c) 1993, 1994 Charles Hannum. 5 * Copyright (c) 1990 William F. Jolitz, TeleMuse 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This software is a component of "386BSD" developed by 19 * William F. Jolitz, TeleMuse. 20 * 4. Neither the name of the developer nor the name "386BSD" 21 * may be used to endorse or promote products derived from this software 22 * without specific prior written permission. 23 * 24 * THIS SOFTWARE IS A COMPONENT OF 386BSD DEVELOPED BY WILLIAM F. JOLITZ 25 * AND IS INTENDED FOR RESEARCH AND EDUCATIONAL PURPOSES ONLY. THIS 26 * SOFTWARE SHOULD NOT BE CONSIDERED TO BE A COMMERCIAL PRODUCT. 27 * THE DEVELOPER URGES THAT USERS WHO REQUIRE A COMMERCIAL PRODUCT 28 * NOT MAKE USE OF THIS WORK. 29 * 30 * FOR USERS WHO WISH TO UNDERSTAND THE 386BSD SYSTEM DEVELOPED 31 * BY WILLIAM F. JOLITZ, WE RECOMMEND THE USER STUDY WRITTEN 32 * REFERENCES SUCH AS THE "PORTING UNIX TO THE 386" SERIES 33 * (BEGINNING JANUARY 1991 "DR. DOBBS JOURNAL", USA AND BEGINNING 34 * JUNE 1991 "UNIX MAGAZIN", GERMANY) BY WILLIAM F. JOLITZ AND 35 * LYNNE GREER JOLITZ, AS WELL AS OTHER BOOKS ON UNIX AND THE 36 * ON-LINE 386BSD USER MANUAL BEFORE USE. A BOOK DISCUSSING THE INTERNALS 37 * OF 386BSD ENTITLED "386BSD FROM THE INSIDE OUT" WILL BE AVAILABLE LATE 1992. 38 * 39 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPER ``AS IS'' AND 40 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 41 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 42 * ARE DISCLAIMED. IN NO EVENT SHALL THE DEVELOPER BE LIABLE 43 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 44 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 45 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 46 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 47 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 48 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 49 * SUCH DAMAGE. 50 */ 51 52 /* 53 * Device Driver for AT parallel printer port 54 */ 55 56 #include <sys/param.h> 57 #include <sys/systm.h> 58 #include <sys/proc.h> 59 #include <sys/user.h> 60 #include <sys/buf.h> 61 #include <sys/kernel.h> 62 #include <sys/ioctl.h> 63 #include <sys/uio.h> 64 #include <sys/device.h> 65 #include <sys/conf.h> 66 #include <sys/syslog.h> 67 68 #include <machine/bus.h> 69 #include <machine/intr.h> 70 71 #include <dev/isa/isavar.h> 72 #include <dev/isa/lptreg.h> 73 74 #define TIMEOUT hz*16 /* wait up to 16 seconds for a ready */ 75 #define STEP hz/4 76 77 #define LPTPRI (PZERO+8) 78 #define LPT_BSIZE 1024 79 80 #if !defined(DEBUG) || !defined(notdef) 81 #define LPRINTF(a) 82 #else 83 #define LPRINTF if (lptdebug) printf a 84 int lptdebug = 1; 85 #endif 86 87 struct lpt_softc { 88 struct device sc_dev; 89 void *sc_ih; 90 91 size_t sc_count; 92 struct buf *sc_inbuf; 93 u_char *sc_cp; 94 int sc_spinmax; 95 int sc_iobase; 96 bus_space_tag_t sc_iot; 97 bus_space_handle_t sc_ioh; 98 int sc_irq; 99 u_char sc_state; 100 #define LPT_OPEN 0x01 /* device is open */ 101 #define LPT_OBUSY 0x02 /* printer is busy doing output */ 102 #define LPT_INIT 0x04 /* waiting to initialize for open */ 103 u_char sc_flags; 104 #define LPT_AUTOLF 0x20 /* automatic LF on CR */ 105 #define LPT_NOPRIME 0x40 /* don't prime on open */ 106 #define LPT_NOINTR 0x80 /* do not use interrupt */ 107 u_char sc_control; 108 u_char sc_laststatus; 109 }; 110 111 /* XXX does not belong here */ 112 cdev_decl(lpt); 113 114 #ifdef __BROKEN_INDIRECT_CONFIG 115 int lptprobe __P((struct device *, void *, void *)); 116 #else 117 int lptprobe __P((struct device *, struct cfdata *, void *)); 118 #endif 119 void lptattach __P((struct device *, struct device *, void *)); 120 int lptintr __P((void *)); 121 122 struct cfattach lpt_ca = { 123 sizeof(struct lpt_softc), lptprobe, lptattach 124 }; 125 126 struct cfdriver lpt_cd = { 127 NULL, "lpt", DV_TTY 128 }; 129 130 #define LPTUNIT(s) (minor(s) & 0x1f) 131 #define LPTFLAGS(s) (minor(s) & 0xe0) 132 133 #define LPS_INVERT (LPS_SELECT|LPS_NERR|LPS_NBSY|LPS_NACK) 134 #define LPS_MASK (LPS_SELECT|LPS_NERR|LPS_NBSY|LPS_NACK|LPS_NOPAPER) 135 #define NOT_READY() ((bus_space_read_1(iot, ioh, lpt_status) ^ LPS_INVERT) & LPS_MASK) 136 #define NOT_READY_ERR() not_ready(bus_space_read_1(iot, ioh, lpt_status), sc) 137 static int not_ready __P((u_char, struct lpt_softc *)); 138 139 static void lptwakeup __P((void *arg)); 140 static int pushbytes __P((struct lpt_softc *)); 141 142 int lpt_port_test __P((bus_space_tag_t, bus_space_handle_t, bus_addr_t, 143 bus_size_t, u_char, u_char)); 144 145 /* 146 * Internal routine to lptprobe to do port tests of one byte value. 147 */ 148 int 149 lpt_port_test(iot, ioh, base, off, data, mask) 150 bus_space_tag_t iot; 151 bus_space_handle_t ioh; 152 bus_addr_t base; 153 bus_size_t off; 154 u_char data, mask; 155 { 156 int timeout; 157 u_char temp; 158 159 data &= mask; 160 bus_space_write_1(iot, ioh, off, data); 161 timeout = 1000; 162 do { 163 delay(10); 164 temp = bus_space_read_1(iot, ioh, off) & mask; 165 } while (temp != data && --timeout); 166 LPRINTF(("lpt: port=0x%x out=0x%x in=0x%x timeout=%d\n", base + off, 167 data, temp, timeout)); 168 return (temp == data); 169 } 170 171 /* 172 * Logic: 173 * 1) You should be able to write to and read back the same value 174 * to the data port. Do an alternating zeros, alternating ones, 175 * walking zero, and walking one test to check for stuck bits. 176 * 177 * 2) You should be able to write to and read back the same value 178 * to the control port lower 5 bits, the upper 3 bits are reserved 179 * per the IBM PC technical reference manauls and different boards 180 * do different things with them. Do an alternating zeros, alternating 181 * ones, walking zero, and walking one test to check for stuck bits. 182 * 183 * Some printers drag the strobe line down when the are powered off 184 * so this bit has been masked out of the control port test. 185 * 186 * XXX Some printers may not like a fast pulse on init or strobe, I 187 * don't know at this point, if that becomes a problem these bits 188 * should be turned off in the mask byte for the control port test. 189 * 190 * 3) Set the data and control ports to a value of 0 191 */ 192 int 193 lptprobe(parent, match, aux) 194 struct device *parent; 195 #ifdef __BROKEN_INDIRECT_CONFIG 196 void *match; 197 #else 198 struct cfdata *match; 199 #endif 200 void *aux; 201 { 202 struct isa_attach_args *ia = aux; 203 bus_space_tag_t iot; 204 bus_space_handle_t ioh; 205 u_long base; 206 u_char mask, data; 207 int i, rv; 208 209 #ifdef DEBUG 210 #define ABORT do {printf("lptprobe: mask %x data %x failed\n", mask, data); \ 211 goto out;} while (0) 212 #else 213 #define ABORT goto out 214 #endif 215 216 iot = ia->ia_iot; 217 base = ia->ia_iobase; 218 if (bus_space_map(iot, base, LPT_NPORTS, 0, &ioh)) 219 return 0; 220 221 rv = 0; 222 mask = 0xff; 223 224 data = 0x55; /* Alternating zeros */ 225 if (!lpt_port_test(iot, ioh, base, lpt_data, data, mask)) 226 ABORT; 227 228 data = 0xaa; /* Alternating ones */ 229 if (!lpt_port_test(iot, ioh, base, lpt_data, data, mask)) 230 ABORT; 231 232 for (i = 0; i < CHAR_BIT; i++) { /* Walking zero */ 233 data = ~(1 << i); 234 if (!lpt_port_test(iot, ioh, base, lpt_data, data, mask)) 235 ABORT; 236 } 237 238 for (i = 0; i < CHAR_BIT; i++) { /* Walking one */ 239 data = (1 << i); 240 if (!lpt_port_test(iot, ioh, base, lpt_data, data, mask)) 241 ABORT; 242 } 243 244 bus_space_write_1(iot, ioh, lpt_data, 0); 245 bus_space_write_1(iot, ioh, lpt_control, 0); 246 247 ia->ia_iosize = LPT_NPORTS; 248 ia->ia_msize = 0; 249 250 rv = 1; 251 252 out: 253 bus_space_unmap(iot, ioh, LPT_NPORTS); 254 return rv; 255 } 256 257 void 258 lptattach(parent, self, aux) 259 struct device *parent, *self; 260 void *aux; 261 { 262 struct lpt_softc *sc = (void *)self; 263 struct isa_attach_args *ia = aux; 264 bus_space_tag_t iot; 265 bus_space_handle_t ioh; 266 267 if (ia->ia_irq != IRQUNK) 268 printf("\n"); 269 else 270 printf(": polled\n"); 271 272 sc->sc_iobase = ia->ia_iobase; 273 sc->sc_irq = ia->ia_irq; 274 sc->sc_state = 0; 275 276 iot = sc->sc_iot = ia->ia_iot; 277 if (bus_space_map(iot, sc->sc_iobase, LPT_NPORTS, 0, &ioh)) 278 panic("lptattach: couldn't map I/O ports"); 279 sc->sc_ioh = ioh; 280 281 bus_space_write_1(iot, ioh, lpt_control, LPC_NINIT); 282 283 if (ia->ia_irq != IRQUNK) 284 sc->sc_ih = isa_intr_establish(ia->ia_ic, ia->ia_irq, IST_EDGE, 285 IPL_TTY, lptintr, sc); 286 } 287 288 /* 289 * Reset the printer, then wait until it's selected and not busy. 290 */ 291 int 292 lptopen(dev, flag, mode, p) 293 dev_t dev; 294 int flag; 295 int mode; 296 struct proc *p; 297 { 298 int unit = LPTUNIT(dev); 299 u_char flags = LPTFLAGS(dev); 300 struct lpt_softc *sc; 301 bus_space_tag_t iot; 302 bus_space_handle_t ioh; 303 u_char control; 304 int error; 305 int spin; 306 307 if (unit >= lpt_cd.cd_ndevs) 308 return ENXIO; 309 sc = lpt_cd.cd_devs[unit]; 310 if (!sc) 311 return ENXIO; 312 313 if (sc->sc_irq == IRQUNK && (flags & LPT_NOINTR) == 0) 314 return ENXIO; 315 316 #ifdef DIAGNOSTIC 317 if (sc->sc_state) 318 printf("%s: stat=0x%x not zero\n", sc->sc_dev.dv_xname, 319 sc->sc_state); 320 #endif 321 322 if (sc->sc_state) 323 return EBUSY; 324 325 sc->sc_state = LPT_INIT; 326 sc->sc_flags = flags; 327 LPRINTF(("%s: open: flags=0x%x\n", sc->sc_dev.dv_xname, flags)); 328 iot = sc->sc_iot; 329 ioh = sc->sc_ioh; 330 331 if ((flags & LPT_NOPRIME) == 0) { 332 /* assert INIT for 100 usec to start up printer */ 333 bus_space_write_1(iot, ioh, lpt_control, LPC_SELECT); 334 delay(100); 335 } 336 337 control = LPC_SELECT | LPC_NINIT; 338 bus_space_write_1(iot, ioh, lpt_control, control); 339 340 /* wait till ready (printer running diagnostics) */ 341 for (spin = 0; NOT_READY_ERR(); spin += STEP) { 342 if (spin >= TIMEOUT) { 343 sc->sc_state = 0; 344 return EBUSY; 345 } 346 347 /* wait 1/4 second, give up if we get a signal */ 348 error = tsleep((caddr_t)sc, LPTPRI | PCATCH, "lptopen", STEP); 349 if (error != EWOULDBLOCK) { 350 sc->sc_state = 0; 351 return error; 352 } 353 } 354 355 if ((flags & LPT_NOINTR) == 0) 356 control |= LPC_IENABLE; 357 if (flags & LPT_AUTOLF) 358 control |= LPC_AUTOLF; 359 sc->sc_control = control; 360 bus_space_write_1(iot, ioh, lpt_control, control); 361 362 sc->sc_inbuf = geteblk(LPT_BSIZE); 363 sc->sc_count = 0; 364 sc->sc_state = LPT_OPEN; 365 366 if ((sc->sc_flags & LPT_NOINTR) == 0) 367 lptwakeup(sc); 368 369 LPRINTF(("%s: opened\n", sc->sc_dev.dv_xname)); 370 return 0; 371 } 372 373 int 374 not_ready(status, sc) 375 u_char status; 376 struct lpt_softc *sc; 377 { 378 u_char new; 379 380 status = (status ^ LPS_INVERT) & LPS_MASK; 381 new = status & ~sc->sc_laststatus; 382 sc->sc_laststatus = status; 383 384 if (new & LPS_SELECT) 385 log(LOG_NOTICE, "%s: offline\n", sc->sc_dev.dv_xname); 386 else if (new & LPS_NOPAPER) 387 log(LOG_NOTICE, "%s: out of paper\n", sc->sc_dev.dv_xname); 388 else if (new & LPS_NERR) 389 log(LOG_NOTICE, "%s: output error\n", sc->sc_dev.dv_xname); 390 391 return status; 392 } 393 394 void 395 lptwakeup(arg) 396 void *arg; 397 { 398 struct lpt_softc *sc = arg; 399 int s; 400 401 s = spltty(); 402 lptintr(sc); 403 splx(s); 404 405 timeout(lptwakeup, sc, STEP); 406 } 407 408 /* 409 * Close the device, and free the local line buffer. 410 */ 411 int 412 lptclose(dev, flag, mode, p) 413 dev_t dev; 414 int flag; 415 int mode; 416 struct proc *p; 417 { 418 int unit = LPTUNIT(dev); 419 struct lpt_softc *sc = lpt_cd.cd_devs[unit]; 420 bus_space_tag_t iot = sc->sc_iot; 421 bus_space_handle_t ioh = sc->sc_ioh; 422 423 if (sc->sc_count) 424 (void) pushbytes(sc); 425 426 if ((sc->sc_flags & LPT_NOINTR) == 0) 427 untimeout(lptwakeup, sc); 428 429 bus_space_write_1(iot, ioh, lpt_control, LPC_NINIT); 430 sc->sc_state = 0; 431 bus_space_write_1(iot, ioh, lpt_control, LPC_NINIT); 432 brelse(sc->sc_inbuf); 433 434 LPRINTF(("%s: closed\n", sc->sc_dev.dv_xname)); 435 return 0; 436 } 437 438 int 439 pushbytes(sc) 440 struct lpt_softc *sc; 441 { 442 bus_space_tag_t iot = sc->sc_iot; 443 bus_space_handle_t ioh = sc->sc_ioh; 444 int error; 445 446 if (sc->sc_flags & LPT_NOINTR) { 447 int spin, tic; 448 u_char control = sc->sc_control; 449 450 while (sc->sc_count > 0) { 451 spin = 0; 452 while (NOT_READY()) { 453 if (++spin < sc->sc_spinmax) 454 continue; 455 tic = 0; 456 /* adapt busy-wait algorithm */ 457 sc->sc_spinmax++; 458 while (NOT_READY_ERR()) { 459 /* exponential backoff */ 460 tic = tic + tic + 1; 461 if (tic > TIMEOUT) 462 tic = TIMEOUT; 463 error = tsleep((caddr_t)sc, 464 LPTPRI | PCATCH, "lptpsh", tic); 465 if (error != EWOULDBLOCK) 466 return error; 467 } 468 break; 469 } 470 471 bus_space_write_1(iot, ioh, lpt_data, *sc->sc_cp++); 472 bus_space_write_1(iot, ioh, lpt_control, control | LPC_STROBE); 473 sc->sc_count--; 474 bus_space_write_1(iot, ioh, lpt_control, control); 475 476 /* adapt busy-wait algorithm */ 477 if (spin*2 + 16 < sc->sc_spinmax) 478 sc->sc_spinmax--; 479 } 480 } else { 481 int s; 482 483 while (sc->sc_count > 0) { 484 /* if the printer is ready for a char, give it one */ 485 if ((sc->sc_state & LPT_OBUSY) == 0) { 486 LPRINTF(("%s: write %d\n", sc->sc_dev.dv_xname, 487 sc->sc_count)); 488 s = spltty(); 489 (void) lptintr(sc); 490 splx(s); 491 } 492 error = tsleep((caddr_t)sc, LPTPRI | PCATCH, 493 "lptwrite2", 0); 494 if (error) 495 return error; 496 } 497 } 498 return 0; 499 } 500 501 /* 502 * Copy a line from user space to a local buffer, then call putc to get the 503 * chars moved to the output queue. 504 */ 505 int 506 lptwrite(dev, uio, flags) 507 dev_t dev; 508 struct uio *uio; 509 int flags; 510 { 511 struct lpt_softc *sc = lpt_cd.cd_devs[LPTUNIT(dev)]; 512 size_t n; 513 int error = 0; 514 515 while ((n = min(LPT_BSIZE, uio->uio_resid)) != 0) { 516 uiomove(sc->sc_cp = sc->sc_inbuf->b_data, n, uio); 517 sc->sc_count = n; 518 error = pushbytes(sc); 519 if (error) { 520 /* 521 * Return accurate residual if interrupted or timed 522 * out. 523 */ 524 uio->uio_resid += sc->sc_count; 525 sc->sc_count = 0; 526 return error; 527 } 528 } 529 return 0; 530 } 531 532 /* 533 * Handle printer interrupts which occur when the printer is ready to accept 534 * another char. 535 */ 536 int 537 lptintr(arg) 538 void *arg; 539 { 540 struct lpt_softc *sc = arg; 541 bus_space_tag_t iot = sc->sc_iot; 542 bus_space_handle_t ioh = sc->sc_ioh; 543 544 #if 0 545 if ((sc->sc_state & LPT_OPEN) == 0) 546 return 0; 547 #endif 548 549 /* is printer online and ready for output */ 550 if (NOT_READY() && NOT_READY_ERR()) 551 return 0; 552 553 if (sc->sc_count) { 554 u_char control = sc->sc_control; 555 /* send char */ 556 bus_space_write_1(iot, ioh, lpt_data, *sc->sc_cp++); 557 bus_space_write_1(iot, ioh, lpt_control, control | LPC_STROBE); 558 sc->sc_count--; 559 bus_space_write_1(iot, ioh, lpt_control, control); 560 sc->sc_state |= LPT_OBUSY; 561 } else 562 sc->sc_state &= ~LPT_OBUSY; 563 564 if (sc->sc_count == 0) { 565 /* none, wake up the top half to get more */ 566 wakeup((caddr_t)sc); 567 } 568 569 return 1; 570 } 571 572 int 573 lptioctl(dev, cmd, data, flag, p) 574 dev_t dev; 575 u_long cmd; 576 caddr_t data; 577 int flag; 578 struct proc *p; 579 { 580 int error = 0; 581 582 switch (cmd) { 583 default: 584 error = ENODEV; 585 } 586 587 return error; 588 } 589