summaryrefslogtreecommitdiff
path: root/drivers/base/class.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/base/class.c')
-rw-r--r--drivers/base/class.c113
1 files changed, 76 insertions, 37 deletions
diff --git a/drivers/base/class.c b/drivers/base/class.c
index b1ea4df85c7d..de8908320f23 100644
--- a/drivers/base/class.c
+++ b/drivers/base/class.c
@@ -10,7 +10,6 @@
*
*/
-#include <linux/config.h>
#include <linux/device.h>
#include <linux/module.h>
#include <linux/init.h>
@@ -91,14 +90,14 @@ void class_remove_file(struct class * cls, const struct class_attribute * attr)
sysfs_remove_file(&cls->subsys.kset.kobj, &attr->attr);
}
-struct class * class_get(struct class * cls)
+static struct class *class_get(struct class *cls)
{
if (cls)
return container_of(subsys_get(&cls->subsys), struct class, subsys);
return NULL;
}
-void class_put(struct class * cls)
+static void class_put(struct class * cls)
{
if (cls)
subsys_put(&cls->subsys);
@@ -142,6 +141,7 @@ int class_register(struct class * cls)
pr_debug("device class '%s': registering\n", cls->name);
INIT_LIST_HEAD(&cls->children);
+ INIT_LIST_HEAD(&cls->devices);
INIT_LIST_HEAD(&cls->interfaces);
init_MUTEX(&cls->sem);
error = kobject_set_name(&cls->subsys.kset.kobj, "%s", cls->name);
@@ -504,22 +504,21 @@ 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 *make_class_name(const char *name, struct kobject *kobj)
{
- char *name;
+ char *class_name;
int size;
- size = strlen(class_dev->class->name) +
- strlen(kobject_name(&class_dev->kobj)) + 2;
+ size = strlen(name) + strlen(kobject_name(kobj)) + 2;
- name = kmalloc(size, GFP_KERNEL);
- if (!name)
+ class_name = kmalloc(size, GFP_KERNEL);
+ if (!class_name)
return ERR_PTR(-ENOMEM);
- strcpy(name, class_dev->class->name);
- strcat(name, ":");
- strcat(name, kobject_name(&class_dev->kobj));
- return name;
+ strcpy(class_name, name);
+ strcat(class_name, ":");
+ strcat(class_name, kobject_name(kobj));
+ return class_name;
}
int class_device_add(struct class_device *class_dev)
@@ -535,18 +534,22 @@ int class_device_add(struct class_device *class_dev)
return -EINVAL;
if (!strlen(class_dev->class_id))
- goto register_done;
+ goto out1;
parent_class = class_get(class_dev->class);
if (!parent_class)
- goto register_done;
+ goto out1;
+
parent_class_dev = class_device_get(class_dev->parent);
pr_debug("CLASS: registering class device: ID = '%s'\n",
class_dev->class_id);
/* first, register with generic layer. */
- kobject_set_name(&class_dev->kobj, "%s", class_dev->class_id);
+ error = kobject_set_name(&class_dev->kobj, "%s", class_dev->class_id);
+ if (error)
+ goto out2;
+
if (parent_class_dev)
class_dev->kobj.parent = &parent_class_dev->kobj;
else
@@ -554,41 +557,58 @@ int class_device_add(struct class_device *class_dev)
error = kobject_add(&class_dev->kobj);
if (error)
- goto register_done;
+ goto out2;
/* add the needed attributes to this device */
+ sysfs_create_link(&class_dev->kobj, &parent_class->subsys.kset.kobj, "subsystem");
class_dev->uevent_attr.attr.name = "uevent";
class_dev->uevent_attr.attr.mode = S_IWUSR;
class_dev->uevent_attr.attr.owner = parent_class->owner;
class_dev->uevent_attr.store = store_uevent;
- class_device_create_file(class_dev, &class_dev->uevent_attr);
+ error = class_device_create_file(class_dev, &class_dev->uevent_attr);
+ if (error)
+ goto out3;
if (MAJOR(class_dev->devt)) {
struct class_device_attribute *attr;
attr = kzalloc(sizeof(*attr), GFP_KERNEL);
if (!attr) {
error = -ENOMEM;
- kobject_del(&class_dev->kobj);
- goto register_done;
+ goto out4;
}
attr->attr.name = "dev";
attr->attr.mode = S_IRUGO;
attr->attr.owner = parent_class->owner;
attr->show = show_dev;
- class_device_create_file(class_dev, attr);
+ error = class_device_create_file(class_dev, attr);
+ if (error) {
+ kfree(attr);
+ goto out4;
+ }
+
class_dev->devt_attr = attr;
}
- class_device_add_attrs(class_dev);
+ error = class_device_add_attrs(class_dev);
+ if (error)
+ goto out5;
+
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);
+ class_name = make_class_name(class_dev->class->name,
+ &class_dev->kobj);
+ error = sysfs_create_link(&class_dev->kobj,
+ &class_dev->dev->kobj, "device");
+ if (error)
+ goto out6;
+ error = sysfs_create_link(&class_dev->dev->kobj, &class_dev->kobj,
+ class_name);
+ if (error)
+ goto out7;
}
- class_device_add_groups(class_dev);
+ error = class_device_add_groups(class_dev);
+ if (error)
+ goto out8;
kobject_uevent(&class_dev->kobj, KOBJ_ADD);
@@ -601,11 +621,28 @@ int class_device_add(struct class_device *class_dev)
}
up(&parent_class->sem);
- register_done:
- if (error) {
- class_put(parent_class);
+ goto out1;
+
+ out8:
+ if (class_dev->dev)
+ sysfs_remove_link(&class_dev->kobj, class_name);
+ out7:
+ if (class_dev->dev)
+ sysfs_remove_link(&class_dev->kobj, "device");
+ out6:
+ class_device_remove_attrs(class_dev);
+ out5:
+ if (class_dev->devt_attr)
+ class_device_remove_file(class_dev, class_dev->devt_attr);
+ out4:
+ class_device_remove_file(class_dev, &class_dev->uevent_attr);
+ out3:
+ kobject_del(&class_dev->kobj);
+ out2:
+ if(parent_class_dev)
class_device_put(parent_class_dev);
- }
+ class_put(parent_class);
+ out1:
class_device_put(class_dev);
kfree(class_name);
return error;
@@ -695,10 +732,12 @@ void class_device_del(struct class_device *class_dev)
}
if (class_dev->dev) {
- class_name = make_class_name(class_dev);
+ class_name = make_class_name(class_dev->class->name,
+ &class_dev->kobj);
sysfs_remove_link(&class_dev->kobj, "device");
sysfs_remove_link(&class_dev->dev->kobj, class_name);
}
+ sysfs_remove_link(&class_dev->kobj, "subsystem");
class_device_remove_file(class_dev, &class_dev->uevent_attr);
if (class_dev->devt_attr)
class_device_remove_file(class_dev, class_dev->devt_attr);
@@ -760,14 +799,16 @@ int class_device_rename(struct class_device *class_dev, char *new_name)
new_name);
if (class_dev->dev)
- old_class_name = make_class_name(class_dev);
+ old_class_name = make_class_name(class_dev->class->name,
+ &class_dev->kobj);
strlcpy(class_dev->class_id, new_name, KOBJ_NAME_LEN);
error = kobject_rename(&class_dev->kobj, new_name);
if (class_dev->dev) {
- new_class_name = make_class_name(class_dev);
+ new_class_name = make_class_name(class_dev->class->name,
+ &class_dev->kobj);
sysfs_create_link(&class_dev->dev->kobj, &class_dev->kobj,
new_class_name);
sysfs_remove_link(&class_dev->dev->kobj, old_class_name);
@@ -858,8 +899,6 @@ EXPORT_SYMBOL_GPL(class_create_file);
EXPORT_SYMBOL_GPL(class_remove_file);
EXPORT_SYMBOL_GPL(class_register);
EXPORT_SYMBOL_GPL(class_unregister);
-EXPORT_SYMBOL_GPL(class_get);
-EXPORT_SYMBOL_GPL(class_put);
EXPORT_SYMBOL_GPL(class_create);
EXPORT_SYMBOL_GPL(class_destroy);