Пример #1
0
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;
}
Пример #2
0
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;
}
Пример #3
0
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;
}
Пример #4
0
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;
}
Пример #5
0
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);
}
Пример #6
0
int
fw_ioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *td)
{
	struct firewire_softc *sc;
	struct firewire_comm *fc;
	struct fw_drv1 *d;
	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;
	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;
	int i, len, err = 0;
	void *ptr;

	sc = device_lookup_private(&ieee1394if_cd, DEV2UNIT(dev));
	if (sc == NULL)
		return ENXIO;

	if (DEV_FWMEM(dev))
		return fwmem_ioctl(dev, cmd, data, flag, td);

	if (!data)
		return EINVAL;

	d = (struct fw_drv1 *)sc->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
Пример #7
0
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;
}
Пример #8
0
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;
}
Пример #9
0
int
fw_close(dev_t dev, int flags, int fmt, struct lwp *td)
{
	struct firewire_softc *sc;
	struct firewire_comm *fc;
	struct fw_drv1 *d;
	struct fw_xfer *xfer;
	struct fw_bind *fwb;
        int err = 0;

	sc = device_lookup_private(&ieee1394if_cd, DEV2UNIT(dev));
	if (sc == NULL)
		return ENXIO;

	if (DEV_FWMEM(dev))
		return fwmem_close(dev, flags, fmt, td);

	d = (struct fw_drv1 *)sc->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(sc->si_drv1, M_FW);
	sc->si_drv1 = NULL;

	return err;
}
Пример #10
0
/*
 * 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
Пример #11
0
/*
 * 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;
}
Пример #12
0
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;
}