USB: composite: Add usb_composite_force_reset utility to force enumeration

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>
diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c
index bf55532..c2684b5 100644
--- a/drivers/usb/gadget/composite.c
+++ b/drivers/usb/gadget/composite.c
@@ -107,6 +107,27 @@
 	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 @@
 	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);
 }
 
 /*-------------------------------------------------------------------------*/