]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/base/bus.c
driver core: move knode_bus into private structure
[linux-2.6-omap-h63xx.git] / drivers / base / bus.c
index ef522ae5548092f83ddabcbf36d7a54ad56f7282..0f0a5044467223b4ac4379565b289d8033d451b1 100644 (file)
@@ -253,7 +253,14 @@ static ssize_t store_drivers_probe(struct bus_type *bus,
 static struct device *next_device(struct klist_iter *i)
 {
        struct klist_node *n = klist_next(i);
-       return n ? container_of(n, struct device, knode_bus) : NULL;
+       struct device *dev = NULL;
+       struct device_private *dev_prv;
+
+       if (n) {
+               dev_prv = to_device_private_bus(n);
+               dev = dev_prv->device;
+       }
+       return dev;
 }
 
 /**
@@ -286,7 +293,7 @@ int bus_for_each_dev(struct bus_type *bus, struct device *start,
                return -EINVAL;
 
        klist_iter_init_node(&bus->p->klist_devices, &i,
-                            (start ? &start->knode_bus : NULL));
+                            (start ? &start->p->knode_bus : NULL));
        while ((dev = next_device(&i)) && !error)
                error = fn(dev, data);
        klist_iter_exit(&i);
@@ -320,7 +327,7 @@ struct device *bus_find_device(struct bus_type *bus,
                return NULL;
 
        klist_iter_init_node(&bus->p->klist_devices, &i,
-                            (start ? &start->knode_bus : NULL));
+                            (start ? &start->p->knode_bus : NULL));
        while ((dev = next_device(&i)))
                if (match(dev, data) && get_device(dev))
                        break;
@@ -333,9 +340,7 @@ static int match_name(struct device *dev, void *data)
 {
        const char *name = data;
 
-       if (strcmp(name, dev->bus_id) == 0)
-               return 1;
-       return 0;
+       return sysfs_streq(name, dev_name(dev));
 }
 
 /**
@@ -463,12 +468,12 @@ int bus_add_device(struct device *dev)
        int error = 0;
 
        if (bus) {
-               pr_debug("bus: '%s': add device %s\n", bus->name, dev->bus_id);
+               pr_debug("bus: '%s': add device %s\n", bus->name, dev_name(dev));
                error = device_add_attrs(bus, dev);
                if (error)
                        goto out_put;
                error = sysfs_create_link(&bus->p->devices_kset->kobj,
-                                               &dev->kobj, dev->bus_id);
+                                               &dev->kobj, dev_name(dev));
                if (error)
                        goto out_id;
                error = sysfs_create_link(&dev->kobj,
@@ -484,7 +489,7 @@ int bus_add_device(struct device *dev)
 out_deprecated:
        sysfs_remove_link(&dev->kobj, "subsystem");
 out_subsys:
-       sysfs_remove_link(&bus->p->devices_kset->kobj, dev->bus_id);
+       sysfs_remove_link(&bus->p->devices_kset->kobj, dev_name(dev));
 out_id:
        device_remove_attrs(bus, dev);
 out_put:
@@ -509,7 +514,8 @@ void bus_attach_device(struct device *dev)
                        ret = device_attach(dev);
                WARN_ON(ret < 0);
                if (ret >= 0)
-                       klist_add_tail(&dev->knode_bus, &bus->p->klist_devices);
+                       klist_add_tail(&dev->p->knode_bus,
+                                      &bus->p->klist_devices);
        }
 }
 
@@ -528,13 +534,13 @@ void bus_remove_device(struct device *dev)
                sysfs_remove_link(&dev->kobj, "subsystem");
                remove_deprecated_bus_links(dev);
                sysfs_remove_link(&dev->bus->p->devices_kset->kobj,
-                                 dev->bus_id);
+                                 dev_name(dev));
                device_remove_attrs(dev->bus, dev);
-               if (klist_node_attached(&dev->knode_bus))
-                       klist_del(&dev->knode_bus);
+               if (klist_node_attached(&dev->p->knode_bus))
+                       klist_del(&dev->p->knode_bus);
 
                pr_debug("bus: '%s': remove device %s\n",
-                        dev->bus->name, dev->bus_id);
+                        dev->bus->name, dev_name(dev));
                device_release_driver(dev);
                bus_put(dev->bus);
        }
@@ -833,14 +839,16 @@ static void bus_remove_attrs(struct bus_type *bus)
 
 static void klist_devices_get(struct klist_node *n)
 {
-       struct device *dev = container_of(n, struct device, knode_bus);
+       struct device_private *dev_prv = to_device_private_bus(n);
+       struct device *dev = dev_prv->device;
 
        get_device(dev);
 }
 
 static void klist_devices_put(struct klist_node *n)
 {
-       struct device *dev = container_of(n, struct device, knode_bus);
+       struct device_private *dev_prv = to_device_private_bus(n);
+       struct device *dev = dev_prv->device;
 
        put_device(dev);
 }
@@ -982,6 +990,60 @@ struct klist *bus_get_device_klist(struct bus_type *bus)
 }
 EXPORT_SYMBOL_GPL(bus_get_device_klist);
 
+/*
+ * Yes, this forcably breaks the klist abstraction temporarily.  It
+ * just wants to sort the klist, not change reference counts and
+ * take/drop locks rapidly in the process.  It does all this while
+ * holding the lock for the list, so objects can't otherwise be
+ * added/removed while we're swizzling.
+ */
+static void device_insertion_sort_klist(struct device *a, struct list_head *list,
+                                       int (*compare)(const struct device *a,
+                                                       const struct device *b))
+{
+       struct list_head *pos;
+       struct klist_node *n;
+       struct device_private *dev_prv;
+       struct device *b;
+
+       list_for_each(pos, list) {
+               n = container_of(pos, struct klist_node, n_node);
+               dev_prv = to_device_private_bus(n);
+               b = dev_prv->device;
+               if (compare(a, b) <= 0) {
+                       list_move_tail(&a->p->knode_bus.n_node,
+                                      &b->p->knode_bus.n_node);
+                       return;
+               }
+       }
+       list_move_tail(&a->p->knode_bus.n_node, list);
+}
+
+void bus_sort_breadthfirst(struct bus_type *bus,
+                          int (*compare)(const struct device *a,
+                                         const struct device *b))
+{
+       LIST_HEAD(sorted_devices);
+       struct list_head *pos, *tmp;
+       struct klist_node *n;
+       struct device_private *dev_prv;
+       struct device *dev;
+       struct klist *device_klist;
+
+       device_klist = bus_get_device_klist(bus);
+
+       spin_lock(&device_klist->k_lock);
+       list_for_each_safe(pos, tmp, &device_klist->k_list) {
+               n = container_of(pos, struct klist_node, n_node);
+               dev_prv = to_device_private_bus(n);
+               dev = dev_prv->device;
+               device_insertion_sort_klist(dev, &sorted_devices, compare);
+       }
+       list_splice(&sorted_devices, &device_klist->k_list);
+       spin_unlock(&device_klist->k_lock);
+}
+EXPORT_SYMBOL_GPL(bus_sort_breadthfirst);
+
 int __init buses_init(void)
 {
        bus_kset = kset_create_and_add("bus", &bus_uevent_ops, NULL);