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