summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPatrick Mochel <mochel@osdl.org>2002-12-01 11:22:05 -0600
committerPatrick Mochel <mochel@osdl.org>2002-12-01 11:22:05 -0600
commitfc8aae5360008cf232c5f5bdc65b772a73a248c2 (patch)
treeab799d6f76a95ac0e2a0a88dda05da3086eba2f1
parent93186e2388e34c792afb4a09c6d99768d0d0dd94 (diff)
driver model: reinstate bus iterators.
This replaces the bus iterators bus_for_each_dev() and bus_for_each_drv(). Though no one in the kernel was using these, the MCA bus updates that are about to appear depend on them. They both now take a start pointer, which is the item to begin walking the list from, if it is not NULL.
-rw-r--r--drivers/base/bus.c90
-rw-r--r--include/linux/device.h9
2 files changed, 98 insertions, 1 deletions
diff --git a/drivers/base/bus.c b/drivers/base/bus.c
index d18effa7f981..ca5ef19aa4a9 100644
--- a/drivers/base/bus.c
+++ b/drivers/base/bus.c
@@ -133,6 +133,91 @@ struct subsystem bus_subsys = {
/**
+ * bus_for_each_dev - device iterator.
+ * @bus: bus type.
+ * @start: device to start iterating from.
+ * @data: data for the callback.
+ * @fn: function to be called for each device.
+ *
+ * Iterate over @bus's list of devices, and call @fn for each,
+ * passing it @data. If @start is not NULL, we use that device to
+ * begin iterating from.
+ *
+ * We check the return of @fn each time. If it returns anything
+ * other than 0, we break out and return that value.
+ *
+ * NOTE: The device that returns a non-zero value is not retained
+ * in any way, nor is its refcount incremented. If the caller needs
+ * to retain this data, it should do, and increment the reference
+ * count in the supplied callback.
+ */
+int bus_for_each_dev(struct bus_type * bus, struct device * start,
+ void * data, int (*fn)(struct device *, void *))
+{
+ struct list_head * head, * entry;
+ int error = 0;
+
+ if (!(bus = get_bus(bus)))
+ return -EINVAL;
+
+ head = start ? &start->bus_list : &bus->devices;
+
+ down_read(&bus->subsys.rwsem);
+ list_for_each(entry,head) {
+ struct device * dev = get_device(to_dev(entry));
+ error = fn(dev,data);
+ put_device(dev);
+ if (error)
+ break;
+ }
+ up_read(&bus->subsys.rwsem);
+ return error;
+}
+
+/**
+ * bus_for_each_drv - driver iterator
+ * @bus: bus we're dealing with.
+ * @start: driver to start iterating on.
+ * @data: data to pass to the callback.
+ * @fn: function to call for each driver.
+ *
+ * This is nearly identical to the device iterator above.
+ * We iterate over each driver that belongs to @bus, and call
+ * @fn for each. If @fn returns anything but 0, we break out
+ * and return it. If @start is not NULL, we use it as the head
+ * of the list.
+ *
+ * NOTE: we don't return the driver that returns a non-zero
+ * value, nor do we leave the reference count incremented for that
+ * driver. If the caller needs to know that info, it must set it
+ * in the callback. It must also be sure to increment the refcount
+ * so it doesn't disappear before returning to the caller.
+ */
+
+int bus_for_each_drv(struct bus_type * bus, struct device_driver * start,
+ void * data, int (*fn)(struct device_driver *, void *))
+{
+ struct list_head * head, * entry;
+ int error = 0;
+
+ if(!(bus = get_bus(bus)))
+ return -EINVAL;
+
+ head = start ? &start->bus_list : &bus->drivers;
+
+ down_read(&bus->subsys.rwsem);
+ list_for_each(entry,head) {
+ struct device_driver * drv = get_driver(to_drv(entry));
+ error = fn(drv,data);
+ put_driver(drv);
+ if(error)
+ break;
+ }
+ up_read(&bus->subsys.rwsem);
+ return error;
+}
+
+/**
* attach - add device to driver.
* @dev: device.
*
@@ -190,7 +275,7 @@ static int bus_match(struct device * dev, struct device_driver * drv)
*/
static int device_attach(struct device * dev)
{
- struct bus_type * bus = dev->bus;
+ struct bus_type * bus = dev->bus;
struct list_head * entry;
int error = 0;
@@ -455,6 +540,9 @@ static int __init bus_subsys_init(void)
core_initcall(bus_subsys_init);
+EXPORT_SYMBOL(bus_for_each_dev);
+EXPORT_SYMBOL(bus_for_each_drv);
+
EXPORT_SYMBOL(bus_add_device);
EXPORT_SYMBOL(bus_remove_device);
EXPORT_SYMBOL(bus_register);
diff --git a/include/linux/device.h b/include/linux/device.h
index 9835d4fcdb12..435159cb14b8 100644
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -85,6 +85,15 @@ extern struct bus_type * get_bus(struct bus_type * bus);
extern void put_bus(struct bus_type * bus);
+/* iterator helpers for buses */
+
+int bus_for_each_dev(struct bus_type * bus, struct device * start, void * data,
+ int (*fn)(struct device *, void *));
+
+int bus_for_each_drv(struct bus_type * bus, struct device_driver * start,
+ void * data, int (*fn)(struct device_driver *, void *));
+
+
/* driverfs interface for exporting bus attributes */
struct bus_attribute {