driver core: bus: implement bus_get/put() without the private pointer
[linux-2.6-microblaze.git] / drivers / base / bus.c
index 4ec6dba..8f46ab8 100644 (file)
@@ -24,6 +24,9 @@
 /* /sys/devices/system */
 static struct kset *system_kset;
 
+/* /sys/bus */
+static struct kset *bus_kset;
+
 #define to_bus_attr(_attr) container_of(_attr, struct bus_attribute, attr)
 
 /*
@@ -39,19 +42,63 @@ static struct kset *system_kset;
 static int __must_check bus_rescan_devices_helper(struct device *dev,
                                                void *data);
 
+/**
+ * bus_to_subsys - Turn a struct bus_type into a struct subsys_private
+ *
+ * @bus: pointer to the struct bus_type to look up
+ *
+ * The driver core internals needs to work on the subsys_private structure, not
+ * the external struct bus_type pointer.  This function walks the list of
+ * registered busses in the system and finds the matching one and returns the
+ * internal struct subsys_private that relates to that bus.
+ *
+ * Note, the reference count of the return value is INCREMENTED if it is not
+ * NULL.  A call to subsys_put() must be done when finished with the pointer in
+ * order for it to be properly freed.
+ */
+static struct subsys_private *bus_to_subsys(const struct bus_type *bus)
+{
+       struct subsys_private *sp = NULL;
+       struct kobject *kobj;
+
+       if (!bus)
+               return NULL;
+
+       spin_lock(&bus_kset->list_lock);
+
+       if (list_empty(&bus_kset->list))
+               goto done;
+
+       list_for_each_entry(kobj, &bus_kset->list, entry) {
+               struct kset *kset = container_of(kobj, struct kset, kobj);
+
+               sp = container_of_const(kset, struct subsys_private, subsys);
+               if (sp->bus == bus)
+                       goto done;
+       }
+       sp = NULL;
+done:
+       sp = subsys_get(sp);
+       spin_unlock(&bus_kset->list_lock);
+       return sp;
+}
+
 static struct bus_type *bus_get(struct bus_type *bus)
 {
-       if (bus) {
-               kset_get(&bus->p->subsys);
+       struct subsys_private *sp = bus_to_subsys(bus);
+
+       if (sp)
                return bus;
-       }
        return NULL;
 }
 
-static void bus_put(struct bus_type *bus)
+static void bus_put(const struct bus_type *bus)
 {
-       if (bus)
-               kset_put(&bus->p->subsys);
+       struct subsys_private *sp = bus_to_subsys(bus);
+
+       /* two puts are required as the call to bus_to_subsys incremented it again */
+       subsys_put(sp);
+       subsys_put(sp);
 }
 
 static ssize_t drv_attr_show(struct kobject *kobj, struct attribute *attr,
@@ -91,7 +138,7 @@ static void driver_release(struct kobject *kobj)
        kfree(drv_priv);
 }
 
-static struct kobj_type driver_ktype = {
+static const struct kobj_type driver_ktype = {
        .sysfs_ops      = &driver_sysfs_ops,
        .release        = driver_release,
 };
@@ -154,11 +201,12 @@ static void bus_release(struct kobject *kobj)
        struct subsys_private *priv = to_subsys_private(kobj);
        struct bus_type *bus = priv->bus;
 
+       lockdep_unregister_key(&priv->lock_key);
        kfree(priv);
        bus->p = NULL;
 }
 
