Subject: kern/36102: some usb device hang up during initial phase
To: None <kern-bug-people@netbsd.org, gnats-admin@netbsd.org,>
From: None <yuo@iijlab.net>
List: netbsd-bugs
Date: 03/29/2007 04:20:01
>Number:         36102
>Category:       kern
>Synopsis:       USB device hang up
>Confidential:   no
>Severity:       critical
>Priority:       high
>Responsible:    kern-bug-people
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Thu Mar 29 04:20:00 +0000 2007
>Originator:     Yojiro UO
>Release:        NetBSD 4.99.16
>Organization:
	Internet Initiative Japan, Inc.
	
>Environment:
System: NetBSD test 4.99.16 NetBSD 4.99.16 (TEST) #9: Thu Mar 29 12:54:56 JST 2007 root@test:/usr/src/sys/arch/i386/compile/obj/TEST i386
Architecture: i386
Machine: i386
>Description:
	Some USB device (I checked uplcom device) alwayes hangup during USB initial setup phase.
	I checked USB bus transactions by USB-bus analiser, I found some types of USB device will
	hanged up when bmRequest = GET_DESCRIPTOR with large size of wLength.
	The usb_subr.c version 1.142->1.143 change is the reason of this hangup.
	I will recomend to revert the logic to 1.142 one.
	Following patches works fine.
>How-To-Repeat:
	attach uplcom device (for example: IO DATA USB-RSAQ3, AmbiCom GPS reciever)
>Fix:
	

--- usb_subr.c-	2007-03-29 11:33:07.000000000 +0900
+++ usb_subr.c	2007-03-29 12:54:43.000000000 +0900
@@ -174,7 +174,23 @@
 	req.bRequest = UR_GET_DESCRIPTOR;
 	USETW2(req.wValue, UDESC_STRING, sindex);
 	USETW(req.wIndex, langid);
+#if 0 /* 
+       * XXX: this method possibly causes device hangup 
+       * e.x. uplcom
+       */
 	USETW(req.wLength, sizeof(usb_string_descriptor_t));
+#else
+	USETW(req.wLength, 2); /* only size byte first */
+	err = usbd_do_request_flags(dev, &req, sdesc, USBD_SHORT_XFER_OK,
+		&actlen, USBD_DEFAULT_TIMEOUT);
+	if (err)
+		return (err);
+
+	if (actlen < 2)
+		return (USBD_SHORT_XFER);
+
+	USETW(req.wLength, sdesc->bLength); /* the whole string */
+#endif
 	err = usbd_do_request_flags(dev, &req, sdesc, USBD_SHORT_XFER_OK,
 		&actlen, USBD_DEFAULT_TIMEOUT);
 	if (err)