diff options
Diffstat (limited to 'drivers/base/core.c')
-rw-r--r-- | drivers/base/core.c | 168 |
1 files changed, 125 insertions, 43 deletions
diff --git a/drivers/base/core.c b/drivers/base/core.c index 0455aa78fa13..3599ab2506d2 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c | |||
@@ -24,6 +24,8 @@ | |||
24 | #include "base.h" | 24 | #include "base.h" |
25 | #include "power/power.h" | 25 | #include "power/power.h" |
26 | 26 | ||
27 | extern const char *kobject_actions[]; | ||
28 | |||
27 | int (*platform_notify)(struct device * dev) = NULL; | 29 | int (*platform_notify)(struct device * dev) = NULL; |
28 | int (*platform_notify_remove)(struct device * dev) = NULL; | 30 | int (*platform_notify_remove)(struct device * dev) = NULL; |
29 | 31 | ||
@@ -303,10 +305,25 @@ out: | |||
303 | static ssize_t store_uevent(struct device *dev, struct device_attribute *attr, | 305 | static ssize_t store_uevent(struct device *dev, struct device_attribute *attr, |
304 | const char *buf, size_t count) | 306 | const char *buf, size_t count) |
305 | { | 307 | { |
306 | if (memcmp(buf, "add", 3) != 0) | 308 | size_t len = count; |
307 | dev_err(dev, "uevent: unsupported action-string; this will " | 309 | enum kobject_action action; |
308 | "be ignored in a future kernel version"); | 310 | |
311 | if (len && buf[len-1] == '\n') | ||
312 | len--; | ||
313 | |||
314 | for (action = 0; action < KOBJ_MAX; action++) { | ||
315 | if (strncmp(kobject_actions[action], buf, len) != 0) | ||
316 | continue; | ||
317 | if (kobject_actions[action][len] != '\0') | ||
318 | continue; | ||
319 | kobject_uevent(&dev->kobj, action); | ||
320 | goto out; | ||
321 | } | ||
322 | |||
323 | dev_err(dev, "uevent: unsupported action-string; this will " | ||
324 | "be ignored in a future kernel version\n"); | ||
309 | kobject_uevent(&dev->kobj, KOBJ_ADD); | 325 | kobject_uevent(&dev->kobj, KOBJ_ADD); |
326 | out: | ||
310 | return count; | 327 | return count; |
311 | } | 328 | } |
312 | 329 | ||
@@ -643,6 +660,82 @@ static int setup_parent(struct device *dev, struct device *parent) | |||
643 | return 0; | 660 | return 0; |
644 | } | 661 | } |
645 | 662 | ||
663 | static int device_add_class_symlinks(struct device *dev) | ||
664 | { | ||
665 | int error; | ||
666 | |||
667 | if (!dev->class) | ||
668 | return 0; | ||
669 | error = sysfs_create_link(&dev->kobj, &dev->class->subsys.kobj, | ||
670 | "subsystem"); | ||
671 | if (error) | ||
672 | goto out; | ||
673 | /* | ||
674 | * If this is not a "fake" compatible device, then create the | ||
675 | * symlink from the class to the device. | ||
676 | */ | ||
677 | if (dev->kobj.parent != &dev->class->subsys.kobj) { | ||
678 | error = sysfs_create_link(&dev->class->subsys.kobj, &dev->kobj, | ||
679 | dev->bus_id); | ||
680 | if (error) | ||
681 | goto out_subsys; | ||
682 | } | ||
683 | /* only bus-device parents get a "device"-link */ | ||
684 | if (dev->parent && dev->parent->bus) { | ||
685 | error = sysfs_create_link(&dev->kobj, &dev->parent->kobj, | ||
686 | "device"); | ||
687 | if (error) | ||
688 | goto out_busid; | ||
689 | #ifdef CONFIG_SYSFS_DEPRECATED | ||
690 | { | ||
691 | char * class_name = make_class_name(dev->class->name, | ||
692 | &dev->kobj); | ||
693 | if (class_name) | ||
694 | error = sysfs_create_link(&dev->parent->kobj, | ||
695 | &dev->kobj, class_name); | ||
696 | kfree(class_name); | ||
697 | if (error) | ||
698 | goto out_device; | ||
699 | } | ||
700 | #endif | ||
701 | } | ||
702 | return 0; | ||
703 | |||
704 | #ifdef CONFIG_SYSFS_DEPRECATED | ||
705 | out_device: | ||
706 | if (dev->parent) | ||
707 | sysfs_remove_link(&dev->kobj, "device"); | ||
708 | #endif | ||
709 | out_busid: | ||
710 | if (dev->kobj.parent != &dev->class->subsys.kobj) | ||
711 | sysfs_remove_link(&dev->class->subsys.kobj, dev->bus_id); | ||
712 | out_subsys: | ||
713 | sysfs_remove_link(&dev->kobj, "subsystem"); | ||
714 | out: | ||
715 | return error; | ||
716 | } | ||
717 | |||
718 | static void device_remove_class_symlinks(struct device *dev) | ||
719 | { | ||
720 | if (!dev->class) | ||
721 | return; | ||
722 | if (dev->parent) { | ||
723 | #ifdef CONFIG_SYSFS_DEPRECATED | ||
724 | char *class_name; | ||
725 | |||
726 | class_name = make_class_name(dev->class->name, &dev->kobj); | ||
727 | if (class_name) { | ||
728 | sysfs_remove_link(&dev->parent->kobj, class_name); | ||
729 | kfree(class_name); | ||
730 | } | ||
731 | #endif | ||
732 | sysfs_remove_link(&dev->kobj, "device"); | ||
733 | } | ||
734 | if (dev->kobj.parent != &dev->class->subsys.kobj) | ||
735 | sysfs_remove_link(&dev->class->subsys.kobj, dev->bus_id); | ||
736 | sysfs_remove_link(&dev->kobj, "subsystem"); | ||
737 | } | ||
738 | |||
646 | /** | 739 | /** |
647 | * device_add - add device to device hierarchy. | 740 | * device_add - add device to device hierarchy. |
648 | * @dev: device. | 741 | * @dev: device. |
@@ -657,7 +750,6 @@ static int setup_parent(struct device *dev, struct device *parent) | |||
657 | int device_add(struct device *dev) | 750 | int device_add(struct device *dev) |
658 | { | 751 | { |
659 | struct device *parent = NULL; | 752 | struct device *parent = NULL; |
660 | char *class_name = NULL; | ||
661 | struct class_interface *class_intf; | 753 | struct class_interface *class_intf; |
662 | int error = -EINVAL; | 754 | int error = -EINVAL; |
663 | 755 | ||
@@ -697,27 +789,9 @@ int device_add(struct device *dev) | |||
697 | goto ueventattrError; | 789 | goto ueventattrError; |
698 | } | 790 | } |
699 | 791 | ||
700 | if (dev->class) { | 792 | error = device_add_class_symlinks(dev); |
701 | sysfs_create_link(&dev->kobj, &dev->class->subsys.kobj, | 793 | if (error) |
702 | "subsystem"); | 794 | goto SymlinkError; |
703 | /* If this is not a "fake" compatible device, then create the | ||
704 | * symlink from the class to the device. */ | ||
705 | if (dev->kobj.parent != &dev->class->subsys.kobj) | ||
706 | sysfs_create_link(&dev->class->subsys.kobj, | ||
707 | &dev->kobj, dev->bus_id); | ||
708 | if (parent) { | ||
709 | sysfs_create_link(&dev->kobj, &dev->parent->kobj, | ||
710 | "device"); | ||
711 | #ifdef CONFIG_SYSFS_DEPRECATED | ||
712 | class_name = make_class_name(dev->class->name, | ||
713 | &dev->kobj); | ||
714 | if (class_name) | ||
715 | sysfs_create_link(&dev->parent->kobj, | ||
716 | &dev->kobj, class_name); | ||
717 | #endif | ||
718 | } | ||
719 | } | ||
720 | |||
721 | error = device_add_attrs(dev); | 795 | error = device_add_attrs(dev); |
722 | if (error) | 796 | if (error) |
723 | goto AttrsError; | 797 | goto AttrsError; |
@@ -744,7 +818,6 @@ int device_add(struct device *dev) | |||
744 | up(&dev->class->sem); | 818 | up(&dev->class->sem); |
745 | } | 819 | } |
746 | Done: | 820 | Done: |
747 | kfree(class_name); | ||
748 | put_device(dev); | 821 | put_device(dev); |
749 | return error; | 822 | return error; |
750 | BusError: | 823 | BusError: |
@@ -755,6 +828,8 @@ int device_add(struct device *dev) | |||
755 | BUS_NOTIFY_DEL_DEVICE, dev); | 828 | BUS_NOTIFY_DEL_DEVICE, dev); |
756 | device_remove_attrs(dev); | 829 | device_remove_attrs(dev); |
757 | AttrsError: | 830 | AttrsError: |
831 | device_remove_class_symlinks(dev); | ||
832 | SymlinkError: | ||
758 | if (MAJOR(dev->devt)) | 833 | if (MAJOR(dev->devt)) |
759 | device_remove_file(dev, &devt_attr); | 834 | device_remove_file(dev, &devt_attr); |
760 | 835 | ||
@@ -1139,7 +1214,7 @@ int device_rename(struct device *dev, char *new_name) | |||
1139 | { | 1214 | { |
1140 | char *old_class_name = NULL; | 1215 | char *old_class_name = NULL; |
1141 | char *new_class_name = NULL; | 1216 | char *new_class_name = NULL; |
1142 | char *old_symlink_name = NULL; | 1217 | char *old_device_name = NULL; |
1143 | int error; | 1218 | int error; |
1144 | 1219 | ||
1145 | dev = get_device(dev); | 1220 | dev = get_device(dev); |
@@ -1153,42 +1228,49 @@ int device_rename(struct device *dev, char *new_name) | |||
1153 | old_class_name = make_class_name(dev->class->name, &dev->kobj); | 1228 | old_class_name = make_class_name(dev->class->name, &dev->kobj); |
1154 | #endif | 1229 | #endif |
1155 | 1230 | ||
1156 | if (dev->class) { | 1231 | old_device_name = kmalloc(BUS_ID_SIZE, GFP_KERNEL); |
1157 | old_symlink_name = kmalloc(BUS_ID_SIZE, GFP_KERNEL); | 1232 | if (!old_device_name) { |
1158 | if (!old_symlink_name) { | 1233 | error = -ENOMEM; |
1159 | error = -ENOMEM; | 1234 | goto out; |
1160 | goto out_free_old_class; | ||
1161 | } | ||
1162 | strlcpy(old_symlink_name, dev->bus_id, BUS_ID_SIZE); | ||
1163 | } | 1235 | } |
1164 | 1236 | strlcpy(old_device_name, dev->bus_id, BUS_ID_SIZE); | |
1165 | strlcpy(dev->bus_id, new_name, BUS_ID_SIZE); | 1237 | strlcpy(dev->bus_id, new_name, BUS_ID_SIZE); |
1166 | 1238 | ||
1167 | error = kobject_rename(&dev->kobj, new_name); | 1239 | error = kobject_rename(&dev->kobj, new_name); |
1240 | if (error) { | ||
1241 | strlcpy(dev->bus_id, old_device_name, BUS_ID_SIZE); | ||
1242 | goto out; | ||
1243 | } | ||
1168 | 1244 | ||
1169 | #ifdef CONFIG_SYSFS_DEPRECATED | 1245 | #ifdef CONFIG_SYSFS_DEPRECATED |
1170 | if (old_class_name) { | 1246 | if (old_class_name) { |
1171 | new_class_name = make_class_name(dev->class->name, &dev->kobj); | 1247 | new_class_name = make_class_name(dev->class->name, &dev->kobj); |
1172 | if (new_class_name) { | 1248 | if (new_class_name) { |
1173 | sysfs_create_link(&dev->parent->kobj, &dev->kobj, | 1249 | error = sysfs_create_link(&dev->parent->kobj, |
1174 | new_class_name); | 1250 | &dev->kobj, new_class_name); |
1251 | if (error) | ||
1252 | goto out; | ||
1175 | sysfs_remove_link(&dev->parent->kobj, old_class_name); | 1253 | sysfs_remove_link(&dev->parent->kobj, old_class_name); |
1176 | } | 1254 | } |
1177 | } | 1255 | } |
1178 | #endif | 1256 | #endif |
1179 | 1257 | ||
1180 | if (dev->class) { | 1258 | if (dev->class) { |
1181 | sysfs_remove_link(&dev->class->subsys.kobj, | 1259 | sysfs_remove_link(&dev->class->subsys.kobj, old_device_name); |
1182 | old_symlink_name); | 1260 | error = sysfs_create_link(&dev->class->subsys.kobj, &dev->kobj, |
1183 | sysfs_create_link(&dev->class->subsys.kobj, &dev->kobj, | 1261 | dev->bus_id); |
1184 | dev->bus_id); | 1262 | if (error) { |
1263 | /* Uh... how to unravel this if restoring can fail? */ | ||
1264 | dev_err(dev, "%s: sysfs_create_symlink failed (%d)\n", | ||
1265 | __FUNCTION__, error); | ||
1266 | } | ||
1185 | } | 1267 | } |
1268 | out: | ||
1186 | put_device(dev); | 1269 | put_device(dev); |
1187 | 1270 | ||
1188 | kfree(new_class_name); | 1271 | kfree(new_class_name); |
1189 | kfree(old_symlink_name); | ||
1190 | out_free_old_class: | ||
1191 | kfree(old_class_name); | 1272 | kfree(old_class_name); |
1273 | kfree(old_device_name); | ||
1192 | 1274 | ||
1193 | return error; | 1275 | return error; |
1194 | } | 1276 | } |