USB: composite: Add usb_composite_force_reset utility to force enumeration
[firefly-linux-kernel-4.4.55.git] / drivers / usb / gadget / composite.c
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);
 }
 
 /*-------------------------------------------------------------------------*/