linux/drivers/platform/x86/dell/dell-wmi-sysman/enum-attributes.c
<<
>>
Prefs
   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
  11get_instance_id(enumeration);
  12
  13static 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 */
  40static 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
  63attribute_s_property_show(display_name_language_code, enumeration);
  64static struct kobj_attribute displ_langcode =
  65                __ATTR_RO(display_name_language_code);
  66
  67attribute_s_property_show(display_name, enumeration);
  68static struct kobj_attribute displ_name =
  69                __ATTR_RO(display_name);
  70
  71attribute_s_property_show(default_value, enumeration);
  72static struct kobj_attribute default_val =
  73                __ATTR_RO(default_value);
  74
  75attribute_property_store(current_value, enumeration);
  76static struct kobj_attribute current_val =
  77                __ATTR_RW_MODE(current_value, 0600);
  78
  79attribute_s_property_show(dell_modifier, enumeration);
  80static struct kobj_attribute modifier =
  81                __ATTR_RO(dell_modifier);
  82
  83attribute_s_property_show(dell_value_modifier, enumeration);
  84static struct kobj_attribute value_modfr =
  85                __ATTR_RO(dell_value_modifier);
  86
  87attribute_s_property_show(possible_values, enumeration);
  88static struct kobj_attribute poss_val =
  89                __ATTR_RO(possible_values);
  90
  91static ssize_t type_show(struct kobject *kobj, struct kobj_attribute *attr,
  92                         char *buf)
  93{
  94        return sprintf(buf, "enumeration\n");
  95}
  96static struct kobj_attribute type =
  97                __ATTR_RO(type);
  98
  99static struct attribute *enumeration_attrs[] = {
 100        &displ_langcode.attr,
 101        &displ_name.attr,
 102        &default_val.attr,
 103        &current_val.attr,
 104        &modifier.attr,
 105        &value_modfr.attr,
 106        &poss_val.attr,
 107        &type.attr,
 108        NULL,
 109};
 110
 111static const struct attribute_group enumeration_attr_group = {
 112        .attrs = enumeration_attrs,
 113};
 114
 115int 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 */
 137int 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 */
 208void 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