@@ -1035,6 +1035,136 @@ void device_remove_groups(struct device *dev,
1035
1035
}
1036
1036
EXPORT_SYMBOL_GPL (device_remove_groups );
1037
1037
1038
+ union device_attr_group_devres {
1039
+ const struct attribute_group * group ;
1040
+ const struct attribute_group * * groups ;
1041
+ };
1042
+
1043
+ static int devm_attr_group_match (struct device * dev , void * res , void * data )
1044
+ {
1045
+ return ((union device_attr_group_devres * )res )-> group == data ;
1046
+ }
1047
+
1048
+ static void devm_attr_group_remove (struct device * dev , void * res )
1049
+ {
1050
+ union device_attr_group_devres * devres = res ;
1051
+ const struct attribute_group * group = devres -> group ;
1052
+
1053
+ dev_dbg (dev , "%s: removing group %p\n" , __func__ , group );
1054
+ sysfs_remove_group (& dev -> kobj , group );
1055
+ }
1056
+
1057
+ static void devm_attr_groups_remove (struct device * dev , void * res )
1058
+ {
1059
+ union device_attr_group_devres * devres = res ;
1060
+ const struct attribute_group * * groups = devres -> groups ;
1061
+
1062
+ dev_dbg (dev , "%s: removing groups %p\n" , __func__ , groups );
1063
+ sysfs_remove_groups (& dev -> kobj , groups );
1064
+ }
1065
+
1066
+ /**
1067
+ * devm_device_add_group - given a device, create a managed attribute group
1068
+ * @dev: The device to create the group for
1069
+ * @grp: The attribute group to create
1070
+ *
1071
+ * This function creates a group for the first time. It will explicitly
1072
+ * warn and error if any of the attribute files being created already exist.
1073
+ *
1074
+ * Returns 0 on success or error code on failure.
1075
+ */
1076
+ int devm_device_add_group (struct device * dev , const struct attribute_group * grp )
1077
+ {
1078
+ union device_attr_group_devres * devres ;
1079
+ int error ;
1080
+
1081
+ devres = devres_alloc (devm_attr_group_remove ,
1082
+ sizeof (* devres ), GFP_KERNEL );
1083
+ if (!devres )
1084
+ return - ENOMEM ;
1085
+
1086
+ error = sysfs_create_group (& dev -> kobj , grp );
1087
+ if (error ) {
1088
+ devres_free (devres );
1089
+ return error ;
1090
+ }
1091
+
1092
+ devres -> group = grp ;
1093
+ devres_add (dev , devres );
1094
+ return 0 ;
1095
+ }
1096
+ EXPORT_SYMBOL_GPL (devm_device_add_group );
1097
+
1098
+ /**
1099
+ * devm_device_remove_group: remove a managed group from a device
1100
+ * @dev: device to remove the group from
1101
+ * @grp: group to remove
1102
+ *
1103
+ * This function removes a group of attributes from a device. The attributes
1104
+ * previously have to have been created for this group, otherwise it will fail.
1105
+ */
1106
+ void devm_device_remove_group (struct device * dev ,
1107
+ const struct attribute_group * grp )
1108
+ {
1109
+ WARN_ON (devres_release (dev , devm_attr_group_remove ,
1110
+ devm_attr_group_match ,
1111
+ /* cast away const */ (void * )grp ));
1112
+ }
1113
+ EXPORT_SYMBOL_GPL (devm_device_remove_group );
1114
+
1115
+ /**
1116
+ * devm_device_add_groups - create a bunch of managed attribute groups
1117
+ * @dev: The device to create the group for
1118
+ * @groups: The attribute groups to create, NULL terminated
1119
+ *
1120
+ * This function creates a bunch of managed attribute groups. If an error
1121
+ * occurs when creating a group, all previously created groups will be
1122
+ * removed, unwinding everything back to the original state when this
1123
+ * function was called. It will explicitly warn and error if any of the
1124
+ * attribute files being created already exist.
1125
+ *
1126
+ * Returns 0 on success or error code from sysfs_create_group on failure.
1127
+ */
1128
+ int devm_device_add_groups (struct device * dev ,
1129
+ const struct attribute_group * * groups )
1130
+ {
1131
+ union device_attr_group_devres * devres ;
1132
+ int error ;
1133
+
1134
+ devres = devres_alloc (devm_attr_groups_remove ,
1135
+ sizeof (* devres ), GFP_KERNEL );
1136
+ if (!devres )
1137
+ return - ENOMEM ;
1138
+
1139
+ error = sysfs_create_groups (& dev -> kobj , groups );
1140
+ if (error ) {
1141
+ devres_free (devres );
1142
+ return error ;
1143
+ }
1144
+
1145
+ devres -> groups = groups ;
1146
+ devres_add (dev , devres );
1147
+ return 0 ;
1148
+ }
1149
+ EXPORT_SYMBOL_GPL (devm_device_add_groups );
1150
+
1151
+ /**
1152
+ * devm_device_remove_groups - remove a list of managed groups
1153
+ *
1154
+ * @dev: The device for the groups to be removed from
1155
+ * @groups: NULL terminated list of groups to be removed
1156
+ *
1157
+ * If groups is not NULL, remove the specified groups from the device.
1158
+ */
1159
+ void devm_device_remove_groups (struct device * dev ,
1160
+ const struct attribute_group * * groups )
1161
+ {
1162
+ WARN_ON (devres_release (dev , devm_attr_groups_remove ,
1163
+ devm_attr_group_match ,
1164
+ /* cast away const */ (void * )groups ));
1165
+ }
1166
+ EXPORT_SYMBOL_GPL (devm_device_remove_groups );
1167
+
1038
1168
static int device_add_attrs (struct device * dev )
1039
1169
{
1040
1170
struct class * class = dev -> class ;
0 commit comments