From: Mike Lockwood Date: Wed, 23 Jun 2010 12:20:59 +0000 (-0400) Subject: USB: gadget: composite: Add userspace notifications for USB state changes X-Git-Tag: firefly_0821_release~7613^2~809 X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=e2dc503c4220b7d86815283f7d18c0b14af64470;p=firefly-linux-kernel-4.4.55.git 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 --- 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 fa785c6cfd61..e15c0b6a5849 100644 --- a/drivers/usb/gadget/composite.c +++ b/drivers/usb/gadget/composite.c @@ -79,7 +79,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( @@ -94,13 +94,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 @@ -315,7 +320,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); @@ -489,7 +494,7 @@ static int set_config(struct usb_composite_dev *cdev, if (!f) break; - if (f->hidden) + if (f->disabled) continue; /* @@ -539,6 +544,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; @@ -1094,6 +1102,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); } /*-------------------------------------------------------------------------*/ @@ -1154,6 +1164,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); @@ -1222,6 +1233,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; @@ -1327,6 +1343,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 = { @@ -1382,6 +1415,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 3b062d976aea..c0c3280a0b61 100644 --- a/drivers/usb/gadget/f_rndis.c +++ b/drivers/usb/gadget/f_rndis.c @@ -864,7 +864,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 a521e8c0e556..0b2d2919edb2 100644 --- a/include/linux/usb/composite.h +++ b/include/linux/usb/composite.h @@ -36,6 +36,7 @@ #include #include +#include /* * USB function drivers should return USB_GADGET_DELAYED_STATUS if they @@ -108,7 +109,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 @@ -147,6 +150,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 @@ -365,6 +370,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);