linux/drivers/platform/x86/dell/dell-wmi-sysman/biosattr-interface.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Functions corresponding to SET methods under BIOS attributes interface GUID for use
   4 * with dell-wmi-sysman
   5 *
   6 *  Copyright (c) 2020 Dell Inc.
   7 */
   8
   9#include <linux/wmi.h>
  10#include "dell-wmi-sysman.h"
  11
  12#define SETDEFAULTVALUES_METHOD_ID                                      0x02
  13#define SETBIOSDEFAULTS_METHOD_ID                                       0x03
  14#define SETATTRIBUTE_METHOD_ID                                          0x04
  15
  16static int call_biosattributes_interface(struct wmi_device *wdev, char *in_args, size_t size,
  17                                        int method_id)
  18{
  19        struct acpi_buffer output = {ACPI_ALLOCATE_BUFFER, NULL};
  20        struct acpi_buffer input;
  21        union acpi_object *obj;
  22        acpi_status status;
  23        int ret = -EIO;
  24
  25        input.length =  (acpi_size) size;
  26        input.pointer = in_args;
  27        status = wmidev_evaluate_method(wdev, 0, method_id, &input, &output);
  28        if (ACPI_FAILURE(status))
  29                return -EIO;
  30        obj = (union acpi_object *)output.pointer;
  31        if (obj->type == ACPI_TYPE_INTEGER)
  32                ret = obj->integer.value;
  33
  34        if (wmi_priv.pending_changes == 0) {
  35                wmi_priv.pending_changes = 1;
  36                /* let userland know it may need to check reboot pending again */
  37                kobject_uevent(&wmi_priv.class_dev->kobj, KOBJ_CHANGE);
  38        }
  39        kfree(output.pointer);
  40        return map_wmi_error(ret);
  41}
  42
  43/**
  44 * set_attribute() - Update an attribute value
  45 * @a_name: The attribute name
  46 * @a_value: The attribute value
  47 *
  48 * Sets an attribute to new value
  49 */
  50int set_attribute(const char *a_name, const char *a_value)
  51{
  52        size_t security_area_size, buffer_size;
  53        size_t a_name_size, a_value_size;
  54        char *buffer = NULL, *start;
  55        int ret;
  56
  57        mutex_lock(&wmi_priv.mutex);
  58        if (!wmi_priv.bios_attr_wdev) {
  59                ret = -ENODEV;
  60                goto out;
  61        }
  62
  63        /* build/calculate buffer */
  64        security_area_size = calculate_security_buffer(wmi_priv.current_admin_password);
  65        a_name_size = calculate_string_buffer(a_name);
  66        a_value_size = calculate_string_buffer(a_value);
  67        buffer_size = security_area_size + a_name_size + a_value_size;
  68        buffer = kzalloc(buffer_size, GFP_KERNEL);
  69        if (!buffer) {
  70                ret = -ENOMEM;
  71                goto out;
  72        }
  73
  74        /* build security area */
  75        populate_security_buffer(buffer, wmi_priv.current_admin_password);
  76
  77        /* build variables to set */
  78        start = buffer + security_area_size;
  79        ret = populate_string_buffer(start, a_name_size, a_name);
  80        if (ret < 0)
  81                goto out;
  82        start += ret;
  83        ret = populate_string_buffer(start, a_value_size, a_value);
  84        if (ret < 0)
  85                goto out;
  86
  87        print_hex_dump_bytes("set attribute data: ", DUMP_PREFIX_NONE, buffer, buffer_size);
  88        ret = call_biosattributes_interface(wmi_priv.bios_attr_wdev,
  89                                            buffer, buffer_size,
  90                                            SETATTRIBUTE_METHOD_ID);
  91        if (ret == -EOPNOTSUPP)
  92                dev_err(&wmi_priv.bios_attr_wdev->dev, "admin password must be configured\n");
  93        else if (ret == -EACCES)
  94                dev_err(&wmi_priv.bios_attr_wdev->dev, "invalid password\n");
  95
  96out:
  97        kfree(buffer);
  98        mutex_unlock(&wmi_priv.mutex);
  99        return ret;
 100}
 101
 102/**
 103 * set_bios_defaults() - Resets BIOS defaults
 104 * @deftype: the type of BIOS value reset to issue.
 105 *
 106 * Resets BIOS defaults
 107 */
 108int set_bios_defaults(u8 deftype)
 109{
 110        size_t security_area_size, buffer_size;
 111        size_t integer_area_size = sizeof(u8);
 112        char *buffer = NULL;
 113        u8 *defaultType;
 114        int ret;
 115
 116        mutex_lock(&wmi_priv.mutex);
 117        if (!wmi_priv.bios_attr_wdev) {
 118                ret = -ENODEV;
 119                goto out;
 120        }
 121
 122        security_area_size = calculate_security_buffer(wmi_priv.current_admin_password);
 123        buffer_size = security_area_size + integer_area_size;
 124        buffer = kzalloc(buffer_size, GFP_KERNEL);
 125        if (!buffer) {
 126                ret = -ENOMEM;
 127                goto out;
 128        }
 129
 130        /* build security area */
 131        populate_security_buffer(buffer, wmi_priv.current_admin_password);
 132
 133        defaultType = buffer + security_area_size;
 134        *defaultType = deftype;
 135
 136        ret = call_biosattributes_interface(wmi_priv.bios_attr_wdev, buffer, buffer_size,
 137                                            SETBIOSDEFAULTS_METHOD_ID);
 138        if (ret)
 139                dev_err(&wmi_priv.bios_attr_wdev->dev, "reset BIOS defaults failed: %d\n", ret);
 140
 141        kfree(buffer);
 142out:
 143        mutex_unlock(&wmi_priv.mutex);
 144        return ret;
 145}
 146
 147static int bios_attr_set_interface_probe(struct wmi_device *wdev, const void *context)
 148{
 149        mutex_lock(&wmi_priv.mutex);
 150        wmi_priv.bios_attr_wdev = wdev;
 151        mutex_unlock(&wmi_priv.mutex);
 152        return 0;
 153}
 154
 155static int bios_attr_set_interface_remove(struct wmi_device *wdev)
 156{
 157        mutex_lock(&wmi_priv.mutex);
 158        wmi_priv.bios_attr_wdev = NULL;
 159        mutex_unlock(&wmi_priv.mutex);
 160        return 0;
 161}
 162
 163static const struct wmi_device_id bios_attr_set_interface_id_table[] = {
 164        { .guid_string = DELL_WMI_BIOS_ATTRIBUTES_INTERFACE_GUID },
 165        { },
 166};
 167static struct wmi_driver bios_attr_set_interface_driver = {
 168        .driver = {
 169                .name = DRIVER_NAME
 170        },
 171        .probe = bios_attr_set_interface_probe,
 172        .remove = bios_attr_set_interface_remove,
 173        .id_table = bios_attr_set_interface_id_table,
 174};
 175
 176int init_bios_attr_set_interface(void)
 177{
 178        return wmi_driver_register(&bios_attr_set_interface_driver);
 179}
 180
 181void exit_bios_attr_set_interface(void)
 182{
 183        wmi_driver_unregister(&bios_attr_set_interface_driver);
 184}
 185
 186MODULE_DEVICE_TABLE(wmi, bios_attr_set_interface_id_table);
 187