regmap: Support register patch sets
[linux-2.6.git] / drivers / base / core.c
index 9649d1c..74dda4f 100644 (file)
 #include <linux/notifier.h>
 #include <linux/genhd.h>
 #include <linux/kallsyms.h>
-#include <linux/semaphore.h>
 #include <linux/mutex.h>
+#include <linux/async.h>
+#include <linux/pm_runtime.h>
 
 #include "base.h"
 #include "power/power.h"
 
+#ifdef CONFIG_SYSFS_DEPRECATED
+#ifdef CONFIG_SYSFS_DEPRECATED_V2
+long sysfs_deprecated = 1;
+#else
+long sysfs_deprecated = 0;
+#endif
+static __init int sysfs_deprecated_setup(char *arg)
+{
+       return strict_strtol(arg, 10, &sysfs_deprecated);
+}
+early_param("sysfs.deprecated", sysfs_deprecated_setup);
+#endif
+
 int (*platform_notify)(struct device *dev) = NULL;
 int (*platform_notify_remove)(struct device *dev) = NULL;
 static struct kobject *dev_kobj;
@@ -55,7 +69,14 @@ static inline int device_is_not_partition(struct device *dev)
  */
 const char *dev_driver_string(const struct device *dev)
 {
-       return dev->driver ? dev->driver->name :
+       struct device_driver *drv;
+
+       /* dev->driver can change to NULL underneath us because of unbinding,
+        * so be careful about accessing it.  dev->bus and dev->class should
+        * never change once they are set, so they don't need special care.
+        */
+       drv = ACCESS_ONCE(dev->driver);
+       return drv ? drv->name :
                        (dev->bus ? dev->bus->name :
                        (dev->class ? dev->class->name : ""));
 }
@@ -92,11 +113,61 @@ static ssize_t dev_attr_store(struct kobject *kobj, struct attribute *attr,
        return ret;
 }
 
-static struct sysfs_ops dev_sysfs_ops = {
+static const struct sysfs_ops dev_sysfs_ops = {
        .show   = dev_attr_show,
        .store  = dev_attr_store,
 };
 
+#define to_ext_attr(x) container_of(x, struct dev_ext_attribute, attr)
+
+ssize_t device_store_ulong(struct device *dev,
+                          struct device_attribute *attr,
+                          const char *buf, size_t size)
+{
+       struct dev_ext_attribute *ea = to_ext_attr(attr);
+       char *end;
+       unsigned long new = simple_strtoul(buf, &end, 0);
+       if (end == buf)
+               return -EINVAL;
+       *(unsigned long *)(ea->var) = new;
+       /* Always return full write size even if we didn't consume all */
+       return size;
+}
+EXPORT_SYMBOL_GPL(device_store_ulong);
+
+ssize_t device_show_ulong(struct device *dev,
+                         struct device_attribute *attr,
+                         char *buf)
+{
+       struct dev_ext_attribute *ea = to_ext_attr(attr);
+       return snprintf(buf, PAGE_SIZE, "%lx\n", *(unsigned long *)(ea->var));
+}
+EXPORT_SYMBOL_GPL(device_show_ulong);
+
+ssize_t device_store_int(struct device *dev,
+                        struct device_attribute *attr,
+                        const char *buf, size_t size)
+{
+       struct dev_ext_attribute *ea = to_ext_attr(attr);
+       char *end;
+       long new = simple_strtol(buf, &end, 0);
+       if (end == buf || new > INT_MAX || new < INT_MIN)
+               return -EINVAL;
+       *(int *)(ea->var) = new;
+       /* Always return full write size even if we didn't consume all */
+       return size;
+}
+EXPORT_SYMBOL_GPL(device_store_int);
+
+ssize_t device_show_int(struct device *dev,
+                       struct device_attribute *attr,
+                       char *buf)
+{
+       struct dev_ext_attribute *ea = to_ext_attr(attr);
+
+       return snprintf(buf, PAGE_SIZE, "%d\n", *(int *)(ea->var));
+}
+EXPORT_SYMBOL_GPL(device_show_int);
 
 /**
  *     device_release - free device structure.
@@ -109,6 +180,7 @@ static struct sysfs_ops dev_sysfs_ops = {
 static void device_release(struct kobject *kobj)
 {
        struct device *dev = to_dev(kobj);
+       struct device_private *p = dev->p;
 
        if (dev->release)
                dev->release(dev);
@@ -119,12 +191,25 @@ static void device_release(struct kobject *kobj)
        else
                WARN(1, KERN_ERR "Device '%s' does not have a release() "
                        "function, it is broken and must be fixed.\n",
-                       dev->bus_id);
+                       dev_name(dev));
+       kfree(p);
+}
+
+static const void *device_namespace(struct kobject *kobj)
+{
+       struct device *dev = to_dev(kobj);
+       const void *ns = NULL;
+
+       if (dev->class && dev->class->ns_type)
+               ns = dev->class->namespace(dev);
+
+       return ns;
 }
 
 static struct kobj_type device_ktype = {
        .release        = device_release,
        .sysfs_ops      = &dev_sysfs_ops,
+       .namespace      = device_namespace,
 };
 
 
@@ -134,8 +219,6 @@ static int dev_uevent_filter(struct kset *kset, struct kobject *kobj)
 
        if (ktype == &device_ktype) {
                struct device *dev = to_dev(kobj);
-               if (dev->uevent_suppress)
-                       return 0;
                if (dev->bus)
                        return 1;
                if (dev->class)
@@ -161,10 +244,21 @@ static int dev_uevent(struct kset *kset, struct kobject *kobj,
        struct device *dev = to_dev(kobj);
        int retval = 0;
 
-       /* add the major/minor if present */
+       /* add device node properties if present */
        if (MAJOR(dev->devt)) {
+               const char *tmp;
+               const char *name;
+               umode_t mode = 0;
+
                add_uevent_var(env, "MAJOR=%u", MAJOR(dev->devt));
                add_uevent_var(env, "MINOR=%u", MINOR(dev->devt));
+               name = device_get_devnode(dev, &mode, &tmp);
+               if (name) {
+                       add_uevent_var(env, "DEVNAME=%s", name);
+                       kfree(tmp);
+                       if (mode)
+                               add_uevent_var(env, "DEVMODE=%#o", mode & 0777);
+               }
        }
 
        if (dev->type && dev->type->name)
@@ -173,43 +267,12 @@ static int dev_uevent(struct kset *kset, struct kobject *kobj,
        if (dev->driver)
                add_uevent_var(env, "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);
-                       if (path) {
-                               add_uevent_var(env, "PHYSDEVPATH=%s", path);
-                               kfree(path);
-                       }
-
-                       add_uevent_var(env, "PHYSDEVBUS=%s", parent->bus->name);
-
-                       if (parent->driver)
-                               add_uevent_var(env, "PHYSDEVDRIVER=%s",
-                                              parent->driver->name);
-               }
-       } else if (dev->bus) {
-               add_uevent_var(env, "PHYSDEVBUS=%s", dev->bus->name);
-
-               if (dev->driver)
-                       add_uevent_var(env, "PHYSDEVDRIVER=%s",
-                                      dev->driver->name);
-       }
-#endif
-
        /* have the bus specific function add its stuff */
        if (dev->bus && dev->bus->uevent) {
                retval = dev->bus->uevent(dev, env);
                if (retval)
                        pr_debug("device: '%s': %s: bus uevent() returned %d\n",
-                                dev->bus_id, __func__, retval);
+                                dev_name(dev), __func__, retval);
        }
 
        /* have the class specific function add its stuff */
