[Midnightbsd-cvs] src [6566] trunk/sys/dev/usb: Update USB stack

laffer1 at midnightbsd.org laffer1 at midnightbsd.org
Sat Dec 28 10:27:54 EST 2013


Revision: 6566
          http://svnweb.midnightbsd.org/src/?rev=6566
Author:   laffer1
Date:     2013-12-28 10:27:54 -0500 (Sat, 28 Dec 2013)
Log Message:
-----------
Update USB stack

Obtained from: FreeBSD 9.2

Modified Paths:
--------------
    trunk/sys/dev/usb/usb.h
    trunk/sys/dev/usb/usb_bus.h
    trunk/sys/dev/usb/usb_controller.h
    trunk/sys/dev/usb/usb_debug.c
    trunk/sys/dev/usb/usb_debug.h
    trunk/sys/dev/usb/usb_dev.c
    trunk/sys/dev/usb/usb_dev.h
    trunk/sys/dev/usb/usb_device.c
    trunk/sys/dev/usb/usb_device.h
    trunk/sys/dev/usb/usb_generic.c
    trunk/sys/dev/usb/usb_handle_request.c
    trunk/sys/dev/usb/usb_hid.c
    trunk/sys/dev/usb/usb_hub.c
    trunk/sys/dev/usb/usb_ioctl.h
    trunk/sys/dev/usb/usb_msctest.c
    trunk/sys/dev/usb/usb_process.c
    trunk/sys/dev/usb/usb_process.h
    trunk/sys/dev/usb/usb_request.c
    trunk/sys/dev/usb/usb_transfer.c
    trunk/sys/dev/usb/usb_util.c
    trunk/sys/dev/usb/usbdi.h
    trunk/sys/dev/usb/usbhid.h

Modified: trunk/sys/dev/usb/usb.h
===================================================================
--- trunk/sys/dev/usb/usb.h	2013-12-28 15:25:37 UTC (rev 6565)
+++ trunk/sys/dev/usb/usb.h	2013-12-28 15:27:54 UTC (rev 6566)
@@ -93,31 +93,29 @@
 #define	USB_POWER_MODE_SUSPEND 3	/* force suspend */
 #define	USB_POWER_MODE_RESUME 4		/* force resume */
 
-#if 0
 /* These are the values from the USB specification. */
-#define	USB_PORT_RESET_DELAY	10	/* ms */
-#define	USB_PORT_ROOT_RESET_DELAY 50	/* ms */
-#define	USB_PORT_RESET_RECOVERY	10	/* ms */
-#define	USB_PORT_POWERUP_DELAY	100	/* ms */
-#define	USB_PORT_RESUME_DELAY	20	/* ms */
-#define	USB_SET_ADDRESS_SETTLE	2	/* ms */
-#define	USB_RESUME_DELAY	(20*5)	/* ms */
-#define	USB_RESUME_WAIT		10	/* ms */
-#define	USB_RESUME_RECOVERY	10	/* ms */
-#define	USB_EXTRA_POWER_UP_TIME	0	/* ms */
-#else
+#define	USB_PORT_RESET_DELAY_SPEC	10	/* ms */
+#define	USB_PORT_ROOT_RESET_DELAY_SPEC	50	/* ms */
+#define	USB_PORT_RESET_RECOVERY_SPEC	10	/* ms */
+#define	USB_PORT_POWERUP_DELAY_SPEC	100	/* ms */
+#define	USB_PORT_RESUME_DELAY_SPEC	20	/* ms */
+#define	USB_SET_ADDRESS_SETTLE_SPEC	2	/* ms */
+#define	USB_RESUME_DELAY_SPEC		(20*5)	/* ms */
+#define	USB_RESUME_WAIT_SPEC		10	/* ms */
+#define	USB_RESUME_RECOVERY_SPEC	10	/* ms */
+#define	USB_EXTRA_POWER_UP_TIME_SPEC	0	/* ms */
+
 /* Allow for marginal and non-conforming devices. */
-#define	USB_PORT_RESET_DELAY	50	/* ms */
-#define	USB_PORT_ROOT_RESET_DELAY 250	/* ms */
-#define	USB_PORT_RESET_RECOVERY	250	/* ms */
-#define	USB_PORT_POWERUP_DELAY	300	/* ms */
-#define	USB_PORT_RESUME_DELAY	(20*2)	/* ms */
-#define	USB_SET_ADDRESS_SETTLE	10	/* ms */
-#define	USB_RESUME_DELAY	(50*5)	/* ms */
-#define	USB_RESUME_WAIT		50	/* ms */
-#define	USB_RESUME_RECOVERY	50	/* ms */
-#define	USB_EXTRA_POWER_UP_TIME	20	/* ms */
-#endif
+#define	USB_PORT_RESET_DELAY		50	/* ms */
+#define	USB_PORT_ROOT_RESET_DELAY	250	/* ms */
+#define	USB_PORT_RESET_RECOVERY		250	/* ms */
+#define	USB_PORT_POWERUP_DELAY		300	/* ms */
+#define	USB_PORT_RESUME_DELAY		(20*2)	/* ms */
+#define	USB_SET_ADDRESS_SETTLE		10	/* ms */
+#define	USB_RESUME_DELAY		(50*5)	/* ms */
+#define	USB_RESUME_WAIT			50	/* ms */
+#define	USB_RESUME_RECOVERY		50	/* ms */
+#define	USB_EXTRA_POWER_UP_TIME		20	/* ms */
 
 #define	USB_MIN_POWER		100	/* mA */
 #define	USB_MAX_POWER		500	/* mA */

Modified: trunk/sys/dev/usb/usb_bus.h
===================================================================
--- trunk/sys/dev/usb/usb_bus.h	2013-12-28 15:25:37 UTC (rev 6565)
+++ trunk/sys/dev/usb/usb_bus.h	2013-12-28 15:27:54 UTC (rev 6566)
@@ -103,16 +103,6 @@
 	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: trunk/sys/dev/usb/usb_controller.h
===================================================================
--- trunk/sys/dev/usb/usb_controller.h	2013-12-28 15:25:37 UTC (rev 6565)
+++ trunk/sys/dev/usb/usb_controller.h	2013-12-28 15:27:54 UTC (rev 6566)
@@ -40,7 +40,6 @@
 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 @@
 	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: trunk/sys/dev/usb/usb_debug.c
===================================================================
--- trunk/sys/dev/usb/usb_debug.c	2013-12-28 15:25:37 UTC (rev 6565)
+++ trunk/sys/dev/usb/usb_debug.c	2013-12-28 15:27:54 UTC (rev 6566)
@@ -63,11 +63,59 @@
 int	usb_debug = 0;
 
 SYSCTL_NODE(_hw, OID_AUTO, usb, CTLFLAG_RW, 0, "USB debugging");