-static struct kobj_type bus_ktype = {
+static const struct kobj_type bus_ktype = {
        .sysfs_ops      = &bus_sysfs_ops,
        .release        = bus_release,
 };
@@ -176,8 +224,6 @@ static const struct kset_uevent_ops bus_uevent_ops = {
        .filter = bus_uevent_filter,
 };
 
-static struct kset *bus_kset;
-
 /* Manually detach a device from its associated driver. */
 static ssize_t unbind_store(struct device_driver *drv, const char *buf,
                            size_t count)
@@ -339,47 +385,6 @@ struct device *bus_find_device(struct bus_type *bus,
 }
 EXPORT_SYMBOL_GPL(bus_find_device);
 
-/**
- * subsys_find_device_by_id - find a device with a specific enumeration number
- * @subsys: subsystem
- * @id: index 'id' in struct device
- * @hint: device to check first
- *
- * Check the hint's next object and if it is a match return it directly,
- * otherwise, fall back to a full list search. Either way a reference for
- * the returned object is taken.
- */
-struct device *subsys_find_device_by_id(struct bus_type *subsys, unsigned int id,
-                                       struct device *hint)
-{
-       struct klist_iter i;
-       struct device *dev;
-
-       if (!subsys)
-               return NULL;
-
-       if (hint) {
-               klist_iter_init_node(&subsys->p->klist_devices, &i, &hint->p->knode_bus);
-               dev = next_device(&i);
-               if (dev && dev->id == id && get_device(dev)) {
-                       klist_iter_exit(&i);
-                       return dev;
-               }
-               klist_iter_exit(&i);
-       }
-
-       klist_iter_init_node(&subsys->p->klist_devices, &i, NULL);
-       while ((dev = next_device(&i))) {
-               if (dev->id == id && get_device(dev)) {
-                       klist_iter_exit(&i);
-                       return dev;
-               }
-       }
-       klist_iter_exit(&i);
-       return NULL;
-}
-EXPORT_SYMBOL_GPL(subsys_find_device_by_id);
-
 static struct device_driver *next_driver(struct klist_iter *i)
 {
        struct klist_node *n = klist_next(i);
@@ -784,7 +789,7 @@ int bus_register(struct bus_type *bus)
 {
        int retval;
        struct subsys_private *priv;
-       struct lock_class_key *key = &bus->lock_key;
+       struct lock_class_key *key;
 
        priv = kzalloc(sizeof(struct subsys_private), GFP_KERNEL);
        if (!priv)
@@ -826,6 +831,8 @@ int bus_register(struct bus_type *bus)
        }
 
        INIT_LIST_HEAD(&priv->interfaces);
+       key = &priv->lock_key;
+       lockdep_register_key(key);
        __mutex_init(&priv->mutex, "subsys mutex", key);
        klist_init(&priv->klist_devices, klist_devices_get, klist_devices_put);
        klist_init(&priv->klist_drivers, NULL, NULL);
@@ -891,17 +898,24 @@ int bus_unregister_notifier(struct bus_type *bus, struct notifier_block *nb)
 }
 EXPORT_SYMBOL_GPL(bus_unregister_notifier);
 
+void bus_notify(struct device *dev, enum bus_notifier_event value)
+{
+       struct bus_type *bus = dev->bus;
+
+       if (bus)
+               blocking_notifier_call_chain(&bus->p->bus_notifier, value, dev);
+}
+
 struct kset *bus_get_kset(struct bus_type *bus)
 {
        return &bus->p->subsys;
 }
 EXPORT_SYMBOL_GPL(bus_get_kset);
 
-struct klist *bus_get_device_klist(struct bus_type *bus)
+static struct klist *bus_get_device_klist(struct bus_type *bus)
 {
        return &bus->p->klist_devices;
 }
-EXPORT_SYMBOL_GPL(bus_get_device_klist);
 
 /*
  * Yes, this forcibly breaks the klist abstraction temporarily.  It
@@ -953,6 +967,11 @@ void bus_sort_breadthfirst(struct bus_type *bus,
 }
 EXPORT_SYMBOL_GPL(bus_sort_breadthfirst);
 
+struct subsys_dev_iter {
+       struct klist_iter               ki;
+       const struct device_type        *type;
+};
+
 /**
  * subsys_dev_iter_init - initialize subsys device iterator
  * @iter: subsys iterator to initialize
@@ -965,8 +984,8 @@ EXPORT_SYMBOL_GPL(bus_sort_breadthfirst);
  * otherwise if it is NULL, the iteration starts at the beginning of
  * the list.
  */
-void subsys_dev_iter_init(struct subsys_dev_iter *iter, struct bus_type *subsys,
-                         struct device *start, const struct device_type *type)
+static void subsys_dev_iter_init(struct subsys_dev_iter *iter, struct bus_type *subsys,
+                                struct device *start, const struct device_type *type)
 {
        struct klist_node *start_knode = NULL;
 
@@ -975,7 +994,6 @@ void subsys_dev_iter_init(struct subsys_dev_iter *iter, struct bus_type *subsys,
        klist_iter_init_node(&subsys->p->klist_devices, &iter->ki, start_knode);
        iter->type = type;
 }
-EXPORT_SYMBOL_GPL(subsys_dev_iter_init);
 
 /**
  * subsys_dev_iter_next - iterate to the next device
@@ -989,7 +1007,7 @@ EXPORT_SYMBOL_GPL(subsys_dev_iter_init);
  * free to do whatever it wants to do with the device including
  * calling back into subsys code.
  */
-struct device *subsys_dev_iter_next(struct subsys_dev_iter *iter)
+static struct device *subsys_dev_iter_next(struct subsys_dev_iter *iter)
 {
        struct klist_node *knode;
        struct device *dev;
@@ -1003,7 +1021,6 @@ struct device *subsys_dev_iter_next(struct subsys_dev_iter *iter)
                        return dev;
        }
 }
-EXPORT_SYMBOL_GPL(subsys_dev_iter_next);
 
 /**
  * subsys_dev_iter_exit - finish iteration
@@ -1012,11 +1029,10 @@ EXPORT_SYMBOL_GPL(subsys_dev_iter_next);
  * Finish an iteration.  Always call this function after iteration is
  * complete whether the iteration ran till the end or not.
  */
-void subsys_dev_iter_exit(struct subsys_dev_iter *iter)
+static void subsys_dev_iter_exit(struct subsys_dev_iter *iter)
 {
        klist_iter_exit(&iter->ki);
 }
-EXPORT_SYMBOL_GPL(subsys_dev_iter_exit);
 
 int subsys_interface_register(struct subsys_interface *sif)
 {