regcache: Make sure we sync register 0 in an rbtree cache
[linux-2.6.git] / drivers / base / core.c
index 6ed6454..78445f4 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/kallsyms.h>
 #include <linux/mutex.h>
 #include <linux/async.h>
+#include <linux/pm_runtime.h>
 
 #include "base.h"
 #include "power/power.h"
@@ -338,6 +339,35 @@ 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,
                             const struct attribute_group **groups)
 {
@@ -371,19 +401,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);
@@ -395,6 +428,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);
@@ -405,15 +441,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);
+       }
 }
 
 
@@ -610,7 +648,7 @@ class_dir_create_and_add(struct class *class, struct kobject *parent_kobj)
        dir->class = class;
        kobject_init(&dir->kobj, &class_dir_ktype);
 
-       dir->kobj.kset = &class->p->class_dirs;
+       dir->kobj.kset = &class->p->glue_dirs;
 
        retval = kobject_add(&dir->kobj, parent_kobj, "%s", class->name);
        if (retval < 0) {
@@ -635,7 +673,7 @@ static struct kobject *get_device_parent(struct device *dev,
                if (sysfs_deprecated && dev->class == &block_class) {
                        if (parent && parent->class == &block_class)
                                return &parent->kobj;
-                       return &block_class.p->class_subsys.kobj;
+                       return &block_class.p->subsys.kobj;
                }
 #endif
 
@@ -654,13 +692,13 @@ static struct kobject *get_device_parent(struct device *dev,
                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);
+               spin_unlock(&dev->class->p->glue_dirs.list_lock);
                if (kobj) {
                        mutex_unlock(&gdp_mutex);
                        return kobj;
@@ -682,7 +720,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);
@@ -709,7 +747,7 @@ 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;
@@ -728,7 +766,7 @@ static int device_add_class_symlinks(struct device *dev)
 #endif
 
        /* link in the class directory pointing to the device */
-       error = sysfs_create_link(&dev->class->p->class_subsys.kobj,
+       error = sysfs_create_link(&dev->class->p->subsys.kobj,
                                  &dev->kobj, dev_name(dev));
        if (error)
                goto out_device;
@@ -756,7 +794,7 @@ static void device_remove_class_symlinks(struct device *dev)
        if (sysfs_deprecated && dev->class == &block_class)
                return;
 #endif
-       sysfs_delete_link(&dev->class->p->class_subsys.kobj, &dev->kobj, dev_name(dev));
+       sysfs_delete_link(&dev->class->p->subsys.kobj, &dev->kobj, dev_name(dev));
 }
 
 /**
@@ -947,7 +985,7 @@ int device_add(struct device *dev)
                mutex_lock(&dev->class->p->class_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,
@@ -1277,13 +1315,15 @@ EXPORT_SYMBOL_GPL(put_device);
 EXPORT_SYMBOL_GPL(device_create_file);
 EXPORT_SYMBOL_GPL(device_remove_file);
 
-struct root_device
-{
+struct root_device {
        struct device dev;
        struct module *owner;
 };
 
-#define to_root_device(dev) container_of(dev, struct root_device, dev)
+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)
 {
@@ -1513,6 +1553,35 @@ EXPORT_SYMBOL_GPL(device_destroy);
  * 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, const char *new_name)
 {
@@ -1535,7 +1604,7 @@ int device_rename(struct device *dev, const char *new_name)
        }
 
        if (dev->class) {
-               error = sysfs_rename_link(&dev->class->p->class_subsys.kobj,
+               error = sysfs_rename_link(&dev->class->p->subsys.kobj,
                        &dev->kobj, old_device_name, new_name);
                if (error)
                        goto out;
@@ -1674,6 +1743,8 @@ void device_shutdown(void)
                 */
                list_del_init(&dev->kobj.entry);
                spin_unlock(&devices_kset->list_lock);
+               /* Disable all device's runtime power management */
+               pm_runtime_disable(dev);
 
                if (dev->bus && dev->bus->shutdown) {
                        dev_dbg(dev, "shutdown\n");