static void fwip_stop(struct fwip_softc *fwip) { struct firewire_comm *fc; struct fw_xferq *xferq; struct ifnet *ifp = fwip->fw_softc.fwip_ifp; struct fw_xfer *xfer, *next; int i; fc = fwip->fd.fc; if (fwip->dma_ch >= 0) { xferq = fc->ir[fwip->dma_ch]; if (xferq->flag & FWXFERQ_RUNNING) fc->irx_disable(fc, fwip->dma_ch); xferq->flag &= ~(FWXFERQ_MODEMASK | FWXFERQ_OPEN | FWXFERQ_STREAM | FWXFERQ_EXTBUF | FWXFERQ_HANDLER | FWXFERQ_CHTAGMASK); xferq->hand = NULL; for (i = 0; i < xferq->bnchunk; i ++) m_freem(xferq->bulkxfer[i].mbuf); free(xferq->bulkxfer, M_FWIP); fw_bindremove(fc, &fwip->fwb); for (xfer = STAILQ_FIRST(&fwip->fwb.xferlist); xfer != NULL; xfer = next) { next = STAILQ_NEXT(xfer, link); fw_xfer_free(xfer); } for (xfer = STAILQ_FIRST(&fwip->xferlist); xfer != NULL; xfer = next) { next = STAILQ_NEXT(xfer, link); fw_xfer_free(xfer); } STAILQ_INIT(&fwip->xferlist); xferq->bulkxfer = NULL; fwip->dma_ch = -1; } #if defined(__FreeBSD__) ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); #else ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); #endif }
struct fw_xfer * fwmem_write_quad( struct fw_device *fwdev, caddr_t sc, uint8_t spd, uint16_t dst_hi, uint32_t dst_lo, void *data, void (*hand)(struct fw_xfer *)) { struct fw_xfer *xfer; struct fw_pkt *fp; xfer = fwmem_xfer_req(fwdev, sc, spd, 0, 0, hand); if (xfer == NULL) return NULL; fp = &xfer->send.hdr; fp->mode.wreqq.tcode = FWTCODE_WREQQ; fp->mode.wreqq.dest_hi = dst_hi; fp->mode.wreqq.dest_lo = dst_lo; fp->mode.wreqq.data = *(uint32_t *)data; xfer->send.payload = xfer->recv.payload = NULL; if (fwmem_debug) printf("fwmem_write_quad: %d %04x:%08x %08x\n", fwdev->dst, dst_hi, dst_lo, *(uint32_t *)data); if (fw_asyreq(xfer->fc, -1, xfer) == 0) return xfer; fw_xfer_free(xfer); return NULL; }
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 fwmem_biodone(struct fw_xfer *xfer) { struct bio *bp; bp = (struct bio *)xfer->sc; bp->bio_error = xfer->resp; if (bp->bio_error != 0) { if (fwmem_debug) printf("%s: err=%d\n", __func__, bp->bio_error); bp->bio_flags |= BIO_ERROR; bp->bio_resid = bp->bio_bcount; } fw_xfer_free(xfer); biodone(bp); }
static void fwe_output_callback(struct fw_xfer *xfer) { struct fwe_softc *fwe; struct ifnet *ifp; fwe = (struct fwe_softc *)xfer->sc; /* XXX error check */ FWEDEBUG("resp = %d\n", xfer->resp); m_freem(xfer->mbuf); xfer->send.buf = NULL; fw_xfer_free(xfer); #if 1 /* XXX for queue full */ ifp = &fwe->fwe_if; if (ifp->if_snd.ifq_head != NULL) fwe_start(ifp); #endif }
struct fw_xfer * fwmem_write_block( struct fw_device *fwdev, caddr_t sc, uint8_t spd, uint16_t dst_hi, uint32_t dst_lo, int len, void *data, void (*hand)(struct fw_xfer *)) { struct fw_xfer *xfer; struct fw_pkt *fp; xfer = fwmem_xfer_req(fwdev, sc, spd, len, 0, hand); if (xfer == NULL) return NULL; fp = &xfer->send.hdr; fp->mode.wreqb.tcode = FWTCODE_WREQB; fp->mode.wreqb.dest_hi = dst_hi; fp->mode.wreqb.dest_lo = dst_lo; fp->mode.wreqb.len = len; fp->mode.wreqb.extcode = 0; xfer->send.payload = data; xfer->recv.payload = NULL; if (fwmem_debug) printf("fwmem_write_block: %d %04x:%08x %d\n", fwdev->dst, dst_hi, dst_lo, len); if (fw_asyreq(xfer->fc, -1, xfer) == 0) return xfer; fw_xfer_free(xfer); return NULL; }
/* * 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; }
/* Async. stream output */ static void fwe_as_input(struct fw_xferq *xferq) { struct mbuf *m; struct ether_header *eh; struct ifnet *ifp; struct fw_xfer *xfer; struct fwe_softc *fwe; u_char *c; int len; caddr_t p; fwe = (struct fwe_softc *)xferq->sc; ifp = &fwe->fwe_if; #if 0 FWE_POLL_REGISTER(fwe_poll, fwe, ifp); #endif while ((xfer = STAILQ_FIRST(&xferq->q)) != NULL) { STAILQ_REMOVE_HEAD(&xferq->q, link); xferq->queued --; MGETHDR(m, M_DONTWAIT, MT_DATA); if (m == NULL) { printf("MGETHDR failed\n"); fw_xfer_free(xfer); return; } len = xfer->recv.off + xfer->recv.len; FWEDEBUG("fwe_as_input len=%d\n", len); #if __FreeBSD_version >= 500000 MEXTADD(m, xfer->recv.buf, len, fwe_free, NULL, 0, EXT_NET_DRV); #else m->m_flags |= M_EXT; m->m_ext.ext_buf = xfer->recv.buf; m->m_ext.ext_size = len; m->m_ext.ext_free = fwe_free; m->m_ext.ext_ref = fwe_ref; *((int *)m->m_ext.ext_buf) = 1; /* XXX refcount */ #endif p = xfer->recv.buf + xfer->recv.off + HDR_LEN + ALIGN_PAD; eh = (struct ether_header *)p; #if __FreeBSD_version >= 500000 len -= xfer->recv.off + HDR_LEN + ALIGN_PAD; #else p += sizeof(struct ether_header); len -= xfer->recv.off + HDR_LEN + ALIGN_PAD + sizeof(struct ether_header); #endif m->m_data = p; m->m_len = m->m_pkthdr.len = len; m->m_pkthdr.rcvif = ifp; c = (char *)eh; #if 0 FWEDEBUG("%02x %02x %02x %02x %02x %02x\n" "%02x %02x %02x %02x %02x %02x\n" "%02x %02x %02x %02x\n" "%02x %02x %02x %02x\n" "%02x %02x %02x %02x\n" "%02x %02x %02x %02x\n", c[0], c[1], c[2], c[3], c[4], c[5], c[6], c[7], c[8], c[9], c[10], c[11], c[12], c[13], c[14], c[15], c[16], c[17], c[18], c[19], c[20], c[21], c[22], c[23], c[20], c[21], c[22], c[23] ); #endif #if __FreeBSD_version >= 500000 (*ifp->if_input)(ifp, m); #else ether_input(ifp, eh, m); #endif ifp->if_ipackets ++; xfer->recv.buf = NULL; fw_xfer_free(xfer); } }