diff options
Diffstat (limited to 'drivers/base/class.c')
-rw-r--r-- | drivers/base/class.c | 171 |
1 files changed, 102 insertions, 69 deletions
diff --git a/drivers/base/class.c b/drivers/base/class.c index b32b77ff2dcd..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); |
@@ -562,7 +613,10 @@ int class_device_add(struct class_device *class_dev) | |||
562 | goto out2; | 613 | goto out2; |
563 | 614 | ||
564 | /* add the needed attributes to this device */ | 615 | /* add the needed attributes to this device */ |
565 | sysfs_create_link(&class_dev->kobj, &parent_class->subsys.kset.kobj, "subsystem"); | 616 | error = sysfs_create_link(&class_dev->kobj, |
617 | &parent_class->subsys.kset.kobj, "subsystem"); | ||
618 | if (error) | ||
619 | goto out3; | ||
566 | class_dev->uevent_attr.attr.name = "uevent"; | 620 | class_dev->uevent_attr.attr.name = "uevent"; |
567 | class_dev->uevent_attr.attr.mode = S_IWUSR; | 621 | class_dev->uevent_attr.attr.mode = S_IWUSR; |
568 | class_dev->uevent_attr.attr.owner = parent_class->owner; | 622 | class_dev->uevent_attr.attr.owner = parent_class->owner; |
@@ -596,20 +650,18 @@ int class_device_add(struct class_device *class_dev) | |||
596 | goto out5; | 650 | goto out5; |
597 | 651 | ||
598 | if (class_dev->dev) { | 652 | if (class_dev->dev) { |
599 | class_name = make_class_name(class_dev->class->name, | ||
600 | &class_dev->kobj); | ||
601 | error = sysfs_create_link(&class_dev->kobj, | 653 | error = sysfs_create_link(&class_dev->kobj, |
602 | &class_dev->dev->kobj, "device"); | 654 | &class_dev->dev->kobj, "device"); |
603 | if (error) | 655 | if (error) |
604 | goto out6; | 656 | goto out6; |
605 | error = sysfs_create_link(&class_dev->dev->kobj, &class_dev->kobj, | ||
606 | class_name); | ||
607 | if (error) | ||
608 | goto out7; | ||
609 | } | 657 | } |
610 | 658 | ||
611 | error = class_device_add_groups(class_dev); | 659 | error = class_device_add_groups(class_dev); |
612 | if (error) | 660 | if (error) |
661 | goto out7; | ||
662 | |||
663 | error = make_deprecated_class_device_links(class_dev); | ||
664 | if (error) | ||
613 | goto out8; | 665 | goto out8; |
614 | 666 | ||
615 | kobject_uevent(&class_dev->kobj, KOBJ_ADD); | 667 | kobject_uevent(&class_dev->kobj, KOBJ_ADD); |
@@ -626,8 +678,7 @@ int class_device_add(struct class_device *class_dev) | |||
626 | goto out1; | 678 | goto out1; |
627 | 679 | ||
628 | out8: | 680 | out8: |
629 | if (class_dev->dev) | 681 | class_device_remove_groups(class_dev); |
630 | sysfs_remove_link(&class_dev->kobj, class_name); | ||
631 | out7: | 682 | out7: |
632 | if (class_dev->dev) | 683 | if (class_dev->dev) |
633 | sysfs_remove_link(&class_dev->kobj, "device"); | 684 | sysfs_remove_link(&class_dev->kobj, "device"); |
@@ -646,7 +697,6 @@ int class_device_add(struct class_device *class_dev) | |||
646 | class_put(parent_class); | 697 | class_put(parent_class); |
647 | out1: | 698 | out1: |
648 | class_device_put(class_dev); | 699 | class_device_put(class_dev); |
649 | kfree(class_name); | ||
650 | return error; | 700 | return error; |
651 | } | 701 | } |
652 | 702 | ||
@@ -723,7 +773,6 @@ void class_device_del(struct class_device *class_dev) | |||
723 | struct class *parent_class = class_dev->class; | 773 | struct class *parent_class = class_dev->class; |
724 | struct class_device *parent_device = class_dev->parent; | 774 | struct class_device *parent_device = class_dev->parent; |
725 | struct class_interface *class_intf; | 775 | struct class_interface *class_intf; |
726 | char *class_name = NULL; | ||
727 | 776 | ||
728 | if (parent_class) { | 777 | if (parent_class) { |
729 | down(&parent_class->sem); | 778 | down(&parent_class->sem); |
@@ -735,10 +784,8 @@ void class_device_del(struct class_device *class_dev) | |||
735 | } | 784 | } |
736 | 785 | ||
737 | if (class_dev->dev) { | 786 | if (class_dev->dev) { |
738 | class_name = make_class_name(class_dev->class->name, | 787 | remove_deprecated_class_device_links(class_dev); |
739 | &class_dev->kobj); | ||
740 | sysfs_remove_link(&class_dev->kobj, "device"); | 788 | sysfs_remove_link(&class_dev->kobj, "device"); |
741 | sysfs_remove_link(&class_dev->dev->kobj, class_name); | ||
742 | } | 789 | } |
743 | sysfs_remove_link(&class_dev->kobj, "subsystem"); | 790 | sysfs_remove_link(&class_dev->kobj, "subsystem"); |
744 | class_device_remove_file(class_dev, &class_dev->uevent_attr); | 791 | class_device_remove_file(class_dev, &class_dev->uevent_attr); |
@@ -752,7 +799,6 @@ void class_device_del(struct class_device *class_dev) | |||
752 | 799 | ||
753 | class_device_put(parent_device); | 800 | class_device_put(parent_device); |
754 | class_put(parent_class); | 801 | class_put(parent_class); |
755 | kfree(class_name); | ||
756 | } | 802 | } |
757 | 803 | ||
758 | void class_device_unregister(struct class_device *class_dev) | 804 | void class_device_unregister(struct class_device *class_dev) |
@@ -801,14 +847,17 @@ int class_device_rename(struct class_device *class_dev, char *new_name) | |||
801 | 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, |
802 | new_name); | 848 | new_name); |
803 | 849 | ||
850 | #ifdef CONFIG_SYSFS_DEPRECATED | ||
804 | if (class_dev->dev) | 851 | if (class_dev->dev) |
805 | old_class_name = make_class_name(class_dev->class->name, | 852 | old_class_name = make_class_name(class_dev->class->name, |
806 | &class_dev->kobj); | 853 | &class_dev->kobj); |
854 | #endif | ||
807 | 855 | ||
808 | strlcpy(class_dev->class_id, new_name, KOBJ_NAME_LEN); | 856 | strlcpy(class_dev->class_id, new_name, KOBJ_NAME_LEN); |
809 | 857 | ||
810 | error = kobject_rename(&class_dev->kobj, new_name); | 858 | error = kobject_rename(&class_dev->kobj, new_name); |
811 | 859 | ||
860 | #ifdef CONFIG_SYSFS_DEPRECATED | ||
812 | if (class_dev->dev) { | 861 | if (class_dev->dev) { |
813 | new_class_name = make_class_name(class_dev->class->name, | 862 | new_class_name = make_class_name(class_dev->class->name, |
814 | &class_dev->kobj); | 863 | &class_dev->kobj); |
@@ -816,6 +865,7 @@ int class_device_rename(struct class_device *class_dev, char *new_name) | |||
816 | new_class_name); | 865 | new_class_name); |
817 | sysfs_remove_link(&class_dev->dev->kobj, old_class_name); | 866 | sysfs_remove_link(&class_dev->dev->kobj, old_class_name); |
818 | } | 867 | } |
868 | #endif | ||
819 | class_device_put(class_dev); | 869 | class_device_put(class_dev); |
820 | 870 | ||
821 | kfree(old_class_name); | 871 | kfree(old_class_name); |
@@ -890,23 +940,6 @@ void class_interface_unregister(struct class_interface *class_intf) | |||
890 | class_put(parent); | 940 | class_put(parent); |
891 | } | 941 | } |
892 | 942 | ||
893 | int virtual_device_parent(struct device *dev) | ||
894 | { | ||
895 | if (!dev->class) | ||
896 | return -ENODEV; | ||
897 | |||
898 | if (!dev->class->virtual_dir) { | ||
899 | static struct kobject *virtual_dir = NULL; | ||
900 | |||
901 | if (!virtual_dir) | ||
902 | virtual_dir = kobject_add_dir(&devices_subsys.kset.kobj, "virtual"); | ||
903 | dev->class->virtual_dir = kobject_add_dir(virtual_dir, dev->class->name); | ||
904 | } | ||
905 | |||
906 | dev->kobj.parent = dev->class->virtual_dir; | ||
907 | return 0; | ||
908 | } | ||
909 | |||
910 | int __init classes_init(void) | 943 | int __init classes_init(void) |
911 | { | 944 | { |
912 | int retval; | 945 | int retval; |