aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorKay Sievers <kay.sievers@vrfy.org>2007-03-13 22:25:56 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2007-04-27 13:57:28 -0400
commit864062457a2e444227bd368ca5f2a2b740de604f (patch)
tree38e516852ee9825b5ffe0b1f2e8abea0a88b1674 /drivers
parent00ed8e3dda47f8421b11da17e353d7db8c878121 (diff)
driver core: fix namespace issue with devices assigned to classes
- uses a kset in "struct class" to keep track of all directories belonging to this class - merges with the /sys/devices/virtual logic. - removes the namespace-dir if the last member of that class leaves the directory. There may be locking or refcounting fixes left, I stopped when it seemed to work with network and sound modules. :) From: Kay Sievers <kay.sievers@vrfy.org> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/base/class.c2
-rw-r--r--drivers/base/core.c82
2 files changed, 66 insertions, 18 deletions
diff --git a/drivers/base/class.c b/drivers/base/class.c
index d5968128be2b..80bbb2074636 100644
--- a/drivers/base/class.c
+++ b/drivers/base/class.c
@@ -145,6 +145,7 @@ int class_register(struct class * cls)
145 INIT_LIST_HEAD(&cls->children); 145 INIT_LIST_HEAD(&cls->children);
146 INIT_LIST_HEAD(&cls->devices); 146 INIT_LIST_HEAD(&cls->devices);
147 INIT_LIST_HEAD(&cls->interfaces); 147 INIT_LIST_HEAD(&cls->interfaces);
148 kset_init(&cls->class_dirs);
148 init_MUTEX(&cls->sem); 149 init_MUTEX(&cls->sem);
149 error = kobject_set_name(&cls->subsys.kset.kobj, "%s", cls->name); 150 error = kobject_set_name(&cls->subsys.kset.kobj, "%s", cls->name);
150 if (error) 151 if (error)
@@ -163,7 +164,6 @@ int class_register(struct class * cls)
163void class_unregister(struct class * cls) 164void class_unregister(struct class * cls)
164{ 165{
165 pr_debug("device class '%s': unregistering\n", cls->name); 166 pr_debug("device class '%s': unregistering\n", cls->name);
166 kobject_unregister(cls->virtual_dir);
167 remove_class_attrs(cls); 167 remove_class_attrs(cls);
168 subsystem_unregister(&cls->subsys); 168 subsystem_unregister(&cls->subsys);
169} 169}
diff --git a/drivers/base/core.c b/drivers/base/core.c
index db3a151be4a1..658eae5dacda 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -477,34 +477,58 @@ static struct kobject * get_device_parent(struct device *dev,
477 return NULL; 477 return NULL;
478} 478}
479#else 479#else
480static struct kobject * virtual_device_parent(struct device *dev) 480static struct kobject *virtual_device_parent(struct device *dev)
481{ 481{
482 if (!dev->class) 482 static struct kobject *virtual_dir = NULL;
483 return ERR_PTR(-ENODEV);
484
485 if (!dev->class->virtual_dir) {
486 static struct kobject *virtual_dir = NULL;
487 483
488 if (!virtual_dir) 484 if (!virtual_dir)
489 virtual_dir = kobject_add_dir(&devices_subsys.kset.kobj, "virtual"); 485 virtual_dir = kobject_add_dir(&devices_subsys.kset.kobj, "virtual");
490 dev->class->virtual_dir = kobject_add_dir(virtual_dir, dev->class->name);
491 }
492 486
493 return dev->class->virtual_dir; 487 return virtual_dir;
494} 488}
495 489
496static struct kobject * get_device_parent(struct device *dev, 490static struct kobject * get_device_parent(struct device *dev,
497 struct device *parent) 491 struct device *parent)
498{ 492{
499 /* if this is a class device, and has no parent, create one */ 493 if (dev->class) {
500 if ((dev->class) && (parent == NULL)) { 494 struct kobject *kobj = NULL;
501 return virtual_device_parent(dev); 495 struct kobject *parent_kobj;
502 } else if (parent) 496 struct kobject *k;
497
498 /*
499 * If we have no parent, we live in "virtual".
500 * Class-devices with a bus-device as parent, live
501 * in a class-directory to prevent namespace collisions.
502 */
503 if (parent == NULL)
504 parent_kobj = virtual_device_parent(dev);
505 else if (parent->class)
506 return &parent->kobj;
507 else
508 parent_kobj = &parent->kobj;
509
510 /* find our class-directory at the parent and reference it */
511 spin_lock(&dev->class->class_dirs.list_lock);
512 list_for_each_entry(k, &dev->class->class_dirs.list, entry)
513 if (k->parent == parent_kobj) {
514 kobj = kobject_get(k);
515 break;
516 }
517 spin_unlock(&dev->class->class_dirs.list_lock);
518 if (kobj)
519 return kobj;
520
521 /* or create a new class-directory at the parent device */
522 return kobject_kset_add_dir(&dev->class->class_dirs,
523 parent_kobj, dev->class->name);
524 }
525
526 if (parent)
503 return &parent->kobj; 527 return &parent->kobj;
504 return NULL; 528 return NULL;
505} 529}
506
507#endif 530#endif
531
508static int setup_parent(struct device *dev, struct device *parent) 532static int setup_parent(struct device *dev, struct device *parent)
509{ 533{
510 struct kobject *kobj; 534 struct kobject *kobj;
@@ -541,7 +565,6 @@ int device_add(struct device *dev)
541 pr_debug("DEV: registering device: ID = '%s'\n", dev->bus_id); 565 pr_debug("DEV: registering device: ID = '%s'\n", dev->bus_id);
542 566
543 parent = get_device(dev->parent); 567 parent = get_device(dev->parent);
544
545 error = setup_parent(dev, parent); 568 error = setup_parent(dev, parent);
546 if (error) 569 if (error)
547 goto Error; 570 goto Error;
@@ -787,6 +810,31 @@ void device_del(struct device * dev)
787 /* remove the device from the class list */ 810 /* remove the device from the class list */
788 list_del_init(&dev->node); 811 list_del_init(&dev->node);
789 up(&dev->class->sem); 812 up(&dev->class->sem);
813
814 /* If we live in a parent class-directory, unreference it */
815 if (dev->kobj.parent->kset == &dev->class->class_dirs) {
816 struct device *d;
817 int other = 0;
818
819 /*
820 * if we are the last child of our class, delete
821 * our class-directory at this parent
822 */
823 down(&dev->class->sem);
824 list_for_each_entry(d, &dev->class->devices, node) {
825 if (d == dev)
826 continue;
827 if (d->kobj.parent == dev->kobj.parent) {
828 other = 1;
829 break;
830 }
831 }
832 if (!other)
833 kobject_del(dev->kobj.parent);
834
835 kobject_put(dev->kobj.parent);
836 up(&dev->class->sem);
837 }
790 } 838 }
791 device_remove_file(dev, &dev->uevent_attr); 839 device_remove_file(dev, &dev->uevent_attr);
792 device_remove_groups(dev); 840 device_remove_groups(dev);