xref: /linux/drivers/platform/x86/lenovo/wmi-helpers.c (revision 9669b2499ea377764f8320dd562dd6cd4ea80a5d)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Lenovo Legion WMI helpers driver.
4  *
5  * The Lenovo Legion WMI interface is broken up into multiple GUID interfaces
6  * that require cross-references between GUID's for some functionality. The
7  * "Custom Mode" interface is a legacy interface for managing and displaying
8  * CPU & GPU power and hwmon settings and readings. The "Other Mode" interface
9  * is a modern interface that replaces or extends the "Custom Mode" interface
10  * methods. The "Gamezone" interface adds advanced features such as fan
11  * profiles and overclocking. The "Lighting" interface adds control of various
12  * status lights related to different hardware components. Each of these
13  * drivers uses a common procedure to get data from the WMI interface,
14  * enumerated here.
15  *
16  * Copyright (C) 2025 Derek J. Clark <derekjohn.clark@gmail.com>
17  */
18 
19 #include <linux/acpi.h>
20 #include <linux/cleanup.h>
21 #include <linux/errno.h>
22 #include <linux/export.h>
23 #include <linux/module.h>
24 #include <linux/wmi.h>
25 
26 #include "wmi-helpers.h"
27 
28 /**
29  * lwmi_dev_evaluate_int() - Helper function for calling WMI methods that
30  * return an integer.
31  * @wdev: Pointer to the WMI device to be called.
32  * @instance: Instance of the called method.
33  * @method_id: WMI Method ID for the method to be called.
34  * @buf: Buffer of all arguments for the given method_id.
35  * @size: Length of the buffer.
36  * @retval: Pointer for the return value to be assigned.
37  *
38  * Calls wmidev_evaluate_method for Lenovo WMI devices that return an ACPI
39  * integer. Validates the return value type and assigns the value to the
40  * retval pointer.
41  *
42  * Return: 0 on success, or an error code.
43  */
lwmi_dev_evaluate_int(struct wmi_device * wdev,u8 instance,u32 method_id,unsigned char * buf,size_t size,u32 * retval)44 int lwmi_dev_evaluate_int(struct wmi_device *wdev, u8 instance, u32 method_id,
45 			  unsigned char *buf, size_t size, u32 *retval)
46 {
47 	struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
48 	union acpi_object *ret_obj __free(kfree) = NULL;
49 	struct acpi_buffer input = { size, buf };
50 	acpi_status status;
51 
52 	status = wmidev_evaluate_method(wdev, instance, method_id, &input,
53 					&output);
54 	if (ACPI_FAILURE(status))
55 		return -EIO;
56 
57 	if (retval) {
58 		ret_obj = output.pointer;
59 		if (!ret_obj)
60 			return -ENODATA;
61 
62 		if (ret_obj->type != ACPI_TYPE_INTEGER)
63 			return -ENXIO;
64 
65 		*retval = (u32)ret_obj->integer.value;
66 	}
67 
68 	return 0;
69 };
70 EXPORT_SYMBOL_NS_GPL(lwmi_dev_evaluate_int, "LENOVO_WMI_HELPERS");
71 
72 MODULE_AUTHOR("Derek J. Clark <derekjohn.clark@gmail.com>");
73 MODULE_DESCRIPTION("Lenovo WMI Helpers Driver");
74 MODULE_LICENSE("GPL");
75