diff options
author | Linus Torvalds <torvalds@g5.osdl.org> | 2005-09-07 20:31:27 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2005-09-07 20:31:27 -0400 |
commit | 0481990b758628e12f4b0a9e15094e70cefc7cd1 (patch) | |
tree | 67a4b4b7acc6a688b87ef2a2d3ec0e296e6e480c /drivers/base | |
parent | db400b3c4ee89d384d9163836a55577abdae772d (diff) | |
parent | 17fa53da1239b8712c5cebbd72a74c713b6c2db9 (diff) |
Merge master.kernel.org:/pub/scm/linux/kernel/git/jejb/scsi-for-linus-2.6
Diffstat (limited to 'drivers/base')
-rw-r--r-- | drivers/base/attribute_container.c | 86 | ||||
-rw-r--r-- | drivers/base/transport_class.c | 19 |
2 files changed, 88 insertions, 17 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 | { |
diff --git a/drivers/base/transport_class.c b/drivers/base/transport_class.c index 6c2b447a3336..f25e7c6b2d27 100644 --- a/drivers/base/transport_class.c +++ b/drivers/base/transport_class.c | |||
@@ -7,7 +7,7 @@ | |||
7 | * This file is licensed under GPLv2 | 7 | * This file is licensed under GPLv2 |
8 | * | 8 | * |
9 | * The basic idea here is to allow any "device controller" (which | 9 | * The basic idea here is to allow any "device controller" (which |
10 | * would most often be a Host Bus Adapter" to use the services of one | 10 | * would most often be a Host Bus Adapter to use the services of one |
11 | * or more tranport classes for performing transport specific | 11 | * or more tranport classes for performing transport specific |
12 | * services. Transport specific services are things that the generic | 12 | * services. Transport specific services are things that the generic |
13 | * command layer doesn't want to know about (speed settings, line | 13 | * command layer doesn't want to know about (speed settings, line |
@@ -64,7 +64,9 @@ void transport_class_unregister(struct transport_class *tclass) | |||
64 | } | 64 | } |
65 | EXPORT_SYMBOL_GPL(transport_class_unregister); | 65 | EXPORT_SYMBOL_GPL(transport_class_unregister); |
66 | 66 | ||
67 | static int anon_transport_dummy_function(struct device *dev) | 67 | static int anon_transport_dummy_function(struct transport_container *tc, |
68 | struct device *dev, | ||
69 | struct class_device *cdev) | ||
68 | { | 70 | { |
69 | /* do nothing */ | 71 | /* do nothing */ |
70 | return 0; | 72 | return 0; |
@@ -115,9 +117,10 @@ static int transport_setup_classdev(struct attribute_container *cont, | |||
115 | struct class_device *classdev) | 117 | struct class_device *classdev) |
116 | { | 118 | { |
117 | struct transport_class *tclass = class_to_transport_class(cont->class); | 119 | struct transport_class *tclass = class_to_transport_class(cont->class); |
120 | struct transport_container *tcont = attribute_container_to_transport_container(cont); | ||
118 | 121 | ||
119 | if (tclass->setup) | 122 | if (tclass->setup) |
120 | tclass->setup(dev); | 123 | tclass->setup(tcont, dev, classdev); |
121 | 124 | ||
122 | return 0; | 125 | return 0; |
123 | } | 126 | } |
@@ -178,12 +181,14 @@ void transport_add_device(struct device *dev) | |||
178 | EXPORT_SYMBOL_GPL(transport_add_device); | 181 | EXPORT_SYMBOL_GPL(transport_add_device); |
179 | 182 | ||
180 | static int transport_configure(struct attribute_container *cont, | 183 | static int transport_configure(struct attribute_container *cont, |
181 | struct device *dev) | 184 | struct device *dev, |
185 | struct class_device *cdev) | ||
182 | { | 186 | { |
183 | struct transport_class *tclass = class_to_transport_class(cont->class); | 187 | struct transport_class *tclass = class_to_transport_class(cont->class); |
188 | struct transport_container *tcont = attribute_container_to_transport_container(cont); | ||
184 | 189 | ||
185 | if (tclass->configure) | 190 | if (tclass->configure) |
186 | tclass->configure(dev); | 191 | tclass->configure(tcont, dev, cdev); |
187 | 192 | ||
188 | return 0; | 193 | return 0; |
189 | } | 194 | } |
@@ -202,7 +207,7 @@ static int transport_configure(struct attribute_container *cont, | |||
202 | */ | 207 | */ |
203 | void transport_configure_device(struct device *dev) | 208 | void transport_configure_device(struct device *dev) |
204 | { | 209 | { |
205 | attribute_container_trigger(dev, transport_configure); | 210 | attribute_container_device_trigger(dev, transport_configure); |
206 | } | 211 | } |
207 | EXPORT_SYMBOL_GPL(transport_configure_device); | 212 | EXPORT_SYMBOL_GPL(transport_configure_device); |
208 | 213 | ||
@@ -215,7 +220,7 @@ static int transport_remove_classdev(struct attribute_container *cont, | |||
215 | struct transport_class *tclass = class_to_transport_class(cont->class); | 220 | struct transport_class *tclass = class_to_transport_class(cont->class); |
216 | 221 | ||
217 | if (tclass->remove) | 222 | if (tclass->remove) |
218 | tclass->remove(dev); | 223 | tclass->remove(tcont, dev, classdev); |
219 | 224 | ||
220 | if (tclass->remove != anon_transport_dummy_function) { | 225 | if (tclass->remove != anon_transport_dummy_function) { |
221 | if (tcont->statistics) | 226 | if (tcont->statistics) |