int fw_open(dev_t dev, int flags, int fmt, struct lwp *td) { struct firewire_softc *sc; struct fw_drv1 *d; int err = 0; sc = device_lookup_private(&ieee1394if_cd, DEV2UNIT(dev)); if (sc == NULL) return ENXIO; if (DEV_FWMEM(dev)) return fwmem_open(dev, flags, fmt, td); mutex_enter(&sc->fc->fc_mtx); if (sc->si_drv1 != NULL) { mutex_exit(&sc->fc->fc_mtx); return EBUSY; } /* set dummy value for allocation */ sc->si_drv1 = (void *)-1; mutex_exit(&sc->fc->fc_mtx); sc->si_drv1 = malloc(sizeof(struct fw_drv1), M_FW, M_WAITOK | M_ZERO); if (sc->si_drv1 == NULL) return ENOMEM; d = (struct fw_drv1 *)sc->si_drv1; d->fc = sc->fc; STAILQ_INIT(&d->binds); STAILQ_INIT(&d->rq); return err; }
static int fw_write (struct dev_write_args *ap) { cdev_t dev = ap->a_head.a_dev; struct uio *uio = ap->a_uio; int err = 0; struct firewire_softc *sc; int unit = DEV2UNIT(dev); int slept = 0; struct fw_pkt *fp; struct fw_xferq *it; if (DEV_FWMEM(dev)) return physwrite(ap); sc = devclass_get_softc(firewire_devclass, unit); it = ((struct fw_drv1 *)dev->si_drv1)->it; if (it == NULL || it->buf == NULL) return (EIO); isoloop: if (it->stproc == NULL) { it->stproc = STAILQ_FIRST(&it->stfree); if (it->stproc != NULL) { crit_enter(); STAILQ_REMOVE_HEAD(&it->stfree, link); crit_exit(); it->queued = 0; } else if (slept == 0) { slept = 1; err = sc->fc->itx_enable(sc->fc, it->dmach); if (err) return err; err = tsleep(it, FWPRI, "fw_write", hz); if (err) return err; goto isoloop; } else { err = EIO; return err; } } fp = (struct fw_pkt *)fwdma_v_addr(it->buf, it->stproc->poffset + it->queued); err = uiomove((caddr_t)fp, sizeof(struct fw_isohdr), uio); err = uiomove((caddr_t)fp->mode.stream.payload, fp->mode.stream.len, uio); it->queued ++; if (it->queued >= it->bnpacket) { crit_enter(); STAILQ_INSERT_TAIL(&it->stvalid, it->stproc, link); crit_exit(); it->stproc = NULL; err = sc->fc->itx_enable(sc->fc, it->dmach); } if (uio->uio_resid >= sizeof(struct fw_isohdr)) { slept = 0; goto isoloop; } return err; }
static int fw_open (struct dev_open_args *ap) { cdev_t dev = ap->a_head.a_dev; int err = 0; if (DEV_FWMEM(dev)) return fwmem_open(ap); if (dev->si_drv1 != NULL) return (EBUSY); #if defined(__FreeBSD__) && __FreeBSD_version >= 500000 if ((dev->si_flags & SI_NAMED) == 0) { int unit = DEV2UNIT(dev); int sub = DEV2SUB(dev); make_dev(&firewire_ops, minor(dev), UID_ROOT, GID_OPERATOR, 0660, "fw%d.%d", unit, sub); } #endif dev->si_drv1 = kmalloc(sizeof(struct fw_drv1), M_FW, M_WAITOK | M_ZERO); return err; }
/* * ioctl support. */ int fw_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, fw_proc *td) { struct firewire_comm *fc; struct fw_drv1 *d; int i, len, err = 0; struct fw_device *fwdev; struct fw_bind *fwb; struct fw_xferq *ir, *it; struct fw_xfer *xfer; struct fw_pkt *fp; struct fw_devinfo *devinfo; void *ptr; struct fw_devlstreq *fwdevlst = (struct fw_devlstreq *)data; struct fw_asyreq *asyreq = (struct fw_asyreq *)data; struct fw_isochreq *ichreq = (struct fw_isochreq *)data; struct fw_isobufreq *ibufreq = (struct fw_isobufreq *)data; struct fw_asybindreq *bindreq = (struct fw_asybindreq *)data; struct fw_crom_buf *crom_buf = (struct fw_crom_buf *)data; if (DEV_FWMEM(dev)) return fwmem_ioctl(dev, cmd, data, flag, td); if (!data) return (EINVAL); d = dev->si_drv1; fc = d->fc; ir = d->ir; it = d->it; switch (cmd) { case FW_STSTREAM: if (it == NULL) { i = fw_open_isodma(fc, /* tx */1); if (i < 0) { err = EBUSY; break; } it = fc->it[i]; err = fwdev_allocbuf(fc, it, &d->bufreq.tx); if (err) { it->flag &= ~FWXFERQ_OPEN; break; } } it->flag &= ~0xff; it->flag |= (0x3f & ichreq->ch); it->flag |= ((0x3 & ichreq->tag) << 6); d->it = it; break; case FW_GTSTREAM: if (it != NULL) { ichreq->ch = it->flag & 0x3f; ichreq->tag = it->flag >> 2 & 0x3; } else
static int fw_open (struct cdev *dev, int flags, int fmt, fw_proc *td) { int err = 0; int unit = DEV2UNIT(dev); struct fw_drv1 *d; struct firewire_softc *sc; if (DEV_FWMEM(dev)) return fwmem_open(dev, flags, fmt, td); sc = devclass_get_softc(firewire_devclass, unit); if (sc == NULL) return (ENXIO); FW_GLOCK(sc->fc); if (dev->si_drv1 != NULL) { FW_GUNLOCK(sc->fc); return (EBUSY); } /* set dummy value for allocation */ dev->si_drv1 = (void *)-1; FW_GUNLOCK(sc->fc); dev->si_drv1 = malloc(sizeof(struct fw_drv1), M_FW, M_WAITOK | M_ZERO); if (dev->si_drv1 == NULL) return (ENOMEM); #if defined(__FreeBSD__) && __FreeBSD_version >= 500000 if ((dev->si_flags & SI_NAMED) == 0) { int unit = DEV2UNIT(dev); int sub = DEV2SUB(dev); make_dev(&firewire_cdevsw, dev2unit(dev), UID_ROOT, GID_OPERATOR, 0660, "fw%d.%d", unit, sub); } #endif d = (struct fw_drv1 *)dev->si_drv1; d->fc = sc->fc; STAILQ_INIT(&d->binds); STAILQ_INIT(&d->rq); return err; }
static int fw_write(struct cdev *dev, struct uio *uio, int ioflag) { int err = 0; int s, slept = 0; struct fw_drv1 *d; struct fw_pkt *fp; struct firewire_comm *fc; struct fw_xferq *it; if (DEV_FWMEM(dev)) return (physio(dev, uio, ioflag)); d = dev->si_drv1; fc = d->fc; it = d->it; if (it == NULL) return (fw_write_async(d, uio, ioflag)); if (it->buf == NULL) return (EIO); FW_GLOCK(fc); isoloop: if (it->stproc == NULL) { it->stproc = STAILQ_FIRST(&it->stfree); if (it->stproc != NULL) { s = splfw(); STAILQ_REMOVE_HEAD(&it->stfree, link); splx(s); it->queued = 0; } else if (slept == 0) { slept = 1; #if 0 /* XXX to avoid lock recursion */ err = fc->itx_enable(fc, it->dmach); if (err) goto out; #endif err = msleep(it, FW_GMTX(fc), FWPRI, "fw_write", hz); if (err) goto out; goto isoloop; } else { err = EIO; goto out; } } FW_GUNLOCK(fc); fp = (struct fw_pkt *)fwdma_v_addr(it->buf, it->stproc->poffset + it->queued); err = uiomove((caddr_t)fp, sizeof(struct fw_isohdr), uio); err = uiomove((caddr_t)fp->mode.stream.payload, fp->mode.stream.len, uio); it->queued++; if (it->queued >= it->bnpacket) { s = splfw(); STAILQ_INSERT_TAIL(&it->stvalid, it->stproc, link); splx(s); it->stproc = NULL; err = fc->itx_enable(fc, it->dmach); } if (uio->uio_resid >= sizeof(struct fw_isohdr)) { slept = 0; FW_GLOCK(fc); goto isoloop; } return err; out: FW_GUNLOCK(fc); return err; }
/* * 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; }
static int fw_close(struct cdev *dev, int flags, int fmt, fw_proc *td) { struct firewire_comm *fc; struct fw_drv1 *d; struct fw_xfer *xfer; struct fw_bind *fwb; int err = 0; if (DEV_FWMEM(dev)) return fwmem_close(dev, flags, fmt, td); d = dev->si_drv1; fc = d->fc; /* remove binding */ for (fwb = STAILQ_FIRST(&d->binds); fwb != NULL; fwb = STAILQ_FIRST(&d->binds)) { fw_bindremove(fc, fwb); STAILQ_REMOVE_HEAD(&d->binds, chlist); fw_xferlist_remove(&fwb->xferlist); free(fwb, M_FW); } if (d->ir != NULL) { struct fw_xferq *ir = d->ir; if ((ir->flag & FWXFERQ_OPEN) == 0) return (EINVAL); if (ir->flag & FWXFERQ_RUNNING) { ir->flag &= ~FWXFERQ_RUNNING; fc->irx_disable(fc, ir->dmach); } /* free extbuf */ fwdev_freebuf(ir); /* drain receiving buffer */ for (xfer = STAILQ_FIRST(&ir->q); xfer != NULL; xfer = STAILQ_FIRST(&ir->q)) { ir->queued--; STAILQ_REMOVE_HEAD(&ir->q, link); xfer->resp = 0; fw_xfer_done(xfer); } ir->flag &= ~(FWXFERQ_OPEN | FWXFERQ_MODEMASK | FWXFERQ_CHTAGMASK); d->ir = NULL; } if (d->it != NULL) { struct fw_xferq *it = d->it; if ((it->flag & FWXFERQ_OPEN) == 0) return (EINVAL); if (it->flag & FWXFERQ_RUNNING) { it->flag &= ~FWXFERQ_RUNNING; fc->itx_disable(fc, it->dmach); } /* free extbuf */ fwdev_freebuf(it); it->flag &= ~(FWXFERQ_OPEN | FWXFERQ_MODEMASK | FWXFERQ_CHTAGMASK); d->it = NULL; } free(dev->si_drv1, M_FW); dev->si_drv1 = NULL; return err; }
int fw_write(dev_t dev, struct uio *uio, int ioflag) { struct firewire_softc *sc; struct firewire_comm *fc; struct fw_drv1 *d; struct fw_pkt *fp; struct fw_xferq *it; int slept = 0, err = 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; it = d->it; if (it == NULL) return fw_write_async(d, uio, ioflag); if (it->buf == NULL) return EIO; mutex_enter(&fc->fc_mtx); isoloop: if (it->stproc == NULL) { it->stproc = STAILQ_FIRST(&it->stfree); if (it->stproc != NULL) { STAILQ_REMOVE_HEAD(&it->stfree, link); it->queued = 0; } else if (slept == 0) { slept = 1; #if 0 /* XXX to avoid lock recursion */ err = fc->itx_enable(fc, it->dmach); if (err) goto out; #endif mutex_exit(&fc->fc_mtx); err = tsleep(it, FWPRI, "fw_write", hz); mutex_enter(&fc->fc_mtx); if (err) goto out; goto isoloop; } else { err = EIO; goto out; } } mutex_exit(&fc->fc_mtx); fp = (struct fw_pkt *)fwdma_v_addr(it->buf, it->stproc->poffset + it->queued); err = uiomove((void *)fp, sizeof(struct fw_isohdr), uio); if (err != 0) return err; err = uiomove((void *)fp->mode.stream.payload, fp->mode.stream.len, uio); it->queued++; if (it->queued >= it->bnpacket) { STAILQ_INSERT_TAIL(&it->stvalid, it->stproc, link); it->stproc = NULL; err = fc->itx_enable(fc, it->dmach); } if (uio->uio_resid >= sizeof(struct fw_isohdr)) { slept = 0; mutex_enter(&fc->fc_mtx); goto isoloop; } return err; out: mutex_exit(&fc->fc_mtx); 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; }
/* * ioctl support. */ int fw_ioctl (struct dev_ioctl_args *ap) { cdev_t dev = ap->a_head.a_dev; struct firewire_softc *sc; struct firewire_comm *fc; struct fw_drv1 *d; int unit = DEV2UNIT(dev); int i, len, err = 0; struct fw_device *fwdev; struct fw_bind *fwb; struct fw_xferq *ir, *it; struct fw_xfer *xfer; struct fw_pkt *fp; struct fw_devinfo *devinfo; void *ptr; struct fw_devlstreq *fwdevlst = (struct fw_devlstreq *)ap->a_data; struct fw_asyreq *asyreq = (struct fw_asyreq *)ap->a_data; struct fw_isochreq *ichreq = (struct fw_isochreq *)ap->a_data; struct fw_isobufreq *ibufreq = (struct fw_isobufreq *)ap->a_data; struct fw_asybindreq *bindreq = (struct fw_asybindreq *)ap->a_data; struct fw_crom_buf *crom_buf = (struct fw_crom_buf *)ap->a_data; if (DEV_FWMEM(dev)) return fwmem_ioctl(ap); if (!ap->a_data) return(EINVAL); sc = devclass_get_softc(firewire_devclass, unit); fc = sc->fc; d = (struct fw_drv1 *)dev->si_drv1; ir = d->ir; it = d->it; switch (ap->a_cmd) { case FW_STSTREAM: if (it == NULL) { for (i = 0; i < fc->nisodma; i ++) { it = fc->it[i]; if ((it->flag & FWXFERQ_OPEN) == 0) break; } if (i >= fc->nisodma) { err = EBUSY; break; } err = fwdev_allocbuf(fc, it, &d->bufreq.tx); if (err) break; it->flag |= FWXFERQ_OPEN; } it->flag &= ~0xff; it->flag |= (0x3f & ichreq->ch); it->flag |= ((0x3 & ichreq->tag) << 6); d->it = it; break; case FW_GTSTREAM: if (it != NULL) { ichreq->ch = it->flag & 0x3f; ichreq->tag = it->flag >> 2 & 0x3; } else
/* * read request. */ static int fw_read (struct dev_read_args *ap) { cdev_t dev = ap->a_head.a_dev; struct uio *uio = ap->a_uio; struct firewire_softc *sc; struct fw_xferq *ir; struct fw_xfer *xfer; int err = 0, slept = 0; int unit = DEV2UNIT(dev); struct fw_pkt *fp; if (DEV_FWMEM(dev)) return physread(ap); sc = devclass_get_softc(firewire_devclass, unit); ir = ((struct fw_drv1 *)dev->si_drv1)->ir; if (ir == NULL || ir->buf == NULL) return (EIO); readloop: xfer = STAILQ_FIRST(&ir->q); if (ir->stproc == NULL) { /* iso bulkxfer */ ir->stproc = STAILQ_FIRST(&ir->stvalid); if (ir->stproc != NULL) { crit_enter(); STAILQ_REMOVE_HEAD(&ir->stvalid, link); crit_exit(); ir->queued = 0; } } if (xfer == NULL && ir->stproc == NULL) { /* no data avaliable */ if (slept == 0) { slept = 1; ir->flag |= FWXFERQ_WAKEUP; err = tsleep(ir, FWPRI, "fw_read", hz); ir->flag &= ~FWXFERQ_WAKEUP; if (err == 0) goto readloop; } else if (slept == 1) err = EIO; return err; } else if(xfer != NULL) { #if 0 /* XXX broken */ /* per packet mode or FWACT_CH bind?*/ crit_enter(); ir->queued --; STAILQ_REMOVE_HEAD(&ir->q, link); crit_exit(); fp = &xfer->recv.hdr; if (sc->fc->irx_post != NULL) sc->fc->irx_post(sc->fc, fp->mode.ld); err = uiomove((void *)fp, 1 /* XXX header size */, uio); /* XXX copy payload too */ /* XXX we should recycle this xfer */ #endif fw_xfer_free( xfer); } else if(ir->stproc != NULL) { /* iso bulkxfer */ fp = (struct fw_pkt *)fwdma_v_addr(ir->buf, ir->stproc->poffset + ir->queued); if(sc->fc->irx_post != NULL) sc->fc->irx_post(sc->fc, fp->mode.ld); if(fp->mode.stream.len == 0){ err = EIO; return err; } err = uiomove((caddr_t)fp, fp->mode.stream.len + sizeof(u_int32_t), uio); ir->queued ++; if(ir->queued >= ir->bnpacket){ crit_enter(); STAILQ_INSERT_TAIL(&ir->stfree, ir->stproc, link); crit_exit(); sc->fc->irx_enable(sc->fc, ir->dmach); ir->stproc = NULL; } if (uio->uio_resid >= ir->psize) { slept = -1; goto readloop; } } return err; }
static int fw_close (struct dev_close_args *ap) { cdev_t dev = ap->a_head.a_dev; struct firewire_softc *sc; struct firewire_comm *fc; struct fw_drv1 *d; int unit = DEV2UNIT(dev); struct fw_xfer *xfer; struct fw_bind *fwb; int err = 0; if (DEV_FWMEM(dev)) return fwmem_close(ap); sc = devclass_get_softc(firewire_devclass, unit); fc = sc->fc; d = (struct fw_drv1 *)dev->si_drv1; if (d->ir != NULL) { struct fw_xferq *ir = d->ir; if ((ir->flag & FWXFERQ_OPEN) == 0) return (EINVAL); if (ir->flag & FWXFERQ_RUNNING) { ir->flag &= ~FWXFERQ_RUNNING; fc->irx_disable(fc, ir->dmach); } /* free extbuf */ fwdev_freebuf(ir); /* drain receiving buffer */ for (xfer = STAILQ_FIRST(&ir->q); xfer != NULL; xfer = STAILQ_FIRST(&ir->q)) { ir->queued --; STAILQ_REMOVE_HEAD(&ir->q, link); xfer->resp = 0; fw_xfer_done(xfer); } /* remove binding */ for (fwb = STAILQ_FIRST(&ir->binds); fwb != NULL; fwb = STAILQ_FIRST(&ir->binds)) { STAILQ_REMOVE(&fc->binds, fwb, fw_bind, fclist); STAILQ_REMOVE_HEAD(&ir->binds, chlist); kfree(fwb, M_FW); } ir->flag &= ~(FWXFERQ_OPEN | FWXFERQ_MODEMASK | FWXFERQ_CHTAGMASK); d->ir = NULL; } if (d->it != NULL) { struct fw_xferq *it = d->it; if ((it->flag & FWXFERQ_OPEN) == 0) return (EINVAL); if (it->flag & FWXFERQ_RUNNING) { it->flag &= ~FWXFERQ_RUNNING; fc->itx_disable(fc, it->dmach); } /* free extbuf */ fwdev_freebuf(it); it->flag &= ~(FWXFERQ_OPEN | FWXFERQ_MODEMASK | FWXFERQ_CHTAGMASK); d->it = NULL; } kfree(dev->si_drv1, M_FW); dev->si_drv1 = NULL; return err; }