diff options
Diffstat (limited to 'drivers/base/core.c')
-rw-r--r-- | drivers/base/core.c | 83 |
1 files changed, 82 insertions, 1 deletions
diff --git a/drivers/base/core.c b/drivers/base/core.c index ee0a51a3a41d..be9aba4dc2fb 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c | |||
@@ -27,6 +27,9 @@ | |||
27 | 27 | ||
28 | int (*platform_notify)(struct device *dev) = NULL; | 28 | int (*platform_notify)(struct device *dev) = NULL; |
29 | int (*platform_notify_remove)(struct device *dev) = NULL; | 29 | int (*platform_notify_remove)(struct device *dev) = NULL; |
30 | static struct kobject *dev_kobj; | ||
31 | struct kobject *sysfs_dev_char_kobj; | ||
32 | struct kobject *sysfs_dev_block_kobj; | ||
30 | 33 | ||
31 | #ifdef CONFIG_BLOCK | 34 | #ifdef CONFIG_BLOCK |
32 | static inline int device_is_not_partition(struct device *dev) | 35 | static inline int device_is_not_partition(struct device *dev) |
@@ -776,6 +779,54 @@ int dev_set_name(struct device *dev, const char *fmt, ...) | |||
776 | EXPORT_SYMBOL_GPL(dev_set_name); | 779 | EXPORT_SYMBOL_GPL(dev_set_name); |
777 | 780 | ||
778 | /** | 781 | /** |
782 | * device_to_dev_kobj - select a /sys/dev/ directory for the device | ||
783 | * @dev: device | ||
784 | * | ||
785 | * By default we select char/ for new entries. Setting class->dev_obj | ||
786 | * to NULL prevents an entry from being created. class->dev_kobj must | ||
787 | * be set (or cleared) before any devices are registered to the class | ||
788 | * otherwise device_create_sys_dev_entry() and | ||
789 | * device_remove_sys_dev_entry() will disagree about the the presence | ||
790 | * of the link. | ||
791 | */ | ||
792 | static struct kobject *device_to_dev_kobj(struct device *dev) | ||
793 | { | ||
794 | struct kobject *kobj; | ||
795 | |||
796 | if (dev->class) | ||
797 | kobj = dev->class->dev_kobj; | ||
798 | else | ||
799 | kobj = sysfs_dev_char_kobj; | ||
800 | |||
801 | return kobj; | ||
802 | } | ||
803 | |||
804 | static int device_create_sys_dev_entry(struct device *dev) | ||
805 | { | ||
806 | struct kobject *kobj = device_to_dev_kobj(dev); | ||
807 | int error = 0; | ||
808 | char devt_str[15]; | ||
809 | |||
810 | if (kobj) { | ||
811 | format_dev_t(devt_str, dev->devt); | ||
812 | error = sysfs_create_link(kobj, &dev->kobj, devt_str); | ||
813 | } | ||
814 | |||
815 | return error; | ||
816 | } | ||
817 | |||
818 | static void device_remove_sys_dev_entry(struct device *dev) | ||
819 | { | ||
820 | struct kobject *kobj = device_to_dev_kobj(dev); | ||
821 | char devt_str[15]; | ||
822 | |||
823 | if (kobj) { | ||
824 | format_dev_t(devt_str, dev->devt); | ||
825 | sysfs_remove_link(kobj, devt_str); | ||
826 | } | ||
827 | } | ||
828 | |||
829 | /** | ||
779 | * device_add - add device to device hierarchy. | 830 | * device_add - add device to device hierarchy. |
780 | * @dev: device. | 831 | * @dev: device. |
781 | * | 832 | * |
@@ -829,6 +880,10 @@ int device_add(struct device *dev) | |||
829 | error = device_create_file(dev, &devt_attr); | 880 | error = device_create_file(dev, &devt_attr); |
830 | if (error) | 881 | if (error) |
831 | goto ueventattrError; | 882 | goto ueventattrError; |
883 | |||
884 | error = device_create_sys_dev_entry(dev); | ||
885 | if (error) | ||
886 | goto devtattrError; | ||
832 | } | 887 | } |
833 | 888 | ||
834 | error = device_add_class_symlinks(dev); | 889 | error = device_add_class_symlinks(dev); |
@@ -873,6 +928,9 @@ int device_add(struct device *dev) | |||
873 | device_remove_class_symlinks(dev); | 928 | device_remove_class_symlinks(dev); |
874 | SymlinkError: | 929 | SymlinkError: |
875 | if (MAJOR(dev->devt)) | 930 | if (MAJOR(dev->devt)) |
931 | device_remove_sys_dev_entry(dev); | ||
932 | devtattrError: | ||
933 | if (MAJOR(dev->devt)) | ||
876 | device_remove_file(dev, &devt_attr); | 934 | device_remove_file(dev, &devt_attr); |
877 | ueventattrError: | 935 | ueventattrError: |
878 | device_remove_file(dev, &uevent_attr); | 936 | device_remove_file(dev, &uevent_attr); |
@@ -948,8 +1006,10 @@ void device_del(struct device *dev) | |||
948 | device_pm_remove(dev); | 1006 | device_pm_remove(dev); |
949 | if (parent) | 1007 | if (parent) |
950 | klist_del(&dev->knode_parent); | 1008 | klist_del(&dev->knode_parent); |
951 | if (MAJOR(dev->devt)) | 1009 | if (MAJOR(dev->devt)) { |
1010 | device_remove_sys_dev_entry(dev); | ||
952 | device_remove_file(dev, &devt_attr); | 1011 | device_remove_file(dev, &devt_attr); |
1012 | } | ||
953 | if (dev->class) { | 1013 | if (dev->class) { |
954 | device_remove_class_symlinks(dev); | 1014 | device_remove_class_symlinks(dev); |
955 | 1015 | ||
@@ -1074,7 +1134,25 @@ int __init devices_init(void) | |||
1074 | devices_kset = kset_create_and_add("devices", &device_uevent_ops, NULL); | 1134 | devices_kset = kset_create_and_add("devices", &device_uevent_ops, NULL); |
1075 | if (!devices_kset) | 1135 | if (!devices_kset) |
1076 | return -ENOMEM; | 1136 | return -ENOMEM; |
1137 | dev_kobj = kobject_create_and_add("dev", NULL); | ||
1138 | if (!dev_kobj) | ||
1139 | goto dev_kobj_err; | ||
1140 | sysfs_dev_block_kobj = kobject_create_and_add("block", dev_kobj); | ||
1141 | if (!sysfs_dev_block_kobj) | ||
1142 | goto block_kobj_err; | ||
1143 | sysfs_dev_char_kobj = kobject_create_and_add("char", dev_kobj); | ||
1144 | if (!sysfs_dev_char_kobj) | ||
1145 | goto char_kobj_err; | ||
1146 | |||
1077 | return 0; | 1147 | return 0; |
1148 | |||
1149 | char_kobj_err: | ||
1150 | kobject_put(sysfs_dev_block_kobj); | ||
1151 | block_kobj_err: | ||
1152 | kobject_put(dev_kobj); | ||
1153 | dev_kobj_err: | ||
1154 | kset_unregister(devices_kset); | ||
1155 | return -ENOMEM; | ||
1078 | } | 1156 | } |
1079 | 1157 | ||
1080 | EXPORT_SYMBOL_GPL(device_for_each_child); | 1158 | EXPORT_SYMBOL_GPL(device_for_each_child); |
@@ -1447,4 +1525,7 @@ void device_shutdown(void) | |||
1447 | dev->driver->shutdown(dev); | 1525 | dev->driver->shutdown(dev); |
1448 | } | 1526 | } |
1449 | } | 1527 | } |
1528 | kobject_put(sysfs_dev_char_kobj); | ||
1529 | kobject_put(sysfs_dev_block_kobj); | ||
1530 | kobject_put(dev_kobj); | ||
1450 | } | 1531 | } |