Skip to content

Commit b990a06

Browse files
Wer-Wolfij-intel
authored andcommitted
platform/wmi: Add helper functions for WMI string conversions
WMI strings are encoded using UTF16-LE characters, forcing WMI drivers to manually convert them to/from standard UTF8 strings. Add a two helper functions for those tasks. Signed-off-by: Armin Wolf <W_Armin@gmx.de> Link: https://patch.msgid.link/20260116204116.4030-4-W_Armin@gmx.de Reviewed-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com> Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
1 parent 29dfba6 commit b990a06

5 files changed

Lines changed: 102 additions & 1 deletion

File tree

Documentation/driver-api/wmi.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,5 +16,8 @@ which will be bound to compatible WMI devices by the driver core.
1616
.. kernel-doc:: include/linux/wmi.h
1717
:internal:
1818

19+
.. kernel-doc:: drivers/platform/wmi/string.c
20+
:export:
21+
1922
.. kernel-doc:: drivers/platform/wmi/core.c
2023
:export:

drivers/platform/wmi/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
menuconfig ACPI_WMI
77
tristate "ACPI-WMI support"
88
depends on ACPI && X86
9+
select NLS
910
help
1011
This option enables support for the ACPI-WMI driver core.
1112

drivers/platform/wmi/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
# ACPI WMI core
55
#
66

7-
wmi-y := core.o marshalling.o
7+
wmi-y := core.o marshalling.o string.o
88
obj-$(CONFIG_ACPI_WMI) += wmi.o
99

1010
# Unit tests

drivers/platform/wmi/string.c

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
// SPDX-License-Identifier: GPL-2.0-or-later
2+
/*
3+
* WMI string utility functions.
4+
*
5+
* Copyright (C) 2025 Armin Wolf <W_Armin@gmx.de>
6+
*/
7+
8+
#include <linux/build_bug.h>
9+
#include <linux/compiler_types.h>
10+
#include <linux/err.h>
11+
#include <linux/export.h>
12+
#include <linux/nls.h>
13+
#include <linux/limits.h>
14+
#include <linux/types.h>
15+
#include <linux/wmi.h>
16+
17+
#include <asm/byteorder.h>
18+
19+
static_assert(sizeof(__le16) == sizeof(wchar_t));
20+
21+
/**
22+
* wmi_string_to_utf8s - Convert a WMI string into a UTF8 string.
23+
* @str: WMI string representation
24+
* @dst: Buffer to fill with UTF8 characters
25+
* @length: Length of the destination buffer
26+
*
27+
* Convert as WMI string into a standard UTF8 string. The conversion will stop
28+
* once a NUL character is detected or when the buffer is full. Any invalid UTF16
29+
* characters will be ignored. The resulting UTF8 string will always be NUL-terminated
30+
* when this function returns successfully.
31+
*
32+
* Return: Length of the resulting UTF8 string or negative errno code on failure.
33+
*/
34+
ssize_t wmi_string_to_utf8s(const struct wmi_string *str, u8 *dst, size_t length)
35+
{
36+
/* Contains the maximum number of UTF16 code points to read */
37+
int inlen = le16_to_cpu(str->length) / 2;
38+
int ret;
39+
40+
if (length < 1)
41+
return -EINVAL;
42+
43+
/* We must leave room for the NUL character at the end of the destination buffer */
44+
ret = utf16s_to_utf8s((__force const wchar_t *)str->chars, inlen, UTF16_LITTLE_ENDIAN, dst,
45+
length - 1);
46+
if (ret < 0)
47+
return ret;
48+
49+
dst[ret] = '\0';
50+
51+
return ret;
52+
}
53+
EXPORT_SYMBOL_GPL(wmi_string_to_utf8s);
54+
55+
/**
56+
* wmi_string_from_utf8s - Convert a UTF8 string into a WMI string.
57+
* @str: WMI string representation
58+
* @max_chars: Maximum number of UTF16 code points to store inside the WMI string
59+
* @src: UTF8 string to convert
60+
* @src_length: Length of the source string without any trailing NUL-characters
61+
*
62+
* Convert a UTF8 string into a WMI string. The conversion will stop when the WMI string is
63+
* full. The resulting WMI string will always be NUL-terminated and have its length field set
64+
* to and appropriate value when this function returns successfully.
65+
*
66+
* Return: Number of UTF16 code points inside the WMI string or negative errno code on failure.
67+
*/
68+
ssize_t wmi_string_from_utf8s(struct wmi_string *str, size_t max_chars, const u8 *src,
69+
size_t src_length)
70+
{
71+
size_t str_length;
72+
int ret;
73+
74+
if (max_chars < 1)
75+
return -EINVAL;
76+
77+
/* We must leave room for the NUL character at the end of the WMI string */
78+
ret = utf8s_to_utf16s(src, src_length, UTF16_LITTLE_ENDIAN, (__force wchar_t *)str->chars,
79+
max_chars - 1);
80+
if (ret < 0)
81+
return ret;
82+
83+
str_length = (ret + 1) * sizeof(u16);
84+
if (str_length > U16_MAX)
85+
return -EOVERFLOW;
86+
87+
str->length = cpu_to_le16(str_length);
88+
str->chars[ret] = '\0';
89+
90+
return ret;
91+
}
92+
EXPORT_SYMBOL_GPL(wmi_string_from_utf8s);

include/linux/wmi.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,11 @@ struct wmi_string {
6262
__le16 chars[];
6363
} __packed;
6464

65+
ssize_t wmi_string_to_utf8s(const struct wmi_string *str, u8 *dst, size_t length);
66+
67+
ssize_t wmi_string_from_utf8s(struct wmi_string *str, size_t max_chars, const u8 *src,
68+
size_t src_length);
69+
6570
int wmidev_invoke_method(struct wmi_device *wdev, u8 instance, u32 method_id,
6671
const struct wmi_buffer *in, struct wmi_buffer *out);
6772

0 commit comments

Comments
 (0)