1
2
3
4
5
6
7
8
9
10
11
12
13#undef DEBUG
14
15#include <linux/kobject.h>
16#include <linux/string.h>
17#include <linux/module.h>
18#include <linux/stat.h>
19
20
21
22
23
24
25
26
27
28
29
30
31
32static int populate_dir(struct kobject * kobj)
33{
34 struct kobj_type * t = get_ktype(kobj);
35 struct attribute * attr;
36 int error = 0;
37 int i;
38
39 if (t && t->default_attrs) {
40 for (i = 0; (attr = t->default_attrs[i]); i++) {
41 if ((error = sysfs_create_file(kobj,attr)))
42 break;
43 }
44 }
45 return error;
46}
47
48static int create_dir(struct kobject * kobj)
49{
50 int error = 0;
51 if (kobject_name(kobj)) {
52 error = sysfs_create_dir(kobj);
53 if (!error) {
54 if ((error = populate_dir(kobj)))
55 sysfs_remove_dir(kobj);
56 }
57 }
58 return error;
59}
60
61
62static inline struct kobject * to_kobj(struct list_head * entry)
63{
64 return container_of(entry,struct kobject,entry);
65}
66
67
68#ifdef CONFIG_HOTPLUG
69static int get_kobj_path_length(struct kset *kset, struct kobject *kobj)
70{
71 int length = 1;
72 struct kobject * parent = kobj;
73
74
75
76
77
78 do {
79 length += strlen(kobject_name(parent)) + 1;
80 parent = parent->parent;
81 } while (parent);
82 return length;
83}
84
85static void fill_kobj_path(struct kset *kset, struct kobject *kobj, char *path, int length)
86{
87 struct kobject * parent;
88
89 --length;
90 for (parent = kobj; parent; parent = parent->parent) {
91 int cur = strlen(kobject_name(parent));
92
93 length -= cur;
94 strncpy (path + length, kobject_name(parent), cur);
95 *(path + --length) = '/';
96 }
97
98 pr_debug("%s: path = '%s'\n",__FUNCTION__,path);
99}
100
101#define BUFFER_SIZE 1024
102#define NUM_ENVP 32
103static unsigned long sequence_num;
104static spinlock_t sequence_lock = SPIN_LOCK_UNLOCKED;
105
106static void kset_hotplug(const char *action, struct kset *kset,
107 struct kobject *kobj)
108{
109 char *argv [3];
110 char **envp = NULL;
111 char *buffer = NULL;
112 char *scratch;
113 int i = 0;
114 int retval;
115 int kobj_path_length;
116 char *kobj_path = NULL;
117 char *name = NULL;
118 unsigned long seq;
119
120
121
122 if (kset->hotplug_ops->filter) {
123 if (!kset->hotplug_ops->filter(kset, kobj))
124 return;
125 }
126
127 pr_debug ("%s\n", __FUNCTION__);
128
129 if (!hotplug_path[0])
130 return;
131
132 envp = kmalloc(NUM_ENVP * sizeof (char *), GFP_KERNEL);
133 if (!envp)
134 return;
135 memset (envp, 0x00, NUM_ENVP * sizeof (char *));
136
137 buffer = kmalloc(BUFFER_SIZE, GFP_KERNEL);
138 if (!buffer)
139 goto exit;
140
141 if (kset->hotplug_ops->name)
142 name = kset->hotplug_ops->name(kset, kobj);
143 if (name == NULL)
144 name = kset->kobj.name;
145
146 argv [0] = hotplug_path;
147 argv [1] = name;
148 argv [2] = 0;
149
150
151 envp [i++] = "HOME=/";
152 envp [i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
153
154 scratch = buffer;
155
156 envp [i++] = scratch;
157 scratch += sprintf(scratch, "ACTION=%s", action) + 1;
158
159 spin_lock(&sequence_lock);
160 seq = sequence_num++;
161 spin_unlock(&sequence_lock);
162
163 envp [i++] = scratch;
164 scratch += sprintf(scratch, "SEQNUM=%ld", seq) + 1;
165
166 kobj_path_length = get_kobj_path_length (kset, kobj);
167 kobj_path = kmalloc (kobj_path_length, GFP_KERNEL);
168 if (!kobj_path)
169 goto exit;
170 memset (kobj_path, 0x00, kobj_path_length);
171 fill_kobj_path (kset, kobj, kobj_path, kobj_path_length);
172
173 envp [i++] = scratch;
174 scratch += sprintf (scratch, "DEVPATH=%s", kobj_path) + 1;
175
176 if (kset->hotplug_ops->hotplug) {
177
178 retval = kset->hotplug_ops->hotplug (kset, kobj,
179 &envp[i], NUM_ENVP - i, scratch,
180 BUFFER_SIZE - (scratch - buffer));
181 if (retval) {
182 pr_debug ("%s - hotplug() returned %d\n",
183 __FUNCTION__, retval);
184 goto exit;
185 }
186 }
187
188 pr_debug ("%s: %s %s %s %s %s %s\n", __FUNCTION__, argv[0], argv[1],
189 envp[0], envp[1], envp[2], envp[3]);
190 retval = call_usermodehelper (argv[0], argv, envp, 0);
191 if (retval)
192 pr_debug ("%s - call_usermodehelper returned %d\n",
193 __FUNCTION__, retval);
194
195exit:
196 kfree(kobj_path);
197 kfree(buffer);
198 kfree(envp);
199 return;
200}
201#else
202static void kset_hotplug(const char *action, struct kset *kset,
203 struct kobject *kobj)
204{
205 return;
206}
207#endif
208
209
210
211
212
213
214void kobject_init(struct kobject * kobj)
215{
216 atomic_set(&kobj->refcount,1);
217 INIT_LIST_HEAD(&kobj->entry);
218 kobj->kset = kset_get(kobj->kset);
219}
220
221
222
223
224
225
226
227
228
229
230
231
232static void unlink(struct kobject * kobj)
233{
234 if (kobj->kset) {
235 down_write(&kobj->kset->subsys->rwsem);
236 list_del_init(&kobj->entry);
237 up_write(&kobj->kset->subsys->rwsem);
238 }
239 kobject_put(kobj);
240}
241
242
243
244
245
246
247int kobject_add(struct kobject * kobj)
248{
249 int error = 0;
250 struct kobject * parent;
251 struct kobject * top_kobj;
252
253 if (!(kobj = kobject_get(kobj)))
254 return -ENOENT;
255 if (!kobj->k_name)
256 kobj->k_name = kobj->name;
257 parent = kobject_get(kobj->parent);
258
259 pr_debug("kobject %s: registering. parent: %s, set: %s\n",
260 kobject_name(kobj), parent ? kobject_name(parent) : "<NULL>",
261 kobj->kset ? kobj->kset->kobj.name : "<NULL>" );
262
263 if (kobj->kset) {
264 down_write(&kobj->kset->subsys->rwsem);
265
266 if (!parent)
267 parent = kobject_get(&kobj->kset->kobj);
268
269 list_add_tail(&kobj->entry,&kobj->kset->list);
270 up_write(&kobj->kset->subsys->rwsem);
271 }
272 kobj->parent = parent;
273
274 error = create_dir(kobj);
275 if (error) {
276 unlink(kobj);
277 if (parent)
278 kobject_put(parent);
279 } else {
280
281
282 top_kobj = kobj;
283 if (!top_kobj->kset && top_kobj->parent) {
284 do {
285 top_kobj = top_kobj->parent;
286 } while (!top_kobj->kset && top_kobj->parent);
287 }
288
289 if (top_kobj->kset && top_kobj->kset->hotplug_ops)
290 kset_hotplug("add", top_kobj->kset, kobj);
291 }
292 return error;
293}
294
295
296
297
298
299
300
301int kobject_register(struct kobject * kobj)
302{
303 int error = 0;
304 if (kobj) {
305 kobject_init(kobj);
306 error = kobject_add(kobj);
307 if (error) {
308 printk("kobject_register failed for %s (%d)\n",
309 kobject_name(kobj),error);
310 dump_stack();
311 }
312 } else
313 error = -EINVAL;
314 return error;
315}
316
317
318
319
320
321
322
323
324
325
326
327
328int kobject_set_name(struct kobject * kobj, const char * fmt, ...)
329{
330 int error = 0;
331 int limit = KOBJ_NAME_LEN;
332 int need;
333 va_list args;
334 char * name;
335
336 va_start(args,fmt);
337
338
339
340 need = vsnprintf(kobj->name,limit,fmt,args);
341 if (need < limit)
342 name = kobj->name;
343 else {
344
345
346
347 name = kmalloc(need,GFP_KERNEL);
348 if (!name) {
349 error = -ENOMEM;
350 goto Done;
351 }
352 limit = need;
353 need = vsnprintf(name,limit,fmt,args);
354
355
356 if (need > limit) {
357 kfree(name);
358 error = -EFAULT;
359 goto Done;
360 }
361 }
362
363
364 if (kobj->k_name && kobj->k_name != kobj->name)
365 kfree(kobj->k_name);
366
367
368 kobj->k_name = name;
369 Done:
370 va_end(args);
371 return error;
372}
373
374EXPORT_SYMBOL(kobject_set_name);
375
376
377
378
379
380
381
382
383void kobject_rename(struct kobject * kobj, char *new_name)
384{
385 kobj = kobject_get(kobj);
386 if (!kobj)
387 return;
388 sysfs_rename_dir(kobj, new_name);
389 kobject_put(kobj);
390}
391
392
393
394
395
396
397void kobject_del(struct kobject * kobj)
398{
399 struct kobject * top_kobj;
400
401
402
403 top_kobj = kobj;
404 if (!top_kobj->kset && top_kobj->parent) {
405 do {
406 top_kobj = top_kobj->parent;
407 } while (!top_kobj->kset && top_kobj->parent);
408 }
409
410 if (top_kobj->kset && top_kobj->kset->hotplug_ops)
411 kset_hotplug("remove", top_kobj->kset, kobj);
412
413 sysfs_remove_dir(kobj);
414 unlink(kobj);
415}
416
417
418
419
420
421
422void kobject_unregister(struct kobject * kobj)
423{
424 pr_debug("kobject %s: unregistering\n",kobject_name(kobj));
425 kobject_del(kobj);
426 kobject_put(kobj);
427}
428
429
430
431
432
433
434struct kobject * kobject_get(struct kobject * kobj)
435{
436 struct kobject * ret = kobj;
437
438 if (kobj) {
439 WARN_ON(!atomic_read(&kobj->refcount));
440 atomic_inc(&kobj->refcount);
441 } else
442 ret = NULL;
443 return ret;
444}
445
446
447
448
449
450
451void kobject_cleanup(struct kobject * kobj)
452{
453 struct kobj_type * t = get_ktype(kobj);
454 struct kset * s = kobj->kset;
455 struct kobject * parent = kobj->parent;
456
457 pr_debug("kobject %s: cleaning up\n",kobject_name(kobj));
458 if (kobj->k_name != kobj->name)
459 kfree(kobj->k_name);
460 kobj->k_name = NULL;
461 if (t && t->release)
462 t->release(kobj);
463 if (s)
464 kset_put(s);
465 if (parent)
466 kobject_put(parent);
467}
468
469
470
471
472
473
474
475
476void kobject_put(struct kobject * kobj)
477{
478 if (atomic_dec_and_test(&kobj->refcount))
479 kobject_cleanup(kobj);
480}
481
482
483
484
485
486
487
488void kset_init(struct kset * k)
489{
490 kobject_init(&k->kobj);
491 INIT_LIST_HEAD(&k->list);
492}
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509int kset_add(struct kset * k)
510{
511 if (!k->kobj.parent && !k->kobj.kset && k->subsys)
512 k->kobj.parent = &k->subsys->kset.kobj;
513
514 return kobject_add(&k->kobj);
515}
516
517
518
519
520
521
522
523int kset_register(struct kset * k)
524{
525 kset_init(k);
526 return kset_add(k);
527}
528
529
530
531
532
533
534
535void kset_unregister(struct kset * k)
536{
537 kobject_unregister(&k->kobj);
538}
539
540
541
542
543
544
545
546
547
548
549
550struct kobject * kset_find_obj(struct kset * kset, const char * name)
551{
552 struct list_head * entry;
553 struct kobject * ret = NULL;
554
555 down_read(&kset->subsys->rwsem);
556 list_for_each(entry,&kset->list) {
557 struct kobject * k = to_kobj(entry);
558 if (!strcmp(kobject_name(k),name)) {
559 ret = k;
560 break;
561 }
562 }
563 up_read(&kset->subsys->rwsem);
564 return ret;
565}
566
567
568void subsystem_init(struct subsystem * s)
569{
570 init_rwsem(&s->rwsem);
571 kset_init(&s->kset);
572}
573
574
575
576
577
578
579
580
581
582
583int subsystem_register(struct subsystem * s)
584{
585 int error;
586
587 subsystem_init(s);
588 pr_debug("subsystem %s: registering\n",s->kset.kobj.name);
589
590 if (!(error = kset_add(&s->kset))) {
591 if (!s->kset.subsys)
592 s->kset.subsys = s;
593 }
594 return error;
595}
596
597void subsystem_unregister(struct subsystem * s)
598{
599 pr_debug("subsystem %s: unregistering\n",s->kset.kobj.name);
600 kset_unregister(&s->kset);
601}
602
603
604
605
606
607
608
609
610int subsys_create_file(struct subsystem * s, struct subsys_attribute * a)
611{
612 int error = 0;
613 if (subsys_get(s)) {
614 error = sysfs_create_file(&s->kset.kobj,&a->attr);
615 subsys_put(s);
616 }
617 return error;
618}
619
620
621
622
623
624
625
626
627void subsys_remove_file(struct subsystem * s, struct subsys_attribute * a)
628{
629 if (subsys_get(s)) {
630 sysfs_remove_file(&s->kset.kobj,&a->attr);
631 subsys_put(s);
632 }
633}
634
635
636EXPORT_SYMBOL(kobject_init);
637EXPORT_SYMBOL(kobject_register);
638EXPORT_SYMBOL(kobject_unregister);
639EXPORT_SYMBOL(kobject_get);
640EXPORT_SYMBOL(kobject_put);
641
642EXPORT_SYMBOL(kset_register);
643EXPORT_SYMBOL(kset_unregister);
644EXPORT_SYMBOL(kset_find_obj);
645
646EXPORT_SYMBOL(subsystem_init);
647EXPORT_SYMBOL(subsystem_register);
648EXPORT_SYMBOL(subsystem_unregister);
649EXPORT_SYMBOL(subsys_create_file);
650EXPORT_SYMBOL(subsys_remove_file);
651