Date: Thu, 14 Sep 2006 13:15:54 GMT From: Hans Petter Selasky <hselasky@FreeBSD.org> To: Perforce Change Reviews <perforce@FreeBSD.org> Subject: PERFORCE change 106096 for review Message-ID: <200609141315.k8EDFsxo087861@repoman.freebsd.org>
next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=106096 Change 106096 by hselasky@hselasky_mini_itx on 2006/09/14 13:15:46 Finished reworking "urio". Please test! Added two new functions to the USB-cdev API. Affected files ... .. //depot/projects/usb/src/sys/dev/usb/rio500_usb.h#3 add .. //depot/projects/usb/src/sys/dev/usb/urio.c#5 edit .. //depot/projects/usb/src/sys/dev/usb/usb_cdev.c#8 edit .. //depot/projects/usb/src/sys/dev/usb/usb_subr.h#22 edit Differences ... ==== //depot/projects/usb/src/sys/dev/usb/urio.c#5 (text+ko) ==== @@ -1,0 +1,594 @@ +/*- + * Copyright (c) 2000 Iwasa Kazmi + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This code is based on ugen.c and ulpt.c developed by Lennart Augustsson. + * This code includes software developed by the NetBSD Foundation, Inc. and + * its contributors. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD: src/sys/dev/usb/urio.c,v 1.35 2005/01/06 01:43:29 imp Exp $"); + + +/* + * 2000/3/24 added NetBSD/OpenBSD support (from Alex Nemirovsky) + * 2000/3/07 use two bulk-pipe handles for read and write (Dirk) + * 2000/3/06 change major number(143), and copyright header + * some fix for 4.0 (Dirk) + * 2000/3/05 codes for FreeBSD 4.x - CURRENT (Thanks to Dirk-Willem van Gulik) + * 2000/3/01 remove retry code from urioioctl() + * change method of bulk transfer (no interrupt) + * 2000/2/28 small fixes for new rio_usb.h + * 2000/2/24 first version. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/fcntl.h> +#include <sys/syslog.h> +#include <sys/uio.h> +#include <sys/malloc.h> + +#include <dev/usb/usb_port.h> +#include <dev/usb/usb.h> +#include <dev/usb/usb_subr.h> + +#include "usbdevs.h" + +#include <dev/usb/rio500_usb.h> + +#ifdef USB_DEBUG +#define DPRINTF(sc,n,fmt,...) do { \ + if (urio_debug > (n)) \ + printf("%s:%s: " fmt, (sc)->sc_name, \ + __FUNCTION__ ,##__VA_ARGS__); \ +} while(0) + +static int urio_debug = 0; +SYSCTL_NODE(_hw_usb, OID_AUTO, urio, CTLFLAG_RW, 0, "USB urio"); +SYSCTL_INT(_hw_usb_urio, OID_AUTO, debug, CTLFLAG_RW, + &urio_debug, 0, "urio debug level"); +#else +#define DPRINTF(...) /* nop */ +#endif + +#define URIO_T_WR 0 +#define URIO_T_RD 1 +#define URIO_T_WR_CS 2 +#define URIO_T_RD_CS 3 +#define URIO_T_MAX 4 + +#define URIO_BSIZE (1<<12) /* bytes */ +#define URIO_IFQ_MAXLEN 2 /* units */ + +struct urio_softc { + struct usb_cdev sc_cdev; + struct mtx sc_mtx; + struct usbd_memory_wait sc_mem_wait; + + device_t sc_dev; + struct usbd_device * sc_udev; + struct usbd_xfer * sc_xfer[URIO_T_MAX]; + + u_int8_t sc_flags; +#define URIO_FLAG_READ_STALL 0x01 /* read transfer stalled */ +#define URIO_FLAG_WRITE_STALL 0x02 /* write transfer stalled */ + + u_int8_t sc_name[16]; +}; + +/* prototypes */ + +static device_probe_t urio_probe; +static device_attach_t urio_attach; +static device_detach_t urio_detach; + +static void +urio_write_callback(struct usbd_xfer *xfer); + +static void +urio_write_clear_stall_callback(struct usbd_xfer *xfer); + +static void +urio_read_callback(struct usbd_xfer *xfer); + +static void +urio_read_clear_stall_callback(struct usbd_xfer *xfer); + +static void +urio_start_read(struct usb_cdev *cdev); + +static void +urio_stop_read(struct usb_cdev *cdev); + +static void +urio_start_write(struct usb_cdev *cdev); + +static void +urio_stop_write(struct usb_cdev *cdev); + +static int32_t +urio_open(struct usb_cdev *cdev, int32_t fflags, + int32_t devtype, struct thread *td); +static int32_t +urio_ioctl(struct usb_cdev *cdev, u_long cmd, caddr_t addr, + int32_t fflags, struct thread *td); + +static const struct usbd_config urio_config[URIO_T_MAX] = { + [URIO_T_WR] = { + .type = UE_BULK, + .endpoint = -1, /* any */ + .direction = UE_DIR_OUT, + .bufsize = URIO_BSIZE, + .flags = 0, + .callback = &urio_write_callback, + }, + + [URIO_T_RD] = { + .type = UE_BULK, + .endpoint = -1, /* any */ + .direction = UE_DIR_IN, + .bufsize = URIO_BSIZE, + .flags = USBD_SHORT_XFER_OK, + .callback = &urio_read_callback, + }, + + [URIO_T_WR_CS] = { + .type = UE_CONTROL, + .endpoint = 0x00, /* Control pipe */ + .direction = -1, + .bufsize = sizeof(usb_device_request_t), + .flags = USBD_USE_DMA, + .callback = &urio_write_clear_stall_callback, + .timeout = 1000, /* 1 second */ + }, + + [URIO_T_RD_CS] = { + .type = UE_CONTROL, + .endpoint = 0x00, /* Control pipe */ + .direction = -1, + .bufsize = sizeof(usb_device_request_t), + .flags = USBD_USE_DMA, + .callback = &urio_read_clear_stall_callback, + .timeout = 1000, /* 1 second */ + }, +}; + +static devclass_t urio_devclass; + +static device_method_t urio_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, urio_probe), + DEVMETHOD(device_attach, urio_attach), + DEVMETHOD(device_detach, urio_detach), + { 0, 0 } +}; + +static driver_t urio_driver = { + .name = "urio", + .methods = urio_methods, + .size = sizeof(struct urio_softc), +}; + +DRIVER_MODULE(urio, uhub, urio_driver, urio_devclass, usbd_driver_load, 0); + +MODULE_DEPEND(urio, usb, 1,1,1); + +static int +urio_probe(device_t dev) +{ + struct usb_attach_arg *uaa = device_get_ivars(dev); + usb_device_descriptor_t *dd; + + if (!uaa->iface) + return UMATCH_NONE; + + dd = usbd_get_device_descriptor(uaa->device); + + if (dd && + (((UGETW(dd->idVendor) == USB_VENDOR_DIAMOND) && + (UGETW(dd->idProduct) == USB_PRODUCT_DIAMOND_RIO500USB)) || + ((UGETW(dd->idVendor) == USB_VENDOR_DIAMOND2) && + ((UGETW(dd->idProduct) == USB_PRODUCT_DIAMOND2_RIO600USB) || + (UGETW(dd->idProduct) == USB_PRODUCT_DIAMOND2_RIO800USB))))) + return UMATCH_VENDOR_PRODUCT; + else + return UMATCH_NONE; +} + +static int +urio_attach(device_t dev) +{ + struct usb_attach_arg *uaa = device_get_ivars(dev); + struct urio_softc *sc = device_get_softc(dev); + const char * p_buf[2]; + int32_t error; + char buf_1[16]; + + if (sc == NULL) { + return ENOMEM; + } + + usbd_set_desc(dev, uaa->device); + + sc->sc_dev = dev; + sc->sc_udev = uaa->device; + + mtx_init(&(sc->sc_mtx), "urio lock", NULL, MTX_DEF|MTX_RECURSE); + + snprintf(sc->sc_name, sizeof(sc->sc_name), + "%s", device_get_nameunit(dev)); + + error = usbd_transfer_setup(uaa->device, uaa->iface_index, + sc->sc_xfer, urio_config, URIO_T_MAX, + sc, &(sc->sc_mtx), &(sc->sc_mem_wait)); + if (error) { + DPRINTF(sc, 0, "error=%s\n", usbd_errstr(error)) ; + goto detach; + } + + snprintf(buf_1, sizeof(buf_1), "urio%d", device_get_unit(dev)); + + p_buf[0] = buf_1; + p_buf[1] = NULL; + + sc->sc_cdev.sc_start_read = &urio_start_read; + sc->sc_cdev.sc_start_write = &urio_start_write; + sc->sc_cdev.sc_stop_read = &urio_stop_read; + sc->sc_cdev.sc_stop_write = &urio_stop_write; + sc->sc_cdev.sc_open = &urio_open; + sc->sc_cdev.sc_ioctl = &urio_ioctl; + sc->sc_cdev.sc_flags |= (USB_CDEV_FLAG_FWD_SHORT| + USB_CDEV_FLAG_WAKEUP_RD_IMMED| + USB_CDEV_FLAG_WAKEUP_WR_IMMED); + + error = usb_cdev_attach(&(sc->sc_cdev), sc, &(sc->sc_mtx), p_buf, + UID_ROOT, GID_OPERATOR, 0644, + URIO_BSIZE, URIO_IFQ_MAXLEN, + URIO_BSIZE, URIO_IFQ_MAXLEN); + if (error) { + goto detach; + } + + return 0; /* success */ + + detach: + urio_detach(dev); + return ENOMEM; /* failure */ +} + +static void +urio_write_callback(struct usbd_xfer *xfer) +{ + struct urio_softc *sc = xfer->priv_sc; + u_int32_t actlen; + + USBD_CHECK_STATUS(xfer); + + tr_transferred: + tr_setup: + if (sc->sc_flags & URIO_FLAG_WRITE_STALL) { + usbd_transfer_start(sc->sc_xfer[URIO_T_WR_CS]); + return; + } + if (usb_cdev_get_data(&(sc->sc_cdev), xfer->buffer, + URIO_BSIZE, &actlen, 0)) { + + xfer->length = actlen; + usbd_start_hardware(xfer); + } + return; + + tr_error: + if (xfer->error != USBD_CANCELLED) { + /* try to clear stall first */ + sc->sc_flags |= URIO_FLAG_WRITE_STALL; + usbd_transfer_start(sc->sc_xfer[URIO_T_WR_CS]); + } + return; +} + +static void +urio_write_clear_stall_callback(struct usbd_xfer *xfer) +{ + struct urio_softc *sc = xfer->priv_sc; + struct usbd_xfer *xfer_other = sc->sc_xfer[URIO_T_WR]; + + USBD_CHECK_STATUS(xfer); + + tr_setup: + /* start clear stall */ + usbd_clear_stall_tr_setup(xfer, xfer_other); + return; + + tr_transferred: + usbd_clear_stall_tr_transferred(xfer, xfer_other); + + sc->sc_flags &= ~URIO_FLAG_WRITE_STALL; + usbd_transfer_start(xfer_other); + return; + + tr_error: + /* bomb out */ + sc->sc_flags &= ~URIO_FLAG_WRITE_STALL; + usb_cdev_get_data_error(&(sc->sc_cdev)); + return; +} + +static void +urio_read_callback(struct usbd_xfer *xfer) +{ + struct urio_softc *sc = xfer->priv_sc; + struct usbd_mbuf *m; + + USBD_CHECK_STATUS(xfer); + + tr_transferred: + usb_cdev_put_data(&(sc->sc_cdev), xfer->buffer, xfer->actlen, 1); + + tr_setup: + if (sc->sc_flags & URIO_FLAG_READ_STALL) { + usbd_transfer_start(sc->sc_xfer[URIO_T_RD_CS]); + return; + } + + USBD_IF_POLL(&sc->sc_cdev.sc_rdq_free, m); + + if (m) { + usbd_start_hardware(xfer); + } + return; + + tr_error: + if (xfer->error != USBD_CANCELLED) { + /* try to clear stall first */ + sc->sc_flags |= URIO_FLAG_READ_STALL; + usbd_transfer_start(sc->sc_xfer[URIO_T_RD_CS]); + } + return; +} + +static void +urio_read_clear_stall_callback(struct usbd_xfer *xfer) +{ + struct urio_softc *sc = xfer->priv_sc; + struct usbd_xfer *xfer_other = sc->sc_xfer[URIO_T_RD]; + + USBD_CHECK_STATUS(xfer); + + tr_setup: + /* start clear stall */ + usbd_clear_stall_tr_setup(xfer, xfer_other); + return; + + tr_transferred: + usbd_clear_stall_tr_transferred(xfer, xfer_other); + + sc->sc_flags &= ~URIO_FLAG_READ_STALL; + usbd_transfer_start(xfer_other); + return; + + tr_error: + /* bomb out */ + sc->sc_flags &= ~URIO_FLAG_READ_STALL; + usb_cdev_put_data_error(&(sc->sc_cdev)); + return; +} + +static void +urio_start_read(struct usb_cdev *cdev) +{ + struct urio_softc *sc = cdev->sc_priv_ptr; + usbd_transfer_start(sc->sc_xfer[URIO_T_RD]); + return; +} + +static void +urio_stop_read(struct usb_cdev *cdev) +{ + struct urio_softc *sc = cdev->sc_priv_ptr; + usbd_transfer_stop(sc->sc_xfer[URIO_T_RD_CS]); + usbd_transfer_stop(sc->sc_xfer[URIO_T_RD]); + return; +} + +static void +urio_start_write(struct usb_cdev *cdev) +{ + struct urio_softc *sc = cdev->sc_priv_ptr; + usbd_transfer_start(sc->sc_xfer[URIO_T_WR]); + return; +} + +static void +urio_stop_write(struct usb_cdev *cdev) +{ + struct urio_softc *sc = cdev->sc_priv_ptr; + usbd_transfer_stop(sc->sc_xfer[URIO_T_WR_CS]); + usbd_transfer_stop(sc->sc_xfer[URIO_T_WR]); + return; +} + +static int32_t +urio_open(struct usb_cdev *cdev, int32_t fflags, + int32_t devtype, struct thread *td) +{ + struct urio_softc *sc = cdev->sc_priv_ptr; + + if ((fflags & (FWRITE|FREAD)) != (FWRITE|FREAD)) { + return EACCES; + } + + if (fflags & FREAD) { + /* clear stall first */ + sc->sc_flags |= URIO_FLAG_READ_STALL; + } + + if (fflags & FWRITE) { + /* clear stall first */ + sc->sc_flags |= URIO_FLAG_WRITE_STALL; + } + return 0; /* success */ +} + +static int32_t +urio_ioctl(struct usb_cdev *cdev, u_long cmd, caddr_t addr, + int32_t fflags, struct thread *td) +{ + usb_device_request_t req; + struct iovec iov; + struct uio uio; + + struct urio_softc *sc = cdev->sc_priv_ptr; + struct RioCommand *rio_cmd; + void *ptr = 0; + + int32_t error = 0; + + u_int16_t len; + u_int8_t requesttype; + + usb_cdev_unlock(cdev, fflags); + + switch (cmd) { + case RIO_RECV_COMMAND: + if (!(fflags & FWRITE)) { + error = EPERM; + goto done; + } + rio_cmd = (struct RioCommand *)addr; + if (rio_cmd == NULL) { + error = EINVAL; + goto done; + } + len = rio_cmd->length; + + requesttype = rio_cmd->requesttype | UT_READ_VENDOR_DEVICE; + DPRINTF(sc, 1, "sending command:reqtype=%0x req=%0x value=%0x index=%0x len=%0x\n", + requesttype, rio_cmd->request, rio_cmd->value, rio_cmd->index, len); + break; + + case RIO_SEND_COMMAND: + if (!(fflags & FWRITE)) { + error = EPERM; + goto done; + } + rio_cmd = (struct RioCommand *)addr; + if (rio_cmd == NULL) { + error = EINVAL; + goto done; + } + len = rio_cmd->length; + + requesttype = rio_cmd->requesttype | UT_WRITE_VENDOR_DEVICE; + DPRINTF(sc, 1, "sending command:reqtype=%0x req=%0x value=%0x index=%0x len=%0x\n", + requesttype, rio_cmd->request, rio_cmd->value, rio_cmd->index, len); + break; + + default: + error = EINVAL; + goto done; + } + + /* Send rio control message */ + req.bmRequestType = requesttype; + req.bRequest = rio_cmd->request; + USETW(req.wValue, rio_cmd->value); + USETW(req.wIndex, rio_cmd->index); + USETW(req.wLength, len); + + if (len > 32767) { + error = EINVAL; + goto done; + } + + if (len != 0) { + iov.iov_base = (caddr_t)rio_cmd->buffer; + iov.iov_len = len; + uio.uio_iov = &iov; + uio.uio_iovcnt = 1; + uio.uio_resid = len; + uio.uio_offset = 0; + uio.uio_segflg = UIO_USERSPACE; + uio.uio_rw = + ((req.bmRequestType & UT_READ) ? + UIO_READ : UIO_WRITE); + uio.uio_procp = td; + ptr = malloc(len, M_TEMP, M_WAITOK); + if (ptr == NULL) { + error = ENOMEM; + goto done; + } + if (uio.uio_rw == UIO_WRITE) { + error = uiomove(ptr, len, &uio); + if (error) { + goto done; + } + } + } + + mtx_lock(cdev->sc_mtx_ptr); + + error = usbd_do_request_flags_mtx + (sc->sc_udev, cdev->sc_mtx_ptr, + &req, ptr, 0, NULL, USBD_DEFAULT_TIMEOUT); + + mtx_unlock(cdev->sc_mtx_ptr); + + if (error == 0) { + if (len != 0) { + if (uio.uio_rw == UIO_READ) { + error = uiomove(ptr, len, &uio); + } + } + } else { + error = EIO; + } + done: + if (ptr) { + free(ptr, M_TEMP); + } + + return usb_cdev_lock(cdev, fflags, error); +} + +static int +urio_detach(device_t dev) +{ + struct urio_softc *sc = device_get_softc(dev); + + DPRINTF(sc, 0, "\n"); + + usb_cdev_detach(&(sc->sc_cdev)); + + usbd_transfer_unsetup(sc->sc_xfer, URIO_T_MAX); + + usbd_transfer_drain(&(sc->sc_mem_wait), &(sc->sc_mtx)); + + mtx_destroy(&(sc->sc_mtx)); + + return 0; +} ==== //depot/projects/usb/src/sys/dev/usb/usb_cdev.c#8 (text+ko) ==== @@ -221,6 +221,35 @@ return; } +void +usb_cdev_unlock(struct usb_cdev *sc, int32_t fflags) +{ + u_int32_t context_bit = usb_cdev_get_context(fflags); + + context_bit &= (USB_CDEV_FLAG_SLEEP_IOCTL_RD| + USB_CDEV_FLAG_SLEEP_IOCTL_WR); + + sc->sc_flags |= context_bit; + + mtx_unlock(sc->sc_mtx_ptr); + + return; +} + +int32_t +usb_cdev_lock(struct usb_cdev *sc, int32_t fflags, + int32_t error) +{ + u_int32_t context_bit = usb_cdev_get_context(fflags); + + context_bit &= (USB_CDEV_FLAG_SLEEP_IOCTL_RD| + USB_CDEV_FLAG_SLEEP_IOCTL_WR); + + mtx_lock(sc->sc_mtx_ptr); + + return usb_cdev_exit_context(sc, context_bit, error); +} + /* * the synchronization part is a little more * complicated, hence there are two modes: ==== //depot/projects/usb/src/sys/dev/usb/usb_subr.h#22 (text+ko) ==== @@ -1164,6 +1164,12 @@ extern void usb_cdev_wakeup(struct usb_cdev *sc); +extern void +usb_cdev_unlock(struct usb_cdev *sc, int32_t fflags); + +extern int32_t +usb_cdev_lock(struct usb_cdev *sc, int32_t fflags, int32_t error); + extern int32_t usb_cdev_attach(struct usb_cdev *sc, void *priv_sc,
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200609141315.k8EDFsxo087861>