186 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Functions corresponding to SET methods under BIOS attributes interface GUID for use4 * with dell-wmi-sysman5 *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 0x0213#define SETBIOSDEFAULTS_METHOD_ID 0x0314#define SETATTRIBUTE_METHOD_ID 0x0415 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 value45 * @a_name: The attribute name46 * @a_value: The attribute value47 *48 * Sets an attribute to new value49 */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 defaults104 * @deftype: the type of BIOS value reset to issue.105 *106 * Resets BIOS defaults107 */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 void 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}161 162static const struct wmi_device_id bios_attr_set_interface_id_table[] = {163 { .guid_string = DELL_WMI_BIOS_ATTRIBUTES_INTERFACE_GUID },164 { },165};166static struct wmi_driver bios_attr_set_interface_driver = {167 .driver = {168 .name = DRIVER_NAME169 },170 .probe = bios_attr_set_interface_probe,171 .remove = bios_attr_set_interface_remove,172 .id_table = bios_attr_set_interface_id_table,173};174 175int init_bios_attr_set_interface(void)176{177 return wmi_driver_register(&bios_attr_set_interface_driver);178}179 180void exit_bios_attr_set_interface(void)181{182 wmi_driver_unregister(&bios_attr_set_interface_driver);183}184 185MODULE_DEVICE_TABLE(wmi, bios_attr_set_interface_id_table);186