diff options
Diffstat (limited to 'drivers/misc/enclosure.c')
-rw-r--r-- | drivers/misc/enclosure.c | 69 |
1 files changed, 49 insertions, 20 deletions
diff --git a/drivers/misc/enclosure.c b/drivers/misc/enclosure.c index 348443bdb23b..7b039306037f 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); |
@@ -295,6 +315,9 @@ int enclosure_add_device(struct enclosure_device *edev, int component, | |||
295 | 315 | ||
296 | cdev = &edev->component[component]; | 316 | cdev = &edev->component[component]; |
297 | 317 | ||
318 | if (cdev->dev == dev) | ||
319 | return -EEXIST; | ||
320 | |||
298 | if (cdev->dev) | 321 | if (cdev->dev) |
299 | enclosure_remove_links(cdev); | 322 | enclosure_remove_links(cdev); |
300 | 323 | ||
@@ -312,19 +335,25 @@ EXPORT_SYMBOL_GPL(enclosure_add_device); | |||
312 | * Returns zero on success or an error. | 335 | * Returns zero on success or an error. |
313 | * | 336 | * |
314 | */ | 337 | */ |
315 | int enclosure_remove_device(struct enclosure_device *edev, int component) | 338 | int enclosure_remove_device(struct enclosure_device *edev, struct device *dev) |
316 | { | 339 | { |
317 | struct enclosure_component *cdev; | 340 | struct enclosure_component *cdev; |
341 | int i; | ||
318 | 342 | ||
319 | if (!edev || component >= edev->components) | 343 | if (!edev || !dev) |
320 | return -EINVAL; | 344 | return -EINVAL; |
321 | 345 | ||
322 | cdev = &edev->component[component]; | 346 | for (i = 0; i < edev->components; i++) { |
323 | 347 | cdev = &edev->component[i]; | |
324 | device_del(&cdev->cdev); | 348 | if (cdev->dev == dev) { |
325 | put_device(cdev->dev); | 349 | enclosure_remove_links(cdev); |
326 | cdev->dev = NULL; | 350 | device_del(&cdev->cdev); |
327 | return device_add(&cdev->cdev); | 351 | put_device(dev); |
352 | cdev->dev = NULL; | ||
353 | return device_add(&cdev->cdev); | ||
354 | } | ||
355 | } | ||
356 | return -ENODEV; | ||
328 | } | 357 | } |
329 | EXPORT_SYMBOL_GPL(enclosure_remove_device); | 358 | EXPORT_SYMBOL_GPL(enclosure_remove_device); |
330 | 359 | ||