PERFORCE change 106096 for review
Hans Petter Selasky
hselasky at FreeBSD.org
Thu Sep 14 06:15:56 PDT 2006
http://perforce.freebsd.org/chv.cgi?CH=106096
Change 106096 by hselasky at 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,
More information about the p4-projects
mailing list