@@ -217,23 +280,23 @@ static int dev_uevent(struct kset *kset, struct kobject *kobj,
                retval = dev->class->dev_uevent(dev, env);
                if (retval)
                        pr_debug("device: '%s': %s: class uevent() "
-                                "returned %d\n", dev->bus_id,
+                                "returned %d\n", dev_name(dev),
                                 __func__, retval);
        }
 
-       /* have the device type specific fuction add its stuff */
+       /* have the device type specific function add its stuff */
        if (dev->type && dev->type->uevent) {
                retval = dev->type->uevent(dev, env);
                if (retval)
                        pr_debug("device: '%s': %s: dev_type uevent() "
-                                "returned %d\n", dev->bus_id,
+                                "returned %d\n", dev_name(dev),
                                 __func__, retval);
        }
 
        return retval;
 }
 
-static struct kset_uevent_ops device_uevent_ops = {
+static const struct kset_uevent_ops device_uevent_ops = {
        .filter =       dev_uevent_filter,
        .name =         dev_uevent_name,
        .uevent =       dev_uevent,
@@ -287,15 +350,10 @@ static ssize_t store_uevent(struct device *dev, struct device_attribute *attr,
 {
        enum kobject_action action;
 
-       if (kobject_action_type(buf, count, &action) == 0) {
+       if (kobject_action_type(buf, count, &action) == 0)
                kobject_uevent(&dev->kobj, action);
-               goto out;
-       }
-
-       dev_err(dev, "uevent: unsupported action-string; this will "
-                    "be ignored in a future kernel version\n");
-       kobject_uevent(&dev->kobj, KOBJ_ADD);
-out:
+       else
+               dev_err(dev, "uevent: unknown action-string\n");
        return count;
 }
 
@@ -331,8 +389,37 @@ static void device_remove_attributes(struct device *dev,
                        device_remove_file(dev, &attrs[i]);
 }
 
+static int device_add_bin_attributes(struct device *dev,
+                                    struct bin_attribute *attrs)
+{
+       int error = 0;
+       int i;
+
+       if (attrs) {
+               for (i = 0; attr_name(attrs[i]); i++) {
+                       error = device_create_bin_file(dev, &attrs[i]);
+                       if (error)
+                               break;
+               }
+               if (error)
+                       while (--i >= 0)
+                               device_remove_bin_file(dev, &attrs[i]);
+       }
+       return error;
+}
+
+static void device_remove_bin_attributes(struct device *dev,
+                                        struct bin_attribute *attrs)
+{
+       int i;
+
+       if (attrs)
+               for (i = 0; attr_name(attrs[i]); i++)
+                       device_remove_bin_file(dev, &attrs[i]);
+}
+
 static int device_add_groups(struct device *dev,
-                            struct attribute_group **groups)
+                            const struct attribute_group **groups)
 {
        int error = 0;
        int i;
@@ -352,7 +439,7 @@ static int device_add_groups(struct device *dev,
 }
 
 static void device_remove_groups(struct device *dev,
-                                struct attribute_group **groups)
+                                const struct attribute_group **groups)
 {
        int i;
 
@@ -364,19 +451,22 @@ 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;
+       const struct device_type *type = dev->type;
        int error;
 
        if (class) {
                error = device_add_attributes(dev, class->dev_attrs);
                if (error)
                        return error;
+               error = device_add_bin_attributes(dev, class->dev_bin_attrs);
+               if (error)
+                       goto err_remove_class_attrs;
        }
 
        if (type) {
                error = device_add_groups(dev, type->groups);
                if (error)
-                       goto err_remove_class_attrs;
+                       goto err_remove_class_bin_attrs;
        }
 
        error = device_add_groups(dev, dev->groups);
@@ -388,6 +478,9 @@ static int device_add_attrs(struct device *dev)
  err_remove_type_groups:
        if (type)
                device_remove_groups(dev, type->groups);
+ err_remove_class_bin_attrs:
+       if (class)
+               device_remove_bin_attributes(dev, class->dev_bin_attrs);
  err_remove_class_attrs:
        if (class)
                device_remove_attributes(dev, class->dev_attrs);
@@ -398,15 +491,17 @@ static int device_add_attrs(struct device *dev)
 static void device_remove_attrs(struct device *dev)
 {
        struct class *class = dev->class;
-       struct device_type *type = dev->type;
+       const struct device_type *type = dev->type;
 
        device_remove_groups(dev, dev->groups);
 
        if (type)
                device_remove_groups(dev, type->groups);
 
-       if (class)
+       if (class) {
                device_remove_attributes(dev, class->dev_attrs);
+               device_remove_bin_attributes(dev, class->dev_bin_attrs);
+       }
 }
 
 
@@ -419,7 +514,7 @@ 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);
 
-/* kset to create /sys/devices/  */
+/* /sys/devices/ */
 struct kset *devices_kset;
 
 /**
@@ -427,7 +522,8 @@ struct kset *devices_kset;
  * @dev: device.
  * @attr: device attribute descriptor.
  */
-int device_create_file(struct device *dev, struct device_attribute *attr)
+int device_create_file(struct device *dev,
+                      const struct device_attribute *attr)
 {
        int error = 0;
        if (dev)
@@ -440,7 +536,8 @@ int device_create_file(struct device *dev, struct device_attribute *attr)
  * @dev: device.
  * @attr: device attribute descriptor.
  */
-void device_remove_file(struct device *dev, struct device_attribute *attr)
+void device_remove_file(struct device *dev,
+                       const struct device_attribute *attr)
 {
        if (dev)
                sysfs_remove_file(&dev->kobj, &attr->attr);
@@ -451,7 +548,8 @@ void device_remove_file(struct device *dev, struct device_attribute *attr)
  * @dev: device.
  * @attr: device binary attribute descriptor.
  */
-int device_create_bin_file(struct device *dev, struct bin_attribute *attr)
+int device_create_bin_file(struct device *dev,
+                          const struct bin_attribute *attr)
 {
        int error = -EINVAL;
        if (dev)
@@ -465,7 +563,8 @@ EXPORT_SYMBOL_GPL(device_create_bin_file);
  * @dev: device.
  * @attr: device binary attribute descriptor.
  */
-void device_remove_bin_file(struct device *dev, struct bin_attribute *attr)
+void device_remove_bin_file(struct device *dev,
+                           const struct bin_attribute *attr)
 {
        if (dev)
                sysfs_remove_bin_file(&dev->kobj, attr);
@@ -507,14 +606,16 @@ EXPORT_SYMBOL_GPL(device_schedule_callback_owner);
 
 static void klist_children_get(struct klist_node *n)
 {
-       struct device *dev = container_of(n, struct device, knode_parent);
+       struct device_private *p = to_device_private_parent(n);
+       struct device *dev = p->device;
 
        get_device(dev);
 }
 
 static void klist_children_put(struct klist_node *n)
 {
-       struct device *dev = container_of(n, struct device, knode_parent);
+       struct device_private *p = to_device_private_parent(n);
+       struct device *dev = p->device;
 
        put_device(dev);
 }
@@ -531,6 +632,11 @@ static void klist_children_put(struct klist_node *n)
  * may be used for reference counting of @dev after calling this
  * function.
  *
+ * All fields in @dev must be initialized by the caller to 0, except
+ * for those explicitly set to some other value.  The simplest
+ * approach is to use kzalloc() to allocate the structure containing
+ * @dev.
+ *
  * NOTE: Use put_device() to give up your reference instead of freeing
  * @dev directly once you have called this function.
  */
@@ -538,35 +644,15 @@ void device_initialize(struct device *dev)
 {
        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);
-       init_MUTEX(&dev->sem);
+       mutex_init(&dev->mutex);
+       lockdep_set_novalidate_class(&dev->mutex);
        spin_lock_init(&dev->devres_lock);
        INIT_LIST_HEAD(&dev->devres_head);
-       device_init_wakeup(dev, 0);
        device_pm_init(dev);
        set_dev_node(dev, -1);
 }
 
-#ifdef CONFIG_SYSFS_DEPRECATED
-static struct kobject *get_device_parent(struct device *dev,
-                                        struct device *parent)
-{
-       /* class devices without a parent live in /sys/class/<classname>/ */
-       if (dev->class && (!parent || parent->class != dev->class))
-               return &dev->class->p->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) {}
-static inline void cleanup_glue_dir(struct device *dev,
-                                   struct kobject *glue_dir) {}
-#else
 static struct kobject *virtual_device_parent(struct device *dev)
 {
        static struct kobject *virtual_dir = NULL;
@@ -578,16 +664,74 @@ static struct kobject *virtual_device_parent(struct device *dev)
        return virtual_dir;
 }
 
-static struct kobject *get_device_parent(struct device *dev,
-                                        struct device *parent)
+struct class_dir {
+       struct kobject kobj;
+       struct class *class;
+};
+
+#define to_class_dir(obj) container_of(obj, struct class_dir, kobj)
+
+static void class_dir_release(struct kobject *kobj)
+{
+       struct class_dir *dir = to_class_dir(kobj);
+       kfree(dir);
+}
+
+static const
+struct kobj_ns_type_operations *class_dir_child_ns_type(struct kobject *kobj)
+{
+       struct class_dir *dir = to_class_dir(kobj);
+       return dir->class->ns_type;
+}
+
+static struct kobj_type class_dir_ktype = {
+       .release        = class_dir_release,
+       .sysfs_ops      = &kobj_sysfs_ops,
+       .child_ns_type  = class_dir_child_ns_type
+};
+
+static struct kobject *
+class_dir_create_and_add(struct class *class, struct kobject *parent_kobj)
 {
+       struct class_dir *dir;
        int retval;
 
+       dir = kzalloc(sizeof(*dir), GFP_KERNEL);
+       if (!dir)
+               return NULL;
+
+       dir->class = class;
+       kobject_init(&dir->kobj, &class_dir_ktype);
+
+       dir->kobj.kset = &class->p->glue_dirs;
+
+       retval = kobject_add(&dir->kobj, parent_kobj, "%s", class->name);
+       if (retval < 0) {
+               kobject_put(&dir->kobj);
+               return NULL;
+       }
+       return &dir->kobj;
+}
+
+
+static struct kobject *get_device_parent(struct device *dev,
+                                        struct device *parent)
+{
        if (dev->class) {
+               static DEFINE_MUTEX(gdp_mutex);
                struct kobject *kobj = NULL;
                struct kobject *parent_kobj;
                struct kobject *k;
 
+#ifdef CONFIG_BLOCK
+               /* block disks show up in /sys/block */
+               if (sysfs_deprecated && dev->class == &block_class) {
+                       if (parent && parent->class == &block_class)
+                               return &parent->kobj;
+                       return &block_class.p->subsys.kobj;
+               }
+#endif
+
                /*
                 * If we have no parent, we live in "virtual".
                 * Class-devices with a non class-device as parent, live
@@ -595,36 +739,37 @@ static struct kobject *get_device_parent(struct device *dev,
                 */
                if (parent == NULL)
                        parent_kobj = virtual_device_parent(dev);
-               else if (parent->class)
+               else if (parent->class && !dev->class->ns_type)
                        return &parent->kobj;
                else
                        parent_kobj = &parent->kobj;
 
+               mutex_lock(&gdp_mutex);
+
                /* find our class-directory at the parent and reference it */
-               spin_lock(&dev->class->p->class_dirs.list_lock);
-               list_for_each_entry(k, &dev->class->p->class_dirs.list, entry)
+               spin_lock(&dev->class->p->glue_dirs.list_lock);
+               list_for_each_entry(k, &dev->class->p->glue_dirs.list, entry)
                        if (k->parent == parent_kobj) {
                                kobj = kobject_get(k);
                                break;
                        }
-               spin_unlock(&dev->class->p->class_dirs.list_lock);
-               if (kobj)
+               spin_unlock(&dev->class->p->glue_dirs.list_lock);
+               if (kobj) {
+                       mutex_unlock(&gdp_mutex);
                        return kobj;
+               }
 
                /* or create a new class-directory at the parent device */
-               k = kobject_create();
-               if (!k)
-                       return NULL;
-               k->kset = &dev->class->p->class_dirs;
-               retval = kobject_add(k, parent_kobj, "%s", dev->class->name);
-               if (retval < 0) {
-                       kobject_put(k);
-                       return NULL;
-               }
+               k = class_dir_create_and_add(dev->class, parent_kobj);
                /* do not emit an uevent for this simple "glue" directory */
+               mutex_unlock(&gdp_mutex);
                return k;
        }
 
+       /* subsystems can specify a default root directory for their devices */
+       if (!parent && dev->bus && dev->bus->dev_root)
+               return &dev->bus->dev_root->kobj;
+
        if (parent)
                return &parent->kobj;
        return NULL;
@@ -634,7 +779,7 @@ static void cleanup_glue_dir(struct device *dev, struct kobject *glue_dir)
 {
        /* see if we live in a "glue" directory */
        if (!glue_dir || !dev->class ||
-           glue_dir->kset != &dev->class->p->class_dirs)
+           glue_dir->kset != &dev->class->p->glue_dirs)
                return;
 
        kobject_put(glue_dir);
@@ -644,15 +789,6 @@ static void cleanup_device_parent(struct device *dev)
 {
        cleanup_glue_dir(dev, dev->kobj.parent);
 }
-#endif
-
-static void setup_parent(struct device *dev, struct device *parent)
-{
-       struct kobject *kobj;
-       kobj = get_device_parent(dev, parent);
-       if (kobj)
-               dev->kobj.parent = kobj;
-}
 
 static int device_add_class_symlinks(struct device *dev)
 {
@@ -662,75 +798,34 @@ static int device_add_class_symlinks(struct device *dev)
                return 0;
 
        error = sysfs_create_link(&dev->kobj,
-                                 &dev->class->p->class_subsys.kobj,
+                                 &dev->class->p->subsys.kobj,
                                  "subsystem");
        if (error)
                goto out;
 
-#ifdef CONFIG_SYSFS_DEPRECATED
-       /* stacked class devices need a symlink in the class directory */
-       if (dev->kobj.parent != &dev->class->p->class_subsys.kobj &&
-           device_is_not_partition(dev)) {
-               error = sysfs_create_link(&dev->class->p->class_subsys.kobj,
-                                         &dev->kobj, dev->bus_id);
-               if (error)
-                       goto out_subsys;
-       }
-
        if (dev->parent && device_is_not_partition(dev)) {
-               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,
+               error = sysfs_create_link(&dev->kobj, &dev->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;
+                       goto out_subsys;
        }
-       return 0;
 
-out_device:
-       if (dev->parent && device_is_not_partition(dev))
-               sysfs_remove_link(&dev->kobj, "device");
-out_busid:
-       if (dev->kobj.parent != &dev->class->p->class_subsys.kobj &&
-           device_is_not_partition(dev))
-               sysfs_remove_link(&dev->class->p->class_subsys.kobj,
-                                 dev->bus_id);
-#else
+#ifdef CONFIG_BLOCK
+       /* /sys/block has directories and does not need symlinks */
+       if (sysfs_deprecated && dev->class == &block_class)
+               return 0;
+#endif
+
        /* link in the class directory pointing to the device */
-       error = sysfs_create_link(&dev->class->p->class_subsys.kobj,
-                                 &dev->kobj, dev->bus_id);
+       error = sysfs_create_link(&dev->class->p->subsys.kobj,
+                                 &dev->kobj, dev_name(dev));
        if (error)
-               goto out_subsys;
+               goto out_device;
 
-       if (dev->parent && device_is_not_partition(dev)) {
-               error = sysfs_create_link(&dev->kobj, &dev->parent->kobj,
-                                         "device");
-               if (error)
-                       goto out_busid;
-       }
        return 0;
 
-out_busid:
-       sysfs_remove_link(&dev->class->p->class_subsys.kobj, dev->bus_id);
-#endif
+out_device:
+       sysfs_remove_link(&dev->kobj, "device");
 
 out_subsys:
        sysfs_remove_link(&dev->kobj, "subsystem");
@@ -743,30 +838,14 @@ static void device_remove_class_symlinks(struct device *dev)
        if (!dev->class)
                return;
 
-#ifdef CONFIG_SYSFS_DEPRECATED
-       if (dev->parent && device_is_not_partition(dev)) {
-               char *class_name;
-
-               class_name = make_class_name(dev->class->name, &dev->kobj);
-               if (class_name) {
-                       sysfs_remove_link(&dev->parent->kobj, class_name);
-                       kfree(class_name);
-               }
-               sysfs_remove_link(&dev->kobj, "device");
-       }
-
-       if (dev->kobj.parent != &dev->class->p->class_subsys.kobj &&
-           device_is_not_partition(dev))
-               sysfs_remove_link(&dev->class->p->class_subsys.kobj,
-                                 dev->bus_id);
-#else
        if (dev->parent && device_is_not_partition(dev))
                sysfs_remove_link(&dev->kobj, "device");
-
-       sysfs_remove_link(&dev->class->p->class_subsys.kobj, dev->bus_id);
-#endif
-
        sysfs_remove_link(&dev->kobj, "subsystem");
+#ifdef CONFIG_BLOCK
+       if (sysfs_deprecated && dev->class == &block_class)
+               return;
+#endif
+       sysfs_delete_link(&dev->class->p->subsys.kobj, &dev->kobj, dev_name(dev));
 }
 
 /**
@@ -777,11 +856,12 @@ static void device_remove_class_symlinks(struct device *dev)
 int dev_set_name(struct device *dev, const char *fmt, ...)
 {
        va_list vargs;
+       int err;
 
        va_start(vargs, fmt);
-       vsnprintf(dev->bus_id, sizeof(dev->bus_id), fmt, vargs);
+       err = kobject_set_name_vargs(&dev->kobj, fmt, vargs);
        va_end(vargs);
-       return 0;
+       return err;
 }
 EXPORT_SYMBOL_GPL(dev_set_name);
 
@@ -833,6 +913,17 @@ static void device_remove_sys_dev_entry(struct device *dev)
        }
 }
 
+int device_private_init(struct device *dev)
+{
+       dev->p = kzalloc(sizeof(*dev->p), GFP_KERNEL);
+       if (!dev->p)
+               return -ENOMEM;
+       dev->p->device = dev;
+       klist_init(&dev->p->klist_children, klist_children_get,
+                  klist_children_put);
+       return 0;
+}
+
 /**
  * device_add - add device to device hierarchy.
  * @dev: device.
@@ -844,6 +935,13 @@ static void device_remove_sys_dev_entry(struct device *dev)
  * to the global and sibling lists for the device, then
  * adds it to the other relevant subsystems of the driver model.
  *
+ * Do not call this routine or device_register() more than once for
+ * any device structure.  The driver model core is not designed to work
+ * with devices that get unregistered and then spring back to life.
+ * (Among other things, it's very hard to guarantee that all references
+ * to the previous incarnation of @dev have been dropped.)  Allocate
+ * and register a fresh new struct device instead.
+ *
  * NOTE: _Never_ directly free @dev after calling this function, even
  * if it returned an error! Always use put_device() to give up your
  * reference instead.
@@ -851,6 +949,7 @@ static void device_remove_sys_dev_entry(struct device *dev)
 int device_add(struct device *dev)
 {
        struct device *parent = NULL;
+       struct kobject *kobj;
        struct class_interface *class_intf;
        int error = -EINVAL;
 
@@ -858,25 +957,45 @@ int device_add(struct device *dev)
        if (!dev)
                goto done;
 
-       /* Temporarily support init_name if it is set.
-        * It will override bus_id for now */
-       if (dev->init_name)
+       if (!dev->p) {
+               error = device_private_init(dev);
+               if (error)
+                       goto done;
+       }
+
+       /*
+        * for statically allocated devices, which should all be converted
+        * some day, we need to initialize the name. We prevent reading back
+        * the name, and force the use of dev_name()
+        */
+       if (dev->init_name) {
                dev_set_name(dev, "%s", dev->init_name);
+               dev->init_name = NULL;
+       }
 
-       if (!strlen(dev->bus_id))
-               goto done;
+       /* subsystems can specify simple device enumeration */
+       if (!dev_name(dev) && dev->bus && dev->bus->dev_name)
+               dev_set_name(dev, "%s%u", dev->bus->dev_name, dev->id);
 
-       pr_debug("device: '%s': %s\n", dev->bus_id, __func__);
+       if (!dev_name(dev)) {
+               error = -EINVAL;
+               goto name_error;
+       }
+
+       pr_debug("device: '%s': %s\n", dev_name(dev), __func__);
 
        parent = get_device(dev->parent);
-       setup_parent(dev, parent);
+       kobj = get_device_parent(dev, parent);
+       if (kobj)
+               dev->kobj.parent = kobj;
 
        /* use parent numa_node */
        if (parent)
                set_dev_node(dev, dev_to_node(parent));
 
        /* first, register with generic layer. */
-       error = kobject_add(&dev->kobj, dev->kobj.parent, "%s", dev->bus_id);
+       /* we require the name to be set before, and pass NULL */
+       error = kobject_add(&dev->kobj, dev->kobj.parent, NULL);
        if (error)
                goto Error;
 
@@ -884,11 +1003,6 @@ int device_add(struct device *dev)
        if (platform_notify)
                platform_notify(dev);
 
-       /* notify clients of device entry (new way) */
-       if (dev->bus)
-               blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
-                                            BUS_NOTIFY_ADD_DEVICE, dev);
-
        error = device_create_file(dev, &uevent_attr);
        if (error)
                goto attrError;
@@ -901,6 +1015,8 @@ int device_add(struct device *dev)
                error = device_create_sys_dev_entry(dev);
                if (error)
                        goto devtattrError;
+
+               devtmpfs_create_node(dev);
        }
 
        error = device_add_class_symlinks(dev);
@@ -916,23 +1032,32 @@ int device_add(struct device *dev)
        if (error)
                goto DPMError;
        device_pm_add(dev);
+
+       /* Notify clients of device addition.  This call must come
+        * after dpm_sysfs_add() and before kobject_uevent().
+        */
+       if (dev->bus)
+               blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
+                                            BUS_NOTIFY_ADD_DEVICE, dev);
+
        kobject_uevent(&dev->kobj, KOBJ_ADD);
-       bus_attach_device(dev);
+       bus_probe_device(dev);
        if (parent)
-               klist_add_tail(&dev->knode_parent, &parent->klist_children);
+               klist_add_tail(&dev->p->knode_parent,
+                              &parent->p->klist_children);
 
        if (dev->class) {
-               mutex_lock(&dev->class->p->class_mutex);
+               mutex_lock(&dev->class->p->mutex);
                /* tie the class to the device */
                klist_add_tail(&dev->knode_class,
-                              &dev->class->p->class_devices);
+                              &dev->class->p->klist_devices);
 
                /* notify any interfaces that the device is here */
                list_for_each_entry(class_intf,
-                                   &dev->class->p->class_interfaces, node)
+                                   &dev->class->p->interfaces, node)
                        if (class_intf->add_dev)
                                class_intf->add_dev(dev, class_intf);
-               mutex_unlock(&dev->class->p->class_mutex);
+               mutex_unlock(&dev->class->p->mutex);
        }
 done:
        put_device(dev);
@@ -940,14 +1065,13 @@ done:
  DPMError:
        bus_remove_device(dev);
  BusError:
-       if (dev->bus)
-               blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
-                                            BUS_NOTIFY_DEL_DEVICE, dev);
        device_remove_attrs(dev);
  AttrsError:
        device_remove_class_symlinks(dev);
  SymlinkError:
        if (MAJOR(dev->devt))
+               devtmpfs_delete_node(dev);
+       if (MAJOR(dev->devt))
                device_remove_sys_dev_entry(dev);
  devtattrError:
        if (MAJOR(dev->devt))
@@ -961,6 +1085,9 @@ done:
        cleanup_device_parent(dev);
        if (parent)
                put_device(parent);
+name_error:
+       kfree(dev->p);
+       dev->p = NULL;
        goto done;
 }
 
@@ -975,6 +1102,9 @@ done:
  * have a clearly defined need to use and refcount the device
  * before it is added to the hierarchy.
  *
+ * For more information, see the kerneldoc for device_initialize()
+ * and device_add().
+ *
  * NOTE: _Never_ directly free @dev after calling this function, even
  * if it returned an error! Always use put_device() to give up the
  * reference initialized in this function instead.
@@ -1027,26 +1157,33 @@ void device_del(struct device *dev)
        struct device *parent = dev->parent;
        struct class_interface *class_intf;
 
+       /* Notify clients of device removal.  This call must come
+        * before dpm_sysfs_remove().
+        */
+       if (dev->bus)
+               blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
+                                            BUS_NOTIFY_DEL_DEVICE, dev);
        device_pm_remove(dev);
        dpm_sysfs_remove(dev);
        if (parent)
-               klist_del(&dev->knode_parent);
+               klist_del(&dev->p->knode_parent);
        if (MAJOR(dev->devt)) {
+               devtmpfs_delete_node(dev);
                device_remove_sys_dev_entry(dev);
                device_remove_file(dev, &devt_attr);
        }
        if (dev->class) {
                device_remove_class_symlinks(dev);
 
-               mutex_lock(&dev->class->p->class_mutex);
+               mutex_lock(&dev->class->p->mutex);
                /* notify any interfaces that the device is now gone */
                list_for_each_entry(class_intf,
-                                   &dev->class->p->class_interfaces, node)
+                                   &dev->class->p->interfaces, node)
                        if (class_intf->remove_dev)
                                class_intf->remove_dev(dev, class_intf);
                /* remove the device from the class list */
                klist_del(&dev->knode_class);
-               mutex_unlock(&dev->class->p->class_mutex);
+               mutex_unlock(&dev->class->p->mutex);
        }
        device_remove_file(dev, &uevent_attr);
        device_remove_attrs(dev);
@@ -1064,9 +1201,6 @@ void device_del(struct device *dev)
         */
        if (platform_notify_remove)
                platform_notify_remove(dev);
-       if (dev->bus)
-               blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
-                                            BUS_NOTIFY_DEL_DEVICE, dev);
        kobject_uevent(&dev->kobj, KOBJ_REMOVE);
        cleanup_device_parent(dev);
        kobject_del(&dev->kobj);
@@ -1086,7 +1220,7 @@ void device_del(struct device *dev)
  */
 void device_unregister(struct device *dev)
 {
-       pr_debug("device: '%s': %s\n", dev->bus_id, __func__);
+       pr_debug("device: '%s': %s\n", dev_name(dev), __func__);
        device_del(dev);
        put_device(dev);
 }
@@ -1094,7 +1228,57 @@ void device_unregister(struct device *dev)
 static struct device *next_device(struct klist_iter *i)
 {
        struct klist_node *n = klist_next(i);
-       return n ? container_of(n, struct device, knode_parent) : NULL;
+       struct device *dev = NULL;
+       struct device_private *p;
+
+       if (n) {
+               p = to_device_private_parent(n);
+               dev = p->device;
+       }
+       return dev;
+}
+
+/**
+ * device_get_devnode - path of device node file
+ * @dev: device
+ * @mode: returned file access mode
+ * @tmp: possibly allocated string
+ *
+ * Return the relative path of a possible device node.
+ * Non-default names may need to allocate a memory to compose
+ * a name. This memory is returned in tmp and needs to be
+ * freed by the caller.
+ */
+const char *device_get_devnode(struct device *dev,
+                              umode_t *mode, const char **tmp)
+{
+       char *s;
+
+       *tmp = NULL;
+
+       /* the device type may provide a specific name */
+       if (dev->type && dev->type->devnode)
+               *tmp = dev->type->devnode(dev, mode);
+       if (*tmp)
+               return *tmp;
+
+       /* the class may provide a specific name */
+       if (dev->class && dev->class->devnode)
+               *tmp = dev->class->devnode(dev, mode);
+       if (*tmp)
+               return *tmp;
+
+       /* return name without allocation, tmp == NULL */
+       if (strchr(dev_name(dev), '!') == NULL)
+               return dev_name(dev);
+
+       /* replace '!' in the name with '/' */
+       *tmp = kstrdup(dev_name(dev), GFP_KERNEL);
+       if (!*tmp)
+               return NULL;
+       while ((s = strchr(*tmp, '!')))
+               s[0] = '/';
+       return *tmp;
 }
 
 /**
@@ -1116,7 +1300,10 @@ int device_for_each_child(struct device *parent, void *data,
        struct device *child;
        int error = 0;
 
-       klist_iter_init(&parent->klist_children, &i);
+       if (!parent->p)
+               return 0;
+
+       klist_iter_init(&parent->p->klist_children, &i);
        while ((child = next_device(&i)) && !error)
                error = fn(child, data);
        klist_iter_exit(&i);
@@ -1147,7 +1334,7 @@ struct device *device_find_child(struct device *parent, void *data,
        if (!parent)
                return NULL;
 
-       klist_iter_init(&parent->klist_children, &i);
+       klist_iter_init(&parent->p->klist_children, &i);
        while ((child = next_device(&i)))
                if (match(child, data) && get_device(child))
                        break;
@@ -1196,10 +1383,105 @@ EXPORT_SYMBOL_GPL(put_device);
 EXPORT_SYMBOL_GPL(device_create_file);
 EXPORT_SYMBOL_GPL(device_remove_file);
 
+struct root_device {
+       struct device dev;
+       struct module *owner;
+};
+
+inline struct root_device *to_root_device(struct device *d)
+{
+       return container_of(d, struct root_device, dev);
+}
+
+static void root_device_release(struct device *dev)
+{
+       kfree(to_root_device(dev));
+}
+
+/**
+ * __root_device_register - allocate and register a root device
+ * @name: root device name
+ * @owner: owner module of the root device, usually THIS_MODULE
+ *
+ * This function allocates a root device and registers it
+ * using device_register(). In order to free the returned
+ * device, use root_device_unregister().
+ *
+ * Root devices are dummy devices which allow other devices
+ * to be grouped under /sys/devices. Use this function to
+ * allocate a root device and then use it as the parent of
+ * any device which should appear under /sys/devices/{name}
+ *
+ * The /sys/devices/{name} directory will also contain a
+ * 'module' symlink which points to the @owner directory
+ * in sysfs.
+ *
+ * Returns &struct device pointer on success, or ERR_PTR() on error.
+ *
+ * Note: You probably want to use root_device_register().
+ */
+struct device *__root_device_register(const char *name, struct module *owner)
+{
+       struct root_device *root;
+       int err = -ENOMEM;
+
+       root = kzalloc(sizeof(struct root_device), GFP_KERNEL);
+       if (!root)
+               return ERR_PTR(err);
+
+       err = dev_set_name(&root->dev, "%s", name);
+       if (err) {
+               kfree(root);
+               return ERR_PTR(err);
+       }
+
+       root->dev.release = root_device_release;
+
+       err = device_register(&root->dev);
+       if (err) {
+               put_device(&root->dev);
+               return ERR_PTR(err);
+       }
+
+#ifdef CONFIG_MODULES  /* gotta find a "cleaner" way to do this */
+       if (owner) {
+               struct module_kobject *mk = &owner->mkobj;
+
+               err = sysfs_create_link(&root->dev.kobj, &mk->kobj, "module");
+               if (err) {
+                       device_unregister(&root->dev);
+                       return ERR_PTR(err);
+               }
+               root->owner = owner;
+       }
+#endif
+
+       return &root->dev;
+}
+EXPORT_SYMBOL_GPL(__root_device_register);
+
+/**
+ * root_device_unregister - unregister and free a root device
+ * @dev: device going away
+ *
+ * This function unregisters and cleans up a device that was created by
+ * root_device_register().
+ */
+void root_device_unregister(struct device *dev)
+{
+       struct root_device *root = to_root_device(dev);
+
+       if (root->owner)
+               sysfs_remove_link(&root->dev.kobj, "module");
+
+       device_unregister(dev);
+}
+EXPORT_SYMBOL_GPL(root_device_unregister);
+
 
 static void device_create_release(struct device *dev)
 {
-       pr_debug("device: '%s': %s\n", dev->bus_id, __func__);
+       pr_debug("device: '%s': %s\n", dev_name(dev), __func__);
        kfree(dev);
 }
 
@@ -1223,6 +1505,8 @@ static void device_create_release(struct device *dev)
  * Any further sysfs files that might be required can be created using this
  * pointer.
  *
+ * Returns &struct device pointer on success, or ERR_PTR() on error.
+ *
  * Note: the struct class passed to this function must have previously
  * been created with a call to class_create().
  */
@@ -1248,7 +1532,10 @@ struct device *device_create_vargs(struct class *class, struct device *parent,
        dev->release = device_create_release;
        dev_set_drvdata(dev, drvdata);
 
-       vsnprintf(dev->bus_id, BUS_ID_SIZE, fmt, args);
+       retval = kobject_set_name_vargs(&dev->kobj, fmt, args);
+       if (retval)
+               goto error;
+
        retval = device_register(dev);
        if (retval)
                goto error;
@@ -1280,6 +1567,8 @@ EXPORT_SYMBOL_GPL(device_create_vargs);
  * Any further sysfs files that might be required can be created using this
  * pointer.
  *
+ * Returns &struct device pointer on success, or ERR_PTR() on error.
+ *
  * Note: the struct class passed to this function must have previously
  * been created with a call to class_create().
  */
@@ -1327,8 +1616,42 @@ EXPORT_SYMBOL_GPL(device_destroy);
  * device_rename - renames a device
  * @dev: the pointer to the struct device to be renamed
  * @new_name: the new name of the device
+ *
+ * It is the responsibility of the caller to provide mutual
+ * exclusion between two different calls of device_rename
+ * on the same device to ensure that new_name is valid and
+ * won't conflict with other devices.
+ *
+ * Note: Don't call this function.  Currently, the networking layer calls this
+ * function, but that will change.  The following text from Kay Sievers offers
+ * some insight:
+ *
+ * Renaming devices is racy at many levels, symlinks and other stuff are not
+ * replaced atomically, and you get a "move" uevent, but it's not easy to
+ * connect the event to the old and new device. Device nodes are not renamed at
+ * all, there isn't even support for that in the kernel now.
+ *
+ * In the meantime, during renaming, your target name might be taken by another
+ * driver, creating conflicts. Or the old name is taken directly after you
+ * renamed it -- then you get events for the same DEVPATH, before you even see
+ * the "move" event. It's just a mess, and nothing new should ever rely on
+ * kernel device renaming. Besides that, it's not even implemented now for
+ * other things than (driver-core wise very simple) network devices.
+ *
+ * We are currently about to change network renaming in udev to completely
+ * disallow renaming of devices in the same namespace as the kernel uses,
+ * because we can't solve the problems properly, that arise with swapping names
+ * of multiple interfaces without races. Means, renaming of eth[0-9]* will only
+ * be allowed to some other name than eth[0-9]*, for the aforementioned
+ * reasons.
+ *
+ * Make up a "real" name in the driver before you register anything, or add
+ * some other attributes for userspace to find the device, or use udev to add
+ * symlinks -- but never rename kernel devices later, it's a complete mess. We
+ * don't even want to get into that and try to implement the missing pieces in
+ * the core. We really have other pieces to fix in the driver core mess. :)
  */
-int device_rename(struct device *dev, char *new_name)
+int device_rename(struct device *dev, const char *new_name)
 {
        char *old_class_name = NULL;
        char *new_class_name = NULL;
@@ -1339,50 +1662,25 @@ int device_rename(struct device *dev, char *new_name)
        if (!dev)
                return -EINVAL;
 
-       pr_debug("device: '%s': %s: renaming to '%s'\n", dev->bus_id,
+       pr_debug("device: '%s': %s: renaming to '%s'\n", dev_name(dev),
                 __func__, new_name);
 
-#ifdef CONFIG_SYSFS_DEPRECATED
-       if ((dev->class) && (dev->parent))
-               old_class_name = make_class_name(dev->class->name, &dev->kobj);
-#endif
-
-       old_device_name = kmalloc(BUS_ID_SIZE, GFP_KERNEL);
+       old_device_name = kstrdup(dev_name(dev), GFP_KERNEL);
        if (!old_device_name) {
                error = -ENOMEM;
                goto out;
        }
-       strlcpy(old_device_name, dev->bus_id, BUS_ID_SIZE);
-       strlcpy(dev->bus_id, new_name, BUS_ID_SIZE);
 
-       error = kobject_rename(&dev->kobj, new_name);
-       if (error) {
-               strlcpy(dev->bus_id, old_device_name, BUS_ID_SIZE);
-               goto out;
-       }
-
-#ifdef CONFIG_SYSFS_DEPRECATED
-       if (old_class_name) {
-               new_class_name = make_class_name(dev->class->name, &dev->kobj);
-               if (new_class_name) {
-                       error = sysfs_create_link_nowarn(&dev->parent->kobj,
-                                                        &dev->kobj,
-                                                        new_class_name);
-                       if (error)
-                               goto out;
-                       sysfs_remove_link(&dev->parent->kobj, old_class_name);
-               }
-       }
-#else
        if (dev->class) {
-               error = sysfs_create_link_nowarn(&dev->class->p->class_subsys.kobj,
-                                                &dev->kobj, dev->bus_id);
+               error = sysfs_rename_link(&dev->class->p->subsys.kobj,
+                       &dev->kobj, old_device_name, new_name);
                if (error)
                        goto out;
-               sysfs_remove_link(&dev->class->p->class_subsys.kobj,
-                                 old_device_name);
        }
-#endif
+
+       error = kobject_rename(&dev->kobj, new_name);
+       if (error)
+               goto out;
 
 out:
        put_device(dev);
@@ -1400,48 +1698,23 @@ static int device_move_class_links(struct device *dev,
                                   struct device *new_parent)
 {
        int error = 0;
-#ifdef CONFIG_SYSFS_DEPRECATED
-       char *class_name;
 
-       class_name = make_class_name(dev->class->name, &dev->kobj);
-       if (!class_name) {
-               error = -ENOMEM;
-               goto out;
-       }
-       if (old_parent) {
-               sysfs_remove_link(&dev->kobj, "device");
-               sysfs_remove_link(&old_parent->kobj, class_name);
-       }
-       if (new_parent) {
-               error = sysfs_create_link(&dev->kobj, &new_parent->kobj,
-                                         "device");
-               if (error)
-                       goto out;
-               error = sysfs_create_link(&new_parent->kobj, &dev->kobj,
-                                         class_name);
-               if (error)
-                       sysfs_remove_link(&dev->kobj, "device");
-       } else
-               error = 0;
-out:
-       kfree(class_name);
-       return error;
-#else
        if (old_parent)
                sysfs_remove_link(&dev->kobj, "device");
        if (new_parent)
                error = sysfs_create_link(&dev->kobj, &new_parent->kobj,
                                          "device");
        return error;
-#endif
 }
 
 /**
  * device_move - moves a device to a new parent
  * @dev: the pointer to the struct device to be moved
  * @new_parent: the new parent of the device (can by NULL)
+ * @dpm_order: how to reorder the dpm_list
  */
-int device_move(struct device *dev, struct device *new_parent)
+int device_move(struct device *dev, struct device *new_parent,
+               enum dpm_order dpm_order)
 {
        int error;
        struct device *old_parent;
@@ -1451,11 +1724,12 @@ int device_move(struct device *dev, struct device *new_parent)
        if (!dev)
                return -EINVAL;
 
+       device_pm_lock();
        new_parent = get_device(new_parent);
        new_parent_kobj = get_device_parent(dev, new_parent);
 
-       pr_debug("device: '%s': %s: moving to '%s'\n", dev->bus_id,
-                __func__, new_parent ? new_parent->bus_id : "<NULL>");
+       pr_debug("device: '%s': %s: moving to '%s'\n", dev_name(dev),
+                __func__, new_parent ? dev_name(new_parent) : "<NULL>");
        error = kobject_move(&dev->kobj, new_parent_kobj);
        if (error) {
                cleanup_glue_dir(dev, new_parent_kobj);
@@ -1465,9 +1739,10 @@ int device_move(struct device *dev, struct device *new_parent)
        old_parent = dev->parent;
        dev->parent = new_parent;
        if (old_parent)
-               klist_remove(&dev->knode_parent);
+               klist_remove(&dev->p->knode_parent);
        if (new_parent) {
-               klist_add_tail(&dev->knode_parent, &new_parent->klist_children);
+               klist_add_tail(&dev->p->knode_parent,
+                              &new_parent->p->klist_children);
                set_dev_node(dev, dev_to_node(new_parent));
        }
 
@@ -1479,11 +1754,11 @@ int device_move(struct device *dev, struct device *new_parent)
                device_move_class_links(dev, new_parent, old_parent);
                if (!kobject_move(&dev->kobj, &old_parent->kobj)) {
                        if (new_parent)
-                               klist_remove(&dev->knode_parent);
+                               klist_remove(&dev->p->knode_parent);
                        dev->parent = old_parent;
                        if (old_parent) {
-                               klist_add_tail(&dev->knode_parent,
-                                              &old_parent->klist_children);
+                               klist_add_tail(&dev->p->knode_parent,
+                                              &old_parent->p->klist_children);
                                set_dev_node(dev, dev_to_node(old_parent));
                        }
                }
@@ -1491,9 +1766,23 @@ int device_move(struct device *dev, struct device *new_parent)
                put_device(new_parent);
                goto out;
        }
+       switch (dpm_order) {
+       case DPM_ORDER_NONE:
+               break;
+       case DPM_ORDER_DEV_AFTER_PARENT:
+               device_pm_move_after(dev, new_parent);
+               break;
+       case DPM_ORDER_PARENT_BEFORE_DEV:
+               device_pm_move_before(new_parent, dev);
+               break;
+       case DPM_ORDER_DEV_LAST:
+               device_pm_move_last(dev);
+               break;
+       }
 out_put:
        put_device(old_parent);
 out:
+       device_pm_unlock();
        put_device(dev);
        return error;
 }
@@ -1504,10 +1793,29 @@ EXPORT_SYMBOL_GPL(device_move);
  */
 void device_shutdown(void)
 {
-       struct device *dev, *devn;
+       struct device *dev;
+
+       spin_lock(&devices_kset->list_lock);
+       /*
+        * Walk the devices list backward, shutting down each in turn.
+        * Beware that device unplug events may also start pulling
+        * devices offline, even as the system is shutting down.
+        */
+       while (!list_empty(&devices_kset->list)) {
+               dev = list_entry(devices_kset->list.prev, struct device,
+                               kobj.entry);
+               get_device(dev);
+               /*
+                * Make sure the device is off the kset list, in the
+                * event that dev->*->shutdown() doesn't remove it.
+                */
+               list_del_init(&dev->kobj.entry);
+               spin_unlock(&devices_kset->list_lock);
+
+               /* Don't allow any more runtime suspends */
+               pm_runtime_get_noresume(dev);
+               pm_runtime_barrier(dev);
 
-       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);
@@ -1515,8 +1823,75 @@ void device_shutdown(void)
                        dev_dbg(dev, "shutdown\n");
                        dev->driver->shutdown(dev);
                }
+               put_device(dev);
+
+               spin_lock(&devices_kset->list_lock);
        }
-       kobject_put(sysfs_dev_char_kobj);
-       kobject_put(sysfs_dev_block_kobj);
-       kobject_put(dev_kobj);
+       spin_unlock(&devices_kset->list_lock);
+       async_synchronize_full();
 }
