Hi, Alan:
I have received a USB stick which refuses to return the descriptor upon
the first 64 byte read (HC returns with code -71). The following patchlet
fixes the problem:
@@ -2162,6 +2162,8 @@ hub_port_init (struct usb_device *hdev,
if (USE_NEW_SCHEME(retry_counter)) {
struct usb_device_descriptor *buf;
+ msleep(10);
+
#define GET_DESCRIPTOR_BUFSIZE 64
buf = kmalloc(GET_DESCRIPTOR_BUFSIZE, GFP_NOIO);
if (!buf) {
Apparently, the device does not like to return descriptors immediately
after a port reset.
HOWEVER, I question the wisdom of going through these hoops for high-speed
devices. Their MaxPacketSize is fixed, isn't it?
I found a message at the following URL:
http://marc.theaimsgroup.com/?l=linux-usb-devel&m=109595376619962&w=2
If you really want to imitate Windows, you should issue the 64-byte
Get-Descriptor request to every device regardless of its speed. Then
skip the existing 8-byte request, as it would no longer be needed.
What is up with that? Does Windows do it? Which one (98, XP)?
I tried a patch which simply skips all this insanity and goes right to
the address setting and reading of descriptors. It seems to work with all
my devices. See appended.
At bare minimum, I need the delay in, but please consider the bigger patch
(it will conflict with the current tree because of retry loop added
recently for the 64-byte descriptor read, but I only want a general
opinion).
Greetings,
-- Pete
diff -urpN -X dontdiff linux-2.6.10/drivers/usb/core/hub.c
linux-2.6.10-lem/drivers/usb/core/hub.c
--- linux-2.6.10/drivers/usb/core/hub.c 2005-01-05 00:37:56.000000000 -0800
+++ linux-2.6.10-lem/drivers/usb/core/hub.c 2005-01-16 01:16:42.000000000
-0800
@@ -2027,7 +2027,7 @@ static int hub_port_debounce(struct usb_
#define usb_sndaddr0pipe() (PIPE_CONTROL << 30)
#define usb_rcvaddr0pipe() ((PIPE_CONTROL << 30) | USB_DIR_IN)
-static int hub_set_address(struct usb_device *udev)
+static int hub_set_address_once(struct usb_device *udev)
{
int retval;
@@ -2051,6 +2051,124 @@ static int hub_set_address(struct usb_de
return retval;
}
+static int hub_set_address(struct usb_device *udev)
+{
+ int i;
+ int retval = -1;
+
+ for (i = 0; i < SET_ADDRESS_TRIES; i++) {
+ if ((retval = hub_set_address_once(udev)) >= 0)
+ return 0;
+ msleep(200);
+ }
+ dev_err(&udev->dev, "device not accepting address %d, error %d\n",
+ udev->devnum, retval);
+ return retval;
+}
+
+/*
+ * Get the bMaxPacketSize0. Returns the value or error.
+ *
+ * For historical reasons, this function is not pure and can set
+ * the udev->descriptor (look for usb_get_device_descriptor below) partially.
+ */
+static int hub_get_maxpacket(struct usb_device *hdev, struct usb_device *udev,
+ int port, int retry_counter, enum usb_device_speed oldspeed,
+ unsigned int delay)
+{
+ enum { GET_DESCRIPTOR_BUFSIZE = 64 };
+ int i, j;
+ u8 maxpacketsize0 = 13; /* Never to happen */
+ int retval = -ENODEV;
+
+ /* Why interleave GET_DESCRIPTOR and SET_ADDRESS this way?
+ * Because device hardware and firmware is sometimes buggy in
+ * this area, and this is how Linux has done it for ages.
+ * Change it cautiously.
+ *
+ * NOTE: If USE_NEW_SCHEME() is true we will start by issuing
+ * a 64-byte GET_DESCRIPTOR request. This is what Windows does,
+ * so it may help with some non-standards-compliant devices.
+ * Otherwise we start with SET_ADDRESS and then try to read the
+ * first 8 bytes of the device descriptor to get the ep0 maxpacket
+ * value.
+ */
+ for (i = 0; i < GET_DESCRIPTOR_TRIES; (++i, msleep(100))) {
+ if (USE_NEW_SCHEME(retry_counter)) {
+ struct usb_device_descriptor *buf;
+
+ buf = kmalloc(GET_DESCRIPTOR_BUFSIZE, GFP_NOIO);
+ if (!buf) {
+ retval = -ENOMEM;
+ continue;
+ }
+ buf->bMaxPacketSize0 = 0;
+
+ /* Use a short timeout the first time through,
+ * so that recalcitrant full-speed devices with
+ * 8- or 16-byte ep0-maxpackets won't slow things
+ * down tremendously by NAKing the unexpectedly
+ * early status stage.
+ */
+ j = usb_control_msg(udev, usb_rcvaddr0pipe(),
+ USB_REQ_GET_DESCRIPTOR, USB_DIR_IN,
+ USB_DT_DEVICE << 8, 0,
+ buf, GET_DESCRIPTOR_BUFSIZE,
+ (i ? HZ * USB_CTRL_GET_TIMEOUT : HZ));
+ maxpacketsize0 = buf->bMaxPacketSize0;
+ kfree(buf);
+
+ retval = hub_port_reset(hdev, port, udev, delay);
+ if (retval < 0) /* error or disconnect */
+ goto fail;
+ if (oldspeed != udev->speed) {
+ dev_dbg(&udev->dev,
+ "device reset changed speed!\n");
+ retval = -ENODEV;
+ goto fail;
+ }
+ if (maxpacketsize0 == 0) {
+ dev_err(&udev->dev, "device descriptor "
+ "read/%s, error %d\n",
+ "64", j);
+ retval = -EMSGSIZE;
+ continue;
+ }
+ }
+
+ if ((retval = hub_set_address(udev)) < 0)
+ goto fail;
+
+ /* cope with hardware quirkiness:
+ * - let SET_ADDRESS settle, some device hardware wants it
+ * - read ep0 maxpacket even for high and low speed,
+ */
+ msleep(10);
+ if (USE_NEW_SCHEME(retry_counter))
+ break;
+
+ retval = usb_get_device_descriptor(udev, 8);
+ if (retval < 8) {
+ dev_err(&udev->dev, "device descriptor "
+ "read/%s, error %d\n",
+ "8", retval);
+ if (retval >= 0)
+ retval = -EMSGSIZE;
+ } else {
+ maxpacketsize0 = udev->descriptor.bMaxPacketSize0;
+ retval = 0;
+ break;
+ }
+ }
+ if (retval)
+ goto fail;
+
+ return maxpacketsize0;
+
+fail:
+ return retval;
+}
+
/* Reset device, (re)assign address, get device descriptor.
* Device connection must be stable, no more debouncing needed.
* Returns device in USB_STATE_ADDRESS, except on error.
@@ -2066,7 +2184,7 @@ hub_port_init (struct usb_device *hdev,
{
static DECLARE_MUTEX(usb_address0_sem);
- int i, j, retval;
+ int i, retval;
unsigned delay = HUB_SHORT_RESET_TIME;
enum usb_device_speed oldspeed = udev->speed;
@@ -2091,7 +2209,6 @@ hub_port_init (struct usb_device *hdev,
if (retval < 0) /* error or disconnect */
goto fail;
/* success, speed is known */
- retval = -ENODEV;
if (oldspeed != USB_SPEED_UNKNOWN && oldspeed != udev->speed) {
dev_dbg(&udev->dev, "device reset changed speed!\n");
@@ -2145,110 +2262,33 @@ hub_port_init (struct usb_device *hdev,
udev->tt = &hub->tt;
udev->ttport = port + 1;
}
-
- /* Why interleave GET_DESCRIPTOR and SET_ADDRESS this way?
- * Because device hardware and firmware is sometimes buggy in
- * this area, and this is how Linux has done it for ages.
- * Change it cautiously.
- *
- * NOTE: If USE_NEW_SCHEME() is true we will start by issuing
- * a 64-byte GET_DESCRIPTOR request. This is what Windows does,
- * so it may help with some non-standards-compliant devices.
- * Otherwise we start with SET_ADDRESS and then try to read the
- * first 8 bytes of the device descriptor to get the ep0 maxpacket
- * value.
- */
- for (i = 0; i < GET_DESCRIPTOR_TRIES; (++i, msleep(100))) {
- if (USE_NEW_SCHEME(retry_counter)) {
- struct usb_device_descriptor *buf;
-#define GET_DESCRIPTOR_BUFSIZE 64
- buf = kmalloc(GET_DESCRIPTOR_BUFSIZE, GFP_NOIO);
- if (!buf) {
- retval = -ENOMEM;
- continue;
- }
- buf->bMaxPacketSize0 = 0;
-
- /* Use a short timeout the first time through,
- * so that recalcitrant full-speed devices with
- * 8- or 16-byte ep0-maxpackets won't slow things
- * down tremendously by NAKing the unexpectedly
- * early status stage.
- */
- j = usb_control_msg(udev, usb_rcvaddr0pipe(),
- USB_REQ_GET_DESCRIPTOR, USB_DIR_IN,
- USB_DT_DEVICE << 8, 0,
- buf, GET_DESCRIPTOR_BUFSIZE,
- (i ? HZ * USB_CTRL_GET_TIMEOUT : HZ));
- udev->descriptor.bMaxPacketSize0 =
- buf->bMaxPacketSize0;
- kfree(buf);
-
- retval = hub_port_reset(hdev, port, udev, delay);
- if (retval < 0) /* error or disconnect */
- goto fail;
- if (oldspeed != udev->speed) {
- dev_dbg(&udev->dev,
- "device reset changed speed!\n");
- retval = -ENODEV;
- goto fail;
- }
- if (udev->descriptor.bMaxPacketSize0 == 0) {
- dev_err(&udev->dev, "device descriptor "
- "read/%s, error %d\n",
- "64", j);
- retval = -EMSGSIZE;
- continue;
- }
-#undef GET_DESCRIPTOR_BUFSIZE
- }
-
- for (j = 0; j < SET_ADDRESS_TRIES; ++j) {
- retval = hub_set_address(udev);
- if (retval >= 0)
- break;
- msleep(200);
+ if (udev->speed != USB_SPEED_HIGH) {
+ retval = hub_get_maxpacket(hdev, udev, port, retry_counter,
+ oldspeed, delay);
+ if (retval < 0)
+ goto fail;
+ /* Should we verify that the value is valid? */
+ if (udev->epmaxpacketin[0] != retval && retval != 0) {
+ dev_dbg(&udev->dev, "ep0 maxpacket = %d\n", retval);
+ usb_disable_endpoint(udev, 0 + USB_DIR_IN);
+ usb_disable_endpoint(udev, 0 + USB_DIR_OUT);
+ udev->epmaxpacketin[0] = retval;
+ udev->epmaxpacketout[0] = retval;
}
- if (retval < 0) {
+ } else {
+ if ((retval = hub_set_address(udev)) < 0) {
dev_err(&udev->dev,
"device not accepting address %d, error %d\n",
udev->devnum, retval);
goto fail;
}
-
/* cope with hardware quirkiness:
* - let SET_ADDRESS settle, some device hardware wants it
- * - read ep0 maxpacket even for high and low speed,
*/
msleep(10);
- if (USE_NEW_SCHEME(retry_counter))
- break;
-
- retval = usb_get_device_descriptor(udev, 8);
- if (retval < 8) {
- dev_err(&udev->dev, "device descriptor "
- "read/%s, error %d\n",
- "8", retval);
- if (retval >= 0)
- retval = -EMSGSIZE;
- } else {
- retval = 0;
- break;
- }
}
- if (retval)
- goto fail;
- /* Should we verify that the value is valid? */
- i = udev->descriptor.bMaxPacketSize0;
- if (udev->epmaxpacketin[0] != i) {
- dev_dbg(&udev->dev, "ep0 maxpacket = %d\n", i);
- usb_disable_endpoint(udev, 0 + USB_DIR_IN);
- usb_disable_endpoint(udev, 0 + USB_DIR_OUT);
- udev->epmaxpacketin[0] = udev->epmaxpacketout[0] = i;
- }
-
retval = usb_get_device_descriptor(udev, USB_DT_DEVICE_SIZE);
if (retval < (signed)sizeof(udev->descriptor)) {
dev_err(&udev->dev, "device descriptor read/%s, error %d\n",
-------------------------------------------------------
The SF.Net email is sponsored by: Beat the post-holiday blues
Get a FREE limited edition SourceForge.net t-shirt from ThinkGeek.
It's fun and FREE -- well, almost....http://www.thinkgeek.com/sfshirt
_______________________________________________
[email protected]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel