diff options
author | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2017-07-22 06:00:15 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2017-07-22 06:00:15 -0400 |
commit | 1af824f085e813e06548212b18bbc788b16f60e6 (patch) | |
tree | 7e4bea76e0780330e27d660633ba514dc02e2fbf /drivers/base/core.c | |
parent | d8bcf4db9244e2b85597c680f4e1c3a837b067fe (diff) | |
parent | 072a7852338af900c302490474939e089f4bd4c4 (diff) |
Merge branch 'bind_unbind' into driver-core-next
This merges the bind_unbind driver core feature into the
driver-core-next branch. bind_unbind is a branch so that others can
pull and work off of it safely.
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/base/core.c')
-rw-r--r-- | drivers/base/core.c | 132 |
1 files changed, 132 insertions, 0 deletions
diff --git a/drivers/base/core.c b/drivers/base/core.c index 755451f684bc..cb4b5b1f1b09 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c | |||
@@ -1023,12 +1023,144 @@ int device_add_groups(struct device *dev, const struct attribute_group **groups) | |||
1023 | { | 1023 | { |
1024 | return sysfs_create_groups(&dev->kobj, groups); | 1024 | return sysfs_create_groups(&dev->kobj, groups); |
1025 | } | 1025 | } |
1026 | EXPORT_SYMBOL_GPL(device_add_groups); | ||
1026 | 1027 | ||
1027 | void device_remove_groups(struct device *dev, | 1028 | void device_remove_groups(struct device *dev, |
1028 | const struct attribute_group **groups) | 1029 | const struct attribute_group **groups) |
1029 | { | 1030 | { |
1030 | sysfs_remove_groups(&dev->kobj, groups); | 1031 | sysfs_remove_groups(&dev->kobj, groups); |
1031 | } | 1032 | } |
1033 | EXPORT_SYMBOL_GPL(device_remove_groups); | ||
1034 | |||
1035 | union device_attr_group_devres { | ||
1036 | const struct attribute_group *group; | ||
1037 | const struct attribute_group **groups; | ||
1038 | }; | ||
1039 | |||
1040 | static int devm_attr_group_match(struct device *dev, void *res, void *data) | ||
1041 | { | ||
1042 | return ((union device_attr_group_devres *)res)->group == data; | ||
1043 | } | ||
1044 | |||
1045 | static void devm_attr_group_remove(struct device *dev, void *res) | ||
1046 | { | ||
1047 | union device_attr_group_devres *devres = res; | ||
1048 | const struct attribute_group *group = devres->group; | ||
1049 | |||
1050 | dev_dbg(dev, "%s: removing group %p\n", __func__, group); | ||
1051 | sysfs_remove_group(&dev->kobj, group); | ||
1052 | } | ||
1053 | |||
1054 | static void devm_attr_groups_remove(struct device *dev, void *res) | ||
1055 | { | ||
1056 | union device_attr_group_devres *devres = res; | ||
1057 | const struct attribute_group **groups = devres->groups; | ||
1058 | |||
1059 | dev_dbg(dev, "%s: removing groups %p\n", __func__, groups); | ||
1060 | sysfs_remove_groups(&dev->kobj, groups); | ||
1061 | } | ||
1062 | |||
1063 | /** | ||
1064 | * devm_device_add_group - given a device, create a managed attribute group | ||
1065 | * @dev: The device to create the group for | ||
1066 | * @grp: The attribute group to create | ||
1067 | * | ||
1068 | * This function creates a group for the first time. It will explicitly | ||
1069 | * warn and error if any of the attribute files being created already exist. | ||
1070 | * | ||
1071 | * Returns 0 on success or error code on failure. | ||
1072 | */ | ||
1073 | int devm_device_add_group(struct device *dev, const struct attribute_group *grp) | ||
1074 | { | ||
1075 | union device_attr_group_devres *devres; | ||
1076 | int error; | ||
1077 | |||
1078 | devres = devres_alloc(devm_attr_group_remove, | ||
1079 | sizeof(*devres), GFP_KERNEL); | ||
1080 | if (!devres) | ||
1081 | return -ENOMEM; | ||
1082 | |||
1083 | error = sysfs_create_group(&dev->kobj, grp); | ||
1084 | if (error) { | ||
1085 | devres_free(devres); | ||
1086 | return error; | ||
1087 | } | ||
1088 | |||
1089 | devres->group = grp; | ||
1090 | devres_add(dev, devres); | ||
1091 | return 0; | ||
1092 | } | ||
1093 | EXPORT_SYMBOL_GPL(devm_device_add_group); | ||
1094 | |||
1095 | /** | ||
1096 | * devm_device_remove_group: remove a managed group from a device | ||
1097 | * @dev: device to remove the group from | ||
1098 | * @grp: group to remove | ||
1099 | * | ||
1100 | * This function removes a group of attributes from a device. The attributes | ||
1101 | * previously have to have been created for this group, otherwise it will fail. | ||
1102 | */ | ||
1103 | void devm_device_remove_group(struct device *dev, | ||
1104 | const struct attribute_group *grp) | ||
1105 | { | ||
1106 | WARN_ON(devres_release(dev, devm_attr_group_remove, | ||
1107 | devm_attr_group_match, | ||
1108 | /* cast away const */ (void *)grp)); | ||
1109 | } | ||
1110 | EXPORT_SYMBOL_GPL(devm_device_remove_group); | ||
1111 | |||
1112 | /** | ||
1113 | * devm_device_add_groups - create a bunch of managed attribute groups | ||
1114 | * @dev: The device to create the group for | ||
1115 | * @groups: The attribute groups to create, NULL terminated | ||
1116 | * | ||
1117 | * This function creates a bunch of managed attribute groups. If an error | ||
1118 | * occurs when creating a group, all previously created groups will be | ||
1119 | * removed, unwinding everything back to the original state when this | ||
1120 | * function was called. It will explicitly warn and error if any of the | ||
1121 | * attribute files being created already exist. | ||
1122 | * | ||
1123 | * Returns 0 on success or error code from sysfs_create_group on failure. | ||
1124 | */ | ||
1125 | int devm_device_add_groups(struct device *dev, | ||
1126 | const struct attribute_group **groups) | ||
1127 | { | ||
1128 | union device_attr_group_devres *devres; | ||
1129 | int error; | ||
1130 | |||
1131 | devres = devres_alloc(devm_attr_groups_remove, | ||
1132 | sizeof(*devres), GFP_KERNEL); | ||
1133 | if (!devres) | ||
1134 | return -ENOMEM; | ||
1135 | |||
1136 | error = sysfs_create_groups(&dev->kobj, groups); | ||
1137 | if (error) { | ||
1138 | devres_free(devres); | ||
1139 | return error; | ||
1140 | } | ||
1141 | |||
1142 | devres->groups = groups; | ||
1143 | devres_add(dev, devres); | ||
1144 | return 0; | ||
1145 | } | ||
1146 | EXPORT_SYMBOL_GPL(devm_device_add_groups); | ||
1147 | |||
1148 | /** | ||
1149 | * devm_device_remove_groups - remove a list of managed groups | ||
1150 | * | ||
1151 | * @dev: The device for the groups to be removed from | ||
1152 | * @groups: NULL terminated list of groups to be removed | ||
1153 | * | ||
1154 | * If groups is not NULL, remove the specified groups from the device. | ||
1155 | */ | ||
1156 | void devm_device_remove_groups(struct device *dev, | ||
1157 | const struct attribute_group **groups) | ||
1158 | { | ||
1159 | WARN_ON(devres_release(dev, devm_attr_groups_remove, | ||
1160 | devm_attr_group_match, | ||
1161 | /* cast away const */ (void *)groups)); | ||
1162 | } | ||
1163 | EXPORT_SYMBOL_GPL(devm_device_remove_groups); | ||
1032 | 1164 | ||
1033 | static int device_add_attrs(struct device *dev) | 1165 | static int device_add_attrs(struct device *dev) |
1034 | { | 1166 | { |