+
+/*
+ * Device logging functions
+ */
+
+#ifdef CONFIG_PRINTK
+
+int __dev_printk(const char *level, const struct device *dev,
+                struct va_format *vaf)
+{
+       if (!dev)
+               return printk("%s(NULL device *): %pV", level, vaf);
+
+       return printk("%s%s %s: %pV",
+                     level, dev_driver_string(dev), dev_name(dev), vaf);
+}
+EXPORT_SYMBOL(__dev_printk);
+
+int dev_printk(const char *level, const struct device *dev,
+              const char *fmt, ...)
+{
+       struct va_format vaf;
+       va_list args;
+       int r;
+
+       va_start(args, fmt);
+
+       vaf.fmt = fmt;
+       vaf.va = &args;
+
+       r = __dev_printk(level, dev, &vaf);
+       va_end(args);
+
+       return r;
+}
+EXPORT_SYMBOL(dev_printk);
+
+#define define_dev_printk_level(func, kern_level)              \
+int func(const struct device *dev, const char *fmt, ...)       \
+{                                                              \
+       struct va_format vaf;                                   \
+       va_list args;                                           \
+       int r;                                                  \
+                                                               \
+       va_start(args, fmt);                                    \
+                                                               \
+       vaf.fmt = fmt;                                          \
+       vaf.va = &args;                                         \
+                                                               \
+       r = __dev_printk(kern_level, dev, &vaf);                \
+       va_end(args);                                           \
+                                                               \
+       return r;                                               \
+}                                                              \
+EXPORT_SYMBOL(func);
+
+define_dev_printk_level(dev_emerg, KERN_EMERG);
+define_dev_printk_level(dev_alert, KERN_ALERT);
+define_dev_printk_level(dev_crit, KERN_CRIT);
+define_dev_printk_level(dev_err, KERN_ERR);
+define_dev_printk_level(dev_warn, KERN_WARNING);
+define_dev_printk_level(dev_notice, KERN_NOTICE);
+define_dev_printk_level(_dev_info, KERN_INFO);
+
+#endif