|
@@ -535,18 +535,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 +558,56 @@ 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 */
|
|
|
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);
|
|
|
+ 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 +620,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;
|