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