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>
This commit is contained in:
Mike Lockwood
2010-06-28 16:19:32 -04:00
committed by Colin Cross
parent 1ee6838659
commit 35ee07a4df
3 changed files with 33 additions and 11 deletions

View 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);
}
}

View File

@@ -103,6 +103,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
@@ -1063,11 +1084,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);
}
/*-------------------------------------------------------------------------*/

View File

@@ -39,6 +39,7 @@
#include <linux/switch.h>
struct usb_composite_dev;
struct usb_configuration;
/**
@@ -143,6 +144,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
@@ -356,6 +358,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;
};