Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 22 Jun 2011 08:01:44 +0000 (UTC)
From:      Hans Petter Selasky <hselasky@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-8@freebsd.org
Subject:   svn commit: r223414 - stable/8/sys/dev/usb
Message-ID:  <201106220801.p5M81ikp038505@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: hselasky
Date: Wed Jun 22 08:01:44 2011
New Revision: 223414
URL: http://svn.freebsd.org/changeset/base/223414

Log:
  MFC r222786 and r222790:
  Improve enumeration of Low- and Full-speed devices connected through a
  High-speed USB HUB.

Modified:
  stable/8/sys/dev/usb/usb_device.h
  stable/8/sys/dev/usb/usb_freebsd.h
  stable/8/sys/dev/usb/usb_generic.c
  stable/8/sys/dev/usb/usb_hub.c
  stable/8/sys/dev/usb/usb_request.c
  stable/8/sys/dev/usb/usb_request.h
  stable/8/sys/dev/usb/usb_transfer.c
  stable/8/sys/dev/usb/usbdi.h
Directory Properties:
  stable/8/sys/   (props changed)
  stable/8/sys/amd64/include/xen/   (props changed)
  stable/8/sys/cddl/contrib/opensolaris/   (props changed)
  stable/8/sys/contrib/dev/acpica/   (props changed)
  stable/8/sys/contrib/pf/   (props changed)

Modified: stable/8/sys/dev/usb/usb_device.h
==============================================================================
--- stable/8/sys/dev/usb/usb_device.h	Wed Jun 22 07:18:14 2011	(r223413)
+++ stable/8/sys/dev/usb/usb_device.h	Wed Jun 22 08:01:44 2011	(r223414)
@@ -187,6 +187,8 @@ struct usb_device {
 	struct usb_host_endpoint *linux_endpoint_end;
 	uint16_t devnum;
 #endif
+
+	uint32_t clear_stall_errors;	/* number of clear-stall failures */
 };
 
 /* globals */

Modified: stable/8/sys/dev/usb/usb_freebsd.h
==============================================================================
--- stable/8/sys/dev/usb/usb_freebsd.h	Wed Jun 22 07:18:14 2011	(r223413)
+++ stable/8/sys/dev/usb/usb_freebsd.h	Wed Jun 22 08:01:44 2011	(r223414)
@@ -58,6 +58,7 @@
 
 #define	USB_HUB_MAX_DEPTH	5
 #define	USB_EP0_BUFSIZE		1024	/* bytes */
+#define	USB_CS_RESET_LIMIT	20	/* failures = 20 * 50 ms = 1sec */
 
 typedef uint32_t usb_timeout_t;		/* milliseconds */
 typedef uint32_t usb_frlength_t;	/* bytes */

Modified: stable/8/sys/dev/usb/usb_generic.c
==============================================================================
--- stable/8/sys/dev/usb/usb_generic.c	Wed Jun 22 07:18:14 2011	(r223413)
+++ stable/8/sys/dev/usb/usb_generic.c	Wed Jun 22 08:01:44 2011	(r223414)
@@ -966,10 +966,8 @@ ugen_re_enumerate(struct usb_fifo *f)
 		/* ignore any errors */
 		DPRINTFN(6, "no FIFOs\n");
 	}
-	if (udev->re_enumerate_wait == 0) {
-		udev->re_enumerate_wait = 1;
-		usb_needs_explore(udev->bus, 0);
-	}
+	/* start re-enumeration of device */
+	usbd_start_re_enumerate(udev);
 	return (0);
 }
 

