/* * lptread --retrieve printer status in IEEE1284 NIBBLE mode */ int lptread(dev_t dev_id, struct uio *uio, int ioflag) { size_t len = 0; int error = 0; device_t dev = device_lookup(&lpt_cd, LPTUNIT(dev_id)); struct lpt_softc *sc = device_private(dev); if(!(sc->sc_state & HAVEBUS)) { LPT_DPRINTF(("%s(%s): attempt to read using device which does " "not own the bus(%s).\n", __func__, device_xname(dev), device_xname(device_parent(dev)))); return (ENODEV); } sc->sc_state &= ~INTERRUPTED; while (uio->uio_resid) { error = ppbus_read(device_parent(dev), sc->sc_outbuf, min(BUFSIZE, uio->uio_resid), 0, &len); /* If error or no more data, stop */ if (error) { if (error != EWOULDBLOCK) sc->sc_state |= INTERRUPTED; break; } if (len == 0) break; if ((error = uiomove(sc->sc_outbuf, len, uio))) break; } return error; }
/* * Copy a line from user space to a local buffer, then call putc to get the * chars moved to the output queue. */ int lptwrite(dev_t dev, struct uio *uio, int flags) { struct lpt_softc *sc; size_t n; int error; sc = device_lookup_private(&lpt_cd, LPTUNIT(dev)); error = 0; while ((n = min(LPT_BSIZE, uio->uio_resid)) != 0) { uiomove(sc->sc_cp = sc->sc_inbuf->b_data, n, uio); sc->sc_count = n; error = pushbytes(sc); if (error) { /* * Return accurate residual if interrupted or timed * out. */ uio->uio_resid += sc->sc_count; sc->sc_count = 0; return (error); } } return (0); }
/* * lptclose -- close the device, free the local line buffer. * * Check for interrupted write call added. */ int lptclose(dev_t dev_id, int flags, int fmt, struct lwp *l) { device_t dev = device_lookup(&lpt_cd, LPTUNIT(dev_id)); struct lpt_softc *sc = device_private(dev); int err; err = lpt_release_ppbus(sc, PPBUS_WAIT|PPBUS_INTR); if(err) { LPT_DPRINTF(("%s(%s): error (%d) while releasing ppbus.\n", __func__, device_xname(dev), err)); } sc->sc_state = 0; return err; }
static int lptwrite(dev_t dev, struct uio * uio, int ioflag) { register unsigned n; int pl, err; struct lpt_softc *sc; sc = devclass_get_softc(olpt_devclass, LPTUNIT(minor(dev))); if(sc->sc_flags & LP_BYPASS) { /* we can't do writes in bypass mode */ return(EPERM); } sc->sc_state &= ~INTERRUPTED; while ((n = min(BUFSIZE, uio->uio_resid)) != 0) { sc->sc_cp = sc->sc_inbuf->b_data ; uiomove(sc->sc_cp, n, uio); sc->sc_xfercnt = n ; while ((sc->sc_xfercnt > 0)&&(sc->sc_irq & LP_USE_IRQ)) { lprintf(("i")); /* if the printer is ready for a char, */ /* give it one */ if ((sc->sc_state & OBUSY) == 0){ lprintf(("\nC %d. ", sc->sc_xfercnt)); pl = spltty(); lpt_intr(sc); (void) splx(pl); } lprintf(("W ")); if (sc->sc_state & OBUSY) if ((err = tsleep ((caddr_t)sc, LPPRI|PCATCH, "lpwrite", 0))) { sc->sc_state |= INTERRUPTED; return(err); } } /* check to see if we must do a polled write */ if(!(sc->sc_irq & LP_USE_IRQ) && (sc->sc_xfercnt)) { lprintf(("p")); if((err = pushbytes(sc))) return(err); } } return(0); }
/* * lptwrite --copy a line from user space to a local buffer, then call * putc to get the chars moved to the output queue. * * Flagging of interrupted write added. */ int lptwrite(dev_t dev_id, struct uio * uio, int ioflag) { int error=0; size_t n, cnt; device_t dev = device_lookup(&lpt_cd, LPTUNIT(dev_id)); struct lpt_softc * sc = device_private(dev); /* Check state and flags */ if(!(sc->sc_state & HAVEBUS)) { LPT_DPRINTF(("%s(%s): attempt to write using device which does " "not own the bus(%s).\n", __func__, device_xname(dev), device_xname(device_parent(dev)))); return EINVAL; } LPT_VPRINTF(("%s(%s): writing %zu bytes\n", __func__, device_xname(dev), uio->uio_resid)); /* Write the data */ sc->sc_state &= ~INTERRUPTED; while (uio->uio_resid) { n = MIN(BUFSIZE, uio->uio_resid); error = uiomove(sc->sc_inbuf, n, uio); if (error) break; error = ppbus_write(device_parent(dev), sc->sc_inbuf, n, ioflag, &cnt); if (error) { if (error != EWOULDBLOCK) sc->sc_state |= INTERRUPTED; break; } } LPT_VPRINTF(("%s(%s): transfer finished, error %d.\n", __func__, device_xname(dev), error)); return error; }
static int lptioctl(dev_t dev, u_long cmd, caddr_t data, int flags, struct thread *td) { int error = 0; struct lpt_softc *sc; u_int unit = LPTUNIT(minor(dev)); u_char old_sc_irq; /* old printer IRQ status */ sc = devclass_get_softc(olpt_devclass, unit); switch (cmd) { case LPT_IRQ : if(sc->sc_irq & LP_HAS_IRQ) { /* * NOTE: * If the IRQ status is changed, * this will only be visible on the * next open. * * If interrupt status changes, * this gets syslog'd. */ old_sc_irq = sc->sc_irq; if(*(int*)data == 0) sc->sc_irq &= (~LP_ENABLE_IRQ); else sc->sc_irq |= LP_ENABLE_IRQ; if (old_sc_irq != sc->sc_irq ) log(LOG_NOTICE, "lpt%c switched to %s mode\n", (char)unit+'0', (sc->sc_irq & LP_ENABLE_IRQ)? "interrupt-driven":"polled"); } else /* polled port */ error = EOPNOTSUPP; break; default: error = ENODEV; } return(error); }
/* * Close the device, and free the local line buffer. */ int lptclose(dev_t dev, int flag, int mode, struct lwp *l) { struct lpt_softc *sc; sc = device_lookup_private(&lpt_cd, LPTUNIT(dev)); if (sc->sc_count) (void) pushbytes(sc); if ((sc->sc_flags & LPT_NOINTR) == 0) callout_stop(&sc->sc_wakeup_ch); (sc->sc_funcs->lf_close) (sc); sc->sc_state = 0; brelse(sc->sc_inbuf, 0); LPRINTF((sc->sc_dev, "%s: closed\n")); return (0); }
static int lptclose(dev_t dev, int flags, int fmt, struct thread *td) { struct lpt_softc *sc; #ifndef PC98 int port; #endif sc = devclass_get_softc(olpt_devclass, LPTUNIT(minor(dev))); if(sc->sc_flags & LP_BYPASS) goto end_close; #ifndef PC98 port = sc->sc_port; #endif sc->sc_state &= ~OPEN; #ifndef PC98 /* if the last write was interrupted, don't complete it */ if((!(sc->sc_state & INTERRUPTED)) && (sc->sc_irq & LP_USE_IRQ)) while ((inb(port+lpt_status) & (LPS_SEL|LPS_OUT|LPS_NBSY|LPS_NERR)) != (LPS_SEL|LPS_NBSY|LPS_NERR) || sc->sc_xfercnt) /* wait 1/4 second, give up if we get a signal */ if (tsleep ((caddr_t)sc, LPPRI|PCATCH, "lpclose", hz) != EWOULDBLOCK) break; outb(sc->sc_port+lpt_control, LPC_NINIT); #endif brelse(sc->sc_inbuf); end_close: sc->sc_state = 0; sc->sc_xfercnt = 0; lprintf(("closed.\n")); return(0); }
/* Printer ioctl */ int lptioctl(dev_t dev_id, u_long cmd, void *data, int flags, struct lwp *l) { device_t dev = device_lookup(&lpt_cd, LPTUNIT(dev_id)); struct lpt_softc *sc = device_private(dev); int val, fl; int error=0; if(!(sc->sc_state & HAVEBUS)) { LPT_DPRINTF(("%s(%s): attempt to perform ioctl on device which " "does not own the bus(%s).\n", __func__, device_xname(dev), device_xname(device_parent(dev)))); return EBUSY; } switch (cmd) { case LPTGMODE: switch (ppbus_get_mode(device_parent(dev))) { case PPBUS_COMPATIBLE: val = mode_standard; break; case PPBUS_NIBBLE: val = mode_nibble; break; case PPBUS_PS2: val = mode_ps2; break; case PPBUS_FAST: val = mode_fast; break; case PPBUS_EPP: val = mode_epp; break; case PPBUS_ECP: val = mode_ecp; break; default: error = EINVAL; val = mode_unknown; break; } *(int *)data = val; break; case LPTSMODE: switch (*(int *)data) { case mode_standard: val = PPBUS_COMPATIBLE; break; case mode_nibble: val = PPBUS_NIBBLE; break; case mode_ps2: val = PPBUS_PS2; break; case mode_fast: val = PPBUS_FAST; break; case mode_epp: val = PPBUS_EPP; break; case mode_ecp: val = PPBUS_ECP; break; default: error = EINVAL; val = mode_unknown; break; } if (!error) error = ppbus_set_mode(device_parent(dev), val, 0); break; case LPTGFLAGS: fl = 0; /* DMA */ error = ppbus_read_ivar(device_parent(dev), PPBUS_IVAR_DMA, &val); if (error) break; if (val) fl |= LPT_DMA; /* IEEE mode negotiation */ error = ppbus_read_ivar(device_parent(dev), PPBUS_IVAR_IEEE, &val); if (error) break; if (val) fl |= LPT_IEEE; /* interrupts */ error = ppbus_read_ivar(device_parent(dev), PPBUS_IVAR_INTR, &val); if (error) break; if (val) fl |= LPT_INTR; /* lpt-only flags */ fl |= sc->sc_flags; *(int *)data = fl; break; case LPTSFLAGS: fl = *(int *)data; /* DMA */ val = (fl & LPT_DMA); error = ppbus_write_ivar(device_parent(dev), PPBUS_IVAR_DMA, &val); if (error) break; /* IEEE mode negotiation */ val = (fl & LPT_IEEE); error = ppbus_write_ivar(device_parent(dev), PPBUS_IVAR_IEEE, &val); if (error) break; /* interrupts */ val = (fl & LPT_INTR); error = ppbus_write_ivar(device_parent(dev), PPBUS_IVAR_INTR, &val); if (error) break; /* lpt-only flags */ sc->sc_flags = fl & (LPT_PRIME|LPT_AUTOLF); break; default: error = EINVAL; break; } return error; }
/* * lptopen -- reset the printer, then wait until it's selected and not busy. */ int lptopen(dev_t dev_id, int flags, int fmt, struct lwp *l) { int trys, err; u_int8_t status; device_t dev; struct lpt_softc * lpt; struct ppbus_device_softc * ppbus_dev; device_t ppbus; dev = device_lookup(&lpt_cd, LPTUNIT(dev_id)); if(!dev) { LPT_DPRINTF(("%s(): device not configured.\n", __func__)); return ENXIO; } lpt = device_private(dev); ppbus = device_parent(dev); ppbus_dev = &(lpt->ppbus_dev); /* Request the ppbus */ err = lpt_request_ppbus(lpt, PPBUS_WAIT|PPBUS_INTR); if(err) { LPT_DPRINTF(("%s(%s): error (%d) while requesting bus.\n", __func__, device_xname(dev), err)); return (err); } /* Update bus mode */ ppbus_dev->ctx.mode = ppbus_get_mode(ppbus); /* init printer */ if ((lpt->sc_flags & LPT_PRIME) && !LPTCTL(dev_id)) { LPT_VPRINTF(("%s(%s): initializing printer.\n", __func__, device_xname(dev))); lpt->sc_state |= LPTINIT; ppbus_wctr(ppbus, LPC_SEL | LPC_NINIT); /* wait till ready (printer running diagnostics) */ for(trys = 0, status = ppbus_rstr(ppbus); (status & RDY_MASK) != LP_READY; trys += LPT_STEP, status = ppbus_rstr(ppbus)) { /* Time up waiting for the printer */ if(trys >= LPT_TIMEOUT) break; /* wait LPT_STEP ticks, give up if we get a signal */ else { err = tsleep((void *)lpt, LPPRI|PCATCH, "lptinit", LPT_STEP); if((err) && (err != EWOULDBLOCK)) { lpt->sc_state &= ~LPTINIT; LPT_DPRINTF(("%s(%s): interrupted " "during initialization.\n", __func__, device_xname(dev))); lpt_release_ppbus(lpt, PPBUS_WAIT); return (err); } } } lpt->sc_state &= ~LPTINIT; if(trys >= LPT_TIMEOUT) { LPT_DPRINTF(("%s(%s): timed out while initializing " "printer. [status %x]\n", __func__, device_xname(dev), status)); err = lpt_logstatus(dev, status); lpt_release_ppbus(lpt, PPBUS_WAIT); return (err); } else { LPT_VPRINTF(("%s(%s): printer ready.\n", __func__, device_xname(dev))); } } /* Set autolinefeed if requested */ if (lpt->sc_flags & LPT_AUTOLF) ppbus_wctr(ppbus, LPC_AUTOL); else ppbus_wctr(ppbus, 0); /* ready now */ lpt->sc_state |= OPEN; return 0; }
/* * Reset the printer, then wait until it's selected and not busy. */ int lptopen(dev_t dev, int flag, int mode, struct lwp *l) { u_char flags; struct lpt_softc *sc; int error; int spin; flags = LPTFLAGS(dev); sc = device_lookup_private(&lpt_cd, LPTUNIT(dev)); if (!sc) return (ENXIO); #ifdef DIAGNOSTIC if (sc->sc_state) aprint_verbose_dev(sc->sc_dev, "stat=0x%x not zero\n", sc->sc_state); #endif if (sc->sc_state) return (EBUSY); sc->sc_state = LPT_INIT; sc->sc_flags = flags; LPRINTF((sc->sc_dev, "open: flags=0x%x\n", flags)); if ((flags & LPT_NOPRIME) == 0) { /* assert Input Prime for 100 usec to start up printer */ (sc->sc_funcs->lf_iprime) (sc); } /* select fast or slow strobe depending on minor device number */ if (flags & LPT_FAST_STROBE) (sc->sc_funcs->lf_speed) (sc, LPT_STROBE_FAST); else (sc->sc_funcs->lf_speed) (sc, LPT_STROBE_SLOW); /* wait till ready (printer running diagnostics) */ for (spin = 0; (sc->sc_funcs->lf_notrdy) (sc, 1); spin += STEP) { if (spin >= TIMEOUT) { sc->sc_state = 0; return (EBUSY); } /* wait 1/4 second, give up if we get a signal */ error = tsleep((void *) sc, LPTPRI | PCATCH, "lptopen", STEP); if (error != EWOULDBLOCK) { sc->sc_state = 0; return (error); } } sc->sc_inbuf = geteblk(LPT_BSIZE); sc->sc_count = 0; sc->sc_state = LPT_OPEN; if ((sc->sc_flags & LPT_NOINTR) == 0) lpt_wakeup(sc); (sc->sc_funcs->lf_open) (sc, sc->sc_flags & LPT_NOINTR); LPRINTF((sc->sc_dev, "opened\n")); return (0); }
/* * Reset the printer, then wait until it's selected and not busy. */ int lptopen(dev_t dev, int flag, int mode, struct proc *p) { int unit = LPTUNIT(dev); u_int8_t flags = LPTFLAGS(dev); struct lpt_softc *sc; u_int8_t control; int error; int spin; if (unit >= lpt_cd.cd_ndevs) return ENXIO; sc = lpt_cd.cd_devs[unit]; if (!sc) return ENXIO; sc->sc_flags = (sc->sc_flags & LPT_POLLED) | flags; if ((sc->sc_flags & (LPT_POLLED|LPT_NOINTR)) == LPT_POLLED) return ENXIO; #ifdef DIAGNOSTIC if (sc->sc_state) printf("%s: stat=0x%x not zero\n", sc->sc_dev.dv_xname, sc->sc_state); #endif if (sc->sc_state) return EBUSY; sc->sc_state = LPT_INIT; LPRINTF(("%s: open: flags=0x%x\n", sc->sc_dev.dv_xname, flags)); if ((flags & LPT_NOPRIME) == 0) { /* assert INIT for 100 usec to start up printer */ bus_space_write_1(sc->sc_iot, sc->sc_ioh, lpt_control, LPC_SELECT); delay(100); } control = LPC_SELECT | LPC_NINIT; bus_space_write_1(sc->sc_iot, sc->sc_ioh, lpt_control, control); /* wait till ready (printer running diagnostics) */ for (spin = 0; NOT_READY_ERR(); spin += STEP) { if (spin >= TIMEOUT) { sc->sc_state = 0; return EBUSY; } /* wait 1/4 second, give up if we get a signal */ error = tsleep((caddr_t)sc, LPTPRI | PCATCH, "lptopen", STEP); if (sc->sc_state == 0) return (EIO); if (error != EWOULDBLOCK) { sc->sc_state = 0; return error; } } if ((flags & LPT_NOINTR) == 0) control |= LPC_IENABLE; if (flags & LPT_AUTOLF) control |= LPC_AUTOLF; sc->sc_control = control; bus_space_write_1(sc->sc_iot, sc->sc_ioh, lpt_control, control); sc->sc_inbuf = geteblk(LPT_BSIZE); sc->sc_count = 0; sc->sc_state = LPT_OPEN; if ((sc->sc_flags & LPT_NOINTR) == 0) lptwakeup(sc); LPRINTF(("%s: opened\n", sc->sc_dev.dv_xname)); return 0; }
/* * Reset the printer, then wait until it's selected and not busy. */ int lptopen(dev_t dev, int flag, int mode, struct lwp *l) { u_char flags = LPTFLAGS(dev); struct lpt_softc *sc; bus_space_tag_t iot; bus_space_handle_t ioh; u_char control; int error; int spin; sc = device_lookup_private(&lpt_cd, LPTUNIT(dev)); if (!sc || !sc->sc_dev_ok) return ENXIO; #if 0 /* XXX what to do? */ if (sc->sc_irq == IRQUNK && (flags & LPT_NOINTR) == 0) return ENXIO; #endif #ifdef DIAGNOSTIC if (sc->sc_state) aprint_verbose_dev(sc->sc_dev, "stat=0x%x not zero\n", sc->sc_state); #endif if (sc->sc_state) return EBUSY; sc->sc_state = LPT_INIT; sc->sc_flags = flags; LPRINTF(("%s: open: flags=0x%x\n", device_xname(sc->sc_dev), (unsigned)flags)); iot = sc->sc_iot; ioh = sc->sc_ioh; if ((flags & LPT_NOPRIME) == 0) { /* assert INIT for 100 usec to start up printer */ bus_space_write_1(iot, ioh, lpt_control, LPC_SELECT); delay(100); } control = LPC_SELECT | LPC_NINIT; bus_space_write_1(iot, ioh, lpt_control, control); /* wait till ready (printer running diagnostics) */ for (spin = 0; NOT_READY_ERR(); spin += STEP) { if (spin >= TIMEOUT) { sc->sc_state = 0; return EBUSY; } /* wait 1/4 second, give up if we get a signal */ error = tsleep((void *)sc, LPTPRI | PCATCH, "lptopen", STEP); if (error != EWOULDBLOCK) { sc->sc_state = 0; return error; } } if ((flags & LPT_NOINTR) == 0) control |= LPC_IENABLE; if (flags & LPT_AUTOLF) control |= LPC_AUTOLF; sc->sc_control = control; bus_space_write_1(iot, ioh, lpt_control, control); sc->sc_inbuf = malloc(LPT_BSIZE, M_DEVBUF, M_WAITOK); sc->sc_count = 0; sc->sc_state = LPT_OPEN; if ((sc->sc_flags & LPT_NOINTR) == 0) lptwakeup(sc); LPRINTF(("%s: opened\n", device_xname(sc->sc_dev))); return 0; }
static int lptopen (dev_t dev, int flags, int fmt, struct thread *td) { struct lpt_softc *sc; int s; #ifdef PC98 int port; #else int trys, port; #endif sc = devclass_get_softc(olpt_devclass, LPTUNIT(minor(dev))); if (sc->sc_port == 0) return (ENXIO); if (sc->sc_state) { lprintf(("lp: still open %x\n", sc->sc_state)); return(EBUSY); } else sc->sc_state |= INIT; sc->sc_flags = LPTFLAGS(minor(dev)); /* Check for open with BYPASS flag set. */ if (sc->sc_flags & LP_BYPASS) { sc->sc_state = OPEN; return(0); } s = spltty(); lprintf(("lp flags 0x%x\n", sc->sc_flags)); port = sc->sc_port; /* set IRQ status according to ENABLE_IRQ flag */ if (sc->sc_irq & LP_ENABLE_IRQ) sc->sc_irq |= LP_USE_IRQ; else sc->sc_irq &= ~LP_USE_IRQ; /* init printer */ #ifndef PC98 if ((sc->sc_flags & LP_NO_PRIME) == 0) { if((sc->sc_flags & LP_PRIMEOPEN) || sc->sc_primed == 0) { outb(port+lpt_control, 0); sc->sc_primed++; DELAY(500); } } outb (port+lpt_control, LPC_SEL|LPC_NINIT); /* wait till ready (printer running diagnostics) */ trys = 0; do { /* ran out of waiting for the printer */ if (trys++ >= LPINITRDY*4) { splx(s); sc->sc_state = 0; lprintf(("status %x\n", inb(port+lpt_status))); return (EBUSY); } /* wait 1/4 second, give up if we get a signal */ if (tsleep ((caddr_t)sc, LPPRI|PCATCH, "lptinit", hz/4) != EWOULDBLOCK) { sc->sc_state = 0; splx(s); return (EBUSY); } /* is printer online and ready for output */ } while ((inb(port+lpt_status) & (LPS_SEL|LPS_OUT|LPS_NBSY|LPS_NERR)) != (LPS_SEL|LPS_NBSY|LPS_NERR)); sc->sc_control = LPC_SEL|LPC_NINIT; if (sc->sc_flags & LP_AUTOLF) sc->sc_control |= LPC_AUTOL; /* enable interrupt if interrupt-driven */ if (sc->sc_irq & LP_USE_IRQ) sc->sc_control |= LPC_ENA; outb(port+lpt_control, sc->sc_control); #endif sc->sc_state = OPEN; sc->sc_inbuf = geteblk(BUFSIZE); sc->sc_xfercnt = 0; splx(s); /* only use timeout if using interrupt */ lprintf(("irq %x\n", sc->sc_irq)); if (sc->sc_irq & LP_USE_IRQ) { sc->sc_state |= TOUT; timeout (lptout, (caddr_t)sc, (sc->sc_backoff = hz/LPTOUTINITIAL)); } lprintf(("opened.\n")); return(0); }