-SYSCTL_INT(_hw_usb, OID_AUTO, debug, CTLFLAG_RW,
+SYSCTL_INT(_hw_usb, OID_AUTO, debug, CTLFLAG_RW | CTLFLAG_TUN,
     &usb_debug, 0, "Debug level");
-
 TUNABLE_INT("hw.usb.debug", &usb_debug);
 
+#ifdef USB_DEBUG
+/*
+ * Sysctls to modify timings/delays
+ */
+static SYSCTL_NODE(_hw_usb, OID_AUTO, timings, CTLFLAG_RW, 0, "Timings");
+static int usb_timings_sysctl_handler(SYSCTL_HANDLER_ARGS);
+
+TUNABLE_INT("hw.usb.timings.port_reset_delay", (int *)&usb_port_reset_delay);
+SYSCTL_PROC(_hw_usb_timings, OID_AUTO, port_reset_delay, CTLTYPE_UINT | CTLFLAG_RW | CTLFLAG_TUN,
+    &usb_port_reset_delay, sizeof(usb_port_reset_delay),
+    usb_timings_sysctl_handler, "IU", "Port Reset Delay");
+TUNABLE_INT("hw.usb.timings.port_root_reset_delay", (int *)&usb_port_root_reset_delay);
+SYSCTL_PROC(_hw_usb_timings, OID_AUTO, port_root_reset_delay, CTLTYPE_UINT | CTLFLAG_RW | CTLFLAG_TUN,
+    &usb_port_root_reset_delay, sizeof(usb_port_root_reset_delay),
+    usb_timings_sysctl_handler, "IU", "Root Port Reset Delay");
+TUNABLE_INT("hw.usb.timings.port_reset_recovery", (int *)&usb_port_reset_recovery);
+SYSCTL_PROC(_hw_usb_timings, OID_AUTO, port_reset_recovery, CTLTYPE_UINT | CTLFLAG_RW | CTLFLAG_TUN,
+    &usb_port_reset_recovery, sizeof(usb_port_reset_recovery),
+    usb_timings_sysctl_handler, "IU", "Port Reset Recovery");
+TUNABLE_INT("hw.usb.timings.port_powerup_delay", (int *)&usb_port_powerup_delay);
+SYSCTL_PROC(_hw_usb_timings, OID_AUTO, port_powerup_delay, CTLTYPE_UINT | CTLFLAG_RW | CTLFLAG_TUN,
+    &usb_port_powerup_delay, sizeof(usb_port_powerup_delay),
+    usb_timings_sysctl_handler, "IU", "Port PowerUp Delay");
+TUNABLE_INT("hw.usb.timings.port_resume_delay", (int *)&usb_port_resume_delay);
+SYSCTL_PROC(_hw_usb_timings, OID_AUTO, port_resume_delay, CTLTYPE_UINT | CTLFLAG_RW | CTLFLAG_TUN,
+    &usb_port_resume_delay, sizeof(usb_port_resume_delay),
+    usb_timings_sysctl_handler, "IU", "Port Resume Delay");
+TUNABLE_INT("hw.usb.timings.set_address_settle", (int *)&usb_set_address_settle);
+SYSCTL_PROC(_hw_usb_timings, OID_AUTO, set_address_settle, CTLTYPE_UINT | CTLFLAG_RW | CTLFLAG_TUN,
+    &usb_set_address_settle, sizeof(usb_set_address_settle),
+    usb_timings_sysctl_handler, "IU", "Set Address Settle");
+TUNABLE_INT("hw.usb.timings.resume_delay", (int *)&usb_resume_delay);
+SYSCTL_PROC(_hw_usb_timings, OID_AUTO, resume_delay, CTLTYPE_UINT | CTLFLAG_RW | CTLFLAG_TUN,
+    &usb_resume_delay, sizeof(usb_resume_delay),
+    usb_timings_sysctl_handler, "IU", "Resume Delay");
+TUNABLE_INT("hw.usb.timings.resume_wait", (int *)&usb_resume_wait);
+SYSCTL_PROC(_hw_usb_timings, OID_AUTO, resume_wait, CTLTYPE_UINT | CTLFLAG_RW | CTLFLAG_TUN,
+    &usb_resume_wait, sizeof(usb_resume_wait),
+    usb_timings_sysctl_handler, "IU", "Resume Wait");
+TUNABLE_INT("hw.usb.timings.resume_recovery", (int *)&usb_resume_recovery);
+SYSCTL_PROC(_hw_usb_timings, OID_AUTO, resume_recovery, CTLTYPE_UINT | CTLFLAG_RW | CTLFLAG_TUN,
+    &usb_resume_recovery, sizeof(usb_resume_recovery),
+    usb_timings_sysctl_handler, "IU", "Resume Recovery");
+TUNABLE_INT("hw.usb.timings.extra_power_up_time", (int *)&usb_extra_power_up_time);
+SYSCTL_PROC(_hw_usb_timings, OID_AUTO, extra_power_up_time, CTLTYPE_UINT | CTLFLAG_RW | CTLFLAG_TUN,
+    &usb_extra_power_up_time, sizeof(usb_extra_power_up_time),
+    usb_timings_sysctl_handler, "IU", "Extra PowerUp Time");
+#endif
+
 /*------------------------------------------------------------------------*
  *	usb_dump_iface
  *
@@ -174,3 +222,87 @@
 	    xfer->endpoint->edesc->bEndpointAddress,
 	    xfer->endpoint->edesc->bmAttributes);
 }
+
+#ifdef USB_DEBUG
+unsigned int usb_port_reset_delay	= USB_PORT_RESET_DELAY;
+unsigned int usb_port_root_reset_delay	= USB_PORT_ROOT_RESET_DELAY;
+unsigned int usb_port_reset_recovery	= USB_PORT_RESET_RECOVERY;
+unsigned int usb_port_powerup_delay	= USB_PORT_POWERUP_DELAY;
+unsigned int usb_port_resume_delay	= USB_PORT_RESUME_DELAY;
+unsigned int usb_set_address_settle	= USB_SET_ADDRESS_SETTLE;
+unsigned int usb_resume_delay		= USB_RESUME_DELAY;
+unsigned int usb_resume_wait		= USB_RESUME_WAIT;
+unsigned int usb_resume_recovery	= USB_RESUME_RECOVERY;
+unsigned int usb_extra_power_up_time	= USB_EXTRA_POWER_UP_TIME;
+
+/*------------------------------------------------------------------------*
+ *	usb_timings_sysctl_handler
+ *
+ * This function updates timings variables, adjusting them where necessary.
+ *------------------------------------------------------------------------*/
+static int usb_timings_sysctl_handler(SYSCTL_HANDLER_ARGS)
+{
+	int error = 0;
+	unsigned int val;
+
+	/*
+	 * Attempt to get a coherent snapshot by making a copy of the data.
+	 */
+	if (arg1)
+		val = *(unsigned int *)arg1;
+	else
+		val = arg2;
+	error = SYSCTL_OUT(req, &val, sizeof(int));
+	if (error || !req->newptr)
+		return (error);
+
+	if (!arg1)
+		return EPERM;
+
+	error = SYSCTL_IN(req, &val, sizeof(unsigned int));
+	if (error)
+		return (error);
+
+	/*
+	 * Now make sure the values are decent, and certainly no lower than
+	 * what the USB spec prescribes.
+	 */
+	unsigned int *p = (unsigned int *)arg1;
+	if (p == &usb_port_reset_delay) {
+		if (val < USB_PORT_RESET_DELAY_SPEC)
+			return (EINVAL);
+	} else if (p == &usb_port_root_reset_delay) {
+		if (val < USB_PORT_ROOT_RESET_DELAY_SPEC)
+			return (EINVAL);
+	} else if (p == &usb_port_reset_recovery) {
+		if (val < USB_PORT_RESET_RECOVERY_SPEC)
+			return (EINVAL);
+	} else if (p == &usb_port_powerup_delay) {
+		if (val < USB_PORT_POWERUP_DELAY_SPEC)
+			return (EINVAL);
+	} else if (p == &usb_port_resume_delay) {
+		if (val < USB_PORT_RESUME_DELAY_SPEC)
+			return (EINVAL);
+	} else if (p == &usb_set_address_settle) {
+		if (val < USB_SET_ADDRESS_SETTLE_SPEC)
+			return (EINVAL);
+	} else if (p == &usb_resume_delay) {
+		if (val < USB_RESUME_DELAY_SPEC)
+			return (EINVAL);
+	} else if (p == &usb_resume_wait) {
+		if (val < USB_RESUME_WAIT_SPEC)
+			return (EINVAL);
+	} else if (p == &usb_resume_recovery) {
+		if (val < USB_RESUME_RECOVERY_SPEC)
+			return (EINVAL);
+	} else if (p == &usb_extra_power_up_time) {
+		if (val < USB_EXTRA_POWER_UP_TIME_SPEC)
+			return (EINVAL);
+	} else {
+		/* noop */
+	}
+
+	*p = val;
+	return 0;
+}
+#endif

Modified: trunk/sys/dev/usb/usb_debug.h
===================================================================
--- trunk/sys/dev/usb/usb_debug.h	2013-12-28 15:25:37 UTC (rev 6565)
+++ trunk/sys/dev/usb/usb_debug.h	2013-12-28 15:27:54 UTC (rev 6566)
@@ -59,4 +59,28 @@
 void	usb_dump_endpoint(struct usb_endpoint *ep);
 void	usb_dump_xfer(struct usb_xfer *xfer);
 
+#ifdef USB_DEBUG
+extern unsigned int usb_port_reset_delay;
+extern unsigned int usb_port_root_reset_delay;
+extern unsigned int usb_port_reset_recovery;
+extern unsigned int usb_port_powerup_delay;
+extern unsigned int usb_port_resume_delay;
+extern unsigned int usb_set_address_settle;
+extern unsigned int usb_resume_delay;
+extern unsigned int usb_resume_wait;
+extern unsigned int usb_resume_recovery;
+extern unsigned int usb_extra_power_up_time;
+#else
+#define usb_port_reset_delay		USB_PORT_RESET_DELAY
+#define usb_port_root_reset_delay	USB_PORT_ROOT_RESET_DELAY
+#define usb_port_reset_recovery		USB_PORT_RESET_RECOVERY
+#define usb_port_powerup_delay		USB_PORT_POWERUP_DELAY
+#define usb_port_resume_delay		USB_PORT_RESUME_DELAY
+#define usb_set_address_settle		USB_SET_ADDRESS_SETTLE
+#define usb_resume_delay		USB_RESUME_DELAY
+#define usb_resume_wait			USB_RESUME_WAIT
+#define usb_resume_recovery		USB_RESUME_RECOVERY
+#define usb_extra_power_up_time		USB_EXTRA_POWER_UP_TIME
+#endif
+
 #endif					/* _USB_DEBUG_H_ */

Modified: trunk/sys/dev/usb/usb_dev.c
===================================================================
--- trunk/sys/dev/usb/usb_dev.c	2013-12-28 15:25:37 UTC (rev 6565)
+++ trunk/sys/dev/usb/usb_dev.c	2013-12-28 15:27:54 UTC (rev 6566)
@@ -81,10 +81,9 @@
 #ifdef USB_DEBUG
 static int usb_fifo_debug = 0;
 
-SYSCTL_NODE(_hw_usb, OID_AUTO, dev, CTLFLAG_RW, 0, "USB device");
-SYSCTL_INT(_hw_usb_dev, OID_AUTO, debug, CTLFLAG_RW,
+static SYSCTL_NODE(_hw_usb, OID_AUTO, dev, CTLFLAG_RW, 0, "USB device");
+SYSCTL_INT(_hw_usb_dev, OID_AUTO, debug, CTLFLAG_RW | CTLFLAG_TUN,
     &usb_fifo_debug, 0, "Debug Level");
-
 TUNABLE_INT("hw.usb.dev.debug", &usb_fifo_debug);
 #endif
 
@@ -215,10 +214,10 @@
 		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);
 
@@ -279,9 +278,10 @@
 	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);
 		}
