svn commit: r247090 - in stable/9/sys: dev/usb dev/usb/controller dev/usb/template sys

Hans Petter Selasky hselasky at FreeBSD.org
Thu Feb 21 07:48:10 UTC 2013


Author: hselasky
Date: Thu Feb 21 07:48:07 2013
New Revision: 247090
URL: http://svnweb.freebsd.org/changeset/base/247090

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/9/sys/dev/usb/controller/usb_controller.c
  stable/9/sys/dev/usb/template/usb_template.c
  stable/9/sys/dev/usb/usb_bus.h
  stable/9/sys/dev/usb/usb_controller.h
  stable/9/sys/dev/usb/usb_dev.c
  stable/9/sys/dev/usb/usb_dev.h
  stable/9/sys/dev/usb/usb_device.c
  stable/9/sys/dev/usb/usb_device.h
  stable/9/sys/dev/usb/usb_generic.c
  stable/9/sys/dev/usb/usb_handle_request.c
  stable/9/sys/dev/usb/usb_hub.c
  stable/9/sys/dev/usb/usb_msctest.c
  stable/9/sys/dev/usb/usb_request.c
  stable/9/sys/dev/usb/usb_transfer.c
  stable/9/sys/dev/usb/usb_util.c
  stable/9/sys/sys/param.h
Directory Properties:
  stable/9/sys/   (props changed)
  stable/9/sys/boot/   (props changed)
  stable/9/sys/dev/   (props changed)

Modified: stable/9/sys/dev/usb/controller/usb_controller.c
==============================================================================
--- stable/9/sys/dev/usb/controller/usb_controller.c	Thu Feb 21 07:19:50 2013	(r247089)
+++ stable/9/sys/dev/usb/controller/usb_controller.c	Thu Feb 21 07:48:07 2013	(r247090)
@@ -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/9/sys/dev/usb/template/usb_template.c
==============================================================================
--- stable/9/sys/dev/usb/template/usb_template.c	Thu Feb 21 07:19:50 2013	(r247089)
+++ stable/9/sys/dev/usb/template/usb_template.c	Thu Feb 21 07:48:07 2013	(r247090)
@@ -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/9/sys/dev/usb/usb_bus.h
==============================================================================
--- stable/9/sys/dev/usb/usb_bus.h	Thu Feb 21 07:19:50 2013	(r247089)
+++ stable/9/sys/dev/usb/usb_bus.h	Thu Feb 21 07:48:07 2013	(r247090)
@@ -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/9/sys/dev/usb/usb_controller.h
==============================================================================
--- stable/9/sys/dev/usb/usb_controller.h	Thu Feb 21 07:19:50 2013	(r247089)
+++ stable/9/sys/dev/usb/usb_controller.h	Thu Feb 21 07:48:07 2013	(r247090)
@@ -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/9/sys/dev/usb/usb_dev.c
==============================================================================
--- stable/9/sys/dev/usb/usb_dev.c	Thu Feb 21 07:19:50 2013	(r247089)
+++ stable/9/sys/dev/usb/usb_dev.c	Thu Feb 21 07:48:07 2013	(r247090)
@@ -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/9/sys/dev/usb/usb_dev.h
==============================================================================
--- stable/9/sys/dev/usb/usb_dev.h	Thu Feb 21 07:19:50 2013	(r247089)
+++ stable/9/sys/dev/usb/usb_dev.h	Thu Feb 21 07:48:07 2013	(r247090)
@@ -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/9/sys/dev/usb/usb_device.c
==============================================================================
--- stable/9/sys/dev/usb/usb_device.c	Thu Feb 21 07:19:50 2013	(r247089)
+++ stable/9/sys/dev/usb/usb_device.c	Thu Feb 21 07:48:07 2013	(r247090)
@@ -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);
 }
 
 /*
@@ -2639,11 +2629,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);
 	/* 
@@ -2652,6 +2648,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/9/sys/dev/usb/usb_device.h
==============================================================================
--- stable/9/sys/dev/usb/usb_device.h	Thu Feb 21 07:19:50 2013	(r247089)
+++ stable/9/sys/dev/usb/usb_device.h	Thu Feb 21 07:48:07 2013	(r247090)
@@ -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;
@@ -191,6 +257,8 @@ struct usb_device {
 #endif
 
 	uint32_t clear_stall_errors;	/* number of clear-stall failures */
+
+	union usb_device_scratch scratch;
 };
 
 /* globals */
@@ -227,7 +295,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/9/sys/dev/usb/usb_generic.c
==============================================================================
--- stable/9/sys/dev/usb/usb_generic.c	Thu Feb 21 07:19:50 2013	(r247089)
+++ stable/9/sys/dev/usb/usb_generic.c	Thu Feb 21 07:48:07 2013	(r247090)
@@ -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/9/sys/dev/usb/usb_handle_request.c
==============================================================================
--- stable/9/sys/dev/usb/usb_handle_request.c	Thu Feb 21 07:19:50 2013	(r247089)
+++ stable/9/sys/dev/usb/usb_handle_request.c	Thu Feb 21 07:48:07 2013	(r247090)
@@ -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/9/sys/dev/usb/usb_hub.c
==============================================================================
--- stable/9/sys/dev/usb/usb_hub.c	Thu Feb 21 07:19:50 2013	(r247089)
+++ stable/9/sys/dev/usb/usb_hub.c	Thu Feb 21 07:48:07 2013	(r247090)
@@ -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/9/sys/dev/usb/usb_msctest.c
==============================================================================
--- stable/9/sys/dev/usb/usb_msctest.c	Thu Feb 21 07:19:50 2013	(r247089)
+++ stable/9/sys/dev/usb/usb_msctest.c	Thu Feb 21 07:48:07 2013	(r247090)
@@ -501,13 +501,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/9/sys/dev/usb/usb_request.c
==============================================================================
--- stable/9/sys/dev/usb/usb_request.c	Thu Feb 21 07:19:50 2013	(r247089)
+++ stable/9/sys/dev/usb/usb_request.c	Thu Feb 21 07:48:07 2013	(r247090)
@@ -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/9/sys/dev/usb/usb_transfer.c
==============================================================================
--- stable/9/sys/dev/usb/usb_transfer.c	Thu Feb 21 07:19:50 2013	(r247089)
+++ stable/9/sys/dev/usb/usb_transfer.c	Thu Feb 21 07:48:07 2013	(r247090)
@@ -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 ***


More information about the svn-src-stable-9 mailing list