aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/misc/enclosure.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/misc/enclosure.c')
-rw-r--r--drivers/misc/enclosure.c69
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);
33static struct class enclosure_class; 33static 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 */
44struct enclosure_device *enclosure_find(struct device *dev) 53struct 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 */
315int enclosure_remove_device(struct enclosure_device *edev, int component) 338int 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}
329EXPORT_SYMBOL_GPL(enclosure_remove_device); 358EXPORT_SYMBOL_GPL(enclosure_remove_device);
330 359