diff options
Diffstat (limited to 'drivers/base/class.c')
-rw-r--r-- | drivers/base/class.c | 112 |
1 files changed, 76 insertions, 36 deletions
diff --git a/drivers/base/class.c b/drivers/base/class.c index b1ea4df85c7d..9aa127460262 100644 --- a/drivers/base/class.c +++ b/drivers/base/class.c | |||
@@ -91,14 +91,14 @@ void class_remove_file(struct class * cls, const struct class_attribute * attr) | |||
91 | sysfs_remove_file(&cls->subsys.kset.kobj, &attr->attr); | 91 | sysfs_remove_file(&cls->subsys.kset.kobj, &attr->attr); |
92 | } | 92 | } |
93 | 93 | ||
94 | struct class * class_get(struct class * cls) | 94 | static struct class *class_get(struct class *cls) |
95 | { | 95 | { |
96 | if (cls) | 96 | if (cls) |
97 | return container_of(subsys_get(&cls->subsys), struct class, subsys); | 97 | return container_of(subsys_get(&cls->subsys), struct class, subsys); |
98 | return NULL; | 98 | return NULL; |
99 | } | 99 | } |
100 | 100 | ||
101 | void class_put(struct class * cls) | 101 | static void class_put(struct class * cls) |
102 | { | 102 | { |
103 | if (cls) | 103 | if (cls) |
104 | subsys_put(&cls->subsys); | 104 | subsys_put(&cls->subsys); |
@@ -142,6 +142,7 @@ int class_register(struct class * cls) | |||
142 | pr_debug("device class '%s': registering\n", cls->name); | 142 | pr_debug("device class '%s': registering\n", cls->name); |
143 | 143 | ||
144 | INIT_LIST_HEAD(&cls->children); | 144 | INIT_LIST_HEAD(&cls->children); |
145 | INIT_LIST_HEAD(&cls->devices); | ||
145 | INIT_LIST_HEAD(&cls->interfaces); | 146 | INIT_LIST_HEAD(&cls->interfaces); |
146 | init_MUTEX(&cls->sem); | 147 | init_MUTEX(&cls->sem); |
147 | error = kobject_set_name(&cls->subsys.kset.kobj, "%s", cls->name); | 148 | error = kobject_set_name(&cls->subsys.kset.kobj, "%s", cls->name); |
@@ -504,22 +505,21 @@ void class_device_initialize(struct class_device *class_dev) | |||
504 | INIT_LIST_HEAD(&class_dev->node); | 505 | INIT_LIST_HEAD(&class_dev->node); |
505 | } | 506 | } |
506 | 507 | ||
507 | static char *make_class_name(struct class_device *class_dev) | 508 | char *make_class_name(const char *name, struct kobject *kobj) |
508 | { | 509 | { |
509 | char *name; | 510 | char *class_name; |
510 | int size; | 511 | int size; |
511 | 512 | ||
512 | size = strlen(class_dev->class->name) + | 513 | size = strlen(name) + strlen(kobject_name(kobj)) + 2; |
513 | strlen(kobject_name(&class_dev->kobj)) + 2; | ||
514 | 514 | ||
515 | name = kmalloc(size, GFP_KERNEL); | 515 | class_name = kmalloc(size, GFP_KERNEL); |
516 | if (!name) | 516 | if (!class_name) |
517 | return ERR_PTR(-ENOMEM); | 517 | return ERR_PTR(-ENOMEM); |
518 | 518 | ||
519 | strcpy(name, class_dev->class->name); | 519 | strcpy(class_name, name); |
520 | strcat(name, ":"); | 520 | strcat(class_name, ":"); |
521 | strcat(name, kobject_name(&class_dev->kobj)); | 521 | strcat(class_name, kobject_name(kobj)); |
522 | return name; | 522 | return class_name; |
523 | } | 523 | } |
524 | 524 | ||
525 | int class_device_add(struct class_device *class_dev) | 525 | int class_device_add(struct class_device *class_dev) |
@@ -535,18 +535,22 @@ int class_device_add(struct class_device *class_dev) | |||
535 | return -EINVAL; | 535 | return -EINVAL; |
536 | 536 | ||
537 | if (!strlen(class_dev->class_id)) | 537 | if (!strlen(class_dev->class_id)) |
538 | goto register_done; | 538 | goto out1; |
539 | 539 | ||
540 | parent_class = class_get(class_dev->class); | 540 | parent_class = class_get(class_dev->class); |
541 | if (!parent_class) | 541 | if (!parent_class) |
542 | goto register_done; | 542 | goto out1; |
543 | |||
543 | parent_class_dev = class_device_get(class_dev->parent); | 544 | parent_class_dev = class_device_get(class_dev->parent); |
544 | 545 | ||
545 | pr_debug("CLASS: registering class device: ID = '%s'\n", | 546 | pr_debug("CLASS: registering class device: ID = '%s'\n", |
546 | class_dev->class_id); | 547 | class_dev->class_id); |
547 | 548 | ||
548 | /* first, register with generic layer. */ | 549 | /* first, register with generic layer. */ |
549 | kobject_set_name(&class_dev->kobj, "%s", class_dev->class_id); | 550 | error = kobject_set_name(&class_dev->kobj, "%s", class_dev->class_id); |
551 | if (error) | ||
552 | goto out2; | ||
553 | |||
550 | if (parent_class_dev) | 554 | if (parent_class_dev) |
551 | class_dev->kobj.parent = &parent_class_dev->kobj; | 555 | class_dev->kobj.parent = &parent_class_dev->kobj; |
552 | else | 556 | else |
@@ -554,41 +558,58 @@ int class_device_add(struct class_device *class_dev) | |||
554 | 558 | ||
555 | error = kobject_add(&class_dev->kobj); | 559 | error = kobject_add(&class_dev->kobj); |
556 | if (error) | 560 | if (error) |
557 | goto register_done; | 561 | goto out2; |
558 | 562 | ||
559 | /* add the needed attributes to this device */ | 563 | /* add the needed attributes to this device */ |
564 | sysfs_create_link(&class_dev->kobj, &parent_class->subsys.kset.kobj, "subsystem"); | ||
560 | class_dev->uevent_attr.attr.name = "uevent"; | 565 | class_dev->uevent_attr.attr.name = "uevent"; |
561 | class_dev->uevent_attr.attr.mode = S_IWUSR; | 566 | class_dev->uevent_attr.attr.mode = S_IWUSR; |
562 | class_dev->uevent_attr.attr.owner = parent_class->owner; | 567 | class_dev->uevent_attr.attr.owner = parent_class->owner; |
563 | class_dev->uevent_attr.store = store_uevent; | 568 | class_dev->uevent_attr.store = store_uevent; |
564 | class_device_create_file(class_dev, &class_dev->uevent_attr); | 569 | error = class_device_create_file(class_dev, &class_dev->uevent_attr); |
570 | if (error) | ||
571 | goto out3; | ||
565 | 572 | ||
566 | if (MAJOR(class_dev->devt)) { | 573 | if (MAJOR(class_dev->devt)) { |
567 | struct class_device_attribute *attr; | 574 | struct class_device_attribute *attr; |
568 | attr = kzalloc(sizeof(*attr), GFP_KERNEL); | 575 | attr = kzalloc(sizeof(*attr), GFP_KERNEL); |
569 | if (!attr) { | 576 | if (!attr) { |
570 | error = -ENOMEM; | 577 | error = -ENOMEM; |
571 | kobject_del(&class_dev->kobj); | 578 | goto out4; |
572 | goto register_done; | ||
573 | } | 579 | } |
574 | attr->attr.name = "dev"; | 580 | attr->attr.name = "dev"; |
575 | attr->attr.mode = S_IRUGO; | 581 | attr->attr.mode = S_IRUGO; |
576 | attr->attr.owner = parent_class->owner; | 582 | attr->attr.owner = parent_class->owner; |
577 | attr->show = show_dev; | 583 | attr->show = show_dev; |
578 | class_device_create_file(class_dev, attr); | 584 | error = class_device_create_file(class_dev, attr); |
585 | if (error) { | ||
586 | kfree(attr); | ||
587 | goto out4; | ||
588 | } | ||
589 | |||
579 | class_dev->devt_attr = attr; | 590 | class_dev->devt_attr = attr; |
580 | } | 591 | } |
581 | 592 | ||
582 | class_device_add_attrs(class_dev); | 593 | error = class_device_add_attrs(class_dev); |
594 | if (error) | ||
595 | goto out5; | ||
596 | |||
583 | if (class_dev->dev) { | 597 | if (class_dev->dev) { |
584 | class_name = make_class_name(class_dev); | 598 | class_name = make_class_name(class_dev->class->name, |
585 | sysfs_create_link(&class_dev->kobj, | 599 | &class_dev->kobj); |
586 | &class_dev->dev->kobj, "device"); | 600 | error = sysfs_create_link(&class_dev->kobj, |
587 | sysfs_create_link(&class_dev->dev->kobj, &class_dev->kobj, | 601 | &class_dev->dev->kobj, "device"); |
588 | class_name); | 602 | if (error) |
603 | goto out6; | ||
604 | error = sysfs_create_link(&class_dev->dev->kobj, &class_dev->kobj, | ||
605 | class_name); | ||
606 | if (error) | ||
607 | goto out7; | ||
589 | } | 608 | } |
590 | 609 | ||
591 | class_device_add_groups(class_dev); | 610 | error = class_device_add_groups(class_dev); |
611 | if (error) | ||
612 | goto out8; | ||
592 | 613 | ||
593 | kobject_uevent(&class_dev->kobj, KOBJ_ADD); | 614 | kobject_uevent(&class_dev->kobj, KOBJ_ADD); |
594 | 615 | ||
@@ -601,11 +622,28 @@ int class_device_add(struct class_device *class_dev) | |||
601 | } | 622 | } |
602 | up(&parent_class->sem); | 623 | up(&parent_class->sem); |
603 | 624 | ||
604 | register_done: | 625 | goto out1; |
605 | if (error) { | 626 | |
606 | class_put(parent_class); | 627 | out8: |
628 | if (class_dev->dev) | ||
629 | sysfs_remove_link(&class_dev->kobj, class_name); | ||
630 | out7: | ||
631 | if (class_dev->dev) | ||
632 | sysfs_remove_link(&class_dev->kobj, "device"); | ||
633 | out6: | ||
634 | class_device_remove_attrs(class_dev); | ||
635 | out5: | ||
636 | if (class_dev->devt_attr) | ||
637 | class_device_remove_file(class_dev, class_dev->devt_attr); | ||
638 | out4: | ||
639 | class_device_remove_file(class_dev, &class_dev->uevent_attr); | ||
640 | out3: | ||
641 | kobject_del(&class_dev->kobj); | ||
642 | out2: | ||
643 | if(parent_class_dev) | ||
607 | class_device_put(parent_class_dev); | 644 | class_device_put(parent_class_dev); |
608 | } | 645 | class_put(parent_class); |
646 | out1: | ||
609 | class_device_put(class_dev); | 647 | class_device_put(class_dev); |
610 | kfree(class_name); | 648 | kfree(class_name); |
611 | return error; | 649 | return error; |
@@ -695,10 +733,12 @@ void class_device_del(struct class_device *class_dev) | |||
695 | } | 733 | } |
696 | 734 | ||
697 | if (class_dev->dev) { | 735 | if (class_dev->dev) { |
698 | class_name = make_class_name(class_dev); | 736 | class_name = make_class_name(class_dev->class->name, |
737 | &class_dev->kobj); | ||
699 | sysfs_remove_link(&class_dev->kobj, "device"); | 738 | sysfs_remove_link(&class_dev->kobj, "device"); |
700 | sysfs_remove_link(&class_dev->dev->kobj, class_name); | 739 | sysfs_remove_link(&class_dev->dev->kobj, class_name); |
701 | } | 740 | } |
741 | sysfs_remove_link(&class_dev->kobj, "subsystem"); | ||
702 | class_device_remove_file(class_dev, &class_dev->uevent_attr); | 742 | class_device_remove_file(class_dev, &class_dev->uevent_attr); |
703 | if (class_dev->devt_attr) | 743 | if (class_dev->devt_attr) |
704 | class_device_remove_file(class_dev, class_dev->devt_attr); | 744 | class_device_remove_file(class_dev, class_dev->devt_attr); |
@@ -760,14 +800,16 @@ int class_device_rename(struct class_device *class_dev, char *new_name) | |||
760 | new_name); | 800 | new_name); |
761 | 801 | ||
762 | if (class_dev->dev) | 802 | if (class_dev->dev) |
763 | old_class_name = make_class_name(class_dev); | 803 | old_class_name = make_class_name(class_dev->class->name, |
804 | &class_dev->kobj); | ||
764 | 805 | ||
765 | strlcpy(class_dev->class_id, new_name, KOBJ_NAME_LEN); | 806 | strlcpy(class_dev->class_id, new_name, KOBJ_NAME_LEN); |
766 | 807 | ||
767 | error = kobject_rename(&class_dev->kobj, new_name); | 808 | error = kobject_rename(&class_dev->kobj, new_name); |
768 | 809 | ||
769 | if (class_dev->dev) { | 810 | if (class_dev->dev) { |
770 | new_class_name = make_class_name(class_dev); | 811 | new_class_name = make_class_name(class_dev->class->name, |
812 | &class_dev->kobj); | ||
771 | sysfs_create_link(&class_dev->dev->kobj, &class_dev->kobj, | 813 | sysfs_create_link(&class_dev->dev->kobj, &class_dev->kobj, |
772 | new_class_name); | 814 | new_class_name); |
773 | sysfs_remove_link(&class_dev->dev->kobj, old_class_name); | 815 | sysfs_remove_link(&class_dev->dev->kobj, old_class_name); |
@@ -858,8 +900,6 @@ EXPORT_SYMBOL_GPL(class_create_file); | |||
858 | EXPORT_SYMBOL_GPL(class_remove_file); | 900 | EXPORT_SYMBOL_GPL(class_remove_file); |
859 | EXPORT_SYMBOL_GPL(class_register); | 901 | EXPORT_SYMBOL_GPL(class_register); |
860 | EXPORT_SYMBOL_GPL(class_unregister); | 902 | EXPORT_SYMBOL_GPL(class_unregister); |
861 | EXPORT_SYMBOL_GPL(class_get); | ||
862 | EXPORT_SYMBOL_GPL(class_put); | ||
863 | EXPORT_SYMBOL_GPL(class_create); | 903 | EXPORT_SYMBOL_GPL(class_create); |
864 | EXPORT_SYMBOL_GPL(class_destroy); | 904 | EXPORT_SYMBOL_GPL(class_destroy); |
865 | 905 | ||