USB: usb_get_string should check the descriptor type
authorAlan Stern <stern@rowland.harvard.edu>
Fri, 20 Feb 2009 21:33:08 +0000 (16:33 -0500)
committerGreg Kroah-Hartman <gregkh@suse.de>
Tue, 17 Mar 2009 00:52:47 +0000 (17:52 -0700)
commit 67f5a4ba9741fcef3f4db3509ad03565d9e33af2 upstream.

This patch (as1218) fixes a problem with a radio-control joystick used
in the "walkera 4#3" helicopter.  This device responds to the initial
Get-String-Descriptor request for string 0 (which is really the list
of supported languages) by sending its config descriptor!  The
usb_get_string() routine needs to check whether it got the right
type of descriptor.

Oddly enough, this sort of check is already present in
usb_get_descriptor().  The patch changes the error code from -EPROTO
to -ENODATA, because -EPROTO shows up in so many other contexts to
indicate a hardware failure rather than a firmware error.

Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
Tested-by: Guillermo Jarabo <williamjap@gmail.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
drivers/usb/core/message.c

index 9cfa366..2aa2a58 100644 (file)
@@ -651,7 +651,7 @@ int usb_get_descriptor(struct usb_device *dev, unsigned char type,
                if (result <= 0 && result != -ETIMEDOUT)
                        continue;
                if (result > 1 && ((u8 *)buf)[1] != type) {
-                       result = -EPROTO;
+                       result = -ENODATA;
                        continue;
                }
                break;
@@ -694,8 +694,13 @@ static int usb_get_string(struct usb_device *dev, unsigned short langid,
                        USB_REQ_GET_DESCRIPTOR, USB_DIR_IN,
                        (USB_DT_STRING << 8) + index, langid, buf, size,
                        USB_CTRL_GET_TIMEOUT);
-               if (!(result == 0 || result == -EPIPE))
-                       break;
+               if (result == 0 || result == -EPIPE)
+                       continue;
+               if (result > 1 && ((u8 *) buf)[1] != USB_DT_STRING) {
+                       result = -ENODATA;
+                       continue;
+               }
+               break;
        }
        return result;
 }