Commit fc8aae53 authored by Patrick Mochel's avatar Patrick Mochel

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.
parent 93186e23
......@@ -132,6 +132,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.
......@@ -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);
......
......@@ -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 {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment