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