@@ -333,7 +333,7 @@
 
 	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: trunk/sys/dev/usb/usb_dev.h
===================================================================
--- trunk/sys/dev/usb/usb_dev.h	2013-12-28 15:25:37 UTC (rev 6565)
+++ trunk/sys/dev/usb/usb_dev.h	2013-12-28 15:27:54 UTC (rev 6566)
@@ -82,6 +82,7 @@
 	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: trunk/sys/dev/usb/usb_device.c
===================================================================
--- trunk/sys/dev/usb/usb_device.c	2013-12-28 15:25:37 UTC (rev 6565)
+++ trunk/sys/dev/usb/usb_device.c	2013-12-28 15:27:54 UTC (rev 6566)
@@ -111,7 +111,7 @@
 int	usb_template = 0;
 
 TUNABLE_INT("hw.usb.usb_template", &usb_template);
-SYSCTL_INT(_hw_usb, OID_AUTO, template, CTLFLAG_RW,
+SYSCTL_INT(_hw_usb, OID_AUTO, template, CTLFLAG_RW | CTLFLAG_TUN,
     &usb_template, 0, "Selected USB device side template");
 
 /* English is default language */
@@ -120,11 +120,11 @@
 static int usb_lang_mask = 0x00FF;
 
 TUNABLE_INT("hw.usb.usb_lang_id", &usb_lang_id);
-SYSCTL_INT(_hw_usb, OID_AUTO, usb_lang_id, CTLFLAG_RW,
+SYSCTL_INT(_hw_usb, OID_AUTO, usb_lang_id, CTLFLAG_RW | CTLFLAG_TUN,
     &usb_lang_id, 0, "Preferred USB language ID");
 
 TUNABLE_INT("hw.usb.usb_lang_mask", &usb_lang_mask);
-SYSCTL_INT(_hw_usb, OID_AUTO, usb_lang_mask, CTLFLAG_RW,
+SYSCTL_INT(_hw_usb, OID_AUTO, usb_lang_mask, CTLFLAG_RW | CTLFLAG_TUN,
     &usb_lang_mask, 0, "Preferred USB language mask");
 
 static const char* statestr[USB_STATE_MAX] = {
@@ -443,13 +443,8 @@
 {
 	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 @@
 
 	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 @@
 	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 @@
 done:
 	if (do_unlock)
 		usbd_enum_unlock(udev);
-
 	return (err);
 }
 
@@ -1285,13 +1270,8 @@
 		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 @@
 done:
 	if (do_unlock)
 		usbd_enum_unlock(udev);
-
 	return (0);
 }
 
@@ -1507,6 +1486,7 @@
 	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 @@
 		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,8 +1702,12 @@
 	 * 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 ||
 	    udev->ddesc.iSerialNumber) {
@@ -1750,7 +1731,7 @@
 		mask = usb_lang_mask;
 
 		/* align length correctly */
-		scratch_ptr[0] &= ~1;
+		scratch_ptr[0] &= ~1U;
 
 		/* fix compiler warning */
 		langid = 0;
@@ -1771,6 +1752,9 @@
 		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 @@
 	    &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,10 +2253,14 @@
 	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 @@
 		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 @@
 	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 @@
 	 * locked multiple times.
 	 */
 	mtx_lock(&Giant);
+	return (1);
 }
 
 /* The following function unlocks enumerating the given USB device. */

Modified: trunk/sys/dev/usb/usb_device.h
===================================================================
--- trunk/sys/dev/usb/usb_device.h	2013-12-28 15:25:37 UTC (rev 6565)
+++ trunk/sys/dev/usb/usb_device.h	2013-12-28 15:27:54 UTC (rev 6566)
@@ -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,6 +117,64 @@
 };
 
 /*
+ * 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.
  */
@@ -114,7 +181,6 @@
 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 @@
 #endif
 
 	uint32_t clear_stall_errors;	/* number of clear-stall failures */
+
+	union usb_device_scratch scratch;
 };
 
 /* globals */
@@ -227,7 +295,7 @@
 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: trunk/sys/dev/usb/usb_generic.c
===================================================================
--- trunk/sys/dev/usb/usb_generic.c	2013-12-28 15:25:37 UTC (rev 6565)
+++ trunk/sys/dev/usb/usb_generic.c	2013-12-28 15:27:54 UTC (rev 6566)
@@ -126,10 +126,9 @@
 #ifdef USB_DEBUG
 static int ugen_debug = 0;
 
