Kobject: rename kobject_init_ng() to kobject_init()
[pandora-kernel.git] / drivers / base / core.c
index 2683eac..675a719 100644 (file)
@@ -18,7 +18,7 @@
 #include <linux/string.h>
 #include <linux/kdev_t.h>
 #include <linux/notifier.h>
-
+#include <linux/genhd.h>
 #include <asm/semaphore.h>
 
 #include "base.h"
@@ -193,15 +193,16 @@ static int dev_uevent(struct kset *kset, struct kobject *kobj,
        if (dev->bus && dev->bus->uevent) {
                retval = dev->bus->uevent(dev, env);
                if (retval)
-                       pr_debug ("%s: bus uevent() returned %d\n",
-                                 __FUNCTION__, retval);
+                       pr_debug("device: '%s': %s: bus uevent() returned %d\n",
+                                dev->bus_id, __FUNCTION__, retval);
        }
 
        /* have the class specific function add its stuff */
        if (dev->class && dev->class->dev_uevent) {
                retval = dev->class->dev_uevent(dev, env);
                if (retval)
-                       pr_debug("%s: class uevent() returned %d\n",
+                       pr_debug("device: '%s': %s: class uevent() "
+                                "returned %d\n", dev->bus_id,
                                 __FUNCTION__, retval);
        }
 
@@ -209,7 +210,8 @@ static int dev_uevent(struct kset *kset, struct kobject *kobj,
        if (dev->type && dev->type->uevent) {
                retval = dev->type->uevent(dev, env);
                if (retval)
-                       pr_debug("%s: dev_type uevent() returned %d\n",
+                       pr_debug("device: '%s': %s: dev_type uevent() "
+                                "returned %d\n", dev->bus_id,
                                 __FUNCTION__, retval);
        }
 
@@ -401,11 +403,8 @@ static ssize_t show_dev(struct device *dev, struct device_attribute *attr,
 static struct device_attribute devt_attr =
        __ATTR(dev, S_IRUGO, show_dev, NULL);
 
-/*
- *     devices_subsys - structure to be registered with kobject core.
- */
-
-decl_subsys(devices, &device_ktype, &device_uevent_ops);
+/* kset to create /sys/devices/  */
+struct kset *devices_kset;
 
 
 /**
@@ -525,8 +524,8 @@ static void klist_children_put(struct klist_node *n)
 
 void device_initialize(struct device *dev)
 {
-       kobj_set_kset_s(dev, devices_subsys);
-       kobject_init(&dev->kobj);
+       dev->kobj.kset = devices_kset;
+       kobject_init(&dev->kobj, &device_ktype);
        klist_init(&dev->klist_children, klist_children_get,
                   klist_children_put);
        INIT_LIST_HEAD(&dev->dma_pools);
@@ -539,36 +538,37 @@ void device_initialize(struct device *dev)
 }
 
 #ifdef CONFIG_SYSFS_DEPRECATED
-static struct kobject * get_device_parent(struct device *dev,
-                                         struct device *parent)
+static struct kobject *get_device_parent(struct device *dev,
+                                        struct device *parent)
 {
-       /*
-        * Set the parent to the class, not the parent device
-        * for topmost devices in class hierarchy.
-        * This keeps sysfs from having a symlink to make old
-        * udevs happy
-        */
+       /* class devices without a parent live in /sys/class/<classname>/ */
        if (dev->class && (!parent || parent->class != dev->class))
                return &dev->class->subsys.kobj;
+       /* all other devices keep their parent */
        else if (parent)
                return &parent->kobj;
 
        return NULL;
 }
+
+static inline void cleanup_device_parent(struct device *dev) {}
 #else
 static struct kobject *virtual_device_parent(struct device *dev)
 {
        static struct kobject *virtual_dir = NULL;
 
        if (!virtual_dir)
-               virtual_dir = kobject_add_dir(&devices_subsys.kobj, "virtual");
+               virtual_dir = kobject_create_and_add("virtual",
+                                                    &devices_kset->kobj);
 
        return virtual_dir;
 }
 
-static struct kobject * get_device_parent(struct device *dev,
-                                         struct device *parent)
+static struct kobject *get_device_parent(struct device *dev,
+                                        struct device *parent)
 {
+       int retval;
+
        if (dev->class) {
                struct kobject *kobj = NULL;
                struct kobject *parent_kobj;
@@ -598,14 +598,52 @@ static struct kobject * get_device_parent(struct device *dev,
                        return kobj;
 
                /* or create a new class-directory at the parent device */
-               return kobject_kset_add_dir(&dev->class->class_dirs,
-                                           parent_kobj, dev->class->name);
+               k = kobject_create();
+               if (!k)
+                       return NULL;
+               k->kset = &dev->class->class_dirs;
+               retval = kobject_add(k, parent_kobj, "%s", dev->class->name);
+               if (retval < 0) {
+                       kobject_put(k);
+                       return NULL;
+               }
+               /* Do not emit a uevent, as it's not needed for this
+                * "class glue" directory. */
+               return k;
        }
 
        if (parent)
                return &parent->kobj;
        return NULL;
 }
+
+static void cleanup_device_parent(struct device *dev)
+{
+       struct device *d;
+       int other = 0;
+
+       if (!dev->class)
+               return;
+
+       /* see if we live in a parent class directory */
+       if (dev->kobj.parent->kset != &dev->class->class_dirs)
+               return;
+
+       /* if we are the last child of our class, delete the directory */
+       down(&dev->class->sem);
+       list_for_each_entry(d, &dev->class->devices, node) {
+               if (d == dev)
+                       continue;
+               if (d->kobj.parent == dev->kobj.parent) {
+                       other = 1;
+                       break;
+               }
+       }
+       if (!other)
+               kobject_del(dev->kobj.parent);
+       kobject_put(dev->kobj.parent);
+       up(&dev->class->sem);
+}
 #endif
 
 static int setup_parent(struct device *dev, struct device *parent)
@@ -625,65 +663,76 @@ static int device_add_class_symlinks(struct device *dev)
 
        if (!dev->class)
                return 0;
+
        error = sysfs_create_link(&dev->kobj, &dev->class->subsys.kobj,
                                  "subsystem");
        if (error)
                goto out;
-       /*
-        * If this is not a "fake" compatible device, then create the
-        * symlink from the class to the device.
-        */
-       if (dev->kobj.parent != &dev->class->subsys.kobj) {
+
+#ifdef CONFIG_SYSFS_DEPRECATED
+       /* stacked class devices need a symlink in the class directory */
+       if (dev->kobj.parent != &dev->class->subsys.kobj &&
+           dev->type != &part_type) {
                error = sysfs_create_link(&dev->class->subsys.kobj, &dev->kobj,
                                          dev->bus_id);
                if (error)
                        goto out_subsys;
        }
-       if (dev->parent) {
-#ifdef CONFIG_SYSFS_DEPRECATED
-               {
-                       struct device *parent = dev->parent;
-                       char *class_name;
-
-                       /*
-                        * In old sysfs stacked class devices had 'device'
-                        * link pointing to real device instead of parent
-                        */
-                       while (parent->class && !parent->bus && parent->parent)
-                               parent = parent->parent;
-
-                       error = sysfs_create_link(&dev->kobj,
-                                                 &parent->kobj,
-                                                 "device");
-                       if (error)
-                               goto out_busid;
 
-                       class_name = make_class_name(dev->class->name,
-                                                       &dev->kobj);
-                       if (class_name)
-                               error = sysfs_create_link(&dev->parent->kobj,
-                                                       &dev->kobj, class_name);
-                       kfree(class_name);
-                       if (error)
-                               goto out_device;
-               }
-#else
-               error = sysfs_create_link(&dev->kobj, &dev->parent->kobj,
+       if (dev->parent && dev->type != &part_type) {
+               struct device *parent = dev->parent;
+               char *class_name;
+
+               /*
+                * stacked class devices have the 'device' link
+                * pointing to the bus device instead of the parent
+                */
+               while (parent->class && !parent->bus && parent->parent)
+                       parent = parent->parent;
+
+               error = sysfs_create_link(&dev->kobj,
+                                         &parent->kobj,
                                          "device");
                if (error)
                        goto out_busid;
-#endif
+
+               class_name = make_class_name(dev->class->name,
+                                               &dev->kobj);
+               if (class_name)
+                       error = sysfs_create_link(&dev->parent->kobj,
+                                               &dev->kobj, class_name);
+               kfree(class_name);
+               if (error)
+                       goto out_device;
        }
        return 0;
 
-#ifdef CONFIG_SYSFS_DEPRECATED
 out_device:
-       if (dev->parent)
+       if (dev->parent && dev->type != &part_type)
                sysfs_remove_link(&dev->kobj, "device");
-#endif
 out_busid:
-       if (dev->kobj.parent != &dev->class->subsys.kobj)
+       if (dev->kobj.parent != &dev->class->subsys.kobj &&
+           dev->type != &part_type)
                sysfs_remove_link(&dev->class->subsys.kobj, dev->bus_id);
+#else
+       /* link in the class directory pointing to the device */
+       error = sysfs_create_link(&dev->class->subsys.kobj, &dev->kobj,
+                                 dev->bus_id);
+       if (error)
+               goto out_subsys;
+
+       if (dev->parent && dev->type != &part_type) {
+               error = sysfs_create_link(&dev->kobj, &dev->parent->kobj,
+                                         "device");
+               if (error)
+                       goto out_busid;
+       }
+       return 0;
+
+out_busid:
+       sysfs_remove_link(&dev->class->subsys.kobj, dev->bus_id);
+#endif
+
 out_subsys:
        sysfs_remove_link(&dev->kobj, "subsystem");
 out:
@@ -694,8 +743,9 @@ static void device_remove_class_symlinks(struct device *dev)
 {
        if (!dev->class)
                return;
-       if (dev->parent) {
+
 #ifdef CONFIG_SYSFS_DEPRECATED
+       if (dev->parent && dev->type != &part_type) {
                char *class_name;
 
                class_name = make_class_name(dev->class->name, &dev->kobj);
@@ -703,11 +753,19 @@ static void device_remove_class_symlinks(struct device *dev)
                        sysfs_remove_link(&dev->parent->kobj, class_name);
                        kfree(class_name);
                }
-#endif
                sysfs_remove_link(&dev->kobj, "device");
        }
-       if (dev->kobj.parent != &dev->class->subsys.kobj)
+
+       if (dev->kobj.parent != &dev->class->subsys.kobj &&
+           dev->type != &part_type)
                sysfs_remove_link(&dev->class->subsys.kobj, dev->bus_id);
+#else
+       if (dev->parent && dev->type != &part_type)
+               sysfs_remove_link(&dev->kobj, "device");
+
+       sysfs_remove_link(&dev->class->subsys.kobj, dev->bus_id);
+#endif
+
        sysfs_remove_link(&dev->kobj, "subsystem");
 }
 
@@ -726,13 +784,22 @@ int device_add(struct device *dev)
 {
        struct device *parent = NULL;
        struct class_interface *class_intf;
-       int error = -EINVAL;
+       int error;
+
+       error = pm_sleep_lock();
+       if (error) {
+               dev_warn(dev, "Suspicious %s during suspend\n", __FUNCTION__);
+               dump_stack();
+               return error;
+       }
 
        dev = get_device(dev);
-       if (!dev || !strlen(dev->bus_id))
+       if (!dev || !strlen(dev->bus_id)) {
+               error = -EINVAL;
                goto Error;
+       }
 
-       pr_debug("DEV: registering device: ID = '%s'\n", dev->bus_id);
+       pr_debug("device: '%s': %s\n", dev->bus_id, __FUNCTION__);
 
        parent = get_device(dev->parent);
        error = setup_parent(dev, parent);
@@ -740,8 +807,7 @@ int device_add(struct device *dev)
                goto Error;
 
        /* first, register with generic layer. */
-       kobject_set_name(&dev->kobj, "%s", dev->bus_id);
-       error = kobject_add(&dev->kobj);
+       error = kobject_add(&dev->kobj, dev->kobj.parent, "%s", dev->bus_id);
        if (error)
                goto Error;
 
@@ -751,7 +817,7 @@ int device_add(struct device *dev)
 
        /* notify clients of device entry (new way) */
        if (dev->bus)
-               blocking_notifier_call_chain(&dev->bus->bus_notifier,
+               blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
                                             BUS_NOTIFY_ADD_DEVICE, dev);
 
        error = device_create_file(dev, &uevent_attr);
@@ -795,13 +861,14 @@ int device_add(struct device *dev)
        }
  Done:
        put_device(dev);
+       pm_sleep_unlock();
        return error;
  BusError:
        device_pm_remove(dev);
        dpm_sysfs_remove(dev);
  PMError:
        if (dev->bus)
-               blocking_notifier_call_chain(&dev->bus->bus_notifier,
+               blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
                                             BUS_NOTIFY_DEL_DEVICE, dev);
        device_remove_attrs(dev);
  AttrsError:
@@ -809,26 +876,6 @@ int device_add(struct device *dev)
  SymlinkError:
        if (MAJOR(dev->devt))
                device_remove_file(dev, &devt_attr);
-
-       if (dev->class) {
-               sysfs_remove_link(&dev->kobj, "subsystem");
-               /* If this is not a "fake" compatible device, remove the
-                * symlink from the class to the device. */
-               if (dev->kobj.parent != &dev->class->subsys.kobj)
-                       sysfs_remove_link(&dev->class->subsys.kobj,
-                                         dev->bus_id);
-               if (parent) {
-#ifdef CONFIG_SYSFS_DEPRECATED
-                       char *class_name = make_class_name(dev->class->name,
-                                                          &dev->kobj);
-                       if (class_name)
-                               sysfs_remove_link(&dev->parent->kobj,
-                                                 class_name);
-                       kfree(class_name);
-#endif
-                       sysfs_remove_link(&dev->kobj, "device");
-               }
-       }
  ueventattrError:
        device_remove_file(dev, &uevent_attr);
  attrError:
@@ -881,6 +928,7 @@ struct device * get_device(struct device * dev)
  */
 void put_device(struct device * dev)
 {
+       /* might_sleep(); */
        if (dev)
                kobject_put(&dev->kobj);
 }
@@ -905,28 +953,13 @@ void device_del(struct device * dev)
        struct device * parent = dev->parent;
        struct class_interface *class_intf;
 
+       device_pm_remove(dev);
        if (parent)
                klist_del(&dev->knode_parent);
        if (MAJOR(dev->devt))
                device_remove_file(dev, &devt_attr);
        if (dev->class) {
-               sysfs_remove_link(&dev->kobj, "subsystem");
-               /* If this is not a "fake" compatible device, remove the
-                * symlink from the class to the device. */
-               if (dev->kobj.parent != &dev->class->subsys.kobj)
-                       sysfs_remove_link(&dev->class->subsys.kobj,
-                                         dev->bus_id);
-               if (parent) {
-#ifdef CONFIG_SYSFS_DEPRECATED
-                       char *class_name = make_class_name(dev->class->name,
-                                                          &dev->kobj);
-                       if (class_name)
-                               sysfs_remove_link(&dev->parent->kobj,
-                                                 class_name);
-                       kfree(class_name);
-#endif
-                       sysfs_remove_link(&dev->kobj, "device");
-               }
+               device_remove_class_symlinks(dev);
 
                down(&dev->class->sem);
                /* notify any interfaces that the device is now gone */
@@ -936,31 +969,6 @@ void device_del(struct device * dev)
                /* remove the device from the class list */
                list_del_init(&dev->node);
                up(&dev->class->sem);
-
-               /* If we live in a parent class-directory, unreference it */
-               if (dev->kobj.parent->kset == &dev->class->class_dirs) {
-                       struct device *d;
-                       int other = 0;
-
-                       /*
-                        * if we are the last child of our class, delete
-                        * our class-directory at this parent
-                        */
-                       down(&dev->class->sem);
-                       list_for_each_entry(d, &dev->class->devices, node) {
-                               if (d == dev)
-                                       continue;
-                               if (d->kobj.parent == dev->kobj.parent) {
-                                       other = 1;
-                                       break;
-                               }
-                       }
-                       if (!other)
-                               kobject_del(dev->kobj.parent);
-
-                       kobject_put(dev->kobj.parent);
-                       up(&dev->class->sem);
-               }
        }
        device_remove_file(dev, &uevent_attr);
        device_remove_attrs(dev);
@@ -979,13 +987,12 @@ void device_del(struct device * dev)
        if (platform_notify_remove)
                platform_notify_remove(dev);
        if (dev->bus)
-               blocking_notifier_call_chain(&dev->bus->bus_notifier,
+               blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
                                             BUS_NOTIFY_DEL_DEVICE, dev);
-       device_pm_remove(dev);
        kobject_uevent(&dev->kobj, KOBJ_REMOVE);
+       cleanup_device_parent(dev);
        kobject_del(&dev->kobj);
-       if (parent)
-               put_device(parent);
+       put_device(parent);
 }
 
 /**
@@ -1001,7 +1008,7 @@ void device_del(struct device * dev)
  */
 void device_unregister(struct device * dev)
 {
-       pr_debug("DEV: Unregistering device. ID = '%s'\n", dev->bus_id);
+       pr_debug("device: '%s': %s\n", dev->bus_id, __FUNCTION__);
        device_del(dev);
        put_device(dev);
 }
@@ -1073,7 +1080,10 @@ struct device * device_find_child(struct device *parent, void *data,
 
 int __init devices_init(void)
 {
-       return subsystem_register(&devices_subsys);
+       devices_kset = kset_create_and_add("devices", &device_uevent_ops, NULL);
+       if (!devices_kset)
+               return -ENOMEM;
+       return 0;
 }
 
 EXPORT_SYMBOL_GPL(device_for_each_child);
@@ -1094,7 +1104,7 @@ EXPORT_SYMBOL_GPL(device_remove_file);
 
 static void device_create_release(struct device *dev)
 {
-       pr_debug("%s called for %s\n", __FUNCTION__, dev->bus_id);
+       pr_debug("device: '%s': %s\n", dev->bus_id, __FUNCTION__);
        kfree(dev);
 }
 
@@ -1156,14 +1166,11 @@ error:
 EXPORT_SYMBOL_GPL(device_create);
 
 /**
- * device_destroy - removes a device that was created with device_create()
+ * find_device - finds a device that was created with device_create()
  * @class: pointer to the struct class that this device was registered with
  * @devt: the dev_t of the device that was previously registered
- *
- * This call unregisters and cleans up a device that was created with a
- * call to device_create().
  */
-void device_destroy(struct class *class, dev_t devt)
+static struct device *find_device(struct class *class, dev_t devt)
 {
        struct device *dev = NULL;
        struct device *dev_tmp;
@@ -1176,12 +1183,54 @@ void device_destroy(struct class *class, dev_t devt)
                }
        }
        up(&class->sem);
+       return dev;
+}
 
+/**
+ * device_destroy - removes a device that was created with device_create()
+ * @class: pointer to the struct class that this device was registered with
+ * @devt: the dev_t of the device that was previously registered
+ *
+ * This call unregisters and cleans up a device that was created with a
+ * call to device_create().
+ */
+void device_destroy(struct class *class, dev_t devt)
+{
+       struct device *dev;
+
+       dev = find_device(class, devt);
        if (dev)
                device_unregister(dev);
 }
 EXPORT_SYMBOL_GPL(device_destroy);
 
+#ifdef CONFIG_PM_SLEEP
+/**
+ * destroy_suspended_device - asks the PM core to remove a suspended device
+ * @class: pointer to the struct class that this device was registered with
+ * @devt: the dev_t of the device that was previously registered
+ *
+ * This call notifies the PM core of the necessity to unregister a suspended
+ * device created with a call to device_create() (devices cannot be
+ * unregistered directly while suspended, since the PM core holds their
+ * semaphores at that time).
+ *
+ * It can only be called within the scope of a system sleep transition.  In
+ * practice this means it has to be directly or indirectly invoked either by
+ * a suspend or resume method, or by the PM core (e.g. via
+ * disable_nonboot_cpus() or enable_nonboot_cpus()).
+ */
+void destroy_suspended_device(struct class *class, dev_t devt)
+{
+       struct device *dev;
+
+       dev = find_device(class, devt);
+       if (dev)
+               device_pm_schedule_removal(dev);
+}
+EXPORT_SYMBOL_GPL(destroy_suspended_device);
+#endif /* CONFIG_PM_SLEEP */
+
 /**
  * device_rename - renames a device
  * @dev: the pointer to the struct device to be renamed
@@ -1198,7 +1247,8 @@ int device_rename(struct device *dev, char *new_name)
        if (!dev)
                return -EINVAL;
 
-       pr_debug("DEVICE: renaming '%s' to '%s'\n", dev->bus_id, new_name);
+       pr_debug("device: '%s': %s: renaming to '%s'\n", dev->bus_id,
+                __FUNCTION__, new_name);
 
 #ifdef CONFIG_SYSFS_DEPRECATED
        if ((dev->class) && (dev->parent))
@@ -1317,8 +1367,8 @@ int device_move(struct device *dev, struct device *new_parent)
                put_device(new_parent);
                goto out;
        }
-       pr_debug("DEVICE: moving '%s' to '%s'\n", dev->bus_id,
-                new_parent ? new_parent->bus_id : "<NULL>");
+       pr_debug("device: '%s': %s: moving to '%s'\n", dev->bus_id,
+                __FUNCTION__, new_parent ? new_parent->bus_id : "<NULL>");
        error = kobject_move(&dev->kobj, new_parent_kobj);
        if (error) {
                put_device(new_parent);
@@ -1352,5 +1402,23 @@ out:
        put_device(dev);
        return error;
 }
-
 EXPORT_SYMBOL_GPL(device_move);
+
+/**
+ * device_shutdown - call ->shutdown() on each device to shutdown.
+ */
+void device_shutdown(void)
+{
+       struct device * dev, *devn;
+
+       list_for_each_entry_safe_reverse(dev, devn, &devices_kset->list,
+                               kobj.entry) {
+               if (dev->bus && dev->bus->shutdown) {
+                       dev_dbg(dev, "shutdown\n");
+                       dev->bus->shutdown(dev);
+               } else if (dev->driver && dev->driver->shutdown) {
+                       dev_dbg(dev, "shutdown\n");
+                       dev->driver->shutdown(dev);
+               }
+       }
+}