USB: composite: Add class driver for enabling and disabling USB functions.
authorMike Lockwood <lockwood@android.com>
Sun, 7 Feb 2010 02:53:51 +0000 (21:53 -0500)
committermgross <mark.gross@intel.com>
Wed, 9 Nov 2011 20:02:47 +0000 (12:02 -0800)
Signed-off-by: Mike Lockwood <lockwood@android.com>
drivers/usb/gadget/composite.c
include/linux/usb/composite.h

index 3b210de..11944bd 100644 (file)
@@ -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);
 }
 
index 8f5a89f..a521e8c 100644 (file)
@@ -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,