diff options
Diffstat (limited to 'drivers/base/attribute_container.c')
| -rw-r--r-- | drivers/base/attribute_container.c | 86 |
1 files changed, 76 insertions, 10 deletions
diff --git a/drivers/base/attribute_container.c b/drivers/base/attribute_container.c index ec615d854be9..373e7b728fa7 100644 --- a/drivers/base/attribute_container.c +++ b/drivers/base/attribute_container.c | |||
| @@ -22,11 +22,26 @@ | |||
| 22 | /* This is a private structure used to tie the classdev and the | 22 | /* This is a private structure used to tie the classdev and the |
| 23 | * container .. it should never be visible outside this file */ | 23 | * container .. it should never be visible outside this file */ |
| 24 | struct internal_container { | 24 | struct internal_container { |
| 25 | struct list_head node; | 25 | struct klist_node node; |
| 26 | struct attribute_container *cont; | 26 | struct attribute_container *cont; |
| 27 | struct class_device classdev; | 27 | struct class_device classdev; |
| 28 | }; | 28 | }; |
| 29 | 29 | ||
| 30 | static void internal_container_klist_get(struct klist_node *n) | ||
| 31 | { | ||
| 32 | struct internal_container *ic = | ||
| 33 | container_of(n, struct internal_container, node); | ||
| 34 | class_device_get(&ic->classdev); | ||
| 35 | } | ||
| 36 | |||
| 37 | static void internal_container_klist_put(struct klist_node *n) | ||
| 38 | { | ||
| 39 | struct internal_container *ic = | ||
| 40 | container_of(n, struct internal_container, node); | ||
| 41 | class_device_put(&ic->classdev); | ||
| 42 | } | ||
| 43 | |||
| 44 | |||
| 30 | /** | 45 | /** |
| 31 | * attribute_container_classdev_to_container - given a classdev, return the container | 46 | * attribute_container_classdev_to_container - given a classdev, return the container |
| 32 | * | 47 | * |
| @@ -57,7 +72,8 @@ int | |||
| 57 | attribute_container_register(struct attribute_container *cont) | 72 | attribute_container_register(struct attribute_container *cont) |
| 58 | { | 73 | { |
| 59 | INIT_LIST_HEAD(&cont->node); | 74 | INIT_LIST_HEAD(&cont->node); |
| 60 | INIT_LIST_HEAD(&cont->containers); | 75 | klist_init(&cont->containers,internal_container_klist_get, |
| 76 | internal_container_klist_put); | ||
| 61 | 77 | ||
| 62 | down(&attribute_container_mutex); | 78 | down(&attribute_container_mutex); |
| 63 | list_add_tail(&cont->node, &attribute_container_list); | 79 | list_add_tail(&cont->node, &attribute_container_list); |
| @@ -77,11 +93,13 @@ attribute_container_unregister(struct attribute_container *cont) | |||
| 77 | { | 93 | { |
| 78 | int retval = -EBUSY; | 94 | int retval = -EBUSY; |
| 79 | down(&attribute_container_mutex); | 95 | down(&attribute_container_mutex); |
| 80 | if (!list_empty(&cont->containers)) | 96 | spin_lock(&cont->containers.k_lock); |
| 97 | if (!list_empty(&cont->containers.k_list)) | ||
| 81 | goto out; | 98 | goto out; |
| 82 | retval = 0; | 99 | retval = 0; |
| 83 | list_del(&cont->node); | 100 | list_del(&cont->node); |
| 84 | out: | 101 | out: |
| 102 | spin_unlock(&cont->containers.k_lock); | ||
| 85 | up(&attribute_container_mutex); | 103 | up(&attribute_container_mutex); |
| 86 | return retval; | 104 | return retval; |
| 87 | 105 | ||
| @@ -140,7 +158,6 @@ attribute_container_add_device(struct device *dev, | |||
| 140 | continue; | 158 | continue; |
| 141 | } | 159 | } |
| 142 | memset(ic, 0, sizeof(struct internal_container)); | 160 | memset(ic, 0, sizeof(struct internal_container)); |
| 143 | INIT_LIST_HEAD(&ic->node); | ||
| 144 | ic->cont = cont; | 161 | ic->cont = cont; |
| 145 | class_device_initialize(&ic->classdev); | 162 | class_device_initialize(&ic->classdev); |
| 146 | ic->classdev.dev = get_device(dev); | 163 | ic->classdev.dev = get_device(dev); |
| @@ -151,11 +168,22 @@ attribute_container_add_device(struct device *dev, | |||
| 151 | fn(cont, dev, &ic->classdev); | 168 | fn(cont, dev, &ic->classdev); |
| 152 | else | 169 | else |
| 153 | attribute_container_add_class_device(&ic->classdev); | 170 | attribute_container_add_class_device(&ic->classdev); |
| 154 | list_add_tail(&ic->node, &cont->containers); | 171 | klist_add_tail(&ic->node, &cont->containers); |
| 155 | } | 172 | } |
| 156 | up(&attribute_container_mutex); | 173 | up(&attribute_container_mutex); |
| 157 | } | 174 | } |
| 158 | 175 | ||
| 176 | /* FIXME: can't break out of this unless klist_iter_exit is also | ||
| 177 | * called before doing the break | ||
| 178 | */ | ||
| 179 | #define klist_for_each_entry(pos, head, member, iter) \ | ||
| 180 | for (klist_iter_init(head, iter); (pos = ({ \ | ||
| 181 | struct klist_node *n = klist_next(iter); \ | ||
| 182 | n ? container_of(n, typeof(*pos), member) : \ | ||
| 183 | ({ klist_iter_exit(iter) ; NULL; }); \ | ||
| 184 | }) ) != NULL; ) | ||
| 185 | |||
| 186 | |||
| 159 | /** | 187 | /** |
| 160 | * attribute_container_remove_device - make device eligible for removal. | 188 | * attribute_container_remove_device - make device eligible for removal. |
| 161 | * | 189 | * |
| @@ -182,17 +210,19 @@ attribute_container_remove_device(struct device *dev, | |||
| 182 | 210 | ||
| 183 | down(&attribute_container_mutex); | 211 | down(&attribute_container_mutex); |
| 184 | list_for_each_entry(cont, &attribute_container_list, node) { | 212 | list_for_each_entry(cont, &attribute_container_list, node) { |
| 185 | struct internal_container *ic, *tmp; | 213 | struct internal_container *ic; |
| 214 | struct klist_iter iter; | ||
| 186 | 215 | ||
| 187 | if (attribute_container_no_classdevs(cont)) | 216 | if (attribute_container_no_classdevs(cont)) |
| 188 | continue; | 217 | continue; |
| 189 | 218 | ||
| 190 | if (!cont->match(cont, dev)) | 219 | if (!cont->match(cont, dev)) |
| 191 | continue; | 220 | continue; |
| 192 | list_for_each_entry_safe(ic, tmp, &cont->containers, node) { | 221 | |
| 222 | klist_for_each_entry(ic, &cont->containers, node, &iter) { | ||
| 193 | if (dev != ic->classdev.dev) | 223 | if (dev != ic->classdev.dev) |
| 194 | continue; | 224 | continue; |
| 195 | list_del(&ic->node); | 225 | klist_del(&ic->node); |
| 196 | if (fn) | 226 | if (fn) |
| 197 | fn(cont, dev, &ic->classdev); | 227 | fn(cont, dev, &ic->classdev); |
| 198 | else { | 228 | else { |
| @@ -225,12 +255,18 @@ attribute_container_device_trigger(struct device *dev, | |||
| 225 | 255 | ||
| 226 | down(&attribute_container_mutex); | 256 | down(&attribute_container_mutex); |
| 227 | list_for_each_entry(cont, &attribute_container_list, node) { | 257 | list_for_each_entry(cont, &attribute_container_list, node) { |
| 228 | struct internal_container *ic, *tmp; | 258 | struct internal_container *ic; |
| 259 | struct klist_iter iter; | ||
| 229 | 260 | ||
| 230 | if (!cont->match(cont, dev)) | 261 | if (!cont->match(cont, dev)) |
| 231 | continue; | 262 | continue; |
| 232 | 263 | ||
| 233 | list_for_each_entry_safe(ic, tmp, &cont->containers, node) { | 264 | if (attribute_container_no_classdevs(cont)) { |
| 265 | fn(cont, dev, NULL); | ||
| 266 | continue; | ||
| 267 | } | ||
| 268 | |||
| 269 | klist_for_each_entry(ic, &cont->containers, node, &iter) { | ||
| 234 | if (dev == ic->classdev.dev) | 270 | if (dev == ic->classdev.dev) |
| 235 | fn(cont, dev, &ic->classdev); | 271 | fn(cont, dev, &ic->classdev); |
| 236 | } | 272 | } |
| @@ -368,6 +404,36 @@ attribute_container_class_device_del(struct class_device *classdev) | |||
| 368 | } | 404 | } |
| 369 | EXPORT_SYMBOL_GPL(attribute_container_class_device_del); | 405 | EXPORT_SYMBOL_GPL(attribute_container_class_device_del); |
| 370 | 406 | ||
| 407 | /** | ||
| 408 | * attribute_container_find_class_device - find the corresponding class_device | ||
| 409 | * | ||
| 410 | * @cont: the container | ||
| 411 | * @dev: the generic device | ||
| 412 | * | ||
| 413 | * Looks up the device in the container's list of class devices and returns | ||
| 414 | * the corresponding class_device. | ||
| 415 | */ | ||
| 416 | struct class_device * | ||
| 417 | attribute_container_find_class_device(struct attribute_container *cont, | ||
| 418 | struct device *dev) | ||
| 419 | { | ||
| 420 | struct class_device *cdev = NULL; | ||
| 421 | struct internal_container *ic; | ||
| 422 | struct klist_iter iter; | ||
| 423 | |||
| 424 | klist_for_each_entry(ic, &cont->containers, node, &iter) { | ||
| 425 | if (ic->classdev.dev == dev) { | ||
| 426 | cdev = &ic->classdev; | ||
| 427 | /* FIXME: must exit iterator then break */ | ||
| 428 | klist_iter_exit(&iter); | ||
| 429 | break; | ||
| 430 | } | ||
| 431 | } | ||
| 432 | |||
| 433 | return cdev; | ||
| 434 | } | ||
| 435 | EXPORT_SYMBOL_GPL(attribute_container_find_class_device); | ||
| 436 | |||
| 371 | int __init | 437 | int __init |
| 372 | attribute_container_init(void) | 438 | attribute_container_init(void) |
| 373 | { | 439 | { |
