driver core: Introduce device_create_groups
authorGuenter Roeck <linux@roeck-us.net>
Sun, 14 Jul 2013 23:05:57 +0000 (16:05 -0700)
committerBen Hutchings <ben@decadent.org.uk>
Fri, 20 Feb 2015 00:49:37 +0000 (00:49 +0000)
commit 39ef311204941ddd01ea2950d6220c8ccc710d15 upstream.

device_create_groups lets callers create devices as well as associated
sysfs attributes with a single call. This avoids race conditions seen
if sysfs attributes on new devices are created later.

[fixed up comment block placement and add checks for printk buffer
formats - gregkh]

Signed-off-by: Guenter Roeck <linux@roeck-us.net>
Cc: Jean Delvare <khali@linux-fr.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
[bwh: Backported to 3.2: adjust context]
Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
drivers/base/core.c
include/linux/device.h

index 919daa7..81e0e87 100644 (file)
@@ -1417,34 +1417,11 @@ static void device_create_release(struct device *dev)
        kfree(dev);
 }
 
        kfree(dev);
 }
 
-/**
- * device_create_vargs - creates a device and registers it with sysfs
- * @class: pointer to the struct class that this device should be registered to
- * @parent: pointer to the parent struct device of this new device, if any
- * @devt: the dev_t for the char device to be added
- * @drvdata: the data to be added to the device for callbacks
- * @fmt: string for the device's name
- * @args: va_list for the device's name
- *
- * This function can be used by char device classes.  A struct device
- * will be created in sysfs, registered to the specified class.
- *
- * A "dev" file will be created, showing the dev_t for the device, if
- * the dev_t is not 0,0.
- * If a pointer to a parent struct device is passed in, the newly created
- * struct device will be a child of that device in sysfs.
- * The pointer to the struct device will be returned from the call.
- * Any further sysfs files that might be required can be created using this
- * pointer.
- *
- * Returns &struct device pointer on success, or ERR_PTR() on error.
- *
- * Note: the struct class passed to this function must have previously
- * been created with a call to class_create().
- */
-struct device *device_create_vargs(struct class *class, struct device *parent,
-                                  dev_t devt, void *drvdata, const char *fmt,
-                                  va_list args)
+static struct device *
+device_create_groups_vargs(struct class *class, struct device *parent,
+                          dev_t devt, void *drvdata,
+                          const struct attribute_group **groups,
+                          const char *fmt, va_list args)
 {
        struct device *dev = NULL;
        int retval = -ENODEV;
 {
        struct device *dev = NULL;
        int retval = -ENODEV;
@@ -1461,6 +1438,7 @@ struct device *device_create_vargs(struct class *class, struct device *parent,
        dev->devt = devt;
        dev->class = class;
        dev->parent = parent;
        dev->devt = devt;
        dev->class = class;
        dev->parent = parent;
+       dev->groups = groups;
        dev->release = device_create_release;
        dev_set_drvdata(dev, drvdata);
 
        dev->release = device_create_release;
        dev_set_drvdata(dev, drvdata);
 
@@ -1478,6 +1456,39 @@ error:
        put_device(dev);
        return ERR_PTR(retval);
 }
        put_device(dev);
        return ERR_PTR(retval);
 }
+
+/**
+ * device_create_vargs - creates a device and registers it with sysfs
+ * @class: pointer to the struct class that this device should be registered to
+ * @parent: pointer to the parent struct device of this new device, if any
+ * @devt: the dev_t for the char device to be added
+ * @drvdata: the data to be added to the device for callbacks
+ * @fmt: string for the device's name
+ * @args: va_list for the device's name
+ *
+ * This function can be used by char device classes.  A struct device
+ * will be created in sysfs, registered to the specified class.
+ *
+ * A "dev" file will be created, showing the dev_t for the device, if
+ * the dev_t is not 0,0.
+ * If a pointer to a parent struct device is passed in, the newly created
+ * struct device will be a child of that device in sysfs.
+ * The pointer to the struct device will be returned from the call.
+ * Any further sysfs files that might be required can be created using this
+ * pointer.
+ *
+ * Returns &struct device pointer on success, or ERR_PTR() on error.
+ *
+ * Note: the struct class passed to this function must have previously
+ * been created with a call to class_create().
+ */
+struct device *device_create_vargs(struct class *class, struct device *parent,
+                                  dev_t devt, void *drvdata, const char *fmt,
+                                  va_list args)
+{
+       return device_create_groups_vargs(class, parent, devt, drvdata, NULL,
+                                         fmt, args);
+}
 EXPORT_SYMBOL_GPL(device_create_vargs);
 
 /**
 EXPORT_SYMBOL_GPL(device_create_vargs);
 
 /**
@@ -1517,6 +1528,50 @@ struct device *device_create(struct class *class, struct device *parent,
 }
 EXPORT_SYMBOL_GPL(device_create);
 
 }
 EXPORT_SYMBOL_GPL(device_create);
 
+/**
+ * device_create_with_groups - creates a device and registers it with sysfs
+ * @class: pointer to the struct class that this device should be registered to
+ * @parent: pointer to the parent struct device of this new device, if any
+ * @devt: the dev_t for the char device to be added
+ * @drvdata: the data to be added to the device for callbacks
+ * @groups: NULL-terminated list of attribute groups to be created
+ * @fmt: string for the device's name
+ *
+ * This function can be used by char device classes.  A struct device
+ * will be created in sysfs, registered to the specified class.
+ * Additional attributes specified in the groups parameter will also
+ * be created automatically.
+ *
+ * A "dev" file will be created, showing the dev_t for the device, if
+ * the dev_t is not 0,0.
+ * If a pointer to a parent struct device is passed in, the newly created
+ * struct device will be a child of that device in sysfs.
+ * The pointer to the struct device will be returned from the call.
+ * Any further sysfs files that might be required can be created using this
+ * pointer.
+ *
+ * Returns &struct device pointer on success, or ERR_PTR() on error.
+ *
+ * Note: the struct class passed to this function must have previously
+ * been created with a call to class_create().
+ */
+struct device *device_create_with_groups(struct class *class,
+                                        struct device *parent, dev_t devt,
+                                        void *drvdata,
+                                        const struct attribute_group **groups,
+                                        const char *fmt, ...)
+{
+       va_list vargs;
+       struct device *dev;
+
+       va_start(vargs, fmt);
+       dev = device_create_groups_vargs(class, parent, devt, drvdata, groups,
+                                        fmt, vargs);
+       va_end(vargs);
+       return dev;
+}
+EXPORT_SYMBOL_GPL(device_create_with_groups);
+
 static int __match_devt(struct device *dev, void *data)
 {
        dev_t *devt = data;
 static int __match_devt(struct device *dev, void *data)
 {
        dev_t *devt = data;
index 3136ede..a31c5d0 100644 (file)
@@ -767,6 +767,11 @@ extern __printf(5, 6)
 struct device *device_create(struct class *cls, struct device *parent,
                             dev_t devt, void *drvdata,
                             const char *fmt, ...);
 struct device *device_create(struct class *cls, struct device *parent,
                             dev_t devt, void *drvdata,
                             const char *fmt, ...);
+extern __printf(6, 7)
+struct device *device_create_with_groups(struct class *cls,
+                            struct device *parent, dev_t devt, void *drvdata,
+                            const struct attribute_group **groups,
+                            const char *fmt, ...);
 extern void device_destroy(struct class *cls, dev_t devt);
 
 /*
 extern void device_destroy(struct class *cls, dev_t devt);
 
 /*