From 28acc1a88c75b08b2ab502a546da61b131b86f5c Mon Sep 17 00:00:00 2001 From: Mike Lockwood Date: Mon, 28 Jun 2010 16:19:32 -0400 Subject: [PATCH] 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 --- drivers/usb/gadget/android.c | 11 ++--------- drivers/usb/gadget/composite.c | 29 +++++++++++++++++++++++++++-- include/linux/usb/composite.h | 4 ++++ 3 files changed, 33 insertions(+), 11 deletions(-) diff --git a/drivers/usb/gadget/android.c b/drivers/usb/gadget/android.c index 7618a073de58..c7a54787a044 100644 --- a/drivers/usb/gadget/android.c +++ b/drivers/usb/gadget/android.c @@ -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); } } diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c index bf555327937f..c2684b5adc02 100644 --- a/drivers/usb/gadget/composite.c +++ b/drivers/usb/gadget/composite.c @@ -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); } /*-------------------------------------------------------------------------*/ diff --git a/include/linux/usb/composite.h b/include/linux/usb/composite.h index 4cc46801652b..37352fc4601a 100644 --- a/include/linux/usb/composite.h +++ b/include/linux/usb/composite.h @@ -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; }; -- 2.34.1