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]) != NULL; 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] = NULL;
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 %s\n", __FUNCTION__, argv[0], argv[1],
189 envp[0], envp[1], envp[2], envp[3], envp[4]);
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
202void kobject_hotplug(const char *action, struct kobject *kobj)
203{
204 struct kobject * top_kobj = kobj;
205
206
207
208 if (!top_kobj->kset && top_kobj->parent) {
209 do {
210 top_kobj = top_kobj->parent;
211 } while (!top_kobj->kset && top_kobj->parent);
212 }
213
214 if (top_kobj->kset && top_kobj->kset->hotplug_ops)
215 kset_hotplug(action, top_kobj->kset, kobj);
216}
217#else
218void kobject_hotplug(const char *action, struct kobject *kobj)
219{
220 return;
221}
222#endif
223
224
225
226
227
228
229void kobject_init(struct kobject * kobj)
230{
231 atomic_set(&kobj->refcount,1);
232 INIT_LIST_HEAD(&kobj->entry);
233 kobj->kset = kset_get(kobj->kset);
234}
235
236
237
238
239
240
241
242
243
244
245
246
247static void unlink(struct kobject * kobj)
248{
249 if (kobj->kset) {
250 down_write(&kobj->kset->subsys->rwsem);
251 list_del_init(&kobj->entry);
252 up_write(&kobj->kset->subsys->rwsem);
253 }
254 kobject_put(kobj);
255}
256
257
258
259
260
261
262int kobject_add(struct kobject * kobj)
263{
264 int error = 0;
265 struct kobject * parent;
266
267 if (!(kobj = kobject_get(kobj)))
268 return -ENOENT;
269 if (!kobj->k_name)
270 kobj->k_name = kobj->name;
271 parent = kobject_get(kobj->parent);
272
273 pr_debug("kobject %s: registering. parent: %s, set: %s\n",
274 kobject_name(kobj), parent ? kobject_name(parent) : "<NULL>",
275 kobj->kset ? kobj->kset->kobj.name : "<NULL>" );
276
277 if (kobj->kset) {
278 down_write(&kobj->kset->subsys->rwsem);
279
280 if (!parent)
281 parent = kobject_get(&kobj->kset->kobj);
282
283 list_add_tail(&kobj->entry,&kobj->kset->list);
284 up_write(&kobj->kset->subsys->rwsem);
285 }
286 kobj->parent = parent;
287
288 error = create_dir(kobj);
289 if (error) {
290 unlink(kobj);
291 if (parent)
292 kobject_put(parent);
293 } else {
294 kobject_hotplug("add", kobj);
295 }
296
297 return error;
298}
299
300
301
302
303
304
305
306int kobject_register(struct kobject * kobj)
307{
308 int error = 0;
309 if (kobj) {
310 kobject_init(kobj);
311 error = kobject_add(kobj);
312 if (error) {
313 printk("kobject_register failed for %s (%d)\n",
314 kobject_name(kobj),error);
315 dump_stack();
316 }
317 } else
318 error = -EINVAL;
319 return error;
320}
321
322
323
324
325
326
327
328
329
330
331
332
333int kobject_set_name(struct kobject * kobj, const char * fmt, ...)
334{
335 int error = 0;
336 int limit = KOBJ_NAME_LEN;
337 int need;
338 va_list args;
339 char * name;
340
341 va_start(args,fmt);
342
343
344
345 need = vsnprintf(kobj->name,limit,fmt,args);
346 if (need < limit)
347 name = kobj->name;
348 else {
349
350
351
352 limit = need + 1;
353 name = kmalloc(limit,GFP_KERNEL);
354 if (!name) {
355 error = -ENOMEM;
356 goto Done;
357 }
358 need = vsnprintf(name,limit,fmt,args);
359
360
361 if (need >= limit) {
362 kfree(name);
363 error = -EFAULT;
364 goto Done;
365 }
366 }
367
368
369 if (kobj->k_name && kobj->k_name != kobj->name)
370 kfree(kobj->k_name);
371
372
373 kobj->k_name = name;
374 Done:
375 va_end(args);
376 return error;
377}
378
379EXPORT_SYMBOL(kobject_set_name);
380
381
382
383
384
385
386
387
388int kobject_rename(struct kobject * kobj, char *new_name)
389{
390 int error = 0;
391
392 kobj = kobject_get(kobj);
393 if (!kobj)
394 return -EINVAL;
395 error = sysfs_rename_dir(kobj, new_name);
396 kobject_put(kobj);
397
398 return error;
399}
400
401
402
403
404
405
406void kobject_del(struct kobject * kobj)
407{
408 kobject_hotplug("remove", kobj);
409 sysfs_remove_dir(kobj);
410 unlink(kobj);
411}
412
413
414
415
416
417
418void kobject_unregister(struct kobject * kobj)
419{
420 pr_debug("kobject %s: unregistering\n",kobject_name(kobj));
421 kobject_del(kobj);
422 kobject_put(kobj);
423}
424
425
426
427
428
429
430struct kobject * kobject_get(struct kobject * kobj)
431{
432 if (kobj) {
433 WARN_ON(!atomic_read(&kobj->refcount));
434 atomic_inc(&kobj->refcount);
435 }
436 return kobj;
437}
438
439
440
441
442
443
444void kobject_cleanup(struct kobject * kobj)
445{
446 struct kobj_type * t = get_ktype(kobj);
447 struct kset * s = kobj->kset;
448 struct kobject * parent = kobj->parent;
449
450 pr_debug("kobject %s: cleaning up\n",kobject_name(kobj));
451 if (kobj->k_name != kobj->name)
452 kfree(kobj->k_name);
453 kobj->k_name = NULL;
454 if (t && t->release)
455 t->release(kobj);
456 if (s)
457 kset_put(s);
458 if (parent)
459 kobject_put(parent);
460}
461
462
463
464
465
466
467
468
469void kobject_put(struct kobject * kobj)
470{
471 if (atomic_dec_and_test(&kobj->refcount))
472 kobject_cleanup(kobj);
473}
474
475
476
477
478
479
480
481void kset_init(struct kset * k)
482{
483 kobject_init(&k->kobj);
484 INIT_LIST_HEAD(&k->list);
485}
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502int kset_add(struct kset * k)
503{
504 if (!k->kobj.parent && !k->kobj.kset && k->subsys)
505 k->kobj.parent = &k->subsys->kset.kobj;
506
507 return kobject_add(&k->kobj);
508}
509
510
511
512
513
514
515
516int kset_register(struct kset * k)
517{
518 kset_init(k);
519 return kset_add(k);
520}
521
522
523
524
525
526
527
528void kset_unregister(struct kset * k)
529{
530 kobject_unregister(&k->kobj);
531}
532
533
534
535
536
537
538
539
540
541
542
543
544struct kobject * kset_find_obj(struct kset * kset, const char * name)
545{
546 struct list_head * entry;
547 struct kobject * ret = NULL;
548
549 down_read(&kset->subsys->rwsem);
550 list_for_each(entry,&kset->list) {
551 struct kobject * k = to_kobj(entry);
552 if (kobject_name(k) && !strcmp(kobject_name(k),name)) {
553 ret = kobject_get(k);
554 break;
555 }
556 }
557 up_read(&kset->subsys->rwsem);
558 return ret;
559}
560
561
562void subsystem_init(struct subsystem * s)
563{
564 init_rwsem(&s->rwsem);
565 kset_init(&s->kset);
566}
567
568
569
570
571
572
573
574
575
576
577int subsystem_register(struct subsystem * s)
578{
579 int error;
580
581 subsystem_init(s);
582 pr_debug("subsystem %s: registering\n",s->kset.kobj.name);
583
584 if (!(error = kset_add(&s->kset))) {
585 if (!s->kset.subsys)
586 s->kset.subsys = s;
587 }
588 return error;
589}
590
591void subsystem_unregister(struct subsystem * s)
592{
593 pr_debug("subsystem %s: unregistering\n",s->kset.kobj.name);
594 kset_unregister(&s->kset);
595}
596
597
598
599
600
601
602
603
604int subsys_create_file(struct subsystem * s, struct subsys_attribute * a)
605{
606 int error = 0;
607 if (subsys_get(s)) {
608 error = sysfs_create_file(&s->kset.kobj,&a->attr);
609 subsys_put(s);
610 }
611 return error;
612}
613
614
615
616
617
618
619
620
621void subsys_remove_file(struct subsystem * s, struct subsys_attribute * a)
622{
623 if (subsys_get(s)) {
624 sysfs_remove_file(&s->kset.kobj,&a->attr);
625 subsys_put(s);
626 }
627}
628
629
630EXPORT_SYMBOL(kobject_init);
631EXPORT_SYMBOL(kobject_register);
632EXPORT_SYMBOL(kobject_unregister);
633EXPORT_SYMBOL(kobject_get);
634EXPORT_SYMBOL(kobject_put);
635EXPORT_SYMBOL(kobject_add);
636EXPORT_SYMBOL(kobject_del);
637EXPORT_SYMBOL(kobject_rename);
638EXPORT_SYMBOL(kobject_hotplug);
639
640EXPORT_SYMBOL(kset_register);
641EXPORT_SYMBOL(kset_unregister);
642EXPORT_SYMBOL(kset_find_obj);
643
644EXPORT_SYMBOL(subsystem_init);
645EXPORT_SYMBOL(subsystem_register);
646EXPORT_SYMBOL(subsystem_unregister);
647EXPORT_SYMBOL(subsys_create_file);
648EXPORT_SYMBOL(subsys_remove_file);
649