]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/base/core.c
Driver core: allow to delay the uevent at device creation time
[linux-2.6-omap-h63xx.git] / drivers / base / core.c
index c60114dbe5f5d7663770cfbc794a65f666f6f787..e13614241c9eeed951141d285bb5d8e041ded23c 100644 (file)
@@ -95,6 +95,8 @@ static void device_release(struct kobject * kobj)
 
        if (dev->release)
                dev->release(dev);
+       else if (dev->type && dev->type->release)
+               dev->type->release(dev);
        else if (dev->class && dev->class->dev_release)
                dev->class->dev_release(dev);
        else {
@@ -154,25 +156,47 @@ static int dev_uevent(struct kset *kset, struct kobject *kobj, char **envp,
                               "MINOR=%u", MINOR(dev->devt));
        }
 
-#ifdef CONFIG_SYSFS_DEPRECATED
-       /* add bus name (same as SUBSYSTEM, deprecated) */
-       if (dev->bus)
-               add_uevent_var(envp, num_envp, &i,
-                              buffer, buffer_size, &length,
-                              "PHYSDEVBUS=%s", dev->bus->name);
-#endif
-
-       /* add driver name (PHYSDEV* values are deprecated)*/
-       if (dev->driver) {
+       if (dev->driver)
                add_uevent_var(envp, num_envp, &i,
                               buffer, buffer_size, &length,
                               "DRIVER=%s", dev->driver->name);
+
 #ifdef CONFIG_SYSFS_DEPRECATED
+       if (dev->class) {
+               struct device *parent = dev->parent;
+
+               /* find first bus device in parent chain */
+               while (parent && !parent->bus)
+                       parent = parent->parent;
+               if (parent && parent->bus) {
+                       const char *path;
+
+                       path = kobject_get_path(&parent->kobj, GFP_KERNEL);
+                       add_uevent_var(envp, num_envp, &i,
+                                      buffer, buffer_size, &length,
+                                      "PHYSDEVPATH=%s", path);
+                       kfree(path);
+
+                       add_uevent_var(envp, num_envp, &i,
+                                      buffer, buffer_size, &length,
+                                      "PHYSDEVBUS=%s", parent->bus->name);
+
+                       if (parent->driver)
+                               add_uevent_var(envp, num_envp, &i,
+                                              buffer, buffer_size, &length,
+                                              "PHYSDEVDRIVER=%s", parent->driver->name);
+               }
+       } else if (dev->bus) {
                add_uevent_var(envp, num_envp, &i,
                               buffer, buffer_size, &length,
-                              "PHYSDEVDRIVER=%s", dev->driver->name);
-#endif
+                              "PHYSDEVBUS=%s", dev->bus->name);
+
+               if (dev->driver)
+                       add_uevent_var(envp, num_envp, &i,
+                                      buffer, buffer_size, &length,
+                                      "PHYSDEVDRIVER=%s", dev->driver->name);
        }
+#endif
 
        /* terminate, set to next free slot, shrink available space */
        envp[i] = NULL;
