Author: hselasky
Date: Thu Feb 21 08:21:14 2013
New Revision: 247091
URL: http://svnweb.freebsd.org/changeset/base/247091

Log:
  MFC r246616 and r246759:
  
  - Move scratch data from the USB bus structure to the USB device
  structure so that simultaneous access cannot happen. Protect scratch
  area using the enumeration lock.
  - Reduce stack usage in usbd_transfer_setup() by moving some big stack
  members to the scratch area. This saves around 200 bytes of stack.
  - Fix a whitespace.
  - Protect control requests using the USB device enumeration lock.
  - Make sure all callers of usbd_enum_lock() check the return value.
  - Remove the control transfer specific lock.
  - Bump the FreeBSD version number, hence external USB modules may need
  to be recompiled due to a USB device structure change.

Modified:
  stable/8/sys/dev/usb/controller/usb_controller.c
  stable/8/sys/dev/usb/template/usb_template.c
  stable/8/sys/dev/usb/usb_bus.h
  stable/8/sys/dev/usb/usb_controller.h
  stable/8/sys/dev/usb/usb_dev.c
  stable/8/sys/dev/usb/usb_dev.h
  stable/8/sys/dev/usb/usb_device.c
  stable/8/sys/dev/usb/usb_device.h
  stable/8/sys/dev/usb/usb_generic.c
  stable/8/sys/dev/usb/usb_handle_request.c
  stable/8/sys/dev/usb/usb_hub.c
  stable/8/sys/dev/usb/usb_msctest.c
  stable/8/sys/dev/usb/usb_request.c
  stable/8/sys/dev/usb/usb_transfer.c
  stable/8/sys/dev/usb/usb_util.c
  stable/8/sys/sys/param.h
Directory Properties:
  stable/8/sys/   (props changed)
  stable/8/sys/boot/   (props changed)
  stable/8/sys/dev/   (props changed)
  stable/8/sys/dev/usb/   (props changed)

Modified: stable/8/sys/dev/usb/controller/usb_controller.c
==============================================================================
--- stable/8/sys/dev/usb/controller/usb_controller.c    Thu Feb 21 07:48:07 
2013        (r247090)
+++ stable/8/sys/dev/usb/controller/usb_controller.c    Thu Feb 21 08:21:14 
2013        (r247091)
@@ -407,6 +407,7 @@ usb_bus_suspend(struct usb_proc_msg *pm)
        struct usb_bus *bus;
        struct usb_device *udev;
        usb_error_t err;
+       uint8_t do_unlock;
 
        bus = ((struct usb_bus_msg *)pm)->bus;
        udev = bus->devices[USB_ROOT_HUB_ADDR];
@@ -427,7 +428,7 @@ usb_bus_suspend(struct usb_proc_msg *pm)
 
        bus_generic_shutdown(bus->bdev);
 
-       usbd_enum_lock(udev);
+       do_unlock = usbd_enum_lock(udev);
 
        err = usbd_set_config_index(udev, USB_UNCONFIG_INDEX);
        if (err)
@@ -444,7 +445,8 @@ usb_bus_suspend(struct usb_proc_msg *pm)
        if (bus->methods->set_hw_power_sleep != NULL)
                (bus->methods->set_hw_power_sleep) (bus, USB_HW_POWER_SUSPEND);
 
-       usbd_enum_unlock(udev);
+       if (do_unlock)
+               usbd_enum_unlock(udev);
 
        USB_BUS_LOCK(bus);
 }
@@ -460,6 +462,7 @@ usb_bus_resume(struct usb_proc_msg *pm)
        struct usb_bus *bus;
        struct usb_device *udev;
        usb_error_t err;
+       uint8_t do_unlock;
 
        bus = ((struct usb_bus_msg *)pm)->bus;
        udev = bus->devices[USB_ROOT_HUB_ADDR];
@@ -469,7 +472,7 @@ usb_bus_resume(struct usb_proc_msg *pm)
 
        USB_BUS_UNLOCK(bus);
 
-       usbd_enum_lock(udev);
+       do_unlock = usbd_enum_lock(udev);
 #if 0
        DEVMETHOD(usb_take_controller, NULL);   /* dummy */
 #endif
@@ -503,7 +506,8 @@ usb_bus_resume(struct usb_proc_msg *pm)
                    "attach root HUB\n");
        }
 
-       usbd_enum_unlock(udev);
+       if (do_unlock)
+               usbd_enum_unlock(udev);
 
        USB_BUS_LOCK(bus);
 }
@@ -519,6 +523,7 @@ usb_bus_shutdown(struct usb_proc_msg *pm
        struct usb_bus *bus;
        struct usb_device *udev;
        usb_error_t err;
+       uint8_t do_unlock;
 
        bus = ((struct usb_bus_msg *)pm)->bus;
        udev = bus->devices[USB_ROOT_HUB_ADDR];
@@ -530,7 +535,7 @@ usb_bus_shutdown(struct usb_proc_msg *pm
 
        bus_generic_shutdown(bus->bdev);
 
-       usbd_enum_lock(udev);
+       do_unlock = usbd_enum_lock(udev);
 
        err = usbd_set_config_index(udev, USB_UNCONFIG_INDEX);
        if (err)
@@ -547,7 +552,8 @@ usb_bus_shutdown(struct usb_proc_msg *pm
        if (bus->methods->set_hw_power_sleep != NULL)
                (bus->methods->set_hw_power_sleep) (bus, USB_HW_POWER_SHUTDOWN);
 
-       usbd_enum_unlock(udev);
+       if (do_unlock)
+               usbd_enum_unlock(udev);
 
        USB_BUS_LOCK(bus);
 }

Modified: stable/8/sys/dev/usb/template/usb_template.c
==============================================================================
--- stable/8/sys/dev/usb/template/usb_template.c        Thu Feb 21 07:48:07 
2013        (r247090)
+++ stable/8/sys/dev/usb/template/usb_template.c        Thu Feb 21 08:21:14 
2013        (r247091)
@@ -845,20 +845,20 @@ usb_hw_ep_resolve(struct usb_device *ude
        struct usb_device_descriptor *dd;
        uint16_t mps;
 
-       if (desc == NULL) {
+       if (desc == NULL)
                return (USB_ERR_INVAL);
-       }
+
        /* get bus methods */
        methods = udev->bus->methods;
 
-       if (methods->get_hw_ep_profile == NULL) {
+       if (methods->get_hw_ep_profile == NULL)
                return (USB_ERR_INVAL);
-       }
+
        if (desc->bDescriptorType == UDESC_DEVICE) {
 
-               if (desc->bLength < sizeof(*dd)) {
+               if (desc->bLength < sizeof(*dd))
                        return (USB_ERR_INVAL);
-               }
+
                dd = (void *)desc;
 
                /* get HW control endpoint 0 profile */
@@ -905,13 +905,12 @@ usb_hw_ep_resolve(struct usb_device *ude
                }
                return (0);             /* success */
        }
-       if (desc->bDescriptorType != UDESC_CONFIG) {
+       if (desc->bDescriptorType != UDESC_CONFIG)
                return (USB_ERR_INVAL);
-       }
-       if (desc->bLength < sizeof(*(ues->cd))) {
+       if (desc->bLength < sizeof(*(ues->cd)))
                return (USB_ERR_INVAL);
-       }
-       ues = udev->bus->scratch[0].hw_ep_scratch;
+
+       ues = udev->scratch.hw_ep_scratch;
 
        memset(ues, 0, sizeof(*ues));
 
@@ -1232,13 +1231,18 @@ usb_temp_setup(struct usb_device *udev,
 {
        struct usb_temp_setup *uts;
        void *buf;
+       usb_error_t error;
        uint8_t n;
+       uint8_t do_unlock;
 
-       if (tdd == NULL) {
-               /* be NULL safe */
+       /* be NULL safe */
+       if (tdd == NULL)
                return (0);
-       }
-       uts = udev->bus->scratch[0].temp_setup;
+
+       /* Protect scratch area */
+       do_unlock = usbd_enum_lock(udev);
+
+       uts = udev->scratch.temp_setup;
 
        memset(uts, 0, sizeof(*uts));
 
@@ -1251,17 +1255,24 @@ usb_temp_setup(struct usb_device *udev,
 
        if (uts->err) {
                /* some error happened */
-               return (uts->err);
+               goto done;
        }
        /* sanity check */
        if (uts->size == 0) {
-               return (USB_ERR_INVAL);
+               uts->err = USB_ERR_INVAL;
+               goto done;
        }
        /* allocate zeroed memory */
        uts->buf = malloc(uts->size, M_USB, M_WAITOK | M_ZERO);
+       /*
+        * Allow malloc() to return NULL regardless of M_WAITOK flag.
+        * This helps when porting the software to non-FreeBSD
+        * systems.
+        */
        if (uts->buf == NULL) {
                /* could not allocate memory */
-               return (USB_ERR_NOMEM);
+               uts->err = USB_ERR_NOMEM;
+               goto done;
        }
        /* second pass */
 
@@ -1276,7 +1287,7 @@ usb_temp_setup(struct usb_device *udev,
 
        if (uts->err) {
                /* some error happened during second pass */
-               goto error;
+               goto done;
        }
        /*
         * Resolve all endpoint addresses !
@@ -1287,7 +1298,7 @@ usb_temp_setup(struct usb_device *udev,
                DPRINTFN(0, "Could not resolve endpoints for "
                    "Device Descriptor, error = %s\n",
                    usbd_errstr(uts->err));
-               goto error;
+               goto done;
        }
        for (n = 0;; n++) {
 
@@ -1300,14 +1311,16 @@ usb_temp_setup(struct usb_device *udev,
                        DPRINTFN(0, "Could not resolve endpoints for "
                            "Config Descriptor %u, error = %s\n", n,
                            usbd_errstr(uts->err));
-                       goto error;
+                       goto done;
                }
        }
-       return (uts->err);
-
-error:
-       usb_temp_unsetup(udev);
-       return (uts->err);
+done:
+       error = uts->err;
+       if (error)
+               usb_temp_unsetup(udev);
+       if (do_unlock)
+               usbd_enum_unlock(udev);
+       return (error);
 }
 
 /*------------------------------------------------------------------------*

Modified: stable/8/sys/dev/usb/usb_bus.h
==============================================================================
--- stable/8/sys/dev/usb/usb_bus.h      Thu Feb 21 07:48:07 2013        
(r247090)
+++ stable/8/sys/dev/usb/usb_bus.h      Thu Feb 21 08:21:14 2013        
(r247091)
@@ -103,16 +103,6 @@ struct usb_bus {
        uint8_t devices_max;            /* maximum number of USB devices */
        uint8_t do_probe;               /* set if USB should be re-probed */
        uint8_t no_explore;             /* don't explore USB ports */
-
-       /* 
-        * The scratch area can only be used inside the explore thread
-        * belonging to the give serial bus.
-        */
-       union {
-               struct usb_hw_ep_scratch hw_ep_scratch[1];
-               struct usb_temp_setup temp_setup[1];
-               uint8_t data[255];
-       }       scratch[1];
 };
 
 #endif                                 /* _USB_BUS_H_ */

Modified: stable/8/sys/dev/usb/usb_controller.h
==============================================================================
--- stable/8/sys/dev/usb/usb_controller.h       Thu Feb 21 07:48:07 2013        
(r247090)
+++ stable/8/sys/dev/usb/usb_controller.h       Thu Feb 21 08:21:14 2013        
(r247091)
@@ -40,7 +40,6 @@ struct usb_page_cache;
 struct usb_setup_params;
 struct usb_hw_ep_profile;
 struct usb_fs_isoc_schedule;
-struct usb_config_descriptor;
 struct usb_endpoint_descriptor;
 
 /* typedefs */
@@ -181,50 +180,6 @@ struct usb_hw_ep_profile {
        uint8_t support_out:1;          /* OUT-token is supported */
 };
 
-/*
- * The following structure is used when trying to allocate hardware
- * endpoints for an USB configuration in USB device side mode.
- */
-struct usb_hw_ep_scratch_sub {
-       const struct usb_hw_ep_profile *pf;
-       uint16_t max_frame_size;
-       uint8_t hw_endpoint_out;
-       uint8_t hw_endpoint_in;
-       uint8_t needs_ep_type;
-       uint8_t needs_in:1;
-       uint8_t needs_out:1;
-};
-
-/*
- * The following structure is used when trying to allocate hardware
- * endpoints for an USB configuration in USB device side mode.
- */
-struct usb_hw_ep_scratch {
-       struct usb_hw_ep_scratch_sub ep[USB_EP_MAX];
-       struct usb_hw_ep_scratch_sub *ep_max;
-       struct usb_config_descriptor *cd;
-       struct usb_device *udev;
-       struct usb_bus_methods *methods;
-       uint8_t bmOutAlloc[(USB_EP_MAX + 15) / 16];
-       uint8_t bmInAlloc[(USB_EP_MAX + 15) / 16];
-};
-
-/*
- * The following structure is used when generating USB descriptors
- * from USB templates.
- */
-struct usb_temp_setup {
-       void   *buf;
-       usb_size_t size;
-       enum usb_dev_speed      usb_speed;
-       uint8_t self_powered;
-       uint8_t bNumEndpoints;
-       uint8_t bInterfaceNumber;
-       uint8_t bAlternateSetting;
-       uint8_t bConfigurationValue;
-       usb_error_t err;
-};
-
 /* prototypes */
 
 void   usb_bus_mem_flush_all(struct usb_bus *bus, usb_bus_mem_cb_t *cb);

Modified: stable/8/sys/dev/usb/usb_dev.c
==============================================================================
--- stable/8/sys/dev/usb/usb_dev.c      Thu Feb 21 07:48:07 2013        
(r247090)
+++ stable/8/sys/dev/usb/usb_dev.c      Thu Feb 21 08:21:14 2013        
(r247091)
@@ -214,10 +214,10 @@ usb_ref_device(struct usb_cdev_privdata 
                mtx_unlock(&usb_ref_lock);
 
                /*
-                * We need to grab the sx-lock before grabbing the
-                * FIFO refs to avoid deadlock at detach!
+                * We need to grab the enumeration SX-lock before
+                * grabbing the FIFO refs to avoid deadlock at detach!
                 */
-               usbd_enum_lock(cpd->udev);
+               crd->do_unlock = usbd_enum_lock(cpd->udev);
 
                mtx_lock(&usb_ref_lock);
 
@@ -278,9 +278,10 @@ usb_ref_device(struct usb_cdev_privdata 
        return (0);
 
 error:
-       if (crd->is_uref) {
+       if (crd->do_unlock)
                usbd_enum_unlock(cpd->udev);
 
+       if (crd->is_uref) {
                if (--(cpd->udev->refcount) == 0) {
                        cv_signal(&cpd->udev->ref_cv);
                }
@@ -332,7 +333,7 @@ usb_unref_device(struct usb_cdev_privdat
 
        DPRINTFN(2, "cpd=%p is_uref=%d\n", cpd, crd->is_uref);
 
-       if (crd->is_uref)
+       if (crd->do_unlock)
                usbd_enum_unlock(cpd->udev);
 
        mtx_lock(&usb_ref_lock);

Modified: stable/8/sys/dev/usb/usb_dev.h
==============================================================================
--- stable/8/sys/dev/usb/usb_dev.h      Thu Feb 21 07:48:07 2013        
(r247090)
+++ stable/8/sys/dev/usb/usb_dev.h      Thu Feb 21 08:21:14 2013        
(r247091)
@@ -82,6 +82,7 @@ struct usb_cdev_refdata {
        uint8_t                 is_write;       /* location has write access */
        uint8_t                 is_uref;        /* USB refcount decr. needed */
        uint8_t                 is_usbfs;       /* USB-FS is active */
+       uint8_t                 do_unlock;      /* USB enum unlock needed */
 };
 
 struct usb_fs_privdata {

Modified: stable/8/sys/dev/usb/usb_device.c
==============================================================================
--- stable/8/sys/dev/usb/usb_device.c   Thu Feb 21 07:48:07 2013        
(r247090)
+++ stable/8/sys/dev/usb/usb_device.c   Thu Feb 21 08:21:14 2013        
(r247091)
@@ -443,13 +443,8 @@ usb_unconfigure(struct usb_device *udev,
 {
        uint8_t do_unlock;
 
-       /* automatic locking */
-       if (usbd_enum_is_locked(udev)) {
-               do_unlock = 0;
-       } else {
-               do_unlock = 1;
-               usbd_enum_lock(udev);
-       }
+       /* Prevent re-enumeration */
+       do_unlock = usbd_enum_lock(udev);
 
        /* detach all interface drivers */
        usb_detach_device(udev, USB_IFACE_INDEX_ANY, flag);
@@ -512,13 +507,8 @@ usbd_set_config_index(struct usb_device 
 
        DPRINTFN(6, "udev=%p index=%d\n", udev, index);
 
-       /* automatic locking */
-       if (usbd_enum_is_locked(udev)) {
-               do_unlock = 0;
-       } else {
-               do_unlock = 1;
-               usbd_enum_lock(udev);
-       }
+       /* Prevent re-enumeration */
+       do_unlock = usbd_enum_lock(udev);
 
        usb_unconfigure(udev, 0);
 
@@ -871,13 +861,9 @@ usbd_set_alt_interface_index(struct usb_
        usb_error_t err;
        uint8_t do_unlock;
 
-       /* automatic locking */
-       if (usbd_enum_is_locked(udev)) {
-               do_unlock = 0;
-       } else {
-               do_unlock = 1;
-               usbd_enum_lock(udev);
-       }
+       /* Prevent re-enumeration */
+       do_unlock = usbd_enum_lock(udev);
+
        if (iface == NULL) {
                err = USB_ERR_INVAL;
                goto done;
@@ -914,7 +900,6 @@ usbd_set_alt_interface_index(struct usb_
 done:
        if (do_unlock)
                usbd_enum_unlock(udev);
-
        return (err);
 }
 
@@ -1285,13 +1270,8 @@ usb_probe_and_attach(struct usb_device *
                DPRINTF("udev == NULL\n");
                return (USB_ERR_INVAL);
        }
-       /* automatic locking */
-       if (usbd_enum_is_locked(udev)) {
-               do_unlock = 0;
-       } else {
-               do_unlock = 1;
-               usbd_enum_lock(udev);
-       }
+       /* Prevent re-enumeration */
+       do_unlock = usbd_enum_lock(udev);
 
        if (udev->curr_config_index == USB_UNCONFIG_INDEX) {
                /* do nothing - no configuration has been set */
@@ -1378,7 +1358,6 @@ usb_probe_and_attach(struct usb_device *
 done:
        if (do_unlock)
                usbd_enum_unlock(udev);
-
        return (0);
 }
 
@@ -1507,6 +1486,7 @@ usb_alloc_device(device_t parent_dev, st
        uint8_t config_index;
        uint8_t config_quirk;
        uint8_t set_config_failed;
+       uint8_t do_unlock;
 
        DPRINTF("parent_dev=%p, bus=%p, parent_hub=%p, depth=%u, "
            "port_index=%u, port_no=%u, speed=%u, usb_mode=%u\n",
@@ -1541,9 +1521,6 @@ usb_alloc_device(device_t parent_dev, st
                return (NULL);
        }
        /* initialise our SX-lock */
-       sx_init_flags(&udev->ctrl_sx, "USB device SX lock", SX_DUPOK);
-
-       /* initialise our SX-lock */
        sx_init_flags(&udev->enum_sx, "USB config SX lock", SX_DUPOK);
        sx_init_flags(&udev->sr_sx, "USB suspend and resume SX lock", 
SX_NOWITNESS);
 
@@ -1725,7 +1702,11 @@ usb_alloc_device(device_t parent_dev, st
         * device descriptor. If no strings are present there we
         * simply disable all USB strings.
         */
-       scratch_ptr = udev->bus->scratch[0].data;
+
+       /* Protect scratch area */
+       do_unlock = usbd_enum_lock(udev);
+
+       scratch_ptr = udev->scratch.data;
 
        if (udev->ddesc.iManufacturer ||
            udev->ddesc.iProduct ||
@@ -1750,7 +1731,7 @@ usb_alloc_device(device_t parent_dev, st
                mask = usb_lang_mask;
 
                /* align length correctly */
-               scratch_ptr[0] &= ~1;
+               scratch_ptr[0] &= ~1U;
 
                /* fix compiler warning */
                langid = 0;
@@ -1771,6 +1752,9 @@ usb_alloc_device(device_t parent_dev, st
                udev->langid = langid;
        }
 
+       if (do_unlock)
+               usbd_enum_unlock(udev);
+
        /* assume 100mA bus powered for now. Changed when configured. */
        udev->power = USB_MIN_POWER;
        /* fetch the vendor and product strings from the device */
@@ -2107,7 +2091,6 @@ usb_free_device(struct usb_device *udev,
            &udev->cs_msg[0], &udev->cs_msg[1]);
        USB_BUS_UNLOCK(udev->bus);
 
-       sx_destroy(&udev->ctrl_sx);
        sx_destroy(&udev->enum_sx);
        sx_destroy(&udev->sr_sx);
 
@@ -2270,9 +2253,13 @@ usbd_set_device_strings(struct usb_devic
        size_t temp_size;
        uint16_t vendor_id;
        uint16_t product_id;
+       uint8_t do_unlock;
 
-       temp_ptr = (char *)udev->bus->scratch[0].data;
-       temp_size = sizeof(udev->bus->scratch[0].data);
+       /* Protect scratch area */
+       do_unlock = usbd_enum_lock(udev);
+
+       temp_ptr = (char *)udev->scratch.data;
+       temp_size = sizeof(udev->scratch.data);
 
        vendor_id = UGETW(udd->idVendor);
        product_id = UGETW(udd->idProduct);
@@ -2327,6 +2314,9 @@ usbd_set_device_strings(struct usb_devic
                snprintf(temp_ptr, temp_size, "product 0x%04x", product_id);
                udev->product = strdup(temp_ptr, M_USB);
        }
+
+       if (do_unlock)
+               usbd_enum_unlock(udev);
 }
 
 /*
@@ -2714,11 +2704,17 @@ usbd_device_attached(struct usb_device *
        return (udev->state > USB_STATE_DETACHED);
 }
 
-/* The following function locks enumerating the given USB device. */
-
-void
+/*
+ * The following function locks enumerating the given USB device. If
+ * the lock is already grabbed this function returns zero. Else a
+ * non-zero value is returned.
+ */
+uint8_t
 usbd_enum_lock(struct usb_device *udev)
 {
+       if (sx_xlocked(&udev->enum_sx))
+               return (0);
+
        sx_xlock(&udev->enum_sx);
        sx_xlock(&udev->sr_sx);
        /* 
@@ -2727,6 +2723,7 @@ usbd_enum_lock(struct usb_device *udev)
         * locked multiple times.
         */
        mtx_lock(&Giant);
+       return (1);
 }
 
 /* The following function unlocks enumerating the given USB device. */

Modified: stable/8/sys/dev/usb/usb_device.h
==============================================================================
--- stable/8/sys/dev/usb/usb_device.h   Thu Feb 21 07:48:07 2013        
(r247090)
+++ stable/8/sys/dev/usb/usb_device.h   Thu Feb 21 08:21:14 2013        
(r247091)
@@ -27,9 +27,18 @@
 #ifndef _USB_DEVICE_H_
 #define        _USB_DEVICE_H_
 
-struct usb_symlink;            /* UGEN */
+#ifndef USB_GLOBAL_INCLUDE_FILE
+#include <dev/usb/usb_core.h>
+#include <dev/usb/usb_busdma.h>
+#include <dev/usb/usb_transfer.h>
+#endif
+
+struct usb_bus_methods;
+struct usb_config_descriptor;
 struct usb_device;             /* linux compat */
 struct usb_fs_privdata;
+struct usb_hw_ep_profile;
+struct usb_symlink;            /* UGEN */
 
 #define        USB_CTRL_XFER_MAX 2
 
@@ -108,13 +117,70 @@ struct usb_power_save {
 };
 
 /*
+ * The following structure is used when trying to allocate hardware
+ * endpoints for an USB configuration in USB device side mode.
+ */
+struct usb_hw_ep_scratch_sub {
+       const struct usb_hw_ep_profile *pf;
+       uint16_t max_frame_size;
+       uint8_t hw_endpoint_out;
+       uint8_t hw_endpoint_in;
+       uint8_t needs_ep_type;
+       uint8_t needs_in:1;
+       uint8_t needs_out:1;
+};
+
+/*
+ * The following structure is used when trying to allocate hardware
+ * endpoints for an USB configuration in USB device side mode.
+ */
+struct usb_hw_ep_scratch {
+       struct usb_hw_ep_scratch_sub ep[USB_EP_MAX];
+       struct usb_hw_ep_scratch_sub *ep_max;
+       struct usb_config_descriptor *cd;
+       struct usb_device *udev;
+       struct usb_bus_methods *methods;
+       uint8_t bmOutAlloc[(USB_EP_MAX + 15) / 16];
+       uint8_t bmInAlloc[(USB_EP_MAX + 15) / 16];
+};
+
+/*
+ * The following structure is used when generating USB descriptors
+ * from USB templates.
+ */
+struct usb_temp_setup {
+       void   *buf;
+       usb_size_t size;
+       enum usb_dev_speed      usb_speed;
+       uint8_t self_powered;
+       uint8_t bNumEndpoints;
+       uint8_t bInterfaceNumber;
+       uint8_t bAlternateSetting;
+       uint8_t bConfigurationValue;
+       usb_error_t err;
+};
+
+/* 
+ * The scratch area for USB devices. Access to this structure is
+ * protected by the enumeration SX lock.
+ */
+union usb_device_scratch {
+       struct usb_hw_ep_scratch hw_ep_scratch[1];
+       struct usb_temp_setup temp_setup[1];
+       struct {
+               struct usb_xfer dummy;
+               struct usb_setup_params parm;
+       } xfer_setup[1];
+       uint8_t data[255];
+};
+
+/*
  * The following structure defines an USB device. There exists one of
  * these structures for every USB device.
  */
 struct usb_device {
        struct usb_clear_stall_msg cs_msg[2];   /* generic clear stall
                                                 * messages */
-       struct sx ctrl_sx;
        struct sx enum_sx;
        struct sx sr_sx;
        struct mtx device_mtx;
@@ -192,6 +258,8 @@ struct usb_device {
        uint32_t clear_stall_errors;    /* number of clear-stall failures */
 
        uint16_t autoQuirk[USB_MAX_AUTO_QUIRK];         /* dynamic quirks */
+
+       union usb_device_scratch scratch;
 };
 
 /* globals */
@@ -228,7 +296,7 @@ struct usb_endpoint *usb_endpoint_foreac
 void   usb_set_device_state(struct usb_device *, enum usb_dev_state);
 enum usb_dev_state usb_get_device_state(struct usb_device *);
 
-void   usbd_enum_lock(struct usb_device *);
+uint8_t        usbd_enum_lock(struct usb_device *);
 void   usbd_enum_unlock(struct usb_device *);
 void   usbd_sr_lock(struct usb_device *);
 void   usbd_sr_unlock(struct usb_device *);

Modified: stable/8/sys/dev/usb/usb_generic.c
==============================================================================
--- stable/8/sys/dev/usb/usb_generic.c  Thu Feb 21 07:48:07 2013        
(r247090)
+++ stable/8/sys/dev/usb/usb_generic.c  Thu Feb 21 08:21:14 2013        
(r247091)
@@ -713,13 +713,20 @@ ugen_get_cdesc(struct usb_fifo *f, struc
        return (error);
 }
 
+/*
+ * This function is called having the enumeration SX locked which
+ * protects the scratch area used.
+ */
 static int
 ugen_get_sdesc(struct usb_fifo *f, struct usb_gen_descriptor *ugd)
 {
-       void *ptr = f->udev->bus->scratch[0].data;
-       uint16_t size = sizeof(f->udev->bus->scratch[0].data);
+       void *ptr;
+       uint16_t size;
        int error;
 
+       ptr = f->udev->scratch.data;
+       size = sizeof(f->udev->scratch.data);
+
        if (usbd_req_get_string_desc(f->udev, NULL, ptr,
            size, ugd->ugd_lang_id, ugd->ugd_string_index)) {
                error = EINVAL;

Modified: stable/8/sys/dev/usb/usb_handle_request.c
==============================================================================
--- stable/8/sys/dev/usb/usb_handle_request.c   Thu Feb 21 07:48:07 2013        
(r247090)
+++ stable/8/sys/dev/usb/usb_handle_request.c   Thu Feb 21 08:21:14 2013        
(r247091)
@@ -145,6 +145,7 @@ usb_handle_set_config(struct usb_xfer *x
 {
        struct usb_device *udev = xfer->xroot->udev;
        usb_error_t err = 0;
+       uint8_t do_unlock;
 
        /*
         * We need to protect against other threads doing probe and
@@ -152,7 +153,8 @@ usb_handle_set_config(struct usb_xfer *x
         */
        USB_XFER_UNLOCK(xfer);
 
-       usbd_enum_lock(udev);
+       /* Prevent re-enumeration */
+       do_unlock = usbd_enum_lock(udev);
 
        if (conf_no == USB_UNCONFIG_NO) {
                conf_no = USB_UNCONFIG_INDEX;
@@ -175,7 +177,8 @@ usb_handle_set_config(struct usb_xfer *x
                goto done;
        }
 done:
-       usbd_enum_unlock(udev);
+       if (do_unlock)
+               usbd_enum_unlock(udev);
        USB_XFER_LOCK(xfer);
        return (err);
 }
@@ -187,13 +190,8 @@ usb_check_alt_setting(struct usb_device 
        uint8_t do_unlock;
        usb_error_t err = 0;
 
-       /* automatic locking */
-       if (usbd_enum_is_locked(udev)) {
-               do_unlock = 0;
-       } else {
-               do_unlock = 1;
-               usbd_enum_lock(udev);
-       }
+       /* Prevent re-enumeration */
+       do_unlock = usbd_enum_lock(udev);
 
        if (alt_index >= usbd_get_no_alts(udev->cdesc, iface->idesc))
                err = USB_ERR_INVAL;
@@ -222,6 +220,7 @@ usb_handle_iface_request(struct usb_xfer
        int error;
        uint8_t iface_index;
        uint8_t temp_state;
+       uint8_t do_unlock;
 
        if ((req.bmRequestType & 0x1F) == UT_INTERFACE) {
                iface_index = req.wIndex[0];    /* unicast */
@@ -235,7 +234,8 @@ usb_handle_iface_request(struct usb_xfer
         */
        USB_XFER_UNLOCK(xfer);
 
-       usbd_enum_lock(udev);
+       /* Prevent re-enumeration */
+       do_unlock = usbd_enum_lock(udev);
 
        error = ENXIO;
 
@@ -351,17 +351,20 @@ tr_repeat:
                goto tr_stalled;
        }
 tr_valid:
-       usbd_enum_unlock(udev);
+       if (do_unlock)
+               usbd_enum_unlock(udev);
        USB_XFER_LOCK(xfer);
        return (0);
 
 tr_short:
-       usbd_enum_unlock(udev);
+       if (do_unlock)
+               usbd_enum_unlock(udev);
        USB_XFER_LOCK(xfer);
        return (USB_ERR_SHORT_XFER);
 
 tr_stalled:
-       usbd_enum_unlock(udev);
+       if (do_unlock)
+               usbd_enum_unlock(udev);
        USB_XFER_LOCK(xfer);
        return (USB_ERR_STALLED);
 }

Modified: stable/8/sys/dev/usb/usb_hub.c
==============================================================================
--- stable/8/sys/dev/usb/usb_hub.c      Thu Feb 21 07:48:07 2013        
(r247090)
+++ stable/8/sys/dev/usb/usb_hub.c      Thu Feb 21 08:21:14 2013        
(r247091)
@@ -240,7 +240,9 @@ uhub_explore_sub(struct uhub_softc *sc, 
        /* check if device should be re-enumerated */
 
        if (child->flags.usb_mode == USB_MODE_HOST) {
-               usbd_enum_lock(child);
+               uint8_t do_unlock;
+               
+               do_unlock = usbd_enum_lock(child);
                if (child->re_enumerate_wait) {
                        err = usbd_set_config_index(child,
                            USB_UNCONFIG_INDEX);
@@ -259,7 +261,8 @@ uhub_explore_sub(struct uhub_softc *sc, 
                        child->re_enumerate_wait = 0;
                        err = 0;
                }
-               usbd_enum_unlock(child);
+               if (do_unlock)
+                       usbd_enum_unlock(child);
        }
 
        /* check if probe and attach should be done */
@@ -710,6 +713,7 @@ uhub_explore(struct usb_device *udev)
        usb_error_t err;
        uint8_t portno;
        uint8_t x;
+       uint8_t do_unlock;
 
        hub = udev->hub;
        sc = hub->hubsoftc;
@@ -731,7 +735,7 @@ uhub_explore(struct usb_device *udev)
         * Make sure we don't race against user-space applications
         * like LibUSB:
         */
-       usbd_enum_lock(udev);
+       do_unlock = usbd_enum_lock(udev);
 
        for (x = 0; x != hub->nports; x++) {
                up = hub->ports + x;
@@ -811,7 +815,8 @@ uhub_explore(struct usb_device *udev)
                up->restartcnt = 0;
        }
 
-       usbd_enum_unlock(udev);
+       if (do_unlock)
+               usbd_enum_unlock(udev);
 
        /* initial status checked */
        sc->sc_flags |= UHUB_FLAG_DID_EXPLORE;

Modified: stable/8/sys/dev/usb/usb_msctest.c
==============================================================================
--- stable/8/sys/dev/usb/usb_msctest.c  Thu Feb 21 07:48:07 2013        
(r247090)
+++ stable/8/sys/dev/usb/usb_msctest.c  Thu Feb 21 08:21:14 2013        
(r247091)
@@ -500,13 +500,8 @@ bbb_attach(struct usb_device *udev, uint
        usb_error_t err;
        uint8_t do_unlock;
 
-       /* automatic locking */
-       if (usbd_enum_is_locked(udev)) {
-               do_unlock = 0;
-       } else {
-               do_unlock = 1;
-               usbd_enum_lock(udev);
-       }
+       /* Prevent re-enumeration */
+       do_unlock = usbd_enum_lock(udev);
 
        /*
         * Make sure any driver which is hooked up to this interface,

Modified: stable/8/sys/dev/usb/usb_request.c
==============================================================================
--- stable/8/sys/dev/usb/usb_request.c  Thu Feb 21 07:48:07 2013        
(r247090)
+++ stable/8/sys/dev/usb/usb_request.c  Thu Feb 21 08:21:14 2013        
(r247091)
@@ -382,9 +382,8 @@ usbd_get_hr_func(struct usb_device *udev
  * than 30 seconds is treated like a 30 second timeout. This USB stack
  * does not allow control requests without a timeout.
  *
- * NOTE: This function is thread safe. All calls to
- * "usbd_do_request_flags" will be serialised by the use of an
- * internal "sx_lock".
+ * NOTE: This function is thread safe. All calls to "usbd_do_request_flags"
+ * will be serialized by the use of the USB device enumeration lock.
  *
  * Returns:
  *    0: Success
@@ -408,7 +407,7 @@ usbd_do_request_flags(struct usb_device 
        uint16_t length;
        uint16_t temp;
        uint16_t acttemp;
-       uint8_t enum_locked;
+       uint8_t do_unlock;
 
        if (timeout < 50) {
                /* timeout is too small */
@@ -420,8 +419,6 @@ usbd_do_request_flags(struct usb_device 
        }
        length = UGETW(req->wLength);
 
-       enum_locked = usbd_enum_is_locked(udev);
-
        DPRINTFN(5, "udev=%p bmRequestType=0x%02x bRequest=0x%02x "
            "wValue=0x%02x%02x wIndex=0x%02x%02x wLength=0x%02x%02x\n",
            udev, req->bmRequestType, req->bRequest,
@@ -452,17 +449,16 @@ usbd_do_request_flags(struct usb_device 
        }
 
        /*
-        * We need to allow suspend and resume at this point, else the
-        * control transfer will timeout if the device is suspended!
+        * Grab the USB device enumeration SX-lock serialization is
+        * achieved when multiple threads are involved:
         */
-       if (enum_locked)
-               usbd_sr_unlock(udev);
+       do_unlock = usbd_enum_lock(udev);
 
        /*
-        * Grab the default sx-lock so that serialisation
-        * is achieved when multiple threads are involved:
+        * We need to allow suspend and resume at this point, else the
+        * control transfer will timeout if the device is suspended!
         */
-       sx_xlock(&udev->ctrl_sx);
+       usbd_sr_unlock(udev);
 
        hr_func = usbd_get_hr_func(udev);
 
@@ -706,10 +702,10 @@ usbd_do_request_flags(struct usb_device 
        USB_XFER_UNLOCK(xfer);
 
 done:
-       sx_xunlock(&udev->ctrl_sx);
+       usbd_sr_lock(udev);
 
-       if (enum_locked)
-               usbd_sr_lock(udev);
+       if (do_unlock)
+               usbd_enum_unlock(udev);
 
        if ((mtx != NULL) && (mtx != &Giant))
                mtx_lock(mtx);

Modified: stable/8/sys/dev/usb/usb_transfer.c
==============================================================================
--- stable/8/sys/dev/usb/usb_transfer.c Thu Feb 21 07:48:07 2013        
(r247090)
+++ stable/8/sys/dev/usb/usb_transfer.c Thu Feb 21 08:21:14 2013        
(r247091)
@@ -22,7 +22,7 @@
  * 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.
- */ 
+ */
 
 #include <sys/stdint.h>
 #include <sys/stddef.h>
@@ -810,20 +810,17 @@ usbd_transfer_setup(struct usb_device *u
     const struct usb_config *setup_start, uint16_t n_setup,
     void *priv_sc, struct mtx *xfer_mtx)
 {
-       struct usb_xfer dummy;
-       struct usb_setup_params parm;
        const struct usb_config *setup_end = setup_start + n_setup;
        const struct usb_config *setup;
+       struct usb_setup_params *parm;
        struct usb_endpoint *ep;
        struct usb_xfer_root *info;
        struct usb_xfer *xfer;
        void *buf = NULL;
+       usb_error_t error = 0;
        uint16_t n;
        uint16_t refcount;
-
-       parm.err = 0;
-       refcount = 0;
-       info = NULL;
+       uint8_t do_unlock;
 
        WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL,
            "usbd_transfer_setup can sleep!");
@@ -842,31 +839,40 @@ usbd_transfer_setup(struct usb_device *u
                DPRINTFN(6, "using global lock\n");
                xfer_mtx = &Giant;
        }
-       /* sanity checks */
+
+       /* more sanity checks */
+
        for (setup = setup_start, n = 0;
            setup != setup_end; setup++, n++) {
                if (setup->bufsize == (usb_frlength_t)-1) {
-                       parm.err = USB_ERR_BAD_BUFSIZE;
+                       error = USB_ERR_BAD_BUFSIZE;
                        DPRINTF("invalid bufsize\n");
                }
                if (setup->callback == NULL) {
-                       parm.err = USB_ERR_NO_CALLBACK;
+                       error = USB_ERR_NO_CALLBACK;
                        DPRINTF("no callback\n");
                }
                ppxfer[n] = NULL;
        }
 
-       if (parm.err) {
-               goto done;
-       }
-       memset(&parm, 0, sizeof(parm));
+       if (error)
+               return (error);
+
+       /* Protect scratch area */
+       do_unlock = usbd_enum_lock(udev);
 
-       parm.udev = udev;
-       parm.speed = usbd_get_speed(udev);
-       parm.hc_max_packet_count = 1;
+       refcount = 0;
+       info = NULL;
 
-       if (parm.speed >= USB_SPEED_MAX) {
-               parm.err = USB_ERR_INVAL;
+       parm = &udev->scratch.xfer_setup[0].parm;
+       memset(parm, 0, sizeof(*parm));
+
+       parm->udev = udev;
+       parm->speed = usbd_get_speed(udev);
+       parm->hc_max_packet_count = 1;
+
+       if (parm->speed >= USB_SPEED_MAX) {
+               parm->err = USB_ERR_INVAL;
                goto done;
        }
        /* setup all transfers */
@@ -881,22 +887,22 @@ usbd_transfer_setup(struct usb_device *u
                        info = USB_ADD_BYTES(buf, 0);
 
                        info->memory_base = buf;

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to