1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * This code gives functions to avoid code duplication while interacting with
4  * the TUXEDO NB04 wmi interfaces.
5  *
6  * Copyright (C) 2024-2025 Werner Sembach <wse@tuxedocomputers.com>
7  */
8 
9 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
10 
11 #include <linux/cleanup.h>
12 #include <linux/wmi.h>
13 
14 #include "wmi_util.h"
15 
16 static int __wmi_method_acpi_object_out(struct wmi_device *wdev,
17 					u32 wmi_method_id,
18 					u8 *in,
19 					acpi_size in_len,
20 					union acpi_object **out)
21 {
22 	struct acpi_buffer acpi_buffer_in = { in_len, in };
23 	struct acpi_buffer acpi_buffer_out = { ACPI_ALLOCATE_BUFFER, NULL };
24 
25 	dev_dbg(&wdev->dev, "Evaluate WMI method: %u in:\n", wmi_method_id);
26 	print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, in, in_len);
27 
28 	acpi_status status = wmidev_evaluate_method(wdev, 0, wmi_method_id,
29 						    &acpi_buffer_in,
30 						    &acpi_buffer_out);
31 	if (ACPI_FAILURE(status)) {
32 		dev_err(&wdev->dev, "Failed to evaluate WMI method.\n");
33 		return -EIO;
34 	}
35 	if (!acpi_buffer_out.pointer) {
36 		dev_err(&wdev->dev, "Unexpected empty out buffer.\n");
37 		return -ENODATA;
38 	}
39 
40 	*out = acpi_buffer_out.pointer;
41 
42 	return 0;
43 }
44 
45 static int __wmi_method_buffer_out(struct wmi_device *wdev,
46 				   u32 wmi_method_id,
47 				   u8 *in,
48 				   acpi_size in_len,
49 				   u8 *out,
50 				   acpi_size out_len)
51 {
52 	int ret;
53 
54 	union acpi_object *acpi_object_out __free(kfree) = NULL;
55 
56 	ret = __wmi_method_acpi_object_out(wdev, wmi_method_id,
57 					   in, in_len,
58 					   &acpi_object_out);
59 	if (ret)
60 		return ret;
61 
62 	if (acpi_object_out->type != ACPI_TYPE_BUFFER) {
63 		dev_err(&wdev->dev, "Unexpected out buffer type. Expected: %u Got: %u\n",
64 			ACPI_TYPE_BUFFER, acpi_object_out->type);
65 		return -EIO;
66 	}
67 	if (acpi_object_out->buffer.length < out_len) {
68 		dev_err(&wdev->dev, "Unexpected out buffer length.\n");
69 		return -EIO;
70 	}
71 
72 	memcpy(out, acpi_object_out->buffer.pointer, out_len);
73 
74 	return 0;
75 }
76 
77 int tux_wmi_xx_8in_80out(struct wmi_device *wdev,
78 			 enum tux_wmi_xx_8in_80out_methods method,
79 			 union tux_wmi_xx_8in_80out_in_t *in,
80 			 union tux_wmi_xx_8in_80out_out_t *out)
81 {
82 	return __wmi_method_buffer_out(wdev, method, in->raw, 8, out->raw, 80);
83 }
84 
85 int tux_wmi_xx_496in_80out(struct wmi_device *wdev,
86 			   enum tux_wmi_xx_496in_80out_methods method,
87 			   union tux_wmi_xx_496in_80out_in_t *in,
88 			   union tux_wmi_xx_496in_80out_out_t *out)
89 {
90 	return __wmi_method_buffer_out(wdev, method, in->raw, 496, out->raw, 80);
91 }
92