コード例 #1
0
static int
ugen_open(struct usb_fifo *f, int fflags)
{
	struct usb_endpoint *ep = usb_fifo_softc(f);
	struct usb_endpoint_descriptor *ed = ep->edesc;
	uint8_t type;

	DPRINTFN(6, "flag=0x%x\n", fflags);

	mtx_lock(f->priv_mtx);
	switch (usbd_get_speed(f->udev)) {
	case USB_SPEED_LOW:
	case USB_SPEED_FULL:
		f->nframes = UGEN_HW_FRAMES;
		f->bufsize = UGEN_BULK_FS_BUFFER_SIZE;
		break;
	default:
		f->nframes = UGEN_HW_FRAMES * 8;
		f->bufsize = UGEN_BULK_HS_BUFFER_SIZE;
		break;
	}

	type = ed->bmAttributes & UE_XFERTYPE;
	if (type == UE_INTERRUPT) {
		f->bufsize = 0;		/* use "wMaxPacketSize" */
	}
	f->timeout = USB_NO_TIMEOUT;
	f->flag_short = 0;
	f->fifo_zlp = 0;
	mtx_unlock(f->priv_mtx);

	return (0);
}
コード例 #2
0
static int
ugen_transfer_setup(struct usb_fifo *f,
    const struct usb_config *setup, uint8_t n_setup)
{
	struct usb_endpoint *ep = usb_fifo_softc(f);
	struct usb_device *udev = f->udev;
	uint8_t iface_index = ep->iface_index;
	int error;

	mtx_unlock(f->priv_mtx);

	/*
	 * "usbd_transfer_setup()" can sleep so one needs to make a wrapper,
	 * exiting the mutex and checking things
	 */
	error = usbd_transfer_setup(udev, &iface_index, f->xfer,
	    setup, n_setup, f, f->priv_mtx);
	if (error == 0) {

		if (f->xfer[0]->nframes == 1) {
			error = usb_fifo_alloc_buffer(f,
			    f->xfer[0]->max_data_length, 2);
		} else {
			error = usb_fifo_alloc_buffer(f,
			    f->xfer[0]->max_frame_size,
			    2 * f->xfer[0]->nframes);
		}
		if (error) {
			usbd_transfer_unsetup(f->xfer, n_setup);
		}
	}
	mtx_lock(f->priv_mtx);

	return (error);
}
コード例 #3
0
static int
uhid_open(struct usb_fifo *fifo, int fflags)
{
	struct uhid_softc *sc = usb_fifo_softc(fifo);

	/*
	 * The buffers are one byte larger than maximum so that one
	 * can detect too large read/writes and short transfers:
	 */
	if (fflags & FREAD) {
		/* reset flags */
		sc->sc_flags &= ~UHID_FLAG_IMMED;

		if (usb_fifo_alloc_buffer(fifo,
		    sc->sc_isize + 1, UHID_FRAME_NUM)) {
			return (ENOMEM);
		}
	}
	if (fflags & FWRITE) {
		if (usb_fifo_alloc_buffer(fifo,
		    sc->sc_osize + 1, UHID_FRAME_NUM)) {
			return (ENOMEM);
		}
	}
	return (0);
}
コード例 #4
0
static void
uhid_stop_write(struct usb_fifo *fifo)
{
	struct uhid_softc *sc = usb_fifo_softc(fifo);

	usbd_transfer_stop(sc->sc_xfer[UHID_CTRL_DT_WR]);
	usbd_transfer_stop(sc->sc_xfer[UHID_INTR_DT_WR]);
}
コード例 #5
0
static void
uhid_start_read(struct usb_fifo *fifo)
{
	struct uhid_softc *sc = usb_fifo_softc(fifo);

	if (sc->sc_flags & UHID_FLAG_IMMED) {
		usbd_transfer_start(sc->sc_xfer[UHID_CTRL_DT_RD]);
	} else {
		usbd_transfer_start(sc->sc_xfer[UHID_INTR_DT_RD]);
	}
}
コード例 #6
0
static void
uhid_start_write(struct usb_fifo *fifo)
{
	struct uhid_softc *sc = usb_fifo_softc(fifo);

	if ((sc->sc_flags & UHID_FLAG_IMMED) ||
	    sc->sc_xfer[UHID_INTR_DT_WR] == NULL) {
		usbd_transfer_start(sc->sc_xfer[UHID_CTRL_DT_WR]);
	} else {
		usbd_transfer_start(sc->sc_xfer[UHID_INTR_DT_WR]);
	}
}
コード例 #7
0
static int
ugen_get_endpoint_desc(struct usb_fifo *f,
    struct usb_endpoint_descriptor *ed)
{
	struct usb_endpoint *ep;

	ep = usb_fifo_softc(f);

