From 2d7c128bea711fe7611d51567bd8247524eed702 Mon Sep 17 00:00:00 2001 From: Mike Lockwood Date: Sat, 6 Feb 2010 21:53:51 -0500 Subject: [PATCH] USB: composite: Add class driver for enabling and disabling USB functions. Signed-off-by: Mike Lockwood --- drivers/usb/gadget/composite.c | 50 ++++++++++++++++++++++++++++++++++++++++-- include/linux/usb/composite.h | 6 +++++ 2 files changed, 54 insertions(+), 2 deletions(-) diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c index 3b210de..11944bd 100644 --- a/drivers/usb/gadget/composite.c +++ b/drivers/usb/gadget/composite.c @@ -75,6 +75,33 @@ static char composite_manufacturer[50]; /*-------------------------------------------------------------------------*/ +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 @@ -92,15 +119,30 @@ static char composite_manufacturer[50]; int 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); @@ -126,7 +168,7 @@ int 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; } @@ -1325,6 +1367,10 @@ int usb_composite_probe(struct usb_composite_driver *driver, composite = driver; composite_gadget_bind = bind; + driver->class = class_create(THIS_MODULE, "usb_composite"); + if (IS_ERR(driver->class)) + return PTR_ERR(driver->class); + return usb_gadget_probe_driver(&composite_driver, composite_bind); } diff --git a/include/linux/usb/composite.h b/include/linux/usb/composite.h index 8f5a89f..a521e8c 100644 --- a/include/linux/usb/composite.h +++ b/include/linux/usb/composite.h @@ -137,6 +137,7 @@ struct usb_function { /* internals */ struct list_head list; DECLARE_BITMAP(endpoints, 32); + struct device *dev; }; int usb_add_function(struct usb_configuration *, struct usb_function *); @@ -282,6 +283,9 @@ struct usb_composite_driver { struct usb_gadget_strings **strings; unsigned needs_serial:1; + struct class *class; + atomic_t function_count; + int (*unbind)(struct usb_composite_dev *); void (*disconnect)(struct usb_composite_dev *); @@ -289,6 +293,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_probe(struct usb_composite_driver *driver, -- 2.7.4