diff options
Diffstat (limited to 'drivers/base/core.c')
-rw-r--r-- | drivers/base/core.c | 85 |
1 files changed, 69 insertions, 16 deletions
diff --git a/drivers/base/core.c b/drivers/base/core.c index 919daa7cd5b1..4dac58aa4a0a 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c | |||
@@ -118,6 +118,56 @@ static const struct sysfs_ops dev_sysfs_ops = { | |||
118 | .store = dev_attr_store, | 118 | .store = dev_attr_store, |
119 | }; | 119 | }; |
120 | 120 | ||
121 | #define to_ext_attr(x) container_of(x, struct dev_ext_attribute, attr) | ||
122 | |||
123 | ssize_t device_store_ulong(struct device *dev, | ||
124 | struct device_attribute *attr, | ||
125 | const char *buf, size_t size) | ||
126 | { | ||
127 | struct dev_ext_attribute *ea = to_ext_attr(attr); | ||
128 | char *end; | ||
129 | unsigned long new = simple_strtoul(buf, &end, 0); | ||
130 | if (end == buf) | ||
131 | return -EINVAL; | ||
132 | *(unsigned long *)(ea->var) = new; | ||
133 | /* Always return full write size even if we didn't consume all */ | ||
134 | return size; | ||
135 | } | ||
136 | EXPORT_SYMBOL_GPL(device_store_ulong); | ||
137 | |||
138 | ssize_t device_show_ulong(struct device *dev, | ||
139 | struct device_attribute *attr, | ||
140 | char *buf) | ||
141 | { | ||
142 | struct dev_ext_attribute *ea = to_ext_attr(attr); | ||
143 | return snprintf(buf, PAGE_SIZE, "%lx\n", *(unsigned long *)(ea->var)); | ||
144 | } | ||
145 | EXPORT_SYMBOL_GPL(device_show_ulong); | ||
146 | |||
147 | ssize_t device_store_int(struct device *dev, | ||
148 | struct device_attribute *attr, | ||
149 | const char *buf, size_t size) | ||
150 | { | ||
151 | struct dev_ext_attribute *ea = to_ext_attr(attr); | ||
152 | char *end; | ||
153 | long new = simple_strtol(buf, &end, 0); | ||
154 | if (end == buf || new > INT_MAX || new < INT_MIN) | ||
155 | return -EINVAL; | ||
156 | *(int *)(ea->var) = new; | ||
157 | /* Always return full write size even if we didn't consume all */ | ||
158 | return size; | ||
159 | } | ||
160 | EXPORT_SYMBOL_GPL(device_store_int); | ||
161 | |||
162 | ssize_t device_show_int(struct device *dev, | ||
163 | struct device_attribute *attr, | ||
164 | char *buf) | ||
165 | { | ||
166 | struct dev_ext_attribute *ea = to_ext_attr(attr); | ||
167 | |||
168 | return snprintf(buf, PAGE_SIZE, "%d\n", *(int *)(ea->var)); | ||
169 | } | ||
170 | EXPORT_SYMBOL_GPL(device_show_int); | ||
121 | 171 | ||
122 | /** | 172 | /** |
123 | * device_release - free device structure. | 173 | * device_release - free device structure. |
@@ -464,7 +514,7 @@ static ssize_t show_dev(struct device *dev, struct device_attribute *attr, | |||
464 | static struct device_attribute devt_attr = | 514 | static struct device_attribute devt_attr = |
465 | __ATTR(dev, S_IRUGO, show_dev, NULL); | 515 | __ATTR(dev, S_IRUGO, show_dev, NULL); |
466 | 516 | ||
467 | /* kset to create /sys/devices/ */ | 517 | /* /sys/devices/ */ |
468 | struct kset *devices_kset; | 518 | struct kset *devices_kset; |
469 | 519 | ||
470 | /** | 520 | /** |
@@ -711,6 +761,10 @@ static struct kobject *get_device_parent(struct device *dev, | |||
711 | return k; | 761 | return k; |
712 | } | 762 | } |
713 | 763 | ||
764 | /* subsystems can specify a default root directory for their devices */ | ||
765 | if (!parent && dev->bus && dev->bus->dev_root) | ||
766 | return &dev->bus->dev_root->kobj; | ||
767 | |||
714 | if (parent) | 768 | if (parent) |
715 | return &parent->kobj; | 769 | return &parent->kobj; |
716 | return NULL; | 770 | return NULL; |
@@ -731,14 +785,6 @@ static void cleanup_device_parent(struct device *dev) | |||
731 | cleanup_glue_dir(dev, dev->kobj.parent); | 785 | cleanup_glue_dir(dev, dev->kobj.parent); |
732 | } | 786 | } |
733 | 787 | ||
734 | static void setup_parent(struct device *dev, struct device *parent) | ||
735 | { | ||
736 | struct kobject *kobj; | ||
737 | kobj = get_device_parent(dev, parent); | ||
738 | if (kobj) | ||
739 | dev->kobj.parent = kobj; | ||
740 | } | ||
741 | |||
742 | static int device_add_class_symlinks(struct device *dev) | 788 | static int device_add_class_symlinks(struct device *dev) |
743 | { | 789 | { |
744 | int error; | 790 | int error; |
@@ -891,6 +937,7 @@ int device_private_init(struct device *dev) | |||
891 | int device_add(struct device *dev) | 937 | int device_add(struct device *dev) |
892 | { | 938 | { |
893 | struct device *parent = NULL; | 939 | struct device *parent = NULL; |
940 | struct kobject *kobj; | ||
894 | struct class_interface *class_intf; | 941 | struct class_interface *class_intf; |
895 | int error = -EINVAL; | 942 | int error = -EINVAL; |
896 | 943 | ||
@@ -914,6 +961,10 @@ int device_add(struct device *dev) | |||
914 | dev->init_name = NULL; | 961 | dev->init_name = NULL; |
915 | } | 962 | } |
916 | 963 | ||
964 | /* subsystems can specify simple device enumeration */ | ||
965 | if (!dev_name(dev) && dev->bus && dev->bus->dev_name) | ||
966 | dev_set_name(dev, "%s%u", dev->bus->dev_name, dev->id); | ||
967 | |||
917 | if (!dev_name(dev)) { | 968 | if (!dev_name(dev)) { |
918 | error = -EINVAL; | 969 | error = -EINVAL; |
919 | goto name_error; | 970 | goto name_error; |
@@ -922,7 +973,9 @@ int device_add(struct device *dev) | |||
922 | pr_debug("device: '%s': %s\n", dev_name(dev), __func__); | 973 | pr_debug("device: '%s': %s\n", dev_name(dev), __func__); |
923 | 974 | ||
924 | parent = get_device(dev->parent); | 975 | parent = get_device(dev->parent); |
925 | setup_parent(dev, parent); | 976 | kobj = get_device_parent(dev, parent); |
977 | if (kobj) | ||
978 | dev->kobj.parent = kobj; | ||
926 | 979 | ||
927 | /* use parent numa_node */ | 980 | /* use parent numa_node */ |
928 | if (parent) | 981 | if (parent) |
@@ -982,17 +1035,17 @@ int device_add(struct device *dev) | |||
982 | &parent->p->klist_children); | 1035 | &parent->p->klist_children); |
983 | 1036 | ||
984 | if (dev->class) { | 1037 | if (dev->class) { |
985 | mutex_lock(&dev->class->p->class_mutex); | 1038 | mutex_lock(&dev->class->p->mutex); |
986 | /* tie the class to the device */ | 1039 | /* tie the class to the device */ |
987 | klist_add_tail(&dev->knode_class, | 1040 | klist_add_tail(&dev->knode_class, |
988 | &dev->class->p->klist_devices); | 1041 | &dev->class->p->klist_devices); |
989 | 1042 | ||
990 | /* notify any interfaces that the device is here */ | 1043 | /* notify any interfaces that the device is here */ |
991 | list_for_each_entry(class_intf, | 1044 | list_for_each_entry(class_intf, |
992 | &dev->class->p->class_interfaces, node) | 1045 | &dev->class->p->interfaces, node) |
993 | if (class_intf->add_dev) | 1046 | if (class_intf->add_dev) |
994 | class_intf->add_dev(dev, class_intf); | 1047 | class_intf->add_dev(dev, class_intf); |
995 | mutex_unlock(&dev->class->p->class_mutex); | 1048 | mutex_unlock(&dev->class->p->mutex); |
996 | } | 1049 | } |
997 | done: | 1050 | done: |
998 | put_device(dev); | 1051 | put_device(dev); |
@@ -1107,15 +1160,15 @@ void device_del(struct device *dev) | |||
1107 | if (dev->class) { | 1160 | if (dev->class) { |
1108 | device_remove_class_symlinks(dev); | 1161 | device_remove_class_symlinks(dev); |
1109 | 1162 | ||
1110 | mutex_lock(&dev->class->p->class_mutex); | 1163 | mutex_lock(&dev->class->p->mutex); |
1111 | /* notify any interfaces that the device is now gone */ | 1164 | /* notify any interfaces that the device is now gone */ |
1112 | list_for_each_entry(class_intf, | 1165 | list_for_each_entry(class_intf, |
1113 | &dev->class->p->class_interfaces, node) | 1166 | &dev->class->p->interfaces, node) |
1114 | if (class_intf->remove_dev) | 1167 | if (class_intf->remove_dev) |
1115 | class_intf->remove_dev(dev, class_intf); | 1168 | class_intf->remove_dev(dev, class_intf); |
1116 | /* remove the device from the class list */ | 1169 | /* remove the device from the class list */ |
1117 | klist_del(&dev->knode_class); | 1170 | klist_del(&dev->knode_class); |
1118 | mutex_unlock(&dev->class->p->class_mutex); | 1171 | mutex_unlock(&dev->class->p->mutex); |
1119 | } | 1172 | } |
1120 | device_remove_file(dev, &uevent_attr); | 1173 | device_remove_file(dev, &uevent_attr); |
1121 | device_remove_attrs(dev); | 1174 | device_remove_attrs(dev); |