Commit e1e5aa9b authored by Patrick Mochel's avatar Patrick Mochel

Device Model: Add helpers bus_for_each_dev and bus_for_each_drv

- iterators for accessing bus's lists of devices and drivers
- does locking on bus for each list access
- does reference counting on objects as it grabs and releases them
- calls callback for each object in list
parent 21a16f65
......@@ -22,6 +22,91 @@ static struct driver_dir_entry bus_dir = {
mode: (S_IFDIR| S_IRWXU | S_IRUGO | S_IXUGO),
};
/**
* bus_for_each_dev - walk list of devices and do something to each
* @bus: bus in question
* @data: data for the callback
* @callback: caller-defined action to perform on each device
*
* Why do we do this? So we can guarantee proper locking and reference
* counting on devices as we touch each one.
*
* Algorithm:
* Take the bus lock and get the first node in the list. We increment
* the reference count and unlock the bus. If we have a device from a
* previous iteration, we decrement the reference count.
* After we call the callback, we get the next node in the list and loop.
* At the end, if @dev is not null, we still have it pinned, so we need
* to let it go.
*/
int bus_for_each_dev(struct bus_type * bus, void * data,
int (*callback)(struct device * dev, void * data))
{
struct device * next;
struct device * dev = NULL;
struct list_head * node;
int error = 0;
get_bus(bus);
read_lock(&bus->lock);
node = bus->devices.next;
while (node != &bus->devices) {
next = list_entry(node,struct device,bus_list);
get_device(next);
read_unlock(&bus->lock);
if (dev)
put_device(dev);
dev = next;
if ((error = callback(dev,data))) {
put_device(dev);
break;
}
read_lock(&bus->lock);
node = dev->bus_list.next;
}
read_unlock(&bus->lock);
if (dev)
put_device(dev);
put_bus(bus);
return error;
}
int bus_for_each_drv(struct bus_type * bus, void * data,
int (*callback)(struct device_driver * drv, void * data))
{
struct device_driver * next;
struct device_driver * drv = NULL;
struct list_head * node;
int error = 0;
/* pin bus in memory */
get_bus(bus);
read_lock(&bus->lock);
node = bus->drivers.next;
while (node != &bus->drivers) {
next = list_entry(node,struct device_driver,bus_list);
get_driver(next);
read_unlock(&bus->lock);
if (drv)
put_driver(drv);
drv = next;
if ((error = callback(drv,data))) {
put_driver(drv);
break;
}
read_lock(&bus->lock);
node = drv->bus_list.next;
}
read_unlock(&bus->lock);
if (drv)
put_driver(drv);
put_bus(bus);
return error;
}
/**
* bus_add_device - add device to bus
* @dev: device being added
......@@ -119,6 +204,8 @@ static int __init bus_init(void)
core_initcall(bus_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);
......
......@@ -54,7 +54,7 @@ enum {
};
struct device;
struct device_driver;
struct bus_type {
char * name;
......@@ -82,6 +82,11 @@ static inline struct bus_type * get_bus(struct bus_type * bus)
extern void put_bus(struct bus_type * bus);
extern int bus_for_each_dev(struct bus_type * bus, void * data,
int (*callback)(struct device * dev, void * data));
extern int bus_for_each_drv(struct bus_type * bus, void * data,
int (*callback)(struct device_driver * drv, void * data));
struct device_driver {
char * name;
......
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