USB: gadget: composite: Add userspace notifications for USB state changes

Add switch to notify current USB configuration.  This can be used to detect
USB connect and disconnect events.

Broadcast a change via the usb_composite class when a USB function is
enabled or disabled.

Rename usb_function.hidden to usb_function.disabled.

Signed-off-by: Mike Lockwood <lockwood@android.com>
This commit is contained in:
Mike Lockwood
2010-06-23 08:20:59 -04:00
committed by Colin Cross
parent ff9cdcd465
commit a9946e705c
5 changed files with 52 additions and 11 deletions

View File

@@ -208,7 +208,7 @@ static int product_matches_functions(struct android_usb_product *p)
{
struct usb_function *f;
list_for_each_entry(f, &android_config_driver.functions, list) {
if (product_has_function(p, f) == !!f->hidden)
if (product_has_function(p, f) == !!f->disabled)
return 0;
}
return 1;
@@ -323,8 +323,8 @@ void android_enable_function(struct usb_function *f, int enable)
int disable = !enable;
int product_id;
if (!!f->hidden != disable) {
f->hidden = disable;
if (!!f->disabled != disable) {
usb_function_set_enabled(f, !disable);
#ifdef CONFIG_USB_ANDROID_RNDIS
if (!strcmp(f->name, "rndis")) {
@@ -347,7 +347,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")) {
func->hidden = enable;
usb_function_set_enabled(f, !enable);
break;
}
}

View File

@@ -75,7 +75,7 @@ static ssize_t enable_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct usb_function *f = dev_get_drvdata(dev);
return sprintf(buf, "%d\n", !f->hidden);
return sprintf(buf, "%d\n", !f->disabled);
}
static ssize_t enable_store(
@@ -90,13 +90,18 @@ static ssize_t enable_store(
if (driver->enable_function)
driver->enable_function(f, value);
else
f->hidden = !value;
usb_function_set_enabled(f, value);
return size;
}
static DEVICE_ATTR(enable, S_IRUGO | S_IWUSR, enable_show, enable_store);
void usb_function_set_enabled(struct usb_function *f, int enabled)
{
f->disabled = !enabled;
kobject_uevent(&f->dev->kobj, KOBJ_CHANGE);
}
/**
* usb_add_function() - add a function to a configuration
@@ -311,7 +316,7 @@ static int config_buf(struct usb_configuration *config,
descriptors = f->hs_descriptors;
else
descriptors = f->descriptors;
if (f->hidden || !descriptors || descriptors[0] == NULL)
if (f->disabled || !descriptors || descriptors[0] == NULL)
continue;
status = usb_descriptor_fillbuf(next, len,
(const struct usb_descriptor_header **) descriptors);
@@ -485,7 +490,7 @@ static int set_config(struct usb_composite_dev *cdev,
if (!f)
break;
if (f->hidden)
if (f->disabled)
continue;
/*
@@ -526,6 +531,8 @@ static int set_config(struct usb_composite_dev *cdev,
power = c->bMaxPower ? (2 * c->bMaxPower) : CONFIG_USB_GADGET_VBUS_DRAW;
done:
usb_gadget_vbus_draw(gadget, power);
switch_set_state(&cdev->sdev, number);
return result;
}
@@ -1044,6 +1051,8 @@ static void composite_disconnect(struct usb_gadget *gadget)
if (composite->disconnect)
composite->disconnect(cdev);
spin_unlock_irqrestore(&cdev->lock, flags);
switch_set_state(&cdev->sdev, 0);
}
/*-------------------------------------------------------------------------*/
@@ -1104,6 +1113,8 @@ composite_unbind(struct usb_gadget *gadget)
kfree(cdev->req->buf);
usb_ep_free_request(gadget->ep0, cdev->req);
}
switch_dev_unregister(&cdev->sdev);
kfree(cdev);
set_gadget_data(gadget, NULL);
device_remove_file(&gadget->dev, &dev_attr_suspended);
@@ -1183,6 +1194,11 @@ static int composite_bind(struct usb_gadget *gadget)
if (status < 0)
goto fail;
cdev->sdev.name = "usb_configuration";
status = switch_dev_register(&cdev->sdev);
if (status < 0)
goto fail;
cdev->desc = *composite->dev;
cdev->desc.bMaxPacketSize0 = gadget->ep0->maxpacket;
@@ -1257,6 +1273,23 @@ composite_resume(struct usb_gadget *gadget)
cdev->suspended = 0;
}
static int
composite_uevent(struct device *dev, struct kobj_uevent_env *env)
{
struct usb_function *f = dev_get_drvdata(dev);
if (!f) {
/* this happens when the device is first created */
return 0;
}
if (add_uevent_var(env, "FUNCTION=%s", f->name))
return -ENOMEM;
if (add_uevent_var(env, "ENABLED=%d", !f->disabled))
return -ENOMEM;
return 0;
}
/*-------------------------------------------------------------------------*/
static struct usb_gadget_driver composite_driver = {
@@ -1305,6 +1338,7 @@ int usb_composite_register(struct usb_composite_driver *driver)
driver->class = class_create(THIS_MODULE, "usb_composite");
if (IS_ERR(driver->class))
return PTR_ERR(driver->class);
driver->class->dev_uevent = composite_uevent;
return usb_gadget_register_driver(&composite_driver);
}

View File

@@ -613,7 +613,7 @@ static int adb_bind_config(struct usb_configuration *c)
dev->function.disable = adb_function_disable;
/* start disabled */
dev->function.hidden = 1;
dev->function.disabled = 1;
/* _adb_dev must be set before calling usb_gadget_register_driver */
_adb_dev = dev;

View File

@@ -865,7 +865,7 @@ rndis_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN])
#ifdef CONFIG_USB_ANDROID_RNDIS
/* start disabled */
rndis->port.func.hidden = 1;
rndis->port.func.disabled = 1;
#endif
status = usb_add_function(c, &rndis->port.func);

View File

@@ -36,6 +36,7 @@
#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>
#include <linux/switch.h>
struct usb_configuration;
@@ -100,7 +101,9 @@ struct usb_function {
struct usb_descriptor_header **hs_descriptors;
struct usb_configuration *config;
int hidden;
/* disabled is zero if the function is enabled */
int disabled;
/* REVISIT: bind() functions can be marked __init, which
* makes trouble for section mismatch analysis. See if
@@ -139,6 +142,8 @@ 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);
/**
* ep_choose - select descriptor endpoint at current device speed
* @g: gadget, connected and running at some speed
@@ -349,6 +354,8 @@ struct usb_composite_dev {
/* protects at least deactivation count */
spinlock_t lock;
struct switch_dev sdev;
};
extern int usb_string_id(struct usb_composite_dev *c);