From: Mike Lockwood Date: Sun, 7 Feb 2010 02:53:51 +0000 (-0500) Subject: USB: composite: Add class driver for enabling and disabling USB functions. X-Git-Tag: firefly_0821_release~11649 X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=f8cf7f90ac799df1f9a34bd7cd6fb0dce063c8c5;p=firefly-linux-kernel-4.4.55.git USB: composite: Add class driver for enabling and disabling USB functions. Signed-off-by: Mike Lockwood --- diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c index 39f61affbae6..a64fb6f4c7ff 100644 --- a/drivers/usb/gadget/composite.c +++ b/drivers/usb/gadget/composite.c @@ -71,6 +71,33 @@ MODULE_PARM_DESC(iSerialNumber, "SerialNumber string"); /*-------------------------------------------------------------------------*/ +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); +} + +static ssize_t enable_store( + struct device *dev, struct device_attribute *attr, + const char *buf, size_t size) +{ + struct usb_function *f = dev_get_drvdata(dev); + struct usb_composite_driver *driver = f->config->cdev->driver; + int value; + + sscanf(buf, "%d", &value); + if (driver->enable_function) + driver->enable_function(f, value); + else + f->hidden = !value; + + return size; +} + +static DEVICE_ATTR(enable, S_IRUGO | S_IWUSR, enable_show, enable_store); + + /** * usb_add_function() - add a function to a configuration * @config: the configuration @@ -88,15 +115,30 @@ MODULE_PARM_DESC(iSerialNumber, "SerialNumber string"); int __init usb_add_function(struct usb_configuration *config, struct usb_function *function) { + struct usb_composite_dev *cdev = config->cdev; int value = -EINVAL; + int index; - DBG(config->cdev, "adding '%s'/%p to config '%s'/%p\n", + DBG(cdev, "adding '%s'/%p to config '%s'/%p\n", function->name, function, config->label, config); if (!function->set_alt || !function->disable) goto done; + index = atomic_inc_return(&cdev->driver->function_count); + function->dev = device_create(cdev->driver->class, NULL, + MKDEV(0, index), NULL, function->name); + if (IS_ERR(function->dev)) + return PTR_ERR(function->dev); + + value = device_create_file(function->dev, &dev_attr_enable); + if (value < 0) { + device_destroy(cdev->driver->class, MKDEV(0, index)); + return value; + } + dev_set_drvdata(function->dev, function); + function->config = config; list_add_tail(&function->list, &config->functions); @@ -122,7 +164,7 @@ int __init usb_add_function(struct usb_configuration *config, done: if (value) - DBG(config->cdev, "adding '%s'/%p --> %d\n", + DBG(cdev, "adding '%s'/%p --> %d\n", function->name, function, value); return value; } @@ -1124,6 +1166,10 @@ int __init usb_composite_register(struct usb_composite_driver *driver) composite_driver.driver.name = driver->name; composite = driver; + driver->class = class_create(THIS_MODULE, "usb_composite"); + if (IS_ERR(driver->class)) + return PTR_ERR(driver->class); + return usb_gadget_register_driver(&composite_driver); } diff --git a/include/linux/usb/composite.h b/include/linux/usb/composite.h index 8f33ae3e00f3..66884030c58a 100644 --- a/include/linux/usb/composite.h +++ b/include/linux/usb/composite.h @@ -128,6 +128,7 @@ struct usb_function { /* private: */ /* internals */ struct list_head list; + struct device *dev; }; int usb_add_function(struct usb_configuration *, struct usb_function *); @@ -268,6 +269,9 @@ struct usb_composite_driver { const struct usb_device_descriptor *dev; struct usb_gadget_strings **strings; + struct class *class; + atomic_t function_count; + /* REVISIT: bind() functions can be marked __init, which * makes trouble for section mismatch analysis. See if * we can't restructure things to avoid mismatching... @@ -279,6 +283,8 @@ struct usb_composite_driver { /* global suspend hooks */ void (*suspend)(struct usb_composite_dev *); void (*resume)(struct usb_composite_dev *); + + void (*enable_function)(struct usb_function *f, int enable); }; extern int usb_composite_register(struct usb_composite_driver *);