1
2
3
4
5
6
7
8
9
10
11
12
13#include <linux/attribute_container.h>
14#include <linux/device.h>
15#include <linux/kernel.h>
16#include <linux/slab.h>
17#include <linux/list.h>
18#include <linux/module.h>
19#include <linux/mutex.h>
20
21#include "base.h"
22
23
24
25struct internal_container {
26 struct klist_node node;
27 struct attribute_container *cont;
28 struct device classdev;
29};
30
31static void internal_container_klist_get(struct klist_node *n)
32{
33 struct internal_container *ic =
34 container_of(n, struct internal_container, node);
35 get_device(&ic->classdev);
36}
37
38static void internal_container_klist_put(struct klist_node *n)
39{
40 struct internal_container *ic =
41 container_of(n, struct internal_container, node);
42 put_device(&ic->classdev);
43}
44
45
46
47
48
49
50
51
52
53struct attribute_container *
54attribute_container_classdev_to_container(struct device *classdev)
55{
56 struct internal_container *ic =
57 container_of(classdev, struct internal_container, classdev);
58 return ic->cont;
59}
60EXPORT_SYMBOL_GPL(attribute_container_classdev_to_container);
61
62static LIST_HEAD(attribute_container_list);
63
64static DEFINE_MUTEX(attribute_container_mutex);
65
66
67
68
69
70
71
72int
73attribute_container_register(struct attribute_container *cont)
74{
75 INIT_LIST_HEAD(&cont->node);
76 klist_init(&cont->containers, internal_container_klist_get,
77 internal_container_klist_put);
78
79 mutex_lock(&attribute_container_mutex);
80 list_add_tail(&cont->node, &attribute_container_list);
81 mutex_unlock(&attribute_container_mutex);
82
83 return 0;
84}
85EXPORT_SYMBOL_GPL(attribute_container_register);
86
87
88
89
90
91
92int
93attribute_container_unregister(struct attribute_container *cont)
94{
95 int retval = -EBUSY;
96
97 mutex_lock(&attribute_container_mutex);
98 spin_lock(&cont->containers.k_lock);
99 if (!list_empty(&cont->containers.k_list))
100 goto out;
101 retval = 0;
102 list_del(&cont->node);
103 out:
104 spin_unlock(&cont->containers.k_lock);
105 mutex_unlock(&attribute_container_mutex);
106 return retval;
107
108}
109EXPORT_SYMBOL_GPL(attribute_container_unregister);
110
111
112static void attribute_container_release(struct device *classdev)
113{
114 struct internal_container *ic
115 = container_of(classdev, struct internal_container, classdev);
116 struct device *dev = classdev->parent;
117
118 kfree(ic);
119 put_device(dev);
120}
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140void
141attribute_container_add_device(struct device *dev,
142 int (*fn)(struct attribute_container *,
143 struct device *,
144 struct device *))
145{
146 struct attribute_container *cont;
147
148 mutex_lock(&attribute_container_mutex);
149 list_for_each_entry(cont, &attribute_container_list, node) {
150 struct internal_container *ic;
151
152 if (attribute_container_no_classdevs(cont))
153 continue;
154
155 if (!cont->match(cont, dev))
156 continue;
157
158 ic = kzalloc(sizeof(*ic), GFP_KERNEL);
159 if (!ic) {
160 dev_err(dev, "failed to allocate class container\n");
161 continue;
162 }
163
164 ic->cont = cont;
165 device_initialize(&ic->classdev);
166 ic->classdev.parent = get_device(dev);
167 ic->classdev.class = cont->class;
168 cont->class->dev_release = attribute_container_release;
169 dev_set_name(&ic->classdev, "%s", dev_name(dev));
170 if (fn)
171 fn(cont, dev, &ic->classdev);
172 else
173 attribute_container_add_class_device(&ic->classdev);
174 klist_add_tail(&ic->node, &cont->containers);
175 }
176 mutex_unlock(&attribute_container_mutex);
177}
178
179
180
181
182#define klist_for_each_entry(pos, head, member, iter) \
183 for (klist_iter_init(head, iter); (pos = ({ \
184 struct klist_node *n = klist_next(iter); \
185 n ? container_of(n, typeof(*pos), member) : \
186 ({ klist_iter_exit(iter) ; NULL; }); \
187 })) != NULL;)
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205void
206attribute_container_remove_device(struct device *dev,
207 void (*fn)(struct attribute_container *,
208 struct device *,
209 struct device *))
210{
211 struct attribute_container *cont;
212
213 mutex_lock(&attribute_container_mutex);
214 list_for_each_entry(cont, &attribute_container_list, node) {
215 struct internal_container *ic;
216 struct klist_iter iter;
217
218 if (attribute_container_no_classdevs(cont))
219 continue;
220
221 if (!cont->match(cont, dev))
222 continue;
223
224 klist_for_each_entry(ic, &cont->containers, node, &iter) {
225 if (dev != ic->classdev.parent)
226 continue;
227 klist_del(&ic->node);
228 if (fn)
229 fn(cont, dev, &ic->classdev);
230 else {
231 attribute_container_remove_attrs(&ic->classdev);
232 device_unregister(&ic->classdev);
233 }
234 }
235 }
236 mutex_unlock(&attribute_container_mutex);
237}
238
239static int
240do_attribute_container_device_trigger_safe(struct device *dev,
241 struct attribute_container *cont,
242 int (*fn)(struct attribute_container *,
243 struct device *, struct device *),
244 int (*undo)(struct attribute_container *,
245 struct device *, struct device *))
246{
247 int ret;
248 struct internal_container *ic, *failed;
249 struct klist_iter iter;
250
251 if (attribute_container_no_classdevs(cont))
252 return fn(cont, dev, NULL);
253
254 klist_for_each_entry(ic, &cont->containers, node, &iter) {
255 if (dev == ic->classdev.parent) {
256 ret = fn(cont, dev, &ic->classdev);
257 if (ret) {
258 failed = ic;
259 klist_iter_exit(&iter);
260 goto fail;
261 }
262 }
263 }
264 return 0;
265
266fail:
267 if (!undo)
268 return ret;
269
270
271 klist_for_each_entry(ic, &cont->containers, node, &iter) {
272 if (ic == failed) {
273 klist_iter_exit(&iter);
274 break;
275 }
276 if (dev == ic->classdev.parent)
277 undo(cont, dev, &ic->classdev);
278 }
279 return ret;
280}
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296int
297attribute_container_device_trigger_safe(struct device *dev,
298 int (*fn)(struct attribute_container *,
299 struct device *,
300 struct device *),
301 int (*undo)(struct attribute_container *,
302 struct device *,
303 struct device *))
304{
305 struct attribute_container *cont, *failed = NULL;
306 int ret = 0;
307
308 mutex_lock(&attribute_container_mutex);
309
310 list_for_each_entry(cont, &attribute_container_list, node) {
311
312 if (!cont->match(cont, dev))
313 continue;
314
315 ret = do_attribute_container_device_trigger_safe(dev, cont,
316 fn, undo);
317 if (ret) {
318 failed = cont;
319 break;
320 }
321 }
322
323 if (ret && !WARN_ON(!undo)) {
324 list_for_each_entry(cont, &attribute_container_list, node) {
325
326 if (failed == cont)
327 break;
328
329 if (!cont->match(cont, dev))
330 continue;
331
332 do_attribute_container_device_trigger_safe(dev, cont,
333 undo, NULL);
334 }
335 }
336
337 mutex_unlock(&attribute_container_mutex);
338 return ret;
339
340}
341
342
343
344
345
346
347
348
349
350
351
352void
353attribute_container_device_trigger(struct device *dev,
354 int (*fn)(struct attribute_container *,
355 struct device *,
356 struct device *))
357{
358 struct attribute_container *cont;
359
360 mutex_lock(&attribute_container_mutex);
361 list_for_each_entry(cont, &attribute_container_list, node) {
362 struct internal_container *ic;
363 struct klist_iter iter;
364
365 if (!cont->match(cont, dev))
366 continue;
367
368 if (attribute_container_no_classdevs(cont)) {
369 fn(cont, dev, NULL);
370 continue;
371 }
372
373 klist_for_each_entry(ic, &cont->containers, node, &iter) {
374 if (dev == ic->classdev.parent)
375 fn(cont, dev, &ic->classdev);
376 }
377 }
378 mutex_unlock(&attribute_container_mutex);
379}
380
381
382
383
384
385
386
387
388
389
390
391
392
393void
394attribute_container_trigger(struct device *dev,
395 int (*fn)(struct attribute_container *,
396 struct device *))
397{
398 struct attribute_container *cont;
399
400 mutex_lock(&attribute_container_mutex);
401 list_for_each_entry(cont, &attribute_container_list, node) {
402 if (cont->match(cont, dev))
403 fn(cont, dev);
404 }
405 mutex_unlock(&attribute_container_mutex);
406}
407
408
409
410
411
412
413
414
415
416int
417attribute_container_add_attrs(struct device *classdev)
418{
419 struct attribute_container *cont =
420 attribute_container_classdev_to_container(classdev);
421 struct device_attribute **attrs = cont->attrs;
422 int i, error;
423
424 BUG_ON(attrs && cont->grp);
425
426 if (!attrs && !cont->grp)
427 return 0;
428
429 if (cont->grp)
430 return sysfs_create_group(&classdev->kobj, cont->grp);
431
432 for (i = 0; attrs[i]; i++) {
433 sysfs_attr_init(&attrs[i]->attr);
434 error = device_create_file(classdev, attrs[i]);
435 if (error)
436 return error;
437 }
438
439 return 0;
440}
441
442
443
444
445
446
447
448
449
450
451int
452attribute_container_add_class_device(struct device *classdev)
453{
454 int error = device_add(classdev);
455
456 if (error)
457 return error;
458 return attribute_container_add_attrs(classdev);
459}
460
461
462
463
464
465
466
467int
468attribute_container_add_class_device_adapter(struct attribute_container *cont,
469 struct device *dev,
470 struct device *classdev)
471{
472 return attribute_container_add_class_device(classdev);
473}
474
475
476
477
478
479
480
481void
482attribute_container_remove_attrs(struct device *classdev)
483{
484 struct attribute_container *cont =
485 attribute_container_classdev_to_container(classdev);
486 struct device_attribute **attrs = cont->attrs;
487 int i;
488
489 if (!attrs && !cont->grp)
490 return;
491
492 if (cont->grp) {
493 sysfs_remove_group(&classdev->kobj, cont->grp);
494 return ;
495 }
496
497 for (i = 0; attrs[i]; i++)
498 device_remove_file(classdev, attrs[i]);
499}
500
501
502
503
504
505
506
507
508
509void
510attribute_container_class_device_del(struct device *classdev)
511{
512 attribute_container_remove_attrs(classdev);
513 device_del(classdev);
514}
515
516
517
518
519
520
521
522
523
524
525struct device *
526attribute_container_find_class_device(struct attribute_container *cont,
527 struct device *dev)
528{
529 struct device *cdev = NULL;
530 struct internal_container *ic;
531 struct klist_iter iter;
532
533 klist_for_each_entry(ic, &cont->containers, node, &iter) {
534 if (ic->classdev.parent == dev) {
535 cdev = &ic->classdev;
536
537 klist_iter_exit(&iter);
538 break;
539 }
540 }
541
542 return cdev;
543}
544EXPORT_SYMBOL_GPL(attribute_container_find_class_device);
545