diff options
author | Mike Lockwood <lockwood@android.com> | 2010-06-23 08:20:59 -0400 |
---|---|---|
committer | Dan Willemsen <dwillemsen@nvidia.com> | 2011-11-30 21:38:06 -0800 |
commit | f0dc4ebd035a22b6f6ac01087dc8a4176166ce8a (patch) | |
tree | a43f4f868d7778be8c3644e7578e8a70c261762b | |
parent | c386e49d9c9de1069be3d6636b0e9d5f053afe83 (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.c | 8 | ||||
-rw-r--r-- | drivers/usb/gadget/composite.c | 42 | ||||
-rw-r--r-- | drivers/usb/gadget/f_adb.c | 2 | ||||
-rw-r--r-- | drivers/usb/gadget/f_rndis.c | 2 | ||||
-rw-r--r-- | include/linux/usb/composite.h | 9 |
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); |