<snip> > > > > > > > > > + > > > > +/* kept variable names same as in sysfs file name for sysfs_show > > > > +macro > > > definition */ > > > > +struct enumeration_data { > > > > + char display_name_language_code[MAX_BUFF]; > > > > + char attribute_name[MAX_BUFF]; > > > > + char display_name[MAX_BUFF]; > > > > + char default_value[MAX_BUFF]; > > > > + char current_value[MAX_BUFF]; > > > > + char modifier[MAX_BUFF]; > > > > + int value_modifier_count; > > > > + char value_modifier[MAX_BUFF]; > > > > + int possible_value_count; > > > > + char possible_value[MAX_BUFF]; > > > > + char type[MAX_BUFF]; > > > > +}; > > > > + > > > > +static struct enumeration_data *enumeration_data; static int > > > > +enumeration_instances_count; > > > > > > Please store these 2 in the global wmi_priv data. > > > > > > Also there is a lot of overlap between structs like struct > > > enumeration_data, struct integer_data, etc. > > > > > > I think it would be good to make a single struct attr_data, which > > > contains fields for all the supported types. > > > > > > I also see a lot of overlapping code between: > > > > > > drivers/platform/x86/dell-wmi-enum-attributes.c > > > drivers/platform/x86/dell-wmi-int-attributes.c > > > drivers/platform/x86/dell-wmi-string-attributes.c > > > > > > I think that folding the data structures together will help with also > > > unifying that code into a single dell-wmi-std-attributes.c file. > > > > > Yes, it does seem like lot of code is overlapping but they differ by > properties that are little unnoticeable. > > If we make single file adding switch cases we may end up in many > switch cases and if conditions. Because, here only attribute_name, > display_lang_code, display_lang and modifier are same. Apart from > these other properties are different either by name or data type. > > Also, one advantage here is if any new type is added in future it will > be easier to create new sysfs_attr_group according to new type's > properties > > We will certainly try and minimize some identical looking code > wherever possible and add inline comments/document the > differences more clearly in v3 which is incoming shortly. > > > > > +get_instance_id(enumeration); > > > > + > > > > +static ssize_t current_value_show(struct kobject *kobj, struct > > > kobj_attribute *attr, char *buf) > > > > +{ > > > > + int instance_id; > > > > + > > > > + if (!capable(CAP_SYS_ADMIN)) > > > > + return -EPERM; > > > > + instance_id = get_enumeration_instance_id(kobj); > > > > > > If you unify the integer, string and enum code then this just becomes: > > > get_std_instance_id(kobj) > > > > > For each type of attribute GUIDs are different and for each type > instance IDs start from zero. So if we populate them in single data > structure then instance IDs may overlap. > > > > > + if (instance_id >= 0) { > > > > + union acpi_object *obj; > > > > + > > > > + obj = get_wmiobj_pointer(instance_id, > > > DELL_WMI_BIOS_ENUMERATION_ATTRIBUTE_GUID); > > > > + if (!obj) > > > > + return -AE_ERROR; > > > > > > > + strncpy_attr(enumeration_data[instance_id].current_value, > > > > + obj->package.elements[CURRENT_VAL].string.pointer); > > > So these 2 lines seem to be the only thing which is different for > > > current_value_show, between enums, ints and strings, so you can put a > > > simple switch-case on the type here. > > > > > > > This is a good point, it will cause a lot of changes as a result and a lot less > > code. > > > > > > + kfree(obj); > > > > + return sprintf(buf, "%s\n", > > > enumeration_data[instance_id].current_value); > > > > + } > > > > + return -EIO; > > > > +} > + > > > > +/** > > > > + * validate_enumeration_input() - Validate input of current_value > > > > +against > > > possible values > > > > + * @instance_id: The instance on which input is validated > > > > + * @buf: Input value > > > > + **/ > > > > +int validate_enumeration_input(int instance_id, const char *buf) { > > > > + char *options, *tmp, *p; > > > > + int ret = -EINVAL; > > > > + > > > > + options = tmp = > > > > +kstrdup((enumeration_data[instance_id].possible_value), > > > GFP_KERNEL); > > > > + if (!options) > > > > + return -ENOMEM; > > > > + > > > > + while ((p = strsep(&options, ";")) != NULL) { > > > > + if (!*p) > > > > + continue; > > > > + if (!strncasecmp(p, buf, strlen(p))) { > > > > + ret = 0; > > > > + break; > > > > + } > > > > + } > > > > + > > > > + kfree(tmp); > > > > + return ret; > > > > +} > > > > > > For the validate functions you can keep all 3 in the new > > > dell-wmi-std-attributes.c file and then call the right one through a > > > switch-case based on the type. > > > > > > > + > > > > +attribute_s_property_show(display_name_language_code, > > enumeration); > > > > +static struct kobj_attribute displ_langcode = > > > > + __ATTR_RO(display_name_language_code); > > > > + > > > > +attribute_s_property_show(display_name, enumeration); struct > > > > +kobj_attribute displ_name = > > > > + __ATTR_RO(display_name); > > > > + > > > > +attribute_s_property_show(default_value, enumeration); struct > > > > +kobj_attribute default_val = > > > > + __ATTR_RO(default_value); > > > > + > > > > +attribute_property_store(current_value, enumeration); struct > > > > +kobj_attribute current_val = > > > > + __ATTR_RW(current_value); > > > > + > > > > +attribute_s_property_show(modifier, enumeration); struct > > > > +kobj_attribute modifier = > > > > + __ATTR_RO(modifier); > > > > + > > > > +attribute_s_property_show(value_modifier, enumeration); struct > > > > +kobj_attribute value_modfr = > > > > + __ATTR_RO(value_modifier); > > > > + > > > > +attribute_s_property_show(possible_value, enumeration); struct > > > > +kobj_attribute poss_val = > > > > + __ATTR_RO(possible_value); > > > > + > > > > +attribute_s_property_show(type, enumeration); struct kobj_attribute > > > > +type = > > > > + __ATTR_RO(type); > > > > + > > > > +static struct attribute *enumeration_attrs[] = { > > > > + &displ_langcode.attr, > > > > + &displ_name.attr, > > > > + &default_val.attr, > > > > + ¤t_val.attr, > > > > + &modifier.attr, > > > > + &value_modfr.attr, > > > > + &poss_val.attr, > > > > + &type.attr, > > > > + NULL, > > > > +}; > > > > + > > > > +static const struct attribute_group enumeration_attr_group = { > > > > + .attrs = enumeration_attrs, > > > > +}; > > > > + > > > > +int alloc_enum_data(void) > > > > +{ > > > > + int ret = 0; > > > > + > > > > + enumeration_instances_count = > > > get_instance_count(DELL_WMI_BIOS_ENUMERATION_ATTRIBUTE_GUID); > > > > + enumeration_data = kzalloc((sizeof(struct enumeration_data) * > > > enumeration_instances_count), > > > > + GFP_KERNEL); > > > > + if (!enumeration_data) > > > > + ret = -ENOMEM; > > > > + return ret; > > > > +} > > > > + > > > > > > The rest of the file is mostly identical between strings, ints and enums. > > > > > > > +/** > > > > + * populate_enum_data() - Populate all properties of an instance > > > > +under > > > enumeration attribute > > > > + * @enumeration_obj: ACPI object with enumeration data > > > > + * @instance_id: The instance to enumerate > > > > + * @attr_name_kobj: The parent kernel object **/ int > > > > +populate_enum_data(union acpi_object *enumeration_obj, int > > instance_id, > > > > + struct kobject *attr_name_kobj) > > > > +{ > > > > + int retval = sysfs_create_group(attr_name_kobj, > > > &enumeration_attr_group); > > > > + int i, next_obj; > > > > + > > > > + if (retval) > > > > + goto out; > > > > + > > > > + mutex_lock(&enum_mutex); > > > > + strncpy_attr(enumeration_data[instance_id].attribute_name, > > > > + enumeration_obj[ATTR_NAME].string.pointer); > > > > + > > strncpy_attr(enumeration_data[instance_id].display_name_language > > _code, > > > > + enumeration_obj[DISPL_NAME_LANG_CODE].string.pointer); > > > > + strncpy_attr(enumeration_data[instance_id].display_name, > > > > + enumeration_obj[DISPLAY_NAME].string.pointer); > > > > + strncpy_attr(enumeration_data[instance_id].default_value, > > > > + enumeration_obj[DEFAULT_VAL].string.pointer); > > > > + strncpy_attr(enumeration_data[instance_id].current_value, > > > > + enumeration_obj[CURRENT_VAL].string.pointer); > > > > + strncpy_attr(enumeration_data[instance_id].modifier, > > > > + enumeration_obj[MODIFIER].string.pointer); > > > > + > > > > + next_obj = MODIFIER + 1; > > > > + > > > > + enumeration_data[instance_id].value_modifier_count = > > > > + (uintptr_t)enumeration_obj[next_obj].string.pointer; > > > > + > > > > + for (i = 0; i < > > > > +enumeration_data[instance_id].value_modifier_count; i++) > > > { > > > > + strcat(enumeration_data[instance_id].value_modifier, > > > > + enumeration_obj[++next_obj].string.pointer); > > > > + strcat(enumeration_data[instance_id].value_modifier, ";"); > > > > + } > > > > + > > > > + enumeration_data[instance_id].possible_value_count = > > > > + (uintptr_t) enumeration_obj[++next_obj].string.pointer; > > > > + > > > > + for (i = 0; i < > > > > +enumeration_data[instance_id].possible_value_count; i++) > > > { > > > > + strcat(enumeration_data[instance_id].possible_value, > > > > + enumeration_obj[++next_obj].string.pointer); > > > > + strcat(enumeration_data[instance_id].possible_value, ";"); > > > > + } > > > > + strncpy_attr(enumeration_data[instance_id].type, "enumeration"); > > > > + mutex_unlock(&enum_mutex); > > > > + > > > > +out: > > > > + return retval; > > > > +} > > > > > > > > > I guess you may also need a switch-case based on the type in the > > > populare function. > > > > > > > + > > > > +/** > > > > + * exit_enum_attributes() - Clear all attribute data > > > > + * @kset: The kset to free > > > > + * > > > > + * Clears all data allocated for this group of attributes **/ void > > > > +exit_enum_attributes(struct kset *kset) { > > > > + struct kobject *pos, *next; > > > > + > > > > + mutex_lock(&kset_mutex); > > > > + list_for_each_entry_safe(pos, next, &kset->list, entry) { > > > > + sysfs_remove_group(pos, &enumeration_attr_group); > > > > + } > > > > + mutex_unlock(&kset_mutex); > > > > + mutex_lock(&enum_mutex); > > > > + kfree(enumeration_data); > > > > + mutex_unlock(&enum_mutex); > > > > +} > > > > > > Since there is now only 1 kset for the main dir, you are now calling > > > sysfs_remove_group 4 times (for all the different times) on each entry > > > in the attributes dir. I guess this may fail silently, but it still is > > > not good. So this needs to be fixed. > > > > > > The remarks to this file also apply to the: > > > > > > drivers/platform/x86/dell-wmi-int-attributes.c > > > drivers/platform/x86/dell-wmi-string-attributes.c > > > > > > files. > > > Since we maintained 4 different attribute groups under 1 kset, each time respective attribute group will be removed. And once all groups are removed, kset is deleted. Regards, Divya