USB: composite: Add usb_composite_force_reset utility to force enumeration
authorMike Lockwood <lockwood@android.com>
Mon, 28 Jun 2010 20:19:32 +0000 (16:19 -0400)
committerColin Cross <ccross@android.com>
Tue, 14 Jun 2011 16:09:08 +0000 (09:09 -0700)
Use this rather than calling usb_gadget_disconnect and usb_gadget_connect
directly to avoid sending USB disconnect events to userspace when resetting
the bus.

Signed-off-by: Mike Lockwood <lockwood@android.com>
drivers/usb/gadget/android.c
drivers/usb/gadget/composite.c
include/linux/usb/composite.h

index 7618a073de586a6744f8cef47afefb34a1e227b4..c7a54787a04488669470c1f7b327a6fea608e158 100644 (file)
@@ -337,7 +337,7 @@ void android_enable_function(struct usb_function *f, int enable)
                         */
                        list_for_each_entry(func, &android_config_driver.functions, list) {
                                if (!strcmp(func->name, "usb_mass_storage")) {
-                                       usb_function_set_enabled(f, !enable);
+                                       usb_function_set_enabled(func, !enable);
                                        break;
                                }
                        }
@@ -348,14 +348,7 @@ void android_enable_function(struct usb_function *f, int enable)
                device_desc.idProduct = __constant_cpu_to_le16(product_id);
                if (dev->cdev)
                        dev->cdev->desc.idProduct = device_desc.idProduct;
-
-               /* force reenumeration */
-               if (dev->cdev && dev->cdev->gadget &&
-                               dev->cdev->gadget->speed != USB_SPEED_UNKNOWN) {
-                       usb_gadget_disconnect(dev->cdev->gadget);
-                       msleep(10);
-                       usb_gadget_connect(dev->cdev->gadget);
-               }
+               usb_composite_force_reset(dev->cdev);
        }
 }
 
index bf555327937f29f7d7eb4814a46291a358318f44..c2684b5adc02c074a4554929ea973c29b52b5c88 100644 (file)
@@ -107,6 +107,27 @@ void usb_function_set_enabled(struct usb_function *f, int enabled)
        kobject_uevent(&f->dev->kobj, KOBJ_CHANGE);
 }
 
+
+void usb_composite_force_reset(struct usb_composite_dev *cdev)
+{
+       unsigned long                   flags;
+
+       spin_lock_irqsave(&cdev->lock, flags);
+       /* force reenumeration */
+       if (cdev && cdev->gadget &&
+                       cdev->gadget->speed != USB_SPEED_UNKNOWN) {
+               /* avoid sending a disconnect switch event until after we disconnect */
+               cdev->mute_switch = 1;
+               spin_unlock_irqrestore(&cdev->lock, flags);
+
+               usb_gadget_disconnect(cdev->gadget);
+               msleep(10);
+               usb_gadget_connect(cdev->gadget);
+       } else {
+               spin_unlock_irqrestore(&cdev->lock, flags);
+       }
+}
+
 /**
  * usb_add_function() - add a function to a configuration
  * @config: the configuration
@@ -1114,11 +1135,15 @@ static void composite_disconnect(struct usb_gadget *gadget)
        spin_lock_irqsave(&cdev->lock, flags);
        if (cdev->config)
                reset_config(cdev);
+
        if (composite->disconnect)
                composite->disconnect(cdev);
-       spin_unlock_irqrestore(&cdev->lock, flags);
 
-       schedule_work(&cdev->switch_work);
+       if (cdev->mute_switch)
+               cdev->mute_switch = 0;
+       else
+               schedule_work(&cdev->switch_work);
+       spin_unlock_irqrestore(&cdev->lock, flags);
 }
 
 /*-------------------------------------------------------------------------*/
index 4cc46801652b2ee0a7f8da29d6da5f9952bdf61a..37352fc4601af58080edb1bc848960fc030ff7b3 100644 (file)
@@ -47,6 +47,7 @@
  */
 #define USB_GADGET_DELAYED_STATUS       0x7fff /* Impossibly large value */
 
+struct usb_composite_dev;
 struct usb_configuration;
 
 /**
@@ -151,6 +152,7 @@ int usb_function_activate(struct usb_function *);
 int usb_interface_id(struct usb_configuration *, struct usb_function *);
 
 void usb_function_set_enabled(struct usb_function *, int);
+void usb_composite_force_reset(struct usb_composite_dev *);
 
 /**
  * ep_choose - select descriptor endpoint at current device speed
@@ -372,6 +374,8 @@ struct usb_composite_dev {
        spinlock_t                      lock;
 
        struct switch_dev sdev;
+       /* used by usb_composite_force_reset to avoid signalling switch changes */
+       bool                            mute_switch;
        struct work_struct switch_work;
 };