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 | ||
