/* * read request. */ static int fw_read(struct cdev *dev, struct uio *uio, int ioflag) { struct fw_drv1 *d; struct fw_xferq *ir; struct firewire_comm *fc; int err = 0, s, slept = 0; struct fw_pkt *fp; if (DEV_FWMEM(dev)) return (physio(dev, uio, ioflag)); d = dev->si_drv1; fc = d->fc; ir = d->ir; if (ir == NULL) return (fw_read_async(d, uio, ioflag)); if (ir->buf == NULL) return (EIO); FW_GLOCK(fc); readloop: if (ir->stproc == NULL) { /* iso bulkxfer */ ir->stproc = STAILQ_FIRST(&ir->stvalid); if (ir->stproc != NULL) { s = splfw(); STAILQ_REMOVE_HEAD(&ir->stvalid, link); splx(s); ir->queued = 0; } } if (ir->stproc == NULL) { /* no data avaliable */ if (slept == 0) { slept = 1; ir->flag |= FWXFERQ_WAKEUP; err = msleep(ir, FW_GMTX(fc), FWPRI, "fw_read", hz); ir->flag &= ~FWXFERQ_WAKEUP; if (err == 0) goto readloop; } else if (slept == 1) err = EIO; FW_GUNLOCK(fc); return err; } else if (ir->stproc != NULL) { /* iso bulkxfer */ FW_GUNLOCK(fc); fp = (struct fw_pkt *)fwdma_v_addr(ir->buf, ir->stproc->poffset + ir->queued); if (fc->irx_post != NULL) fc->irx_post(fc, fp->mode.ld); if (fp->mode.stream.len == 0) { err = EIO; return err; } err = uiomove((caddr_t)fp, fp->mode.stream.len + sizeof(uint32_t), uio); ir->queued++; if (ir->queued >= ir->bnpacket) { s = splfw(); STAILQ_INSERT_TAIL(&ir->stfree, ir->stproc, link); splx(s); fc->irx_enable(fc, ir->dmach); ir->stproc = NULL; } if (uio->uio_resid >= ir->psize) { slept = -1; FW_GLOCK(fc); goto readloop; } } return err; }
int fw_read(dev_t dev, struct uio *uio, int ioflag) { struct firewire_softc *sc; struct firewire_comm *fc; struct fw_drv1 *d; struct fw_xferq *ir; struct fw_pkt *fp; int err = 0, slept = 0; sc = device_lookup_private(&ieee1394if_cd, DEV2UNIT(dev)); if (sc == NULL) return ENXIO; if (DEV_FWMEM(dev)) return physio(fw_strategy, NULL, dev, ioflag, minphys, uio); d = (struct fw_drv1 *)sc->si_drv1; fc = d->fc; ir = d->ir; if (ir == NULL) return fw_read_async(d, uio, ioflag); if (ir->buf == NULL) return EIO; mutex_enter(&fc->fc_mtx); readloop: if (ir->stproc == NULL) { /* iso bulkxfer */ ir->stproc = STAILQ_FIRST(&ir->stvalid); if (ir->stproc != NULL) { STAILQ_REMOVE_HEAD(&ir->stvalid, link); ir->queued = 0; } } if (ir->stproc == NULL) { /* no data avaliable */ if (slept == 0) { slept = 1; ir->flag |= FWXFERQ_WAKEUP; mutex_exit(&fc->fc_mtx); err = tsleep(ir, FWPRI, "fw_read", hz); mutex_enter(&fc->fc_mtx); ir->flag &= ~FWXFERQ_WAKEUP; if (err == 0) goto readloop; } else if (slept == 1) err = EIO; mutex_exit(&fc->fc_mtx); return err; } else if (ir->stproc != NULL) { /* iso bulkxfer */ mutex_exit(&fc->fc_mtx); fp = (struct fw_pkt *)fwdma_v_addr(ir->buf, ir->stproc->poffset + ir->queued); if (fc->irx_post != NULL) fc->irx_post(fc, fp->mode.ld); if (fp->mode.stream.len == 0) return EIO; err = uiomove((void *)fp, fp->mode.stream.len + sizeof(uint32_t), uio); ir->queued++; if (ir->queued >= ir->bnpacket) { STAILQ_INSERT_TAIL(&ir->stfree, ir->stproc, link); fc->irx_enable(fc, ir->dmach); ir->stproc = NULL; } if (uio->uio_resid >= ir->psize) { slept = -1; mutex_enter(&fc->fc_mtx); goto readloop; } } else mutex_exit(&fc->fc_mtx); return err; }