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_read_async(struct fw_drv1 *d, struct uio *uio, int ioflag) { int err = 0, s; struct fw_xfer *xfer; struct fw_bind *fwb; struct fw_pkt *fp; struct tcode_info *tinfo; FW_GLOCK(d->fc); while ((xfer = STAILQ_FIRST(&d->rq)) == NULL && err == 0) err = msleep(&d->rq, FW_GMTX(d->fc), FWPRI, "fwra", 0); if (err != 0) { FW_GUNLOCK(d->fc); return (err); } s = splfw(); STAILQ_REMOVE_HEAD(&d->rq, link); FW_GUNLOCK(xfer->fc); splx(s); fp = &xfer->recv.hdr; #if 0 /* for GASP ?? */ if (fc->irx_post != NULL) fc->irx_post(fc, fp->mode.ld); #endif tinfo = &xfer->fc->tcode[fp->mode.hdr.tcode]; err = uiomove(fp, tinfo->hdr_len, uio); if (err) goto out; err = uiomove(xfer->recv.payload, xfer->recv.pay_len, uio); out: /* recycle this xfer */ fwb = (struct fw_bind *)xfer->sc; fw_xfer_unload(xfer); xfer->recv.pay_len = PAGE_SIZE; FW_GLOCK(xfer->fc); STAILQ_INSERT_TAIL(&fwb->xferlist, xfer, link); FW_GUNLOCK(xfer->fc); return (err); }
static int fw_write_async(struct fw_drv1 *d, struct uio *uio, int ioflag) { struct fw_xfer *xfer; struct fw_pkt pkt; struct tcode_info *tinfo; int err; bzero(&pkt, sizeof(struct fw_pkt)); if ((err = uiomove((caddr_t)&pkt, sizeof(uint32_t), uio))) return (err); tinfo = &d->fc->tcode[pkt.mode.hdr.tcode]; if ((err = uiomove((caddr_t)&pkt + sizeof(uint32_t), tinfo->hdr_len - sizeof(uint32_t), uio))) return (err); if ((xfer = fw_xfer_alloc_buf(M_FWXFER, uio->uio_resid, PAGE_SIZE/*XXX*/)) == NULL) return (ENOMEM); bcopy(&pkt, &xfer->send.hdr, sizeof(struct fw_pkt)); xfer->send.pay_len = uio->uio_resid; if (uio->uio_resid > 0) { if ((err = uiomove((caddr_t)&xfer->send.payload[0], uio->uio_resid, uio))) goto out; } xfer->fc = d->fc; xfer->sc = NULL; xfer->hand = fw_xferwake; xfer->send.spd = 2 /* XXX */; if ((err = fw_asyreq(xfer->fc, -1, xfer))) goto out; if ((err = fw_xferwait(xfer))) goto out; if (xfer->resp != 0) { err = xfer->resp; goto out; } if (xfer->flag & FWXF_RCVD) { FW_GLOCK(xfer->fc); STAILQ_INSERT_TAIL(&d->rq, xfer, link); FW_GUNLOCK(xfer->fc); return (0); } out: fw_xfer_free(xfer); return (err); }
static void fw_hand(struct fw_xfer *xfer) { struct fw_bind *fwb; struct fw_drv1 *d; fwb = (struct fw_bind *)xfer->sc; d = fwb->sc; FW_GLOCK(xfer->fc); STAILQ_INSERT_TAIL(&d->rq, xfer, link); FW_GUNLOCK(xfer->fc); wakeup(&d->rq); }
int fwmem_open(struct cdev *dev, int flags, int fmt, fw_proc *td) { struct fwmem_softc *fms; struct firewire_softc *sc; int unit = DEV2UNIT(dev); sc = devclass_get_softc(firewire_devclass, unit); if (sc == NULL) return (ENXIO); FW_GLOCK(sc->fc); if (dev->si_drv1 != NULL) { if ((flags & FWRITE) != 0) { FW_GUNLOCK(sc->fc); return (EBUSY); } FW_GUNLOCK(sc->fc); fms = dev->si_drv1; fms->refcount++; } else { dev->si_drv1 = (void *)-1; FW_GUNLOCK(sc->fc); dev->si_drv1 = malloc(sizeof(struct fwmem_softc), M_FWMEM, M_WAITOK); if (dev->si_drv1 == NULL) return (ENOMEM); dev->si_iosize_max = DFLTPHYS; fms = dev->si_drv1; bcopy(&fwmem_eui64, &fms->eui, sizeof(struct fw_eui64)); fms->sc = sc; fms->refcount = 1; } if (fwmem_debug) printf("%s: refcount=%d\n", __func__, fms->refcount); return (0); }
int fwmem_close (struct cdev *dev, int flags, int fmt, fw_proc *td) { struct fwmem_softc *fms; fms = dev->si_drv1; FW_GLOCK(fms->sc->fc); fms->refcount--; FW_GUNLOCK(fms->sc->fc); if (fwmem_debug) printf("%s: refcount=%d\n", __func__, fms->refcount); if (fms->refcount < 1) { free(dev->si_drv1, M_FWMEM); dev->si_drv1 = NULL; } return (0); }
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; }