-SYSCTL_NODE(_hw_usb, OID_AUTO, ugen, CTLFLAG_RW, 0, "USB generic");
-SYSCTL_INT(_hw_usb_ugen, OID_AUTO, debug, CTLFLAG_RW, &ugen_debug,
+static SYSCTL_NODE(_hw_usb, OID_AUTO, ugen, CTLFLAG_RW, 0, "USB generic");
+SYSCTL_INT(_hw_usb_ugen, OID_AUTO, debug, CTLFLAG_RW | CTLFLAG_TUN, &ugen_debug,
     0, "Debug level");
-
 TUNABLE_INT("hw.usb.ugen.debug", &ugen_debug);
 #endif
 
@@ -714,13 +713,20 @@
 	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;
@@ -1825,6 +1831,17 @@
 }
 
 static int
+ugen_get_power_usage(struct usb_fifo *f)
+{
+	struct usb_device *udev = f->udev;
+
+	if (udev == NULL)
+		return (0);
+
+	return (udev->power);
+}
+
+static int
 ugen_do_port_feature(struct usb_fifo *f, uint8_t port_no,
     uint8_t set, uint16_t feature)
 {
@@ -2186,6 +2203,10 @@
 		*u.pint = ugen_get_power_mode(f);
 		break;
 
+	case USB_GET_POWER_USAGE:
+		*u.pint = ugen_get_power_usage(f);
+		break;
+
 	case USB_SET_PORT_ENABLE:
 		error = ugen_do_port_feature(f,
 		    *u.pint, 1, UHF_PORT_ENABLE);

Modified: trunk/sys/dev/usb/usb_handle_request.c
===================================================================
--- trunk/sys/dev/usb/usb_handle_request.c	2013-12-28 15:25:37 UTC (rev 6565)
+++ trunk/sys/dev/usb/usb_handle_request.c	2013-12-28 15:27:54 UTC (rev 6566)
@@ -145,6 +145,7 @@
 {
 	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_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 @@
 		goto done;
 	}
 done:
-	usbd_enum_unlock(udev);
+	if (do_unlock)
+		usbd_enum_unlock(udev);
 	USB_XFER_LOCK(xfer);
 	return (err);
 }
@@ -187,13 +190,8 @@
 	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 @@
 	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_XFER_UNLOCK(xfer);
 
-	usbd_enum_lock(udev);
+	/* Prevent re-enumeration */
+	do_unlock = usbd_enum_lock(udev);
 
 	error = ENXIO;
 
@@ -351,17 +351,20 @@
 		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: trunk/sys/dev/usb/usb_hid.c
===================================================================
--- trunk/sys/dev/usb/usb_hid.c	2013-12-28 15:25:37 UTC (rev 6565)
+++ trunk/sys/dev/usb/usb_hid.c	2013-12-28 15:27:54 UTC (rev 6566)
@@ -845,3 +845,79 @@
 	}
 	return (USB_ERR_NORMAL_COMPLETION);
 }
+
+/*------------------------------------------------------------------------*
+ *	hid_is_mouse
+ *
+ * This function will decide if a USB descriptor belongs to a USB mouse.
+ *
+ * Return values:
+ * Zero: Not a USB mouse.
+ * Else: Is a USB mouse.
+ *------------------------------------------------------------------------*/
+int
+hid_is_mouse(const void *d_ptr, uint16_t d_len)
+{
+	struct hid_data *hd;
+	struct hid_item hi;
+	int mdepth;
+	int found;
+
+	hd = hid_start_parse(d_ptr, d_len, 1 << hid_input);
+	if (hd == NULL)
+		return (0);
+
+	mdepth = 0;
+	found = 0;
+
+	while (hid_get_item(hd, &hi)) {
+		switch (hi.kind) {
+		case hid_collection:
+			if (mdepth != 0)
+				mdepth++;
+			else if (hi.collection == 1 &&
+			     hi.usage ==
+			      HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_MOUSE))
+				mdepth++;
+			break;
+		case hid_endcollection:
+			if (mdepth != 0)
+				mdepth--;
+			break;
+		case hid_input:
+			if (mdepth == 0)
+				break;
+			if (hi.usage ==
+			     HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_X) &&
+			    (hi.flags & (HIO_CONST|HIO_RELATIVE)) == HIO_RELATIVE)
+				found++;
+			if (hi.usage ==
+			     HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_Y) &&
+			    (hi.flags & (HIO_CONST|HIO_RELATIVE)) == HIO_RELATIVE)
+				found++;
+			break;
+		default:
+			break;
+		}
+	}
+	hid_end_parse(hd);
+	return (found);
+}
+
+/*------------------------------------------------------------------------*
+ *	hid_is_keyboard
+ *
+ * This function will decide if a USB descriptor belongs to a USB keyboard.
+ *
+ * Return values:
+ * Zero: Not a USB keyboard.
+ * Else: Is a USB keyboard.
+ *------------------------------------------------------------------------*/
+int
+hid_is_keyboard(const void *d_ptr, uint16_t d_len)
+{
+	if (hid_is_collection(d_ptr, d_len,
+	    HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_KEYBOARD)))
+		return (1);
+	return (0);
+}

Modified: trunk/sys/dev/usb/usb_hub.c
===================================================================
--- trunk/sys/dev/usb/usb_hub.c	2013-12-28 15:25:37 UTC (rev 6565)
+++ trunk/sys/dev/usb/usb_hub.c	2013-12-28 15:27:54 UTC (rev 6566)
@@ -76,10 +76,9 @@
 #ifdef USB_DEBUG
 static int uhub_debug = 0;
 
-SYSCTL_NODE(_hw_usb, OID_AUTO, uhub, CTLFLAG_RW, 0, "USB HUB");
-SYSCTL_INT(_hw_usb_uhub, OID_AUTO, debug, CTLFLAG_RW, &uhub_debug, 0,
+static SYSCTL_NODE(_hw_usb, OID_AUTO, uhub, CTLFLAG_RW, 0, "USB HUB");
+SYSCTL_INT(_hw_usb_uhub, OID_AUTO, debug, CTLFLAG_RW | CTLFLAG_TUN, &uhub_debug, 0,
     "Debug level");
-
 TUNABLE_INT("hw.usb.uhub.debug", &uhub_debug);
 #endif
 
@@ -241,7 +240,9 @@
 	/* 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);
@@ -260,7 +261,8 @@
 			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 */
@@ -415,7 +417,7 @@
 		/* wait for maximum device power up time */
 
 		usb_pause_mtx(NULL, 
-		    USB_MS_TO_TICKS(USB_PORT_POWERUP_DELAY));
+		    USB_MS_TO_TICKS(usb_port_powerup_delay));
 
 		/* reset port, which implies enabling it */
 
@@ -711,6 +713,7 @@
 	usb_error_t err;
 	uint8_t portno;
 	uint8_t x;
+	uint8_t do_unlock;
 
 	hub = udev->hub;
 	sc = hub->hubsoftc;
@@ -732,7 +735,7 @@
 	 * 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;
@@ -812,7 +815,8 @@
 		up->restartcnt = 0;
 	}
 
-	usbd_enum_unlock(udev);
+	if (do_unlock)
+		usbd_enum_unlock(udev);
 
 	/* initial status checked */
 	sc->sc_flags |= UHUB_FLAG_DID_EXPLORE;
