summaryrefslogtreecommitdiff
path: root/drivers/usb/gadget/android.c
diff options
context:
space:
mode:
authorJohn Michelau <john.michelau@motorola.com>2010-12-10 11:33:54 -0600
committerColin Cross <ccross@android.com>2011-06-14 09:09:11 -0700
commitd5d2de6539f4a588d8a6187cfe8396d4300b4653 (patch)
tree208e0fef98174d9d0842d8c948bd937c84f28f63 /drivers/usb/gadget/android.c
parent677ba87bdfc5765bb2ed80692d74f8de41b83f11 (diff)
USB: gadget: android Fix gadget descriptor compliance for IAD's
USB-IF core team mandates that composite devices containing IAD's must use bDeviceClass=0xEF, bDeviceSubClass=0x02, & bDeviceProtocol=0x01 instead of the usual 0x00 in all fields. This is not a problem currently on Linux hosts, but it is a problem when connecting to Windows hosts. Without this change the default Microsoft composite driver will not group interfaces properly, which is what allows child function drivers with IAD's to load correctly. Signed-off-by: Mike Lockwood <lockwood@android.com>
Diffstat (limited to 'drivers/usb/gadget/android.c')
-rw-r--r--drivers/usb/gadget/android.c56
1 files changed, 43 insertions, 13 deletions
diff --git a/drivers/usb/gadget/android.c b/drivers/usb/gadget/android.c
index d9d4d2fd599..213e8a2d782 100644
--- a/drivers/usb/gadget/android.c
+++ b/drivers/usb/gadget/android.c
@@ -351,6 +351,47 @@ void android_register_function(struct android_usb_function *f)
bind_functions(dev);
}
+void update_dev_desc(struct android_dev *dev)
+{
+ struct usb_function *f;
+ struct usb_function *last_enabled_f = NULL;
+ int num_enabled = 0;
+ int has_iad = 0;
+
+ dev->cdev->desc.bDeviceClass = USB_CLASS_PER_INTERFACE;
+ dev->cdev->desc.bDeviceSubClass = 0x00;
+ dev->cdev->desc.bDeviceProtocol = 0x00;
+
+ list_for_each_entry(f, &android_config_driver.functions, list) {
+ if (!f->disabled) {
+ num_enabled++;
+ last_enabled_f = f;
+ if (f->descriptors[0]->bDescriptorType ==
+ USB_DT_INTERFACE_ASSOCIATION)
+ has_iad = 1;
+ }
+ if (num_enabled > 1 && has_iad) {
+ dev->cdev->desc.bDeviceClass = USB_CLASS_MISC;
+ dev->cdev->desc.bDeviceSubClass = 0x02;
+ dev->cdev->desc.bDeviceProtocol = 0x01;
+ break;
+ }
+ }
+
+ if (num_enabled == 1) {
+#ifdef CONFIG_USB_ANDROID_RNDIS
+ if (!strcmp(last_enabled_f->name, "rndis")) {
+#ifdef CONFIG_USB_ANDROID_RNDIS_WCEIS
+ dev->cdev->desc.bDeviceClass =
+ USB_CLASS_WIRELESS_CONTROLLER;
+#else
+ dev->cdev->desc.bDeviceClass = USB_CLASS_COMM;
+#endif
+ }
+#endif
+ }
+}
+
void android_enable_function(struct usb_function *f, int enable)
{
struct android_dev *dev = _android_dev;
@@ -363,19 +404,6 @@ void android_enable_function(struct usb_function *f, int enable)
#ifdef CONFIG_USB_ANDROID_RNDIS
if (!strcmp(f->name, "rndis")) {
struct usb_function *func;
-
- /* We need to specify the COMM class in the device descriptor
- * if we are using RNDIS.
- */
- if (enable)
-#ifdef CONFIG_USB_ANDROID_RNDIS_WCEIS
- dev->cdev->desc.bDeviceClass = USB_CLASS_WIRELESS_CONTROLLER;
-#else
- dev->cdev->desc.bDeviceClass = USB_CLASS_COMM;
-#endif
- else
- dev->cdev->desc.bDeviceClass = USB_CLASS_PER_INTERFACE;
-
/* Windows does not support other interfaces when RNDIS is enabled,
* so we disable UMS and MTP when RNDIS is on.
*/
@@ -388,6 +416,8 @@ void android_enable_function(struct usb_function *f, int enable)
}
#endif
+ update_dev_desc(dev);
+
product_id = get_product_id(dev);
device_desc.idProduct = __constant_cpu_to_le16(product_id);
if (dev->cdev)