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
__wmi_method_acpi_object_out(struct wmi_device * wdev,u32 wmi_method_id,u8 * in,acpi_size in_len,union acpi_object ** out)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
__wmi_method_buffer_out(struct wmi_device * wdev,u32 wmi_method_id,u8 * in,acpi_size in_len,u8 * out,acpi_size out_len)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
tux_wmi_xx_8in_80out(struct wmi_device * wdev,enum tux_wmi_xx_8in_80out_methods method,union tux_wmi_xx_8in_80out_in_t * in,union tux_wmi_xx_8in_80out_out_t * out)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
tux_wmi_xx_496in_80out(struct wmi_device * wdev,enum tux_wmi_xx_496in_80out_methods method,union tux_wmi_xx_496in_80out_in_t * in,union tux_wmi_xx_496in_80out_out_t * out)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