summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Lockwood <lockwood@android.com>2010-06-23 08:20:59 -0400
committerDan Willemsen <dwillemsen@nvidia.com>2011-11-30 21:38:06 -0800
commitf0dc4ebd035a22b6f6ac01087dc8a4176166ce8a (patch)
treea43f4f868d7778be8c3644e7578e8a70c261762b
parentc386e49d9c9de1069be3d6636b0e9d5f053afe83 (diff)
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>
-rw-r--r--drivers/usb/gadget/android.c8
-rw-r--r--drivers/usb/gadget/composite.c42
-rw-r--r--drivers/usb/gadget/f_adb.c2
-rw-r--r--drivers/usb/gadget/f_rndis.c2
-rw-r--r--include/linux/usb/composite.h9
5 files changed, 52 insertions, 11 deletions
diff --git a/drivers/usb/gadget/android.c b/drivers/usb/gadget/android.c
index 3c4d44d663c0..6e3c32e3f7e0 100644
--- a/drivers/usb/gadget/android.c
+++ b/drivers/usb/gadget/android.c
@@ -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;
}
}
diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c
index 3ab387adb161..2d0e9ef90f51 100644
--- a/drivers/usb/gadget/composite.c
+++ b/drivers/usb/gadget/composite.c
@@ -203,7 +203,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(
@@ -218,13 +218,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
@@ -448,7 +453,7 @@ static int config_buf(struct usb_configuration *config,
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);
@@ -719,7 +724,7 @@ static int set_config(struct usb_composite_dev *cdev,
if (!f)
break;
- if (f->hidden)
+ if (f->disabled)
continue;
/*
@@ -775,6 +780,9 @@ 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);
+
if (result >= 0 && cdev->delayed_status)
result = USB_GADGET_DELAYED_STATUS;
return result;
@@ -1406,6 +1414,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);
}
/*-------------------------------------------------------------------------*/
@@ -1466,6 +1476,7 @@ composite_unbind(struct usb_gadget *gadget)
kfree(cdev->req->buf);
usb_ep_free_request(gadget->ep0, cdev->req);
}
+ switch_dev_unregister(&cdev->sdev);
device_remove_file(&gadget->dev, &dev_attr_suspended);
kfree(cdev);
set_gadget_data(gadget, NULL);
@@ -1534,6 +1545,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;
/* standardized runtime overrides for device ID data */
@@ -1638,6 +1654,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 = {
@@ -1699,6 +1732,7 @@ int usb_composite_probe(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_probe_driver(&composite_driver, composite_bind);
}
diff --git a/drivers/usb/gadget/f_adb.c b/drivers/usb/gadget/f_adb.c
index 194c767efddb..0d252766d83f 100644
--- a/drivers/usb/gadget/f_adb.c
+++ b/drivers/usb/gadget/f_adb.c
@@ -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;
diff --git a/drivers/usb/gadget/f_rndis.c b/drivers/usb/gadget/f_rndis.c
index e7a788d97c83..36980d98c9e2 100644
--- a/drivers/usb/gadget/f_rndis.c
+++ b/drivers/usb/gadget/f_rndis.c
@@ -939,7 +939,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);
diff --git a/include/linux/usb/composite.h b/include/linux/usb/composite.h
index 9bb851fb5a0e..f9ca73feb9ea 100644
--- a/include/linux/usb/composite.h
+++ b/include/linux/usb/composite.h
@@ -36,6 +36,7 @@
#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>
+#include <linux/switch.h>
/*
* USB function drivers should return USB_GADGET_DELAYED_STATUS if they
@@ -117,7 +118,9 @@ struct usb_function {
struct usb_descriptor_header **ss_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
@@ -160,6 +163,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);
+
int config_ep_by_speed(struct usb_gadget *g, struct usb_function *f,
struct usb_ep *_ep);
@@ -369,6 +374,8 @@ struct usb_composite_dev {
/* protects deactivations and delayed_status counts*/
spinlock_t lock;
+
+ struct switch_dev sdev;
};
extern int usb_string_id(struct usb_composite_dev *c);