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