@@ -979,7 +983,7 @@
 
 		/* get power delay */
 		pwrdly = ((hubdesc20.bPwrOn2PwrGood * UHD_PWRON_FACTOR) +
-		    USB_EXTRA_POWER_UP_TIME);
+		    usb_extra_power_up_time);
 
 		/* get complete HUB descriptor */
 		if (nports >= 8) {
@@ -1024,7 +1028,7 @@
 
 		/* get power delay */
 		pwrdly = ((hubdesc30.bPwrOn2PwrGood * UHD_PWRON_FACTOR) +
-		    USB_EXTRA_POWER_UP_TIME);
+		    usb_extra_power_up_time);
 
 		/* get complete HUB descriptor */
 		if (nports >= 8) {
@@ -1053,7 +1057,7 @@
 		/* default number of ports */
 		nports = 1;
 		/* default power delay */
-		pwrdly = ((10 * UHD_PWRON_FACTOR) + USB_EXTRA_POWER_UP_TIME);
+		pwrdly = ((10 * UHD_PWRON_FACTOR) + usb_extra_power_up_time);
 		break;
 	}
 	if (nports == 0) {
@@ -2261,7 +2265,7 @@
 	}
 
 	/* resume settle time */
-	usb_pause_mtx(NULL, USB_MS_TO_TICKS(USB_PORT_RESUME_DELAY));
+	usb_pause_mtx(NULL, USB_MS_TO_TICKS(usb_port_resume_delay));
 
 	if (bus->methods->device_resume != NULL) {
 		/* resume USB device on the USB controller */
@@ -2414,7 +2418,7 @@
 			    NULL, udev->port_no, UHF_PORT_SUSPEND);
 
 			/* resume settle time */
-			usb_pause_mtx(NULL, USB_MS_TO_TICKS(USB_PORT_RESUME_DELAY));
+			usb_pause_mtx(NULL, USB_MS_TO_TICKS(usb_port_resume_delay));
 		}
 		DPRINTF("Suspend was cancelled!\n");
 		return;

Modified: trunk/sys/dev/usb/usb_ioctl.h
===================================================================
--- trunk/sys/dev/usb/usb_ioctl.h	2013-12-28 15:25:37 UTC (rev 6565)
+++ trunk/sys/dev/usb/usb_ioctl.h	2013-12-28 15:27:54 UTC (rev 6566)
@@ -270,7 +270,8 @@
 #define	USB_IFACE_DRIVER_DETACH	_IOW ('U', 125, int)
 #define	USB_GET_PLUGTIME	_IOR ('U', 126, uint32_t)
 #define	USB_READ_DIR		_IOW ('U', 127, struct usb_read_dir)
-/* 128 - 135 unused */
+/* 128 - 134 unused */
+#define	USB_GET_POWER_USAGE	_IOR ('U', 135, int)
 #define	USB_SET_TX_FORCE_SHORT	_IOW ('U', 136, int)
 #define	USB_SET_TX_TIMEOUT	_IOW ('U', 137, int)
 #define	USB_GET_TX_FRAME_SIZE	_IOR ('U', 138, int)

Modified: trunk/sys/dev/usb/usb_msctest.c
===================================================================
--- trunk/sys/dev/usb/usb_msctest.c	2013-12-28 15:25:37 UTC (rev 6565)
+++ trunk/sys/dev/usb/usb_msctest.c	2013-12-28 15:27:54 UTC (rev 6566)
@@ -103,6 +103,8 @@
 					  0x00, 0x00, 0x00, 0x00 };
 static uint8_t scsi_request_sense[] =	{ 0x03, 0x00, 0x00, 0x00, 0x12, 0x00,
 					  0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+static uint8_t scsi_read_capacity[] =	{ 0x25, 0x00, 0x00, 0x00, 0x00, 0x00,
+					  0x00, 0x00, 0x00, 0x00 };
 
 #define	BULK_SIZE		64	/* dummy */
 #define	ERR_CSW_FAILED		-1
@@ -499,13 +501,8 @@
 	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,
@@ -652,7 +649,7 @@
 	}
 
 	is_no_direct = 1;
-	for (timeout = 4; timeout; timeout--) {
+	for (timeout = 4; timeout != 0; timeout--) {
 		err = bbb_command_start(sc, DIR_IN, 0, sc->buffer,
 		    SCSI_INQ_LEN, &scsi_inquiry, sizeof(scsi_inquiry),
 		    USB_MS_HZ);
@@ -662,8 +659,11 @@
 			if (sid_type == 0x00)
 				is_no_direct = 0;
 			break;
-		} else if (err != ERR_CSW_FAILED)
-			break;	/* non retryable error */
+		} else if (err != ERR_CSW_FAILED) {
+			DPRINTF("Device is not responding "
+			    "properly to SCSI INQUIRY command.\n");
+			goto error;	/* non retryable error */
+		}
 		usb_pause_mtx(NULL, hz);
 	}
 
@@ -681,7 +681,9 @@
 		if (err != ERR_CSW_FAILED)
 			goto error;
 	}
+	timeout = 1;
 
+retry_sync_cache:
 	err = bbb_command_start(sc, DIR_IN, 0, NULL, 0,
 	    &scsi_sync_cache, sizeof(scsi_sync_cache),
 	    USB_MS_HZ);
@@ -694,6 +696,42 @@
 		DPRINTF("Device doesn't handle synchronize cache\n");
 
 		usbd_add_dynamic_quirk(udev, UQ_MSC_NO_SYNC_CACHE);
+
+	} else {
+
+		/*
+		 * Certain Kingston memory sticks fail the first
+		 * read capacity after a synchronize cache command
+		 * has been issued. Disable the synchronize cache
+		 * command for such devices.
+		 */
+
+		err = bbb_command_start(sc, DIR_IN, 0, sc->buffer, 8,
+		    &scsi_read_capacity, sizeof(scsi_read_capacity),
+		    USB_MS_HZ);
+
+		if (err != 0) {
+			if (err != ERR_CSW_FAILED)
+				goto error;
+
+			err = bbb_command_start(sc, DIR_IN, 0, sc->buffer, 8,
+			    &scsi_read_capacity, sizeof(scsi_read_capacity),
+			    USB_MS_HZ);
+
+			if (err == 0) {
+				if (timeout--)
+					goto retry_sync_cache;
+
+				DPRINTF("Device most likely doesn't "
+				    "handle synchronize cache\n");
+
+				usbd_add_dynamic_quirk(udev,
+				    UQ_MSC_NO_SYNC_CACHE);
+			} else {
+				if (err != ERR_CSW_FAILED)
+					goto error;
+			}
+		}
 	}
 
 	/* clear sense status of any failed commands on the device */

Modified: trunk/sys/dev/usb/usb_process.c
===================================================================
--- trunk/sys/dev/usb/usb_process.c	2013-12-28 15:25:37 UTC (rev 6565)
+++ trunk/sys/dev/usb/usb_process.c	2013-12-28 15:27:54 UTC (rev 6566)
@@ -81,10 +81,9 @@
 #ifdef USB_DEBUG
 static int usb_proc_debug;
 
-SYSCTL_NODE(_hw_usb, OID_AUTO, proc, CTLFLAG_RW, 0, "USB process");
-SYSCTL_INT(_hw_usb_proc, OID_AUTO, debug, CTLFLAG_RW, &usb_proc_debug, 0,
+static SYSCTL_NODE(_hw_usb, OID_AUTO, proc, CTLFLAG_RW, 0, "USB process");
+SYSCTL_INT(_hw_usb_proc, OID_AUTO, debug, CTLFLAG_RW | CTLFLAG_TUN, &usb_proc_debug, 0,
     "Debug level");
-
 TUNABLE_INT("hw.usb.proc.debug", &usb_proc_debug);
 #endif
 

Modified: trunk/sys/dev/usb/usb_process.h
===================================================================
--- trunk/sys/dev/usb/usb_process.h	2013-12-28 15:25:37 UTC (rev 6565)
+++ trunk/sys/dev/usb/usb_process.h	2013-12-28 15:27:54 UTC (rev 6566)
@@ -42,6 +42,7 @@
 /* structure prototypes */
 
 struct usb_proc_msg;
+struct usb_device;
 
 /*
  * The following structure defines the USB process.
@@ -79,4 +80,9 @@
 void   *usb_proc_msignal(struct usb_process *up, void *pm0, void *pm1);
 void	usb_proc_rewakeup(struct usb_process *up);
 
+void	usb_proc_explore_mwait(struct usb_device *, void *, void *);
+void   *usb_proc_explore_msignal(struct usb_device *, void *, void *);
+void	usb_proc_explore_lock(struct usb_device *);
+void	usb_proc_explore_unlock(struct usb_device *);
+
 #endif					/* _USB_PROCESS_H_ */

Modified: trunk/sys/dev/usb/usb_request.c
===================================================================
--- trunk/sys/dev/usb/usb_request.c	2013-12-28 15:25:37 UTC (rev 6565)
+++ trunk/sys/dev/usb/usb_request.c	2013-12-28 15:27:54 UTC (rev 6566)
@@ -73,14 +73,6 @@
     &usb_no_cs_fail, 0, "USB clear stall failures are ignored, if set");
 
 #ifdef USB_DEBUG
