]> err.no Git - linux-2.6/blobdiff - drivers/base/class.c
[netdrvr] natsemi: minor cleanups
[linux-2.6] / drivers / base / class.c
index db65fd0babe937f4ba88682293db9a2bae5907d2..9aa1274602625fa6beb6c463838d77a770800919 100644 (file)
@@ -91,14 +91,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 +142,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);
@@ -178,7 +179,7 @@ static void class_device_create_release(struct class_device *class_dev)
 }
 
 /* needed to allow these devices to have parent class devices */
-static int class_device_create_hotplug(struct class_device *class_dev,
+static int class_device_create_uevent(struct class_device *class_dev,
                                       char **envp, int num_envp,
                                       char *buffer, int buffer_size)
 {
@@ -331,7 +332,7 @@ static struct kobj_type ktype_class_device = {
        .release        = class_dev_release,
 };
 
-static int class_hotplug_filter(struct kset *kset, struct kobject *kobj)
+static int class_uevent_filter(struct kset *kset, struct kobject *kobj)
 {
        struct kobj_type *ktype = get_ktype(kobj);
 
@@ -343,14 +344,14 @@ static int class_hotplug_filter(struct kset *kset, struct kobject *kobj)
        return 0;
 }
 
-static const char *class_hotplug_name(struct kset *kset, struct kobject *kobj)
+static const char *class_uevent_name(struct kset *kset, struct kobject *kobj)
 {
        struct class_device *class_dev = to_class_dev(kobj);
 
        return class_dev->class->name;
 }
 
-static int class_hotplug(struct kset *kset, struct kobject *kobj, char **envp,
+static int class_uevent(struct kset *kset, struct kobject *kobj, char **envp,
                         int num_envp, char *buffer, int buffer_size)
 {
        struct class_device *class_dev = to_class_dev(kobj);
@@ -365,29 +366,29 @@ static int class_hotplug(struct kset *kset, struct kobject *kobj, char **envp,
                struct device *dev = class_dev->dev;
                char *path = kobject_get_path(&dev->kobj, GFP_KERNEL);
 
-               add_hotplug_env_var(envp, num_envp, &i, buffer, buffer_size,
-                                   &length, "PHYSDEVPATH=%s", path);
+               add_uevent_var(envp, num_envp, &i, buffer, buffer_size,
+                              &length, "PHYSDEVPATH=%s", path);
                kfree(path);
 
                if (dev->bus)
-                       add_hotplug_env_var(envp, num_envp, &i,
-                                           buffer, buffer_size, &length,
-                                           "PHYSDEVBUS=%s", dev->bus->name);
+                       add_uevent_var(envp, num_envp, &i,
+                                      buffer, buffer_size, &length,
+                                      "PHYSDEVBUS=%s", dev->bus->name);
 
                if (dev->driver)
-                       add_hotplug_env_var(envp, num_envp, &i,
-                                           buffer, buffer_size, &length,
-                                           "PHYSDEVDRIVER=%s", dev->driver->name);
+                       add_uevent_var(envp, num_envp, &i,
+                                      buffer, buffer_size, &length,
+                                      "PHYSDEVDRIVER=%s", dev->driver->name);
        }
 
        if (MAJOR(class_dev->devt)) {
-               add_hotplug_env_var(envp, num_envp, &i,
-                                   buffer, buffer_size, &length,
-                                   "MAJOR=%u", MAJOR(class_dev->devt));
+               add_uevent_var(envp, num_envp, &i,
+                              buffer, buffer_size, &length,
+                              "MAJOR=%u", MAJOR(class_dev->devt));
 
-               add_hotplug_env_var(envp, num_envp, &i,
-                                   buffer, buffer_size, &length,
-                                   "MINOR=%u", MINOR(class_dev->devt));
+               add_uevent_var(envp, num_envp, &i,
+                              buffer, buffer_size, &length,
+                              "MINOR=%u", MINOR(class_dev->devt));
        }
 
        /* terminate, set to next free slot, shrink available space */
@@ -397,30 +398,30 @@ static int class_hotplug(struct kset *kset, struct kobject *kobj, char **envp,
        buffer = &buffer[length];
        buffer_size -= length;
 
-       if (class_dev->hotplug) {
+       if (class_dev->uevent) {
                /* have the class device specific function add its stuff */
-               retval = class_dev->hotplug(class_dev, envp, num_envp,
+               retval = class_dev->uevent(class_dev, envp, num_envp,
                                            buffer, buffer_size);
                if (retval)
-                       pr_debug("class_dev->hotplug() returned %d\n", retval);
-       } else if (class_dev->class->hotplug) {
+                       pr_debug("class_dev->uevent() returned %d\n", retval);
+       } else if (class_dev->class->uevent) {
                /* have the class specific function add its stuff */
-               retval = class_dev->class->hotplug(class_dev, envp, num_envp,
+               retval = class_dev->class->uevent(class_dev, envp, num_envp,
                                                   buffer, buffer_size);
                if (retval)
-                       pr_debug("class->hotplug() returned %d\n", retval);
+                       pr_debug("class->uevent() returned %d\n", retval);
        }
 
        return retval;
 }
 
-static struct kset_hotplug_ops class_hotplug_ops = {
-       .filter =       class_hotplug_filter,
-       .name =         class_hotplug_name,
-       .hotplug =      class_hotplug,
+static struct kset_uevent_ops class_uevent_ops = {
+       .filter =       class_uevent_filter,
+       .name =         class_uevent_name,
+       .uevent =       class_uevent,
 };
 
-static decl_subsys(class_obj, &ktype_class_device, &class_hotplug_ops);
+static decl_subsys(class_obj, &ktype_class_device, &class_uevent_ops);
 
 
 static int class_device_add_attrs(struct class_device * cd)
@@ -456,6 +457,35 @@ static void class_device_remove_attrs(struct class_device * cd)
        }
 }
 
+static int class_device_add_groups(struct class_device * cd)
+{
+       int i;
+       int error = 0;
+
+       if (cd->groups) {
+               for (i = 0; cd->groups[i]; i++) {
+                       error = sysfs_create_group(&cd->kobj, cd->groups[i]);
+                       if (error) {
+                               while (--i >= 0)
+                                       sysfs_remove_group(&cd->kobj, cd->groups[i]);
+                               goto out;
+                       }
+               }
+       }
+out:
+       return error;
+}
+
+static void class_device_remove_groups(struct class_device * cd)
+{
+       int i;
+       if (cd->groups) {
+               for (i = 0; cd->groups[i]; i++) {
+                       sysfs_remove_group(&cd->kobj, cd->groups[i]);
+               }
+       }
+}
+
 static ssize_t show_dev(struct class_device *class_dev, char *buf)
 {
        return print_dev_t(buf, class_dev->devt);
@@ -464,7 +494,7 @@ static ssize_t show_dev(struct class_device *class_dev, char *buf)
 static ssize_t store_uevent(struct class_device *class_dev,
                            const char *buf, size_t count)
 {
-       kobject_hotplug(&class_dev->kobj, KOBJ_ADD);
+       kobject_uevent(&class_dev->kobj, KOBJ_ADD);
        return count;
 }
 
@@ -475,22 +505,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)
@@ -506,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
@@ -525,57 +558,92 @@ 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;
        }
 
-       kobject_hotplug(&class_dev->kobj, KOBJ_ADD);
+       error = class_device_add_groups(class_dev);
+       if (error)
+               goto out8;
+
+       kobject_uevent(&class_dev->kobj, KOBJ_ADD);
 
        /* notify any interfaces this device is now here */
-       if (parent_class) {
-               down(&parent_class->sem);
-               list_add_tail(&class_dev->node, &parent_class->children);
-               list_for_each_entry(class_intf, &parent_class->interfaces, node)
-                       if (class_intf->add)
-                               class_intf->add(class_dev, class_intf);
-               up(&parent_class->sem);
+       down(&parent_class->sem);
+       list_add_tail(&class_dev->node, &parent_class->children);
+       list_for_each_entry(class_intf, &parent_class->interfaces, node) {
+               if (class_intf->add)
+                       class_intf->add(class_dev, class_intf);
        }
+       up(&parent_class->sem);
+
+       goto out1;
 
- register_done:
-       if (error) {
-               class_put(parent_class);
+ 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;
@@ -632,7 +700,7 @@ struct class_device *class_device_create(struct class *cls,
        class_dev->class = cls;
        class_dev->parent = parent;
        class_dev->release = class_device_create_release;
-       class_dev->hotplug = class_device_create_hotplug;
+       class_dev->uevent = class_device_create_uevent;
 
        va_start(args, fmt);
        vsnprintf(class_dev->class_id, BUS_ID_SIZE, fmt, args);
@@ -665,16 +733,19 @@ 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);
        class_device_remove_attrs(class_dev);
+       class_device_remove_groups(class_dev);
 
-       kobject_hotplug(&class_dev->kobj, KOBJ_REMOVE);
+       kobject_uevent(&class_dev->kobj, KOBJ_REMOVE);
        kobject_del(&class_dev->kobj);
 
        class_device_put(parent_device);
@@ -729,14 +800,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);
@@ -827,8 +900,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);