diff options
Diffstat (limited to 'drivers/base/class.c')
-rw-r--r-- | drivers/base/class.c | 166 |
1 files changed, 98 insertions, 68 deletions
diff --git a/drivers/base/class.c b/drivers/base/class.c index 0ff267a248db..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); |
@@ -893,23 +940,6 @@ void class_interface_unregister(struct class_interface *class_intf) | |||
893 | class_put(parent); | 940 | class_put(parent); |
894 | } | 941 | } |
895 | 942 | ||
896 | int virtual_device_parent(struct device *dev) | ||
897 | { | ||
898 | if (!dev->class) | ||
899 | return -ENODEV; | ||
900 | |||
901 | if (!dev->class->virtual_dir) { | ||
902 | static struct kobject *virtual_dir = NULL; | ||
903 | |||
904 | if (!virtual_dir) | ||
905 | virtual_dir = kobject_add_dir(&devices_subsys.kset.kobj, "virtual"); | ||
906 | dev->class->virtual_dir = kobject_add_dir(virtual_dir, dev->class->name); | ||
907 | } | ||
908 | |||
909 | dev->kobj.parent = dev->class->virtual_dir; | ||
910 | return 0; | ||
911 | } | ||
912 | |||
913 | int __init classes_init(void) | 943 | int __init classes_init(void) |
914 | { | 944 | { |
915 | int retval; | 945 | int retval; |