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