@@ -184,19 +208,25 @@ static int dev_uevent(struct kset *kset, struct kobject *kobj, char **envp,
        if (dev->bus && dev->bus->uevent) {
                /* have the bus specific function add its stuff */
                retval = dev->bus->uevent(dev, envp, num_envp, buffer, buffer_size);
-                       if (retval) {
-                       pr_debug ("%s - uevent() returned %d\n",
+               if (retval)
+                       pr_debug ("%s: bus uevent() returned %d\n",
                                  __FUNCTION__, retval);
-               }
        }
 
        if (dev->class && dev->class->dev_uevent) {
                /* have the class specific function add its stuff */
                retval = dev->class->dev_uevent(dev, envp, num_envp, buffer, buffer_size);
-                       if (retval) {
-                               pr_debug("%s - dev_uevent() returned %d\n",
-                                        __FUNCTION__, retval);
-               }
+               if (retval)
+                       pr_debug("%s: class uevent() returned %d\n",
+                                __FUNCTION__, retval);
+       }
+
+       if (dev->type && dev->type->uevent) {
+               /* have the device type specific fuction add its stuff */
+               retval = dev->type->uevent(dev, envp, num_envp, buffer, buffer_size);
+               if (retval)
+                       pr_debug("%s: dev_type uevent() returned %d\n",
+                                __FUNCTION__, retval);
        }
 
        return retval;
@@ -247,37 +277,50 @@ static void device_remove_groups(struct device *dev)
 static int device_add_attrs(struct device *dev)
 {
        struct class *class = dev->class;
+       struct device_type *type = dev->type;
        int error = 0;
        int i;
 
-       if (!class)
-               return 0;
-
-       if (class->dev_attrs) {
+       if (class && class->dev_attrs) {
                for (i = 0; attr_name(class->dev_attrs[i]); i++) {
                        error = device_create_file(dev, &class->dev_attrs[i]);
                        if (error)
                                break;
                }
+               if (error)
+                       while (--i >= 0)
+                               device_remove_file(dev, &class->dev_attrs[i]);
        }
-       if (error)
-               while (--i >= 0)
-                       device_remove_file(dev, &class->dev_attrs[i]);
+
+       if (type && type->attrs) {
+               for (i = 0; attr_name(type->attrs[i]); i++) {
+                       error = device_create_file(dev, &type->attrs[i]);
+                       if (error)
+                               break;
+               }
+               if (error)
+                       while (--i >= 0)
+                               device_remove_file(dev, &type->attrs[i]);
+       }
+
        return error;
 }
 
 static void device_remove_attrs(struct device *dev)
 {
        struct class *class = dev->class;
+       struct device_type *type = dev->type;
        int i;
 
-       if (!class)
-               return;
-
-       if (class->dev_attrs) {
+       if (class && class->dev_attrs) {
                for (i = 0; attr_name(class->dev_attrs[i]); i++)
                        device_remove_file(dev, &class->dev_attrs[i]);
        }
+
+       if (type && type->attrs) {
+               for (i = 0; attr_name(type->attrs[i]); i++)
+                       device_remove_file(dev, &type->attrs[i]);
+       }
 }
 
 
@@ -527,9 +570,13 @@ int device_add(struct device *dev)
                                          &dev->kobj, dev->bus_id);
 #ifdef CONFIG_SYSFS_DEPRECATED
                if (parent) {
-                       sysfs_create_link(&dev->kobj, &dev->parent->kobj, "device");
-                       class_name = make_class_name(dev->class->name, &dev->kobj);
-                       sysfs_create_link(&dev->parent->kobj, &dev->kobj, class_name);
+                       sysfs_create_link(&dev->kobj, &dev->parent->kobj,
+                                                       "device");
+                       class_name = make_class_name(dev->class->name,
+                                                       &dev->kobj);
+                       if (class_name)
+                               sysfs_create_link(&dev->parent->kobj,
+                                                 &dev->kobj, class_name);
                }
 #endif
        }
@@ -542,7 +589,8 @@ int device_add(struct device *dev)
                goto PMError;
        if ((error = bus_add_device(dev)))
                goto BusError;
-       kobject_uevent(&dev->kobj, KOBJ_ADD);
+       if (!dev->uevent_suppress)
+               kobject_uevent(&dev->kobj, KOBJ_ADD);
        if ((error = bus_attach_device(dev)))
                goto AttachError;
        if (parent)
@@ -672,7 +720,9 @@ void device_del(struct device * dev)
                if (parent) {
                        char *class_name = make_class_name(dev->class->name,
                                                           &dev->kobj);
-                       sysfs_remove_link(&dev->parent->kobj, class_name);
+                       if (class_name)
+                               sysfs_remove_link(&dev->parent->kobj,
+                                                 class_name);
                        kfree(class_name);
                        sysfs_remove_link(&dev->kobj, "device");
                }
@@ -975,8 +1025,7 @@ static int device_move_class_links(struct device *dev,
 
        class_name = make_class_name(dev->class->name, &dev->kobj);
        if (!class_name) {
-               error = PTR_ERR(class_name);
-               class_name = NULL;
+               error = -ENOMEM;
                goto out;
        }
        if (old_parent) {