diff options
Diffstat (limited to 'drivers/base/class.c')
-rw-r--r-- | drivers/base/class.c | 72 |
1 files changed, 54 insertions, 18 deletions
diff --git a/drivers/base/class.c b/drivers/base/class.c index b1ea4df85c7d..48ad5df72812 100644 --- a/drivers/base/class.c +++ b/drivers/base/class.c | |||
@@ -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,56 @@ 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 */ |
560 | class_dev->uevent_attr.attr.name = "uevent"; | 564 | class_dev->uevent_attr.attr.name = "uevent"; |
561 | class_dev->uevent_attr.attr.mode = S_IWUSR; | 565 | class_dev->uevent_attr.attr.mode = S_IWUSR; |
562 | class_dev->uevent_attr.attr.owner = parent_class->owner; | 566 | class_dev->uevent_attr.attr.owner = parent_class->owner; |
563 | class_dev->uevent_attr.store = store_uevent; | 567 | class_dev->uevent_attr.store = store_uevent; |
564 | class_device_create_file(class_dev, &class_dev->uevent_attr); | 568 | error = class_device_create_file(class_dev, &class_dev->uevent_attr); |
569 | if (error) | ||
570 | goto out3; | ||
565 | 571 | ||
566 | if (MAJOR(class_dev->devt)) { | 572 | if (MAJOR(class_dev->devt)) { |
567 | struct class_device_attribute *attr; | 573 | struct class_device_attribute *attr; |
568 | attr = kzalloc(sizeof(*attr), GFP_KERNEL); | 574 | attr = kzalloc(sizeof(*attr), GFP_KERNEL); |
569 | if (!attr) { | 575 | if (!attr) { |
570 | error = -ENOMEM; | 576 | error = -ENOMEM; |
571 | kobject_del(&class_dev->kobj); | 577 | goto out4; |
572 | goto register_done; | ||
573 | } | 578 | } |
574 | attr->attr.name = "dev"; | 579 | attr->attr.name = "dev"; |
575 | attr->attr.mode = S_IRUGO; | 580 | attr->attr.mode = S_IRUGO; |
576 | attr->attr.owner = parent_class->owner; | 581 | attr->attr.owner = parent_class->owner; |
577 | attr->show = show_dev; | 582 | attr->show = show_dev; |
578 | class_device_create_file(class_dev, attr); | 583 | error = class_device_create_file(class_dev, attr); |
584 | if (error) { | ||
585 | kfree(attr); | ||
586 | goto out4; | ||
587 | } | ||
588 | |||
579 | class_dev->devt_attr = attr; | 589 | class_dev->devt_attr = attr; |
580 | } | 590 | } |
581 | 591 | ||
582 | class_device_add_attrs(class_dev); | 592 | error = class_device_add_attrs(class_dev); |
593 | if (error) | ||
594 | goto out5; | ||
595 | |||
583 | if (class_dev->dev) { | 596 | if (class_dev->dev) { |
584 | class_name = make_class_name(class_dev); | 597 | class_name = make_class_name(class_dev); |
585 | sysfs_create_link(&class_dev->kobj, | 598 | error = sysfs_create_link(&class_dev->kobj, |
586 | &class_dev->dev->kobj, "device"); | 599 | &class_dev->dev->kobj, "device"); |
587 | sysfs_create_link(&class_dev->dev->kobj, &class_dev->kobj, | 600 | if (error) |
588 | class_name); | 601 | goto out6; |
602 | error = sysfs_create_link(&class_dev->dev->kobj, &class_dev->kobj, | ||
603 | class_name); | ||
604 | if (error) | ||
605 | goto out7; | ||
589 | } | 606 | } |
590 | 607 | ||
591 | class_device_add_groups(class_dev); | 608 | error = class_device_add_groups(class_dev); |
609 | if (error) | ||
610 | goto out8; | ||
592 | 611 | ||
593 | kobject_uevent(&class_dev->kobj, KOBJ_ADD); | 612 | kobject_uevent(&class_dev->kobj, KOBJ_ADD); |
594 | 613 | ||
@@ -601,11 +620,28 @@ int class_device_add(struct class_device *class_dev) | |||
601 | } | 620 | } |
602 | up(&parent_class->sem); | 621 | up(&parent_class->sem); |
603 | 622 | ||
604 | register_done: | 623 | goto out1; |
605 | if (error) { | 624 | |
606 | class_put(parent_class); | 625 | out8: |
626 | if (class_dev->dev) | ||
627 | sysfs_remove_link(&class_dev->kobj, class_name); | ||
628 | out7: | ||
629 | if (class_dev->dev) | ||
630 | sysfs_remove_link(&class_dev->kobj, "device"); | ||
631 | out6: | ||
632 | class_device_remove_attrs(class_dev); | ||
633 | out5: | ||
634 | if (class_dev->devt_attr) | ||
635 | class_device_remove_file(class_dev, class_dev->devt_attr); | ||
636 | out4: | ||
637 | class_device_remove_file(class_dev, &class_dev->uevent_attr); | ||
638 | out3: | ||
639 | kobject_del(&class_dev->kobj); | ||
640 | out2: | ||
641 | if(parent_class_dev) | ||
607 | class_device_put(parent_class_dev); | 642 | class_device_put(parent_class_dev); |
608 | } | 643 | class_put(parent_class); |
644 | out1: | ||
609 | class_device_put(class_dev); | 645 | class_device_put(class_dev); |
610 | kfree(class_name); | 646 | kfree(class_name); |
611 | return error; | 647 | return error; |