1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Functions corresponding to enumeration type attributes under 4 * BIOS Enumeration GUID for use with dell-wmi-sysman 5 * 6 * Copyright (c) 2020 Dell Inc. 7 */ 8 9 #include "dell-wmi-sysman.h" 10 11 get_instance_id(enumeration); 12 13 static ssize_t current_value_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) 14 { 15 int instance_id = get_enumeration_instance_id(kobj); 16 union acpi_object *obj; 17 ssize_t ret; 18 19 if (instance_id < 0) 20 return instance_id; 21 22 /* need to use specific instance_id and guid combination to get right data */ 23 obj = get_wmiobj_pointer(instance_id, DELL_WMI_BIOS_ENUMERATION_ATTRIBUTE_GUID); 24 if (!obj) 25 return -EIO; 26 if (obj->package.elements[CURRENT_VAL].type != ACPI_TYPE_STRING) { 27 kfree(obj); 28 return -EINVAL; 29 } 30 ret = snprintf(buf, PAGE_SIZE, "%s\n", obj->package.elements[CURRENT_VAL].string.pointer); 31 kfree(obj); 32 return ret; 33 } 34 35 /** 36 * validate_enumeration_input() - Validate input of current_value against possible values 37 * @instance_id: The instance on which input is validated 38 * @buf: Input value 39 */ 40 static int validate_enumeration_input(int instance_id, const char *buf) 41 { 42 char *options, *tmp, *p; 43 int ret = -EINVAL; 44 45 options = tmp = kstrdup(wmi_priv.enumeration_data[instance_id].possible_values, 46 GFP_KERNEL); 47 if (!options) 48 return -ENOMEM; 49 50 while ((p = strsep(&options, ";")) != NULL) { 51 if (!*p) 52 continue; 53 if (!strcasecmp(p, buf)) { 54 ret = 0; 55 break; 56 } 57 } 58 59 kfree(tmp); 60 return ret; 61 } 62 63 attribute_s_property_show(display_name_language_code, enumeration); 64 static struct kobj_attribute displ_langcode = 65 __ATTR_RO(display_name_language_code); 66 67 attribute_s_property_show(display_name, enumeration); 68 static struct kobj_attribute displ_name = 69 __ATTR_RO(display_name); 70 71 attribute_s_property_show(default_value, enumeration); 72 static struct kobj_attribute default_val = 73 __ATTR_RO(default_value); 74 75 attribute_property_store(current_value, enumeration); 76 static struct kobj_attribute current_val = 77 __ATTR_RW_MODE(current_value, 0600); 78 79 attribute_s_property_show(dell_modifier, enumeration); 80 static struct kobj_attribute modifier = 81 __ATTR_RO(dell_modifier); 82 83 attribute_s_property_show(dell_value_modifier, enumeration); 84 static struct kobj_attribute value_modfr = 85 __ATTR_RO(dell_value_modifier); 86 87 attribute_s_property_show(possible_values, enumeration); 88 static struct kobj_attribute poss_val = 89 __ATTR_RO(possible_values); 90 91 static ssize_t type_show(struct kobject *kobj, struct kobj_attribute *attr, 92 char *buf) 93 { 94 return sprintf(buf, "enumeration\n"); 95 } 96 static struct kobj_attribute type = 97 __ATTR_RO(type); 98 99 static struct attribute *enumeration_attrs[] = { 100 &displ_langcode.attr, 101 &displ_name.attr, 102 &default_val.attr, 103 ¤t_val.attr, 104 &modifier.attr, 105 &value_modfr.attr, 106 &poss_val.attr, 107 &type.attr, 108 NULL, 109 }; 110 111 static const struct attribute_group enumeration_attr_group = { 112 .attrs = enumeration_attrs, 113 }; 114 115 int alloc_enum_data(void) 116 { 117 int ret = 0; 118 119 wmi_priv.enumeration_instances_count = 120 get_instance_count(DELL_WMI_BIOS_ENUMERATION_ATTRIBUTE_GUID); 121 wmi_priv.enumeration_data = kcalloc(wmi_priv.enumeration_instances_count, 122 sizeof(struct enumeration_data), GFP_KERNEL); 123 if (!wmi_priv.enumeration_data) { 124 wmi_priv.enumeration_instances_count = 0; 125 ret = -ENOMEM; 126 } 127 return ret; 128 } 129 130 /** 131 * populate_enum_data() - Populate all properties of an instance under enumeration attribute 132 * @enumeration_obj: ACPI object with enumeration data 133 * @instance_id: The instance to enumerate 134 * @attr_name_kobj: The parent kernel object 135 * @enum_property_count: Total properties count under enumeration type 136 */ 137 int populate_enum_data(union acpi_object *enumeration_obj, int instance_id, 138 struct kobject *attr_name_kobj, u32 enum_property_count) 139 { 140 int i, next_obj, value_modifier_count, possible_values_count; 141 142 wmi_priv.enumeration_data[instance_id].attr_name_kobj = attr_name_kobj; 143 if (check_property_type(enumeration, ATTR_NAME, ACPI_TYPE_STRING)) 144 return -EINVAL; 145 strlcpy_attr(wmi_priv.enumeration_data[instance_id].attribute_name, 146 enumeration_obj[ATTR_NAME].string.pointer); 147 if (check_property_type(enumeration, DISPL_NAME_LANG_CODE, ACPI_TYPE_STRING)) 148 return -EINVAL; 149 strlcpy_attr(wmi_priv.enumeration_data[instance_id].display_name_language_code, 150 enumeration_obj[DISPL_NAME_LANG_CODE].string.pointer); 151 if (check_property_type(enumeration, DISPLAY_NAME, ACPI_TYPE_STRING)) 152 return -EINVAL; 153 strlcpy_attr(wmi_priv.enumeration_data[instance_id].display_name, 154 enumeration_obj[DISPLAY_NAME].string.pointer); 155 if (check_property_type(enumeration, DEFAULT_VAL, ACPI_TYPE_STRING)) 156 return -EINVAL; 157 strlcpy_attr(wmi_priv.enumeration_data[instance_id].default_value, 158 enumeration_obj[DEFAULT_VAL].string.pointer); 159 if (check_property_type(enumeration, MODIFIER, ACPI_TYPE_STRING)) 160 return -EINVAL; 161 strlcpy_attr(wmi_priv.enumeration_data[instance_id].dell_modifier, 162 enumeration_obj[MODIFIER].string.pointer); 163 164 next_obj = MODIFIER + 1; 165 166 if (next_obj >= enum_property_count) 167 return -EINVAL; 168 169 if (check_property_type(enumeration, next_obj, ACPI_TYPE_INTEGER)) 170 return -EINVAL; 171 value_modifier_count = (uintptr_t)enumeration_obj[next_obj++].string.pointer; 172 173 for (i = 0; i < value_modifier_count; i++) { 174 if (next_obj >= enum_property_count) 175 return -EINVAL; 176 if (check_property_type(enumeration, next_obj, ACPI_TYPE_STRING)) 177 return -EINVAL; 178 strcat(wmi_priv.enumeration_data[instance_id].dell_value_modifier, 179 enumeration_obj[next_obj++].string.pointer); 180 strcat(wmi_priv.enumeration_data[instance_id].dell_value_modifier, ";"); 181 } 182 183 if (next_obj >= enum_property_count) 184 return -EINVAL; 185 186 if (check_property_type(enumeration, next_obj, ACPI_TYPE_INTEGER)) 187 return -EINVAL; 188 possible_values_count = (uintptr_t) enumeration_obj[next_obj++].string.pointer; 189 190 for (i = 0; i < possible_values_count; i++) { 191 if (next_obj >= enum_property_count) 192 return -EINVAL; 193 if (check_property_type(enumeration, next_obj, ACPI_TYPE_STRING)) 194 return -EINVAL; 195 strcat(wmi_priv.enumeration_data[instance_id].possible_values, 196 enumeration_obj[next_obj++].string.pointer); 197 strcat(wmi_priv.enumeration_data[instance_id].possible_values, ";"); 198 } 199 200 return sysfs_create_group(attr_name_kobj, &enumeration_attr_group); 201 } 202 203 /** 204 * exit_enum_attributes() - Clear all attribute data 205 * 206 * Clears all data allocated for this group of attributes 207 */ 208 void exit_enum_attributes(void) 209 { 210 int instance_id; 211 212 for (instance_id = 0; instance_id < wmi_priv.enumeration_instances_count; instance_id++) { 213 if (wmi_priv.enumeration_data[instance_id].attr_name_kobj) 214 sysfs_remove_group(wmi_priv.enumeration_data[instance_id].attr_name_kobj, 215 &enumeration_attr_group); 216 } 217 wmi_priv.enumeration_instances_count = 0; 218 219 kfree(wmi_priv.enumeration_data); 220 wmi_priv.enumeration_data = NULL; 221 } 222