-static int usb_pr_poll_delay = USB_PORT_RESET_DELAY;
-static int usb_pr_recovery_delay = USB_PORT_RESET_RECOVERY;
-
-SYSCTL_INT(_hw_usb, OID_AUTO, pr_poll_delay, CTLFLAG_RW,
-    &usb_pr_poll_delay, 0, "USB port reset poll delay in ms");
-SYSCTL_INT(_hw_usb, OID_AUTO, pr_recovery_delay, CTLFLAG_RW,
-    &usb_pr_recovery_delay, 0, "USB port reset recovery delay in ms");
-
 #ifdef USB_REQ_DEBUG
 /* The following structures are used in connection to fault injection. */
 struct usb_ctrl_debug {
@@ -87,7 +79,7 @@
 	int bus_index;		/* target bus */
 	int dev_index;		/* target address */
 	int ds_fail;		/* fail data stage */
-	int ss_fail;		/* fail data stage */
+	int ss_fail;		/* fail status stage */
 	int ds_delay;		/* data stage delay in ms */
 	int ss_delay;		/* status stage delay in ms */
 	int bmRequestType_value;
@@ -390,9 +382,8 @@
  * 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
@@ -416,7 +407,7 @@
 	uint16_t length;
 	uint16_t temp;
 	uint16_t acttemp;
-	uint8_t enum_locked;
+	uint8_t do_unlock;
 
 	if (timeout < 50) {
 		/* timeout is too small */
@@ -428,8 +419,6 @@
 	}
 	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,
@@ -460,17 +449,16 @@
 	}
 
 	/*
-	 * 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);
 
@@ -714,10 +702,10 @@
 	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);
@@ -788,12 +776,6 @@
 	uint16_t status;
 	uint16_t change;
 
-#ifdef USB_DEBUG
-	uint16_t pr_poll_delay;
-	uint16_t pr_recovery_delay;
-
-#endif
-
 	DPRINTF("\n");
 
 	/* clear any leftover port reset changes first */
@@ -808,29 +790,12 @@
 	if (err)
 		goto done;
 #ifdef USB_DEBUG
-	/* range check input parameters */
-	pr_poll_delay = usb_pr_poll_delay;
-	if (pr_poll_delay < 1) {
-		pr_poll_delay = 1;
-	} else if (pr_poll_delay > 1000) {
-		pr_poll_delay = 1000;
-	}
-	pr_recovery_delay = usb_pr_recovery_delay;
-	if (pr_recovery_delay > 1000) {
-		pr_recovery_delay = 1000;
-	}
 #endif
 	n = 0;
 	while (1) {
-#ifdef USB_DEBUG
 		/* wait for the device to recover from reset */
-		usb_pause_mtx(mtx, USB_MS_TO_TICKS(pr_poll_delay));
-		n += pr_poll_delay;
-#else
-		/* wait for the device to recover from reset */
-		usb_pause_mtx(mtx, USB_MS_TO_TICKS(USB_PORT_RESET_DELAY));
-		n += USB_PORT_RESET_DELAY;
-#endif
+		usb_pause_mtx(mtx, USB_MS_TO_TICKS(usb_port_reset_delay));
+		n += usb_port_reset_delay;
 		err = usbd_req_get_port_status(udev, mtx, &ps, port);
 		if (err)
 			goto done;
@@ -872,13 +837,8 @@
 		err = USB_ERR_TIMEOUT;
 		goto done;
 	}
-#ifdef USB_DEBUG
 	/* wait for the device to recover from reset */
-	usb_pause_mtx(mtx, USB_MS_TO_TICKS(pr_recovery_delay));
-#else
-	/* wait for the device to recover from reset */
-	usb_pause_mtx(mtx, USB_MS_TO_TICKS(USB_PORT_RESET_RECOVERY));
-#endif
+	usb_pause_mtx(mtx, USB_MS_TO_TICKS(usb_port_reset_recovery));
 
 done:
 	DPRINTFN(2, "port %d reset returning error=%s\n",
@@ -909,12 +869,6 @@
 	uint16_t status;
 	uint16_t change;
 
-#ifdef USB_DEBUG
-	uint16_t pr_poll_delay;
-	uint16_t pr_recovery_delay;
-
-#endif
-
 	DPRINTF("\n");
 
 	err = usbd_req_get_port_status(udev, mtx, &ps, port);
@@ -944,30 +898,11 @@
 	if (err)
 		goto done;
 
-#ifdef USB_DEBUG
-	/* range check input parameters */
-	pr_poll_delay = usb_pr_poll_delay;
-	if (pr_poll_delay < 1) {
-		pr_poll_delay = 1;
-	} else if (pr_poll_delay > 1000) {
-		pr_poll_delay = 1000;
-	}
-	pr_recovery_delay = usb_pr_recovery_delay;
-	if (pr_recovery_delay > 1000) {
-		pr_recovery_delay = 1000;
-	}
-#endif
 	n = 0;
 	while (1) {
-#ifdef USB_DEBUG
 		/* wait for the device to recover from reset */
-		usb_pause_mtx(mtx, USB_MS_TO_TICKS(pr_poll_delay));
-		n += pr_poll_delay;
-#else
-		/* wait for the device to recover from reset */
-		usb_pause_mtx(mtx, USB_MS_TO_TICKS(USB_PORT_RESET_DELAY));
-		n += USB_PORT_RESET_DELAY;
-#endif
+		usb_pause_mtx(mtx, USB_MS_TO_TICKS(usb_port_reset_delay));
+		n += usb_port_reset_delay;
 		err = usbd_req_get_port_status(udev, mtx, &ps, port);
 		if (err)
 			goto done;
@@ -1001,13 +936,8 @@
 		err = USB_ERR_TIMEOUT;
 		goto done;
 	}
-#ifdef USB_DEBUG
 	/* wait for the device to recover from reset */
-	usb_pause_mtx(mtx, USB_MS_TO_TICKS(pr_recovery_delay));
-#else
-	/* wait for the device to recover from reset */
-	usb_pause_mtx(mtx, USB_MS_TO_TICKS(USB_PORT_RESET_RECOVERY));
-#endif
+	usb_pause_mtx(mtx, USB_MS_TO_TICKS(usb_port_reset_recovery));
 
 done:
 	DPRINTFN(2, "port %d warm reset returning error=%s\n",
@@ -1566,7 +1496,7 @@
 done:
 	/* allow device time to set new address */
 	usb_pause_mtx(mtx,
-	    USB_MS_TO_TICKS(USB_SET_ADDRESS_SETTLE));
+	    USB_MS_TO_TICKS(usb_set_address_settle));
 
 	return (err);
 }

Modified: trunk/sys/dev/usb/usb_transfer.c
===================================================================
--- trunk/sys/dev/usb/usb_transfer.c	2013-12-28 15:25:37 UTC (rev 6565)
+++ trunk/sys/dev/usb/usb_transfer.c	2013-12-28 15:27:54 UTC (rev 6566)
@@ -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,21 +810,18 @@
     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;