	if (ep && ep->edesc) {
		*ed = *ep->edesc;
	} else {
		return (EINVAL);
	}
	return (0);
}
コード例 #8
0
static int
ugen_open_pipe_read(struct usb_fifo *f)
{
	struct usb_config usb_config[2];
	struct usb_endpoint *ep = usb_fifo_softc(f);
	struct usb_endpoint_descriptor *ed = ep->edesc;

	mtx_assert(f->priv_mtx, MA_OWNED);

	if (f->xfer[0] || f->xfer[1]) {
		/* transfers are already opened */
		return (0);
	}
	bzero(usb_config, sizeof(usb_config));

	usb_config[1].type = UE_CONTROL;
	usb_config[1].endpoint = 0;
	usb_config[1].direction = UE_DIR_ANY;
	usb_config[1].timeout = 1000;	/* 1 second */
	usb_config[1].interval = 50;/* 50 milliseconds */
	usb_config[1].bufsize = sizeof(struct usb_device_request);
	usb_config[1].callback = &ugen_read_clear_stall_callback;
	usb_config[1].usb_mode = USB_MODE_HOST;

	usb_config[0].type = ed->bmAttributes & UE_XFERTYPE;
	usb_config[0].endpoint = ed->bEndpointAddress & UE_ADDR;
	usb_config[0].direction = UE_DIR_RX;
	usb_config[0].interval = USB_DEFAULT_INTERVAL;
	usb_config[0].flags.proxy_buffer = 1;
	usb_config[0].usb_mode = USB_MODE_DUAL;	/* both modes */

	switch (ed->bmAttributes & UE_XFERTYPE) {
	case UE_INTERRUPT:
	case UE_BULK:
		if (f->flag_short) {
			usb_config[0].flags.short_xfer_ok = 1;
		}
		usb_config[0].timeout = f->timeout;
		usb_config[0].frames = 1;
		usb_config[0].callback = &ugen_default_read_callback;
		usb_config[0].bufsize = f->bufsize;

		if (ugen_transfer_setup(f, usb_config, 2)) {
			return (EIO);
		}
		/* first transfer does not clear stall */
		f->flag_stall = 0;
		break;

	case UE_ISOCHRONOUS:
		usb_config[0].flags.short_xfer_ok = 1;
		usb_config[0].bufsize = 0;	/* use default */
		usb_config[0].frames = f->nframes;
		usb_config[0].callback = &ugen_isoc_read_callback;
		usb_config[0].timeout = 0;

		/* clone configuration */
		usb_config[1] = usb_config[0];

		if (ugen_transfer_setup(f, usb_config, 2)) {
			return (EIO);
		}
		break;

	default:
		return (EINVAL);
	}
	return (0);
}
コード例 #9
0
static int
uhid_ioctl(struct usb_fifo *fifo, u_long cmd, void *addr,
    int fflags)
{
	struct uhid_softc *sc = usb_fifo_softc(fifo);
	struct usb_gen_descriptor *ugd;
	uint32_t size;
	int error = 0;
	uint8_t id;

	switch (cmd) {
	case USB_GET_REPORT_DESC:
		ugd = addr;
		if (sc->sc_repdesc_size > ugd->ugd_maxlen) {
			size = ugd->ugd_maxlen;
		} else {
			size = sc->sc_repdesc_size;
		}
		ugd->ugd_actlen = size;
		if (ugd->ugd_data == NULL)
			break;		/* descriptor length only */
		error = copyout(sc->sc_repdesc_ptr, ugd->ugd_data, size);
		break;

	case USB_SET_IMMED:
		if (!(fflags & FREAD)) {
			error = EPERM;
			break;
		}
		if (*(int *)addr) {

			/* do a test read */

			error = uhid_get_report(sc, UHID_INPUT_REPORT,
			    sc->sc_iid, NULL, NULL, sc->sc_isize);
			if (error) {
				break;
			}
			mtx_lock(&sc->sc_mtx);
			sc->sc_flags |= UHID_FLAG_IMMED;
			mtx_unlock(&sc->sc_mtx);
		} else {
			mtx_lock(&sc->sc_mtx);
			sc->sc_flags &= ~UHID_FLAG_IMMED;
			mtx_unlock(&sc->sc_mtx);
		}
		break;

	case USB_GET_REPORT:
		if (!(fflags & FREAD)) {
			error = EPERM;
			break;
		}
		ugd = addr;
		switch (ugd->ugd_report_type) {
		case UHID_INPUT_REPORT:
			size = sc->sc_isize;
			id = sc->sc_iid;
			break;
		case UHID_OUTPUT_REPORT:
			size = sc->sc_osize;
			id = sc->sc_oid;
			break;
		case UHID_FEATURE_REPORT:
			size = sc->sc_fsize;
			id = sc->sc_fid;
			break;
		default:
			return (EINVAL);
		}
		if (id != 0)
			copyin(ugd->ugd_data, &id, 1);
		error = uhid_get_report(sc, ugd->ugd_report_type, id,
		    NULL, ugd->ugd_data, imin(ugd->ugd_maxlen, size));
		break;

	case USB_SET_REPORT:
		if (!(fflags & FWRITE)) {
			error = EPERM;
			break;
		}
		ugd = addr;
		switch (ugd->ugd_report_type) {
		case UHID_INPUT_REPORT:
			size = sc->sc_isize;
			id = sc->sc_iid;
			break;
		case UHID_OUTPUT_REPORT:
			size = sc->sc_osize;
			id = sc->sc_oid;
			break;
		case UHID_FEATURE_REPORT:
			size = sc->sc_fsize;
			id = sc->sc_fid;
			break;
		default:
			return (EINVAL);
		}
		if (id != 0)
			copyin(ugd->ugd_data, &id, 1);
		error = uhid_set_report(sc, ugd->ugd_report_type, id,
		    NULL, ugd->ugd_data, imin(ugd->ugd_maxlen, size));
		break;

	case USB_GET_REPORT_ID:
		*(int *)addr = 0;	/* XXX: we only support reportid 0? */
		break;

	default:
		error = EINVAL;
		break;
	}
	return (error);
}