diff options
| -rw-r--r-- | drivers/base/class.c | 149 |
1 files changed, 98 insertions, 51 deletions
diff --git a/drivers/base/class.c b/drivers/base/class.c index 2e705f6abb4c..f098881f45b2 100644 --- a/drivers/base/class.c +++ b/drivers/base/class.c | |||
| @@ -352,6 +352,92 @@ static const char *class_uevent_name(struct kset *kset, struct kobject *kobj) | |||
| 352 | return class_dev->class->name; | 352 | return class_dev->class->name; |
| 353 | } | 353 | } |
| 354 | 354 | ||
| 355 | #ifdef CONFIG_SYSFS_DEPRECATED | ||
| 356 | char *make_class_name(const char *name, struct kobject *kobj) | ||
| 357 | { | ||
| 358 | char *class_name; | ||
| 359 | int size; | ||
| 360 | |||
| 361 | size = strlen(name) + strlen(kobject_name(kobj)) + 2; | ||
| 362 | |||
| 363 | class_name = kmalloc(size, GFP_KERNEL); | ||
| 364 | if (!class_name) | ||
| 365 | return ERR_PTR(-ENOMEM); | ||
| 366 | |||
| 367 | strcpy(class_name, name); | ||
| 368 | strcat(class_name, ":"); | ||
| 369 | strcat(class_name, kobject_name(kobj)); | ||
| 370 | return class_name; | ||
| 371 | } | ||
| 372 | |||
| 373 | static int deprecated_class_uevent(char **envp, int num_envp, int *cur_index, | ||
| 374 | char *buffer, int buffer_size, | ||
| 375 | int *cur_len, | ||
| 376 | struct class_device *class_dev) | ||
| 377 | { | ||
| 378 | struct device *dev = class_dev->dev; | ||
| 379 | char *path; | ||
| 380 | |||
| 381 | if (!dev) | ||
| 382 | return 0; | ||
| 383 | |||
| 384 | /* add device, backing this class device (deprecated) */ | ||
| 385 | path = kobject_get_path(&dev->kobj, GFP_KERNEL); | ||
| 386 | |||
| 387 | add_uevent_var(envp, num_envp, cur_index, buffer, buffer_size, | ||
| 388 | cur_len, "PHYSDEVPATH=%s", path); | ||
| 389 | kfree(path); | ||
| 390 | |||
| 391 | if (dev->bus) | ||
| 392 | add_uevent_var(envp, num_envp, cur_index, | ||
| 393 | buffer, buffer_size, cur_len, | ||
| 394 | "PHYSDEVBUS=%s", dev->bus->name); | ||
| 395 | |||
| 396 | if (dev->driver) | ||
| 397 | add_uevent_var(envp, num_envp, cur_index, | ||
| 398 | buffer, buffer_size, cur_len, | ||
| 399 | "PHYSDEVDRIVER=%s", dev->driver->name); | ||
| 400 | return 0; | ||
| 401 | } | ||
| 402 | |||
| 403 | static int make_deprecated_class_device_links(struct class_device *class_dev) | ||
| 404 | { | ||
| 405 | char *class_name; | ||
| 406 | int error; | ||
| 407 | |||
| 408 | if (!class_dev->dev) | ||
| 409 | return 0; | ||
| 410 | |||
| 411 | class_name = make_class_name(class_dev->class->name, &class_dev->kobj); | ||
| 412 | error = sysfs_create_link(&class_dev->dev->kobj, &class_dev->kobj, | ||
| 413 | class_name); | ||
| 414 | kfree(class_name); | ||
| 415 | return error; | ||
| 416 | } | ||
| 417 | |||
| 418 | static void remove_deprecated_class_device_links(struct class_device *class_dev) | ||
| 419 | { | ||
| 420 | char *class_name; | ||
| 421 | |||
| 422 | if (!class_dev->dev) | ||
| 423 | return; | ||
| 424 | |||
| 425 | class_name = make_class_name(class_dev->class->name, &class_dev->kobj); | ||
| 426 | sysfs_remove_link(&class_dev->dev->kobj, class_name); | ||
| 427 | kfree(class_name); | ||
| 428 | } | ||
| 429 | #else | ||
| 430 | static inline int deprecated_class_uevent(char **envp, int num_envp, | ||
| 431 | int *cur_index, char *buffer, | ||
| 432 | int buffer_size, int *cur_len, | ||
| 433 | struct class_device *class_dev) | ||
| 434 | { return 0; } | ||
| 435 | static inline int make_deprecated_class_device_links(struct class_device *cd) | ||
| 436 | { return 0; } | ||
| 437 | static void remove_deprecated_class_device_links(struct class_device *cd) | ||
| 438 | { } | ||
| 439 | #endif | ||
| 440 | |||
| 355 | static int class_uevent(struct kset *kset, struct kobject *kobj, char **envp, | 441 | static int class_uevent(struct kset *kset, struct kobject *kobj, char **envp, |
| 356 | int num_envp, char *buffer, int buffer_size) | 442 | int num_envp, char *buffer, int buffer_size) |
| 357 | { | 443 | { |
| @@ -362,25 +448,8 @@ static int class_uevent(struct kset *kset, struct kobject *kobj, char **envp, | |||
| 362 | 448 | ||
| 363 | pr_debug("%s - name = %s\n", __FUNCTION__, class_dev->class_id); | 449 | pr_debug("%s - name = %s\n", __FUNCTION__, class_dev->class_id); |
| 364 | 450 | ||
| 365 | if (class_dev->dev) { | 451 | deprecated_class_uevent(envp, num_envp, &i, buffer, buffer_size, |
| 366 | /* add device, backing this class device (deprecated) */ | 452 | &length, class_dev); |
| 367 | struct device *dev = class_dev->dev; | ||
| 368 | char *path = kobject_get_path(&dev->kobj, GFP_KERNEL); | ||
| 369 | |||
| 370 | add_uevent_var(envp, num_envp, &i, buffer, buffer_size, | ||
| 371 | &length, "PHYSDEVPATH=%s", path); | ||
| 372 | kfree(path); | ||
| 373 | |||
| 374 | if (dev->bus) | ||
| 375 | add_uevent_var(envp, num_envp, &i, | ||
| 376 | buffer, buffer_size, &length, | ||
| 377 | "PHYSDEVBUS=%s", dev->bus->name); | ||
| 378 | |||
| 379 | if (dev->driver) | ||
| 380 | add_uevent_var(envp, num_envp, &i, | ||
| 381 | buffer, buffer_size, &length, | ||
| 382 | "PHYSDEVDRIVER=%s", dev->driver->name); | ||
| 383 | } | ||
| 384 | 453 | ||
| 385 | if (MAJOR(class_dev->devt)) { | 454 | if (MAJOR(class_dev->devt)) { |
| 386 | add_uevent_var(envp, num_envp, &i, | 455 | add_uevent_var(envp, num_envp, &i, |
| @@ -506,29 +575,11 @@ void class_device_initialize(struct class_device *class_dev) | |||
| 506 | INIT_LIST_HEAD(&class_dev->node); | 575 | INIT_LIST_HEAD(&class_dev->node); |
| 507 | } | 576 | } |
| 508 | 577 | ||
| 509 | char *make_class_name(const char *name, struct kobject *kobj) | ||
| 510 | { | ||
| 511 | char *class_name; | ||
| 512 | int size; | ||
| 513 | |||
| 514 | size = strlen(name) + strlen(kobject_name(kobj)) + 2; | ||
| 515 | |||
| 516 | class_name = kmalloc(size, GFP_KERNEL); | ||
| 517 | if (!class_name) | ||
| 518 | return ERR_PTR(-ENOMEM); | ||
| 519 | |||
| 520 | strcpy(class_name, name); | ||
| 521 | strcat(class_name, ":"); | ||
| 522 | strcat(class_name, kobject_name(kobj)); | ||
| 523 | return class_name; | ||
| 524 | } | ||
| 525 | |||
| 526 | int class_device_add(struct class_device *class_dev) | 578 | int class_device_add(struct class_device *class_dev) |
| 527 | { | 579 | { |
| 528 | struct class *parent_class = NULL; | 580 | struct class *parent_class = NULL; |
| 529 | struct class_device *parent_class_dev = NULL; | 581 | struct class_device *parent_class_dev = NULL; |
| 530 | struct class_interface *class_intf; | 582 | struct class_interface *class_intf; |
| 531 | char *class_name = NULL; | ||
| 532 | int error = -EINVAL; | 583 | int error = -EINVAL; |
| 533 | 584 | ||
| 534 | class_dev = class_device_get(class_dev); | 585 | class_dev = class_device_get(class_dev); |
| @@ -599,20 +650,18 @@ int class_device_add(struct class_device *class_dev) | |||
| 599 | goto out5; | 650 | goto out5; |
| 600 | 651 | ||
| 601 | if (class_dev->dev) { | 652 | if (class_dev->dev) { |
| 602 | class_name = make_class_name(class_dev->class->name, | ||
| 603 | &class_dev->kobj); | ||
| 604 | error = sysfs_create_link(&class_dev->kobj, | 653 | error = sysfs_create_link(&class_dev->kobj, |
| 605 | &class_dev->dev->kobj, "device"); | 654 | &class_dev->dev->kobj, "device"); |
| 606 | if (error) | 655 | if (error) |
| 607 | goto out6; | 656 | goto out6; |
| 608 | error = sysfs_create_link(&class_dev->dev->kobj, &class_dev->kobj, | ||
| 609 | class_name); | ||
| 610 | if (error) | ||
| 611 | goto out7; | ||
| 612 | } | 657 | } |
| 613 | 658 | ||
| 614 | error = class_device_add_groups(class_dev); | 659 | error = class_device_add_groups(class_dev); |
| 615 | if (error) | 660 | if (error) |
| 661 | goto out7; | ||
| 662 | |||
| 663 | error = make_deprecated_class_device_links(class_dev); | ||
| 664 | if (error) | ||
| 616 | goto out8; | 665 | goto out8; |
| 617 | 666 | ||
| 618 | kobject_uevent(&class_dev->kobj, KOBJ_ADD); | 667 | kobject_uevent(&class_dev->kobj, KOBJ_ADD); |
| @@ -629,8 +678,7 @@ int class_device_add(struct class_device *class_dev) | |||
| 629 | goto out1; | 678 | goto out1; |
| 630 | 679 | ||
| 631 | out8: | 680 | out8: |
| 632 | if (class_dev->dev) | 681 | class_device_remove_groups(class_dev); |
| 633 | sysfs_remove_link(&class_dev->kobj, class_name); | ||
| 634 | out7: | 682 | out7: |
| 635 | if (class_dev->dev) | 683 | if (class_dev->dev) |
| 636 | sysfs_remove_link(&class_dev->kobj, "device"); | 684 | sysfs_remove_link(&class_dev->kobj, "device"); |
| @@ -649,7 +697,6 @@ int class_device_add(struct class_device *class_dev) | |||
| 649 | class_put(parent_class); | 697 | class_put(parent_class); |
| 650 | out1: | 698 | out1: |
| 651 | class_device_put(class_dev); | 699 | class_device_put(class_dev); |
| 652 | kfree(class_name); | ||
| 653 | return error; | 700 | return error; |
| 654 | } | 701 | } |
| 655 | 702 | ||
| @@ -726,7 +773,6 @@ void class_device_del(struct class_device *class_dev) | |||
| 726 | struct class *parent_class = class_dev->class; | 773 | struct class *parent_class = class_dev->class; |
| 727 | struct class_device *parent_device = class_dev->parent; | 774 | struct class_device *parent_device = class_dev->parent; |
| 728 | struct class_interface *class_intf; | 775 | struct class_interface *class_intf; |
| 729 | char *class_name = NULL; | ||
| 730 | 776 | ||
| 731 | if (parent_class) { | 777 | if (parent_class) { |
| 732 | down(&parent_class->sem); | 778 | down(&parent_class->sem); |
| @@ -738,10 +784,8 @@ void class_device_del(struct class_device *class_dev) | |||
| 738 | } | 784 | } |
| 739 | 785 | ||
| 740 | if (class_dev->dev) { | 786 | if (class_dev->dev) { |
| 741 | class_name = make_class_name(class_dev->class->name, | 787 | remove_deprecated_class_device_links(class_dev); |
| 742 | &class_dev->kobj); | ||
| 743 | sysfs_remove_link(&class_dev->kobj, "device"); | 788 | sysfs_remove_link(&class_dev->kobj, "device"); |
| 744 | sysfs_remove_link(&class_dev->dev->kobj, class_name); | ||
| 745 | } | 789 | } |
| 746 | sysfs_remove_link(&class_dev->kobj, "subsystem"); | 790 | sysfs_remove_link(&class_dev->kobj, "subsystem"); |
| 747 | class_device_remove_file(class_dev, &class_dev->uevent_attr); | 791 | class_device_remove_file(class_dev, &class_dev->uevent_attr); |
| @@ -755,7 +799,6 @@ void class_device_del(struct class_device *class_dev) | |||
| 755 | 799 | ||
| 756 | class_device_put(parent_device); | 800 | class_device_put(parent_device); |
| 757 | class_put(parent_class); | 801 | class_put(parent_class); |
| 758 | kfree(class_name); | ||
| 759 | } | 802 | } |
| 760 | 803 | ||
| 761 | void class_device_unregister(struct class_device *class_dev) | 804 | void class_device_unregister(struct class_device *class_dev) |
| @@ -804,14 +847,17 @@ int class_device_rename(struct class_device *class_dev, char *new_name) | |||
| 804 | pr_debug("CLASS: renaming '%s' to '%s'\n", class_dev->class_id, | 847 | pr_debug("CLASS: renaming '%s' to '%s'\n", class_dev->class_id, |
| 805 | new_name); | 848 | new_name); |
| 806 | 849 | ||
| 850 | #ifdef CONFIG_SYSFS_DEPRECATED | ||
| 807 | if (class_dev->dev) | 851 | if (class_dev->dev) |
| 808 | old_class_name = make_class_name(class_dev->class->name, | 852 | old_class_name = make_class_name(class_dev->class->name, |
| 809 | &class_dev->kobj); | 853 | &class_dev->kobj); |
| 854 | #endif | ||
| 810 | 855 | ||
| 811 | strlcpy(class_dev->class_id, new_name, KOBJ_NAME_LEN); | 856 | strlcpy(class_dev->class_id, new_name, KOBJ_NAME_LEN); |
| 812 | 857 | ||
| 813 | error = kobject_rename(&class_dev->kobj, new_name); | 858 | error = kobject_rename(&class_dev->kobj, new_name); |
| 814 | 859 | ||
| 860 | #ifdef CONFIG_SYSFS_DEPRECATED | ||
| 815 | if (class_dev->dev) { | 861 | if (class_dev->dev) { |
| 816 | new_class_name = make_class_name(class_dev->class->name, | 862 | new_class_name = make_class_name(class_dev->class->name, |
| 817 | &class_dev->kobj); | 863 | &class_dev->kobj); |
| @@ -819,6 +865,7 @@ int class_device_rename(struct class_device *class_dev, char *new_name) | |||
| 819 | new_class_name); | 865 | new_class_name); |
| 820 | sysfs_remove_link(&class_dev->dev->kobj, old_class_name); | 866 | sysfs_remove_link(&class_dev->dev->kobj, old_class_name); |
| 821 | } | 867 | } |
| 868 | #endif | ||
| 822 | class_device_put(class_dev); | 869 | class_device_put(class_dev); |
| 823 | 870 | ||
| 824 | kfree(old_class_name); | 871 | kfree(old_class_name); |