+	uint8_t do_unlock;
 
-	parm.err = 0;
-	refcount = 0;
-	info = NULL;
-
 	WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL,
 	    "usbd_transfer_setup can sleep!");
 
@@ -842,31 +839,40 @@
 		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);
 
-	parm.udev = udev;
-	parm.speed = usbd_get_speed(udev);
-	parm.hc_max_packet_count = 1;
+	/* Protect scratch area */
+	do_unlock = usbd_enum_lock(udev);
 
-	if (parm.speed >= USB_SPEED_MAX) {
-		parm.err = USB_ERR_INVAL;
+	refcount = 0;
+	info = NULL;
+
+	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,14 +887,14 @@
 			info = USB_ADD_BYTES(buf, 0);
 
 			info->memory_base = buf;
-			info->memory_size = parm.size[0];
+			info->memory_size = parm->size[0];
 
 #if USB_HAVE_BUSDMA
-			info->dma_page_cache_start = USB_ADD_BYTES(buf, parm.size[4]);
-			info->dma_page_cache_end = USB_ADD_BYTES(buf, parm.size[5]);
+			info->dma_page_cache_start = USB_ADD_BYTES(buf, parm->size[4]);
+			info->dma_page_cache_end = USB_ADD_BYTES(buf, parm->size[5]);
 #endif
-			info->xfer_page_cache_start = USB_ADD_BYTES(buf, parm.size[5]);
-			info->xfer_page_cache_end = USB_ADD_BYTES(buf, parm.size[2]);
+			info->xfer_page_cache_start = USB_ADD_BYTES(buf, parm->size[5]);
+			info->xfer_page_cache_end = USB_ADD_BYTES(buf, parm->size[2]);
 
 			cv_init(&info->cv_drain, "WDRAIN");
 
@@ -895,8 +901,8 @@
 			info->xfer_mtx = xfer_mtx;
 #if USB_HAVE_BUSDMA
 			usb_dma_tag_setup(&info->dma_parent_tag,
-			    parm.dma_tag_p, udev->bus->dma_parent_tag[0].tag,
-			    xfer_mtx, &usb_bdma_done_event, 32, parm.dma_tag_max);
+			    parm->dma_tag_p, udev->bus->dma_parent_tag[0].tag,
+			    xfer_mtx, &usb_bdma_done_event, 32, parm->dma_tag_max);
 #endif
 
 			info->bus = udev->bus;
@@ -931,9 +937,9 @@
 		}
 		/* reset sizes */
 
-		parm.size[0] = 0;
-		parm.buf = buf;
-		parm.size[0] += sizeof(info[0]);
+		parm->size[0] = 0;
+		parm->buf = buf;
+		parm->size[0] += sizeof(info[0]);
 
 		for (setup = setup_start, n = 0;
 		    setup != setup_end; setup++, n++) {
@@ -952,15 +958,15 @@
 				if ((setup->usb_mode != USB_MODE_DUAL) &&
 				    (setup->usb_mode != udev->flags.usb_mode))
 					continue;
-				parm.err = USB_ERR_NO_PIPE;
+				parm->err = USB_ERR_NO_PIPE;
 				goto done;
 			}
 
 			/* align data properly */
-			parm.size[0] += ((-parm.size[0]) & (USB_HOST_ALIGN - 1));
+			parm->size[0] += ((-parm->size[0]) & (USB_HOST_ALIGN - 1));
 
 			/* store current setup pointer */
-			parm.curr_setup = setup;
+			parm->curr_setup = setup;
 
 			if (buf) {
 				/*
@@ -967,7 +973,7 @@
 				 * Common initialization of the
 				 * "usb_xfer" structure.
 				 */
-				xfer = USB_ADD_BYTES(buf, parm.size[0]);
+				xfer = USB_ADD_BYTES(buf, parm->size[0]);
 				xfer->address = udev->address;
 				xfer->priv_sc = priv_sc;
 				xfer->xroot = info;
@@ -982,8 +988,8 @@
 				 * before we have allocated any
 				 * memory:
 				 */
-				xfer = &dummy;
-				memset(&dummy, 0, sizeof(dummy));
+				xfer = &udev->scratch.xfer_setup[0].dummy;
+				memset(xfer, 0, sizeof(*xfer));
 				refcount++;
 			}
 
@@ -990,18 +996,18 @@
 			/* set transfer endpoint pointer */
 			xfer->endpoint = ep;
 
-			parm.size[0] += sizeof(xfer[0]);
-			parm.methods = xfer->endpoint->methods;
-			parm.curr_xfer = xfer;
+			parm->size[0] += sizeof(xfer[0]);
+			parm->methods = xfer->endpoint->methods;
+			parm->curr_xfer = xfer;
 
 			/*
 			 * Call the Host or Device controller transfer
 			 * setup routine:
 			 */
-			(udev->bus->methods->xfer_setup) (&parm);
+			(udev->bus->methods->xfer_setup) (parm);
 
 			/* check for error */
-			if (parm.err)
+			if (parm->err)
 				goto done;
 
 			if (buf) {
@@ -1016,7 +1022,7 @@
 				 */
 				USB_BUS_LOCK(info->bus);
 				if (xfer->endpoint->refcount_alloc >= USB_EP_REF_MAX)
-					parm.err = USB_ERR_INVAL;
+					parm->err = USB_ERR_INVAL;
 
 				xfer->endpoint->refcount_alloc++;
 
@@ -1039,22 +1045,22 @@
 			}
 
 			/* check for error */
-			if (parm.err)
+			if (parm->err)
 				goto done;
 		}
 
-		if (buf || parm.err) {
+		if (buf != NULL || parm->err != 0)
 			goto done;
-		}
-		if (refcount == 0) {
-			/* no transfers - nothing to do ! */
+
+		/* if no transfers, nothing to do */
+		if (refcount == 0)
 			goto done;
-		}
+
 		/* align data properly */
-		parm.size[0] += ((-parm.size[0]) & (USB_HOST_ALIGN - 1));
+		parm->size[0] += ((-parm->size[0]) & (USB_HOST_ALIGN - 1));
 
 		/* store offset temporarily */
-		parm.size[1] = parm.size[0];
+		parm->size[1] = parm->size[0];
 
 		/*
 		 * The number of DMA tags required depends on
@@ -1062,72 +1068,72 @@
 		 * for maximum number of DMA tags per endpoint
 		 * is two.
 		 */
-		parm.dma_tag_max += 2 * MIN(n_setup, USB_EP_MAX);
+		parm->dma_tag_max += 2 * MIN(n_setup, USB_EP_MAX);
 
 		/*
 		 * DMA tags for QH, TD, Data and more.
 		 */
-		parm.dma_tag_max += 8;
+		parm->dma_tag_max += 8;
 
-		parm.dma_tag_p += parm.dma_tag_max;
+		parm->dma_tag_p += parm->dma_tag_max;
 
-		parm.size[0] += ((uint8_t *)parm.dma_tag_p) -
+		parm->size[0] += ((uint8_t *)parm->dma_tag_p) -
 		    ((uint8_t *)0);
 
 		/* align data properly */
-		parm.size[0] += ((-parm.size[0]) & (USB_HOST_ALIGN - 1));
+		parm->size[0] += ((-parm->size[0]) & (USB_HOST_ALIGN - 1));
 
 		/* store offset temporarily */
-		parm.size[3] = parm.size[0];
+		parm->size[3] = parm->size[0];
 
-		parm.size[0] += ((uint8_t *)parm.dma_page_ptr) -
+		parm->size[0] += ((uint8_t *)parm->dma_page_ptr) -
 		    ((uint8_t *)0);
 
 		/* align data properly */
