diff options
Diffstat (limited to 'drivers/misc/enclosure.c')
-rw-r--r-- | drivers/misc/enclosure.c | 44 |
1 files changed, 32 insertions, 12 deletions
diff --git a/drivers/misc/enclosure.c b/drivers/misc/enclosure.c index 348443bdb23b..789d12128c24 100644 --- a/drivers/misc/enclosure.c +++ b/drivers/misc/enclosure.c | |||
@@ -33,24 +33,44 @@ static DEFINE_MUTEX(container_list_lock); | |||
33 | static struct class enclosure_class; | 33 | static struct class enclosure_class; |
34 | 34 | ||
35 | /** | 35 | /** |
36 | * enclosure_find - find an enclosure given a device | 36 | * enclosure_find - find an enclosure given a parent device |
37 | * @dev: the device to find for | 37 | * @dev: the parent to match against |
38 | * @start: Optional enclosure device to start from (NULL if none) | ||
38 | * | 39 | * |
39 | * Looks through the list of registered enclosures to see | 40 | * Looks through the list of registered enclosures to find all those |
40 | * if it can find a match for a device. Returns NULL if no | 41 | * with @dev as a parent. Returns NULL if no enclosure is |
41 | * enclosure is found. Obtains a reference to the enclosure class | 42 | * found. @start can be used as a starting point to obtain multiple |
42 | * device which must be released with device_put(). | 43 | * enclosures per parent (should begin with NULL and then be set to |
44 | * each returned enclosure device). Obtains a reference to the | ||
45 | * enclosure class device which must be released with device_put(). | ||
46 | * If @start is not NULL, a reference must be taken on it which is | ||
47 | * released before returning (this allows a loop through all | ||
48 | * enclosures to exit with only the reference on the enclosure of | ||
49 | * interest held). Note that the @dev may correspond to the actual | ||
50 | * device housing the enclosure, in which case no iteration via @start | ||
51 | * is required. | ||
43 | */ | 52 | */ |
44 | struct enclosure_device *enclosure_find(struct device *dev) | 53 | struct enclosure_device *enclosure_find(struct device *dev, |
54 | struct enclosure_device *start) | ||
45 | { | 55 | { |
46 | struct enclosure_device *edev; | 56 | struct enclosure_device *edev; |
47 | 57 | ||
48 | mutex_lock(&container_list_lock); | 58 | mutex_lock(&container_list_lock); |
49 | list_for_each_entry(edev, &container_list, node) { | 59 | edev = list_prepare_entry(start, &container_list, node); |
50 | if (edev->edev.parent == dev) { | 60 | if (start) |
51 | get_device(&edev->edev); | 61 | put_device(&start->edev); |
52 | mutex_unlock(&container_list_lock); | 62 | |
53 | return edev; | 63 | list_for_each_entry_continue(edev, &container_list, node) { |
64 | struct device *parent = edev->edev.parent; | ||
65 | /* parent might not be immediate, so iterate up to | ||
66 | * the root of the tree if necessary */ | ||
67 | while (parent) { | ||
68 | if (parent == dev) { | ||
69 | get_device(&edev->edev); | ||
70 | mutex_unlock(&container_list_lock); | ||
71 | return edev; | ||
72 | } | ||
73 | parent = parent->parent; | ||
54 | } | 74 | } |
55 | } | 75 | } |
56 | mutex_unlock(&container_list_lock); | 76 | mutex_unlock(&container_list_lock); |