aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/base/core.c
diff options
context:
space:
mode:
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>2017-07-22 06:00:15 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2017-07-22 06:00:15 -0400
commit1af824f085e813e06548212b18bbc788b16f60e6 (patch)
tree7e4bea76e0780330e27d660633ba514dc02e2fbf /drivers/base/core.c
parentd8bcf4db9244e2b85597c680f4e1c3a837b067fe (diff)
parent072a7852338af900c302490474939e089f4bd4c4 (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.c132
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}
1026EXPORT_SYMBOL_GPL(device_add_groups);
1026 1027
1027void device_remove_groups(struct device *dev, 1028void 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}
1033EXPORT_SYMBOL_GPL(device_remove_groups);
1034
1035union device_attr_group_devres {
1036 const struct attribute_group *group;
1037 const struct attribute_group **groups;
1038};
1039
1040static 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
1045static 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
1054static 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 */
1073int 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}
1093EXPORT_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 */
1103void 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}
1110EXPORT_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 */
1125int 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}
1146EXPORT_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 */
1156void 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}
1163EXPORT_SYMBOL_GPL(devm_device_remove_groups);
1032 1164
1033static int device_add_attrs(struct device *dev) 1165static int device_add_attrs(struct device *dev)
1034{ 1166{