-		parm.size[0] += ((-parm.size[0]) & (USB_HOST_ALIGN - 1));
+		parm->size[0] += ((-parm->size[0]) & (USB_HOST_ALIGN - 1));
 
 		/* store offset temporarily */
-		parm.size[4] = parm.size[0];
+		parm->size[4] = parm->size[0];
 
-		parm.size[0] += ((uint8_t *)parm.dma_page_cache_ptr) -
+		parm->size[0] += ((uint8_t *)parm->dma_page_cache_ptr) -
 		    ((uint8_t *)0);
 
 		/* store end offset temporarily */
-		parm.size[5] = parm.size[0];
+		parm->size[5] = parm->size[0];
 
-		parm.size[0] += ((uint8_t *)parm.xfer_page_cache_ptr) -
+		parm->size[0] += ((uint8_t *)parm->xfer_page_cache_ptr) -
 		    ((uint8_t *)0);
 
 		/* store end offset temporarily */
 
-		parm.size[2] = parm.size[0];
+		parm->size[2] = parm->size[0];
 
 		/* align data properly */
-		parm.size[0] += ((-parm.size[0]) & (USB_HOST_ALIGN - 1));
+		parm->size[0] += ((-parm->size[0]) & (USB_HOST_ALIGN - 1));
 
-		parm.size[6] = parm.size[0];
+		parm->size[6] = parm->size[0];
 
-		parm.size[0] += ((uint8_t *)parm.xfer_length_ptr) -
+		parm->size[0] += ((uint8_t *)parm->xfer_length_ptr) -
 		    ((uint8_t *)0);
 
 		/* align data properly */
-		parm.size[0] += ((-parm.size[0]) & (USB_HOST_ALIGN - 1));
+		parm->size[0] += ((-parm->size[0]) & (USB_HOST_ALIGN - 1));
 
 		/* allocate zeroed memory */
-		buf = malloc(parm.size[0], M_USB, M_WAITOK | M_ZERO);
+		buf = malloc(parm->size[0], M_USB, M_WAITOK | M_ZERO);
 
 		if (buf == NULL) {
-			parm.err = USB_ERR_NOMEM;
+			parm->err = USB_ERR_NOMEM;
 			DPRINTFN(0, "cannot allocate memory block for "
 			    "configuration (%d bytes)\n",
-			    parm.size[0]);
+			    parm->size[0]);
 			goto done;
 		}
-		parm.dma_tag_p = USB_ADD_BYTES(buf, parm.size[1]);
-		parm.dma_page_ptr = USB_ADD_BYTES(buf, parm.size[3]);
-		parm.dma_page_cache_ptr = USB_ADD_BYTES(buf, parm.size[4]);
-		parm.xfer_page_cache_ptr = USB_ADD_BYTES(buf, parm.size[5]);
-		parm.xfer_length_ptr = USB_ADD_BYTES(buf, parm.size[6]);
+		parm->dma_tag_p = USB_ADD_BYTES(buf, parm->size[1]);
+		parm->dma_page_ptr = USB_ADD_BYTES(buf, parm->size[3]);
+		parm->dma_page_cache_ptr = USB_ADD_BYTES(buf, parm->size[4]);
+		parm->xfer_page_cache_ptr = USB_ADD_BYTES(buf, parm->size[5]);
+		parm->xfer_length_ptr = USB_ADD_BYTES(buf, parm->size[6]);
 	}
 
 done:
@@ -1143,10 +1149,17 @@
 			usbd_transfer_unsetup_sub(info, 0);
 		}
 	}
-	if (parm.err) {
+
+	/* check if any errors happened */
+	if (parm->err)
 		usbd_transfer_unsetup(ppxfer, n_setup);
-	}
-	return (parm.err);
+
+	error = parm->err;
+
+	if (do_unlock)
+		usbd_enum_unlock(udev);
+
+	return (error);
 }
 
 /*------------------------------------------------------------------------*
@@ -1923,6 +1936,17 @@
 	return (&xfer->frbuffers[frindex]);
 }
 
+void *
+usbd_xfer_get_frame_buffer(struct usb_xfer *xfer, usb_frcount_t frindex)
+{
+	struct usb_page_search page_info;
+
+	KASSERT(frindex < xfer->max_frame_count, ("frame index overflow"));
+
+	usbd_get_page(&xfer->frbuffers[frindex], 0, &page_info);
+	return (page_info.buffer);
+}
+
 /*------------------------------------------------------------------------*
  *	usbd_xfer_get_fps_shift
  *

Modified: trunk/sys/dev/usb/usb_util.c
===================================================================
--- trunk/sys/dev/usb/usb_util.c	2013-12-28 15:25:37 UTC (rev 6565)
+++ trunk/sys/dev/usb/usb_util.c	2013-12-28 15:27:54 UTC (rev 6566)
@@ -71,6 +71,7 @@
 	struct usb_interface *iface;
 	char *temp_p;
 	usb_error_t err;
+	uint8_t do_unlock;
 
 	if (dev == NULL) {
 		/* should not happen */
@@ -92,19 +93,26 @@
 		err = 0;
 	}
 
-	temp_p = (char *)udev->bus->scratch[0].data;
+	/* Protect scratch area */
+	do_unlock = usbd_enum_lock(udev);
 
-	if (!err) {
+	temp_p = (char *)udev->scratch.data;
+
+	if (err == 0) {
 		/* try to get the interface string ! */
-		err = usbd_req_get_string_any
-		    (udev, NULL, temp_p,
-		    sizeof(udev->bus->scratch), iface->idesc->iInterface);
+		err = usbd_req_get_string_any(udev, NULL, temp_p,
+		    sizeof(udev->scratch.data),
+		    iface->idesc->iInterface);
 	}
-	if (err) {
+	if (err != 0) {
 		/* use default description */
 		usb_devinfo(udev, temp_p,
-		    sizeof(udev->bus->scratch));
+		    sizeof(udev->scratch.data));
 	}
+
+	if (do_unlock)
+		usbd_enum_unlock(udev);
+
 	device_set_desc_copy(dev, temp_p);
 	device_printf(dev, "<%s> on %s\n", temp_p,
 	    device_get_nameunit(udev->bus->bdev));

Modified: trunk/sys/dev/usb/usbdi.h
===================================================================
--- trunk/sys/dev/usb/usbdi.h	2013-12-28 15:25:37 UTC (rev 6565)
+++ trunk/sys/dev/usb/usbdi.h	2013-12-28 15:27:54 UTC (rev 6566)
@@ -522,6 +522,7 @@
 	    int *aframes, int *nframes);
 struct usb_page_cache *usbd_xfer_get_frame(struct usb_xfer *xfer,
 	    usb_frcount_t frindex);
+void	*usbd_xfer_get_frame_buffer(struct usb_xfer *, usb_frcount_t);
 void	*usbd_xfer_softc(struct usb_xfer *xfer);
 void	*usbd_xfer_get_priv(struct usb_xfer *xfer);
 void	usbd_xfer_set_priv(struct usb_xfer *xfer, void *);

Modified: trunk/sys/dev/usb/usbhid.h
===================================================================
--- trunk/sys/dev/usb/usbhid.h	2013-12-28 15:25:37 UTC (rev 6565)
+++ trunk/sys/dev/usb/usbhid.h	2013-12-28 15:27:54 UTC (rev 6566)
@@ -242,5 +242,7 @@
 usb_error_t usbd_req_get_hid_desc(struct usb_device *udev, struct mtx *mtx,
 	    void **descp, uint16_t *sizep, struct malloc_type *mem,
 	    uint8_t iface_index);
+int	hid_is_mouse(const void *d_ptr, uint16_t d_len);
+int	hid_is_keyboard(const void *d_ptr, uint16_t d_len);
 #endif					/* _KERNEL */
 #endif					/* _USB_HID_H_ */



More information about the Midnightbsd-cvs mailing list