Modified: stable/8/sys/dev/usb/usb_hub.c
==============================================================================
--- stable/8/sys/dev/usb/usb_hub.c	Wed Jun 22 07:18:14 2011	(r223413)
+++ stable/8/sys/dev/usb/usb_hub.c	Wed Jun 22 08:01:44 2011	(r223414)
@@ -242,9 +242,14 @@ uhub_explore_sub(struct uhub_softc *sc, 
 	if (child->flags.usb_mode == USB_MODE_HOST) {
 		usbd_enum_lock(child);
 		if (child->re_enumerate_wait) {
-			err = usbd_set_config_index(child, USB_UNCONFIG_INDEX);
-			if (err == 0)
-				err = usbd_req_re_enumerate(child, NULL);
+			err = usbd_set_config_index(child,
+			    USB_UNCONFIG_INDEX);
+			if (err != 0) {
+				DPRINTF("Unconfigure failed: "
+				    "%s: Ignored.\n",
+				    usbd_errstr(err));
+			}
+			err = usbd_req_re_enumerate(child, NULL);
 			if (err == 0)
 				err = usbd_set_config_index(child, 0);
 			if (err == 0) {
@@ -2471,3 +2476,19 @@ usbd_filter_power_mode(struct usb_device
 	/* use fixed power mode given by hardware driver */
 	return (temp);
 }
+
+/*------------------------------------------------------------------------*
+ *	usbd_start_re_enumerate
+ *
+ * This function starts re-enumeration of the given USB device. This
+ * function does not need to be called BUS-locked. This function does
+ * not wait until the re-enumeration is completed.
+ *------------------------------------------------------------------------*/
+void
+usbd_start_re_enumerate(struct usb_device *udev)
+{
+	if (udev->re_enumerate_wait == 0) {
+		udev->re_enumerate_wait = 1;
+		usb_needs_explore(udev->bus, 0);
+	}
+}

Modified: stable/8/sys/dev/usb/usb_request.c
==============================================================================
--- stable/8/sys/dev/usb/usb_request.c	Wed Jun 22 07:18:14 2011	(r223413)
+++ stable/8/sys/dev/usb/usb_request.c	Wed Jun 22 08:01:44 2011	(r223414)
@@ -238,6 +238,10 @@ usb_do_clear_stall_callback(struct usb_x
 
 	switch (USB_GET_STATE(xfer)) {
 	case USB_ST_TRANSFERRED:
+
+		/* reset error counter */
+		udev->clear_stall_errors = 0;
+
 		if (ep == NULL)
 			goto tr_setup;		/* device was unconfigured */
 		if (ep->edesc &&
@@ -289,8 +293,23 @@ tr_setup:
 		goto tr_setup;
 
 	default:
-		if (xfer->error == USB_ERR_CANCELLED) {
+		if (error == USB_ERR_CANCELLED)
 			break;
+
+		DPRINTF("Clear stall failed.\n");
+		if (udev->clear_stall_errors == USB_CS_RESET_LIMIT)
+			goto tr_setup;
+
+		if (error == USB_ERR_TIMEOUT) {
+			udev->clear_stall_errors = USB_CS_RESET_LIMIT;
+			DPRINTF("Trying to re-enumerate.\n");
+			usbd_start_re_enumerate(udev);
+		} else {
+			udev->clear_stall_errors++;
+			if (udev->clear_stall_errors == USB_CS_RESET_LIMIT) {
+				DPRINTF("Trying to re-enumerate.\n");
+				usbd_start_re_enumerate(udev);
+			}
 		}
 		goto tr_setup;
 	}
@@ -1936,6 +1955,23 @@ usbd_req_re_enumerate(struct usb_device 
 		return (USB_ERR_INVAL);
 	}
 retry:
+	/*
+	 * Try to reset the High Speed parent HUB of a LOW- or FULL-
+	 * speed device, if any.
+	 */
+	if (udev->parent_hs_hub != NULL &&
+	    udev->speed != USB_SPEED_HIGH) {
+		DPRINTF("Trying to reset parent High Speed TT.\n");
+		err = usbd_req_reset_tt(udev->parent_hs_hub, NULL,
+		    udev->hs_port_no);
+		if (err) {
+			DPRINTF("Resetting parent High "
+			    "Speed TT failed (%s).\n",
+			    usbd_errstr(err));
+		}
+	}
+
+	/* Try to reset the parent HUB port. */
 	err = usbd_req_reset_port(parent_hub, mtx, udev->port_no);
 	if (err) {
 		DPRINTFN(0, "addr=%d, port reset failed, %s\n", 
@@ -2033,3 +2069,65 @@ usbd_req_set_device_feature(struct usb_d
 	USETW(req.wLength, 0);
 	return (usbd_do_request(udev, mtx, &req, 0));
 }
+
+/*------------------------------------------------------------------------*
+ *	usbd_req_reset_tt
+ *
+ * Returns:
+ *    0: Success
+ * Else: Failure
+ *------------------------------------------------------------------------*/
+usb_error_t
+usbd_req_reset_tt(struct usb_device *udev, struct mtx *mtx,
+    uint8_t port)
+{
+	struct usb_device_request req;
+
+	/* For single TT HUBs the port should be 1 */
+
+	if (udev->ddesc.bDeviceClass == UDCLASS_HUB &&
+	    udev->ddesc.bDeviceProtocol == UDPROTO_HSHUBSTT)
+		port = 1;
+
+	req.bmRequestType = UT_WRITE_CLASS_OTHER;
+	req.bRequest = UR_RESET_TT;
+	USETW(req.wValue, 0);
+	req.wIndex[0] = port;
+	req.wIndex[1] = 0;
+	USETW(req.wLength, 0);
+	return (usbd_do_request(udev, mtx, &req, 0));
+}
+
+/*------------------------------------------------------------------------*
+ *	usbd_req_clear_tt_buffer
+ *
+ * For single TT HUBs the port should be 1.
+ *
+ * Returns:
+ *    0: Success
+ * Else: Failure
+ *------------------------------------------------------------------------*/
+usb_error_t
+usbd_req_clear_tt_buffer(struct usb_device *udev, struct mtx *mtx,
+    uint8_t port, uint8_t addr, uint8_t type, uint8_t endpoint)
+{
+	struct usb_device_request req;
+	uint16_t wValue;
+
+	/* For single TT HUBs the port should be 1 */
+
+	if (udev->ddesc.bDeviceClass == UDCLASS_HUB &&
+	    udev->ddesc.bDeviceProtocol == UDPROTO_HSHUBSTT)
+		port = 1;
+
+	wValue = (endpoint & 0xF) | ((addr & 0x7F) << 4) |
+	    ((endpoint & 0x80) << 8) | ((type & 3) << 12);
+
+	req.bmRequestType = UT_WRITE_CLASS_OTHER;
+	req.bRequest = UR_CLEAR_TT_BUFFER;
+	USETW(req.wValue, wValue);
+	req.wIndex[0] = port;
+	req.wIndex[1] = 0;
+	USETW(req.wLength, 0);
+	return (usbd_do_request(udev, mtx, &req, 0));
+}

Modified: stable/8/sys/dev/usb/usb_request.h
==============================================================================
--- stable/8/sys/dev/usb/usb_request.h	Wed Jun 22 07:18:14 2011	(r223413)
+++ stable/8/sys/dev/usb/usb_request.h	Wed Jun 22 08:01:44 2011	(r223414)
@@ -85,5 +85,9 @@ usb_error_t usbd_req_set_hub_u2_timeout(
 		    struct mtx *mtx, uint8_t port, uint8_t timeout);
 usb_error_t usbd_req_set_hub_depth(struct usb_device *udev,
 		    struct mtx *mtx, uint16_t depth);
+usb_error_t usbd_req_reset_tt(struct usb_device *udev, struct mtx *mtx,
+		    uint8_t port);
+usb_error_t usbd_req_clear_tt_buffer(struct usb_device *udev, struct mtx *mtx,
+		    uint8_t port, uint8_t addr, uint8_t type, uint8_t endpoint);
 
 #endif					/* _USB_REQUEST_H_ */

Modified: stable/8/sys/dev/usb/usb_transfer.c
==============================================================================
--- stable/8/sys/dev/usb/usb_transfer.c	Wed Jun 22 07:18:14 2011	(r223413)
+++ stable/8/sys/dev/usb/usb_transfer.c	Wed Jun 22 08:01:44 2011	(r223414)
@@ -2928,6 +2928,11 @@ repeat:
 	usbd_transfer_unsetup(udev->ctrl_xfer, USB_CTRL_XFER_MAX);
 
 	/*
+	 * Reset clear stall error counter.
+	 */
+	udev->clear_stall_errors = 0;
+
+	/*
 	 * Try to setup a new USB transfer for the
 	 * default control endpoint:
 	 */

Modified: stable/8/sys/dev/usb/usbdi.h
==============================================================================
--- stable/8/sys/dev/usb/usbdi.h	Wed Jun 22 07:18:14 2011	(r223413)
+++ stable/8/sys/dev/usb/usbdi.h	Wed Jun 22 08:01:44 2011	(r223414)
@@ -542,6 +542,7 @@ void	usbd_m_copy_in(struct usb_page_cach
 	    struct mbuf *m, usb_size_t src_offset, usb_frlength_t src_len);
 void	usbd_frame_zero(struct usb_page_cache *cache, usb_frlength_t offset,
 	    usb_frlength_t len);
+void	usbd_start_re_enumerate(struct usb_device *udev);
 
 int	usb_fifo_attach(struct usb_device *udev, void *priv_sc,
 	    struct mtx *priv_mtx, struct usb_fifo_methods *pm,



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201106220801.p5M81ikp038505>