int parrw(dev_t dev, register struct uio *uio) { int unit = UNIT(dev); register struct par_softc *sc = getparsp(unit); register int s, len, cnt; register char *cp; int error = 0, gotdata = 0; int buflen; char *buf; len = 0; cnt = 0; if (!!(sc->sc_flags & PARF_OREAD) ^ (uio->uio_rw == UIO_READ)) return EINVAL; if (uio->uio_resid == 0) return(0); #ifdef DEBUG if (pardebug & (PDB_FOLLOW|PDB_IO)) printf("parrw(%llx, %p, %c): burst %d, timo %d, resid %x\n", dev, uio, uio->uio_rw == UIO_READ ? 'R' : 'W', sc->sc_burst, sc->sc_timo, uio->uio_resid); #endif buflen = min(sc->sc_burst, uio->uio_resid); buf = (char *)malloc(buflen, M_DEVBUF, M_WAITOK); sc->sc_flags |= PARF_UIO; if (sc->sc_timo > 0) { sc->sc_flags |= PARF_TIMO; callout_reset(&sc->sc_timo_ch, sc->sc_timo, partimo, sc); } while (uio->uio_resid > 0) { len = min(buflen, uio->uio_resid); cp = buf; if (uio->uio_rw == UIO_WRITE) { error = uiomove(cp, len, uio); if (error) break; } again: #if 0 if ((sc->sc_flags & PARF_UIO) && hpibreq(&sc->sc_dq) == 0) sleep(sc, PRIBIO+1); #endif /* * Check if we timed out during sleep or uiomove */ s = splsoftclock(); if ((sc->sc_flags & PARF_UIO) == 0) { #ifdef DEBUG if (pardebug & PDB_IO) printf("parrw: uiomove/sleep timo, flags %x\n", sc->sc_flags); #endif if (sc->sc_flags & PARF_TIMO) { callout_stop(&sc->sc_timo_ch); sc->sc_flags &= ~PARF_TIMO; } splx(s); break; } splx(s); /* * Perform the operation */ if (uio->uio_rw == UIO_WRITE) cnt = parsend (cp, len); else cnt = parreceive (cp, len); if (cnt < 0) { error = -cnt; break; } s = splbio(); #if 0 hpibfree(&sc->sc_dq); #endif #ifdef DEBUG if (pardebug & PDB_IO) printf("parrw: %s(%p, %d) -> %d\n", uio->uio_rw == UIO_READ ? "recv" : "send", cp, len, cnt); #endif splx(s); if (uio->uio_rw == UIO_READ) { if (cnt) { error = uiomove(cp, cnt, uio); if (error) break; gotdata++; } /* * Didn't get anything this time, but did in the past. * Consider us done. */ else if (gotdata) break; } s = splsoftclock(); /* * Operation timeout (or non-blocking), quit now. */ if ((sc->sc_flags & PARF_UIO) == 0) { #ifdef DEBUG if (pardebug & PDB_IO) printf("parrw: timeout/done\n"); #endif splx(s); break; } /* * Implement inter-read delay */ if (sc->sc_delay > 0) { sc->sc_flags |= PARF_DELAY; callout_reset(&sc->sc_start_ch, sc->sc_delay, parstart, sc); error = tsleep(sc, PCATCH | (PZERO - 1), "par-cdelay", 0); if (error) { splx(s); break; } } splx(s); /* * Must not call uiomove again til we've used all data * that we already grabbed. */ if (uio->uio_rw == UIO_WRITE && cnt != len) { cp += cnt; len -= cnt; cnt = 0; goto again; } } s = splsoftclock(); if (sc->sc_flags & PARF_TIMO) { callout_stop(&sc->sc_timo_ch); sc->sc_flags &= ~PARF_TIMO; } if (sc->sc_flags & PARF_DELAY) { callout_stop(&sc->sc_start_ch); sc->sc_flags &= ~PARF_DELAY; } splx(s); /* * Adjust for those chars that we uiomove'ed but never wrote */ if (uio->uio_rw == UIO_WRITE && cnt != len) { uio->uio_resid += (len - cnt); #ifdef DEBUG if (pardebug & PDB_IO) printf("parrw: short write, adjust by %d\n", len-cnt); #endif } free(buf, M_DEVBUF); #ifdef DEBUG if (pardebug & (PDB_FOLLOW|PDB_IO)) printf("parrw: return %d, resid %d\n", error, uio->uio_resid); #endif return (error); }
int parrw(dev_t dev, struct uio *uio) { int unit = UNIT(dev); struct par_softc *sc = device_lookup_private(&par_cd, unit); int len=0xdeadbeef; /* XXX: shutup gcc */ int s, cnt=0; char *cp; int error = 0; int buflen; char *buf; if (!!(sc->sc_flags & PARF_OREAD) ^ (uio->uio_rw == UIO_READ)) return EINVAL; if (uio->uio_resid == 0) return(0); buflen = min(sc->sc_burst, uio->uio_resid); buf = (char *)malloc(buflen, M_DEVBUF, M_WAITOK); sc->sc_flags |= PARF_UIO; if (sc->sc_timo > 0) { sc->sc_flags |= PARF_TIMO; callout_reset(&sc->sc_timo_ch, sc->sc_timo, partimo, sc); } while (uio->uio_resid > 0) { len = min(buflen, uio->uio_resid); cp = buf; if (uio->uio_rw == UIO_WRITE) { error = uiomove(cp, len, uio); if (error) break; } again: s = splsoftclock(); /* * Check if we timed out during sleep or uiomove */ if ((sc->sc_flags & PARF_UIO) == 0) { #ifdef DEBUG if (pardebug & PDB_IO) printf("parrw: uiomove/sleep timo, flags %x\n", sc->sc_flags); #endif if (sc->sc_flags & PARF_TIMO) { callout_stop(&sc->sc_timo_ch); sc->sc_flags &= ~PARF_TIMO; } splx(s); break; } splx(s); /* * Perform the operation */ cnt = parsend(sc, cp, len); if (cnt < 0) { error = -cnt; break; } s = splsoftclock(); /* * Operation timeout (or non-blocking), quit now. */ if ((sc->sc_flags & PARF_UIO) == 0) { #ifdef DEBUG if (pardebug & PDB_IO) printf("parrw: timeout/done\n"); #endif splx(s); break; } /* * Implement inter-read delay */ if (sc->sc_delay > 0) { sc->sc_flags |= PARF_DELAY; callout_reset(&sc->sc_start_ch, sc->sc_delay, parstart, sc); error = tsleep(sc, PCATCH|(PZERO-1), "par-cdelay", 0); if (error) { splx(s); break; } } splx(s); /* * Must not call uiomove again til we've used all data * that we already grabbed. */ if (uio->uio_rw == UIO_WRITE && cnt != len) { cp += cnt; len -= cnt; cnt = 0; goto again; } } s = splsoftclock(); if (sc->sc_flags & PARF_TIMO) { callout_stop(&sc->sc_timo_ch); sc->sc_flags &= ~PARF_TIMO; } if (sc->sc_flags & PARF_DELAY) { callout_stop(&sc->sc_start_ch); sc->sc_flags &= ~PARF_DELAY; } splx(s); /* * Adjust for those chars that we uiomove'ed but never wrote */ /* * XXXjdolecek: this len usage is wrong, this will be incorrect * if the transfer size is longer than sc_burst */ if (uio->uio_rw == UIO_WRITE && cnt != len) { uio->uio_resid += (len - cnt); #ifdef DEBUG if (pardebug & PDB_IO) printf("parrw: short write, adjust by %d\n", len-cnt); #endif } free(buf, M_DEVBUF); #ifdef DEBUG if (pardebug & (PDB_FOLLOW|PDB_IO)) printf("parrw: return %d, resid %d\n", error, uio->uio_resid); #endif return (error); }