[PATCH] drivers/base/*: use kzalloc instead of kmalloc+memset
[powerpc.git] / drivers / base / class.c
index a3b006b..3b112e3 100644 (file)
@@ -173,17 +173,27 @@ static void class_device_create_release(struct class_device *class_dev)
        kfree(class_dev);
 }
 
+/**
+ * class_create - create a struct class structure
+ * @owner: pointer to the module that is to "own" this struct class
+ * @name: pointer to a string for the name of this class.
+ *
+ * This is used to create a struct class pointer that can then be used
+ * in calls to class_device_create().
+ *
+ * Note, the pointer created here is to be destroyed when finished by
+ * making a call to class_destroy().
+ */
 struct class *class_create(struct module *owner, char *name)
 {
        struct class *cls;
        int retval;
 
-       cls = kmalloc(sizeof(struct class), GFP_KERNEL);
+       cls = kzalloc(sizeof(*cls), GFP_KERNEL);
        if (!cls) {
                retval = -ENOMEM;
                goto error;
        }
-       memset(cls, 0x00, sizeof(struct class));
 
        cls->name = name;
        cls->owner = owner;
@@ -201,6 +211,13 @@ error:
        return ERR_PTR(retval);
 }
 
+/**
+ * class_destroy - destroys a struct class structure
+ * @cs: pointer to the struct class that is to be destroyed
+ *
+ * Note, the pointer to be destroyed must have been created with a call
+ * to class_create().
+ */
 void class_destroy(struct class *cls)
 {
        if ((cls == NULL) || (IS_ERR(cls)))
@@ -281,6 +298,9 @@ static void class_dev_release(struct kobject * kobj)
 
        pr_debug("device class '%s': release.\n", cd->class_id);
 
+       kfree(cd->devt_attr);
+       cd->devt_attr = NULL;
+
        if (cls->release)
                cls->release(cd);
        else {
@@ -429,10 +449,29 @@ void class_device_initialize(struct class_device *class_dev)
        INIT_LIST_HEAD(&class_dev->node);
 }
 
+static char *make_class_name(struct class_device *class_dev)
+{
+       char *name;
+       int size;
+
+       size = strlen(class_dev->class->name) +
+               strlen(kobject_name(&class_dev->kobj)) + 2;
+
+       name = kmalloc(size, GFP_KERNEL);
+       if (!name)
+               return ERR_PTR(-ENOMEM);
+
+       strcpy(name, class_dev->class->name);
+       strcat(name, ":");
+       strcat(name, kobject_name(&class_dev->kobj));
+       return name;
+}
+
 int class_device_add(struct class_device *class_dev)
 {
        struct class * parent = NULL;
        struct class_interface * class_intf;
+       char *class_name = NULL;
        int error;
 
        class_dev = class_device_get(class_dev);
@@ -460,13 +499,13 @@ int class_device_add(struct class_device *class_dev)
        /* add the needed attributes to this device */
        if (MAJOR(class_dev->devt)) {
                struct class_device_attribute *attr;
-               attr = kmalloc(sizeof(*attr), GFP_KERNEL);
+               attr = kzalloc(sizeof(*attr), GFP_KERNEL);
                if (!attr) {
                        error = -ENOMEM;
                        kobject_del(&class_dev->kobj);
                        goto register_done;
                }
-               memset(attr, sizeof(*attr), 0x00);
+
                attr->attr.name = "dev";
                attr->attr.mode = S_IRUGO;
                attr->attr.owner = parent->owner;
@@ -477,9 +516,13 @@ int class_device_add(struct class_device *class_dev)
        }
 
        class_device_add_attrs(class_dev);
-       if (class_dev->dev)
+       if (class_dev->dev) {
+               class_name = make_class_name(class_dev);
                sysfs_create_link(&class_dev->kobj,
                                  &class_dev->dev->kobj, "device");
+               sysfs_create_link(&class_dev->dev->kobj, &class_dev->kobj,
+                                 class_name);
+       }
 
        /* notify any interfaces this device is now here */
        if (parent) {
@@ -496,6 +539,7 @@ int class_device_add(struct class_device *class_dev)
        if (error && parent)
                class_put(parent);
        class_device_put(class_dev);
+       kfree(class_name);
        return error;
 }
 
@@ -505,6 +549,23 @@ int class_device_register(struct class_device *class_dev)
        return class_device_add(class_dev);
 }
 
+/**
+ * class_device_create - creates a class device and registers it with sysfs
+ * @cs: pointer to the struct class that this device should be registered to.
+ * @dev: the dev_t for the char device to be added.
+ * @device: a pointer to a struct device that is assiociated with this class device.
+ * @fmt: string for the class device's name
+ *
+ * This function can be used by char device classes.  A struct
+ * class_device will be created in sysfs, registered to the specified
+ * class.  A "dev" file will be created, showing the dev_t for the
+ * device.  The pointer to the struct class_device will be returned from
+ * the call.  Any further sysfs files that might be required can be
+ * created using this pointer.
+ *
+ * Note: the struct class passed to this function must have previously
+ * been created with a call to class_create().
+ */
 struct class_device *class_device_create(struct class *cls, dev_t devt,
                                         struct device *device, char *fmt, ...)
 {
@@ -515,12 +576,11 @@ struct class_device *class_device_create(struct class *cls, dev_t devt,
        if (cls == NULL || IS_ERR(cls))
                goto error;
 
-       class_dev = kmalloc(sizeof(struct class_device), GFP_KERNEL);
+       class_dev = kzalloc(sizeof(*class_dev), GFP_KERNEL);
        if (!class_dev) {
                retval = -ENOMEM;
                goto error;
        }
-       memset(class_dev, 0x00, sizeof(struct class_device));
 
        class_dev->devt = devt;
        class_dev->dev = device;
@@ -544,6 +604,7 @@ void class_device_del(struct class_device *class_dev)
 {
        struct class * parent = class_dev->class;
        struct class_interface * class_intf;
+       char *class_name = NULL;
 
        if (parent) {
                down(&parent->sem);
@@ -554,13 +615,13 @@ void class_device_del(struct class_device *class_dev)
                up(&parent->sem);
        }
 
-       if (class_dev->dev)
+       if (class_dev->dev) {
+               class_name = make_class_name(class_dev);
                sysfs_remove_link(&class_dev->kobj, "device");
-       if (class_dev->devt_attr) {
-               class_device_remove_file(class_dev, class_dev->devt_attr);
-               kfree(class_dev->devt_attr);
-               class_dev->devt_attr = NULL;
+               sysfs_remove_link(&class_dev->dev->kobj, class_name);
        }
+       if (class_dev->devt_attr)
+               class_device_remove_file(class_dev, class_dev->devt_attr);
        class_device_remove_attrs(class_dev);
 
        kobject_hotplug(&class_dev->kobj, KOBJ_REMOVE);
@@ -568,6 +629,7 @@ void class_device_del(struct class_device *class_dev)
 
        if (parent)
                class_put(parent);
+       kfree(class_name);
 }
 
 void class_device_unregister(struct class_device *class_dev)
@@ -578,6 +640,14 @@ void class_device_unregister(struct class_device *class_dev)
        class_device_put(class_dev);
 }
 
+/**
+ * class_device_destroy - removes a class device that was created with class_device_create()
+ * @cls: the pointer to the struct class that this device was registered * with.
+ * @dev: the dev_t of the device that was previously registered.
+ *
+ * This call unregisters and cleans up a class device that was created with a
+ * call to class_device_create()
+ */
 void class_device_destroy(struct class *cls, dev_t devt)
 {
        struct class_device *class_dev = NULL;