Re: [PATCH 9/9] platform/wmi: Update driver development guide

From: Randy Dunlap

Date: Sat Nov 22 2025 - 20:32:24 EST




On 11/22/25 12:38 PM, Armin Wolf wrote:
> New WMI drivers should use the new buffer-based WMI API instead of
> the deprecated ACPI-based API. Update the driver development guide
> to recommend the buffer-based API to driver developers and explain
> the purpose of struct wmi_buffer.
>
> Also update the ACPI interface documentation to describe the
> conversion rules for converting ACPI objects into WMI buffers.
>
> Signed-off-by: Armin Wolf <W_Armin@xxxxxx>
> ---
> Documentation/wmi/acpi-interface.rst | 68 +++++++++++++++++
> .../wmi/driver-development-guide.rst | 76 +++++++++++++------
> 2 files changed, 121 insertions(+), 23 deletions(-)
>
> diff --git a/Documentation/wmi/acpi-interface.rst b/Documentation/wmi/acpi-interface.rst
> index 1ef003b033bf..6dad191ac59d 100644
> --- a/Documentation/wmi/acpi-interface.rst
> +++ b/Documentation/wmi/acpi-interface.rst
> @@ -104,3 +104,71 @@ holding the notification ID of the event. This method should be evaluated every
> time an ACPI notification is received, since some ACPI implementations use a
> queue to store WMI event data items. This queue will overflow after a couple
> of WMI events are received without retrieving the associated WMI event data.
> +
> +Conversion rules for ACPI data types
> +------------------------------------
> +
> +Consumers of the ACPI-WMI interface use binary buffers to exchange data with the WMI driver core,
> +with the internal structure of the buffer being only know to the consumers. The WMI driver core is
> +thus responsible for converting the data inside the buffer into an appropriate ACPI data type for
> +consumtion by the ACPI firmware. Additionally, any data returned by the various ACPI methods needs

consumption (or: use)

> +to be converted back into a binary buffer.
> +
> +The layout of said buffers is defined by the MOF description of the WMI method or data block in
> +question [1]_:
> +
> +=============== ======================================================================= =========
> +Data Type Layout Alignment
> +=============== ======================================================================= =========
> +``string`` Starts with a unsigned 16-bit little endian integer specifying 2 bytes

an unsigned

> + the length of the string data in bytes, followed by the string data
> + encoded as UTF-16LE with **optional** nul termination and padding.

NUL

> + Keep in mind that some firmware implementations might depend on the
> + terminating nul character to be present. Also the padding should
NUL

> + always be performed with nul characters.
NUL

> +``boolean`` Single byte where 0 means ``false`` and nonzero means ``true``. 1 byte
> +``sint8`` Signed 8-bit integer. 1 byte
> +``uint8`` Unsigned 8-bit integer. 1 byte
> +``sint16`` Signed 16-bit little endian integer. 2 byte
> +``uint16`` Unsigned 16-bit little endian integer. 2 byte
> +``sint32`` Signed 32-bit little endian integer. 4 byte
> +``uint32`` Unsigned 32-bit little endian integer. 4 byte

Above 4 lines should end with "bytes".

> +``sint64`` Signed 64-bit little endian integer. 8 bytes
> +``uint64`` Unsigned 64-bit little endian integer. 8 bytes
> +``datetime`` A fixed-length 25-character UTF-16LE string with the format 2 bytes
> + *yyyymmddhhmmss.mmmmmmsutf* where *yyyy* is the 4-digit year, *mm* is
> + the 2-digit month, *dd* is the 2-digit day, *hh* is the 2-digit hour
> + based on a 24-hour clock, *mm* is the 2-digit minute, *ss* is the
> + 2-digit second, *mmmmmm* is the 6-digit microsecond, *s* is a plus or
> + minus character depending on whether *utc* is a positive or negative

^^^ utf: or 5 lines up should be utc

> + offset from UTC (or a colon if the date is an interval). Unpopulated
> + fields should be filled with asterisks.
> +=============== ======================================================================= =========
> +
> +Arrays should be aligned based on the alignment of their base type, while objects should be
> +aligned based on the largest alignment of an element inside them.
> +
> +All buffers returned by the WMI driver core are 8-byte aligned. When converting ACPI data types
> +into such buffers the following conversion rules apply:
> +
> +=============== ============================================================
> +ACPI Data Type Converted into
> +=============== ============================================================
> +Buffer Copied as-is.
> +Integer Converted into a ``uint32``.
> +String Converted into a ``string`` with a terminating nul character

NUL

> + to match the behavior the of the Windows driver.
> +Package Each element inside the package is converted with alignment
> + of the resulting data types being respected. Nested packages
> + are not allowed.
> +=============== ============================================================
> +
> +The Windows driver does attempt to handle nested packages, but this results in internal data
> +structures (``_ACPI_METHOD_ARGUMENT_V1``) erroneously being copied into the resulting buffer.
> +ACPI firmware implementations should thus not return nested packages from ACPI methods
> +associated with the ACPI-WMI interface.
> +
> +References
> +==========
> +
> +.. [1] https://learn.microsoft.com/en-us/windows-hardware/drivers/kernel/driver-defined-wmi-data-items
> diff --git a/Documentation/wmi/driver-development-guide.rst b/Documentation/wmi/driver-development-guide.rst
> index 99ef21fc1c1e..9019661180a0 100644
> --- a/Documentation/wmi/driver-development-guide.rst
> +++ b/Documentation/wmi/driver-development-guide.rst
> @@ -69,7 +69,7 @@ to matching WMI devices using a struct wmi_device_id table:
> .probe = foo_probe,
> .remove = foo_remove, /* optional, devres is preferred */
> .shutdown = foo_shutdown, /* optional, called during shutdown */
> - .notify = foo_notify, /* optional, for event handling */
> + .notify_new = foo_notify, /* optional, for event handling */
> .no_notify_data = true, /* optional, enables events containing no additional data */
> .no_singleton = true, /* required for new WMI drivers */
> };
> @@ -89,9 +89,9 @@ the WMI device and put it in a well-known state for the WMI driver to pick up la
> or kexec. Most WMI drivers need no special shutdown handling and can thus omit this callback.
>
> Please note that new WMI drivers are required to be able to be instantiated multiple times,
> -and are forbidden from using any deprecated GUID-based WMI functions. This means that the
> -WMI driver should be prepared for the scenario that multiple matching WMI devices are present
> -on a given machine.
> +and are forbidden from using any deprecated GUID-based and ACPI-based WMI functions. This means

I would say: or

> +that the WMI driver should be prepared for the scenario that multiple matching WMI devices are
> +present on a given machine.
>
> Because of this, WMI drivers should use the state container design pattern as described in
> Documentation/driver-api/driver-model/design-patterns.rst.
> @@ -103,38 +103,37 @@ Documentation/driver-api/driver-model/design-patterns.rst.
> WMI method drivers
> ------------------
>
> -WMI drivers can call WMI device methods using wmidev_evaluate_method(), the
> -structure of the ACPI buffer passed to this function is device-specific and usually
> -needs some tinkering to get right. Looking at the ACPI tables containing the WMI
> -device usually helps here. The method id and instance number passed to this function
> -are also device-specific, looking at the decoded Binary MOF is usually enough to
> -find the right values.
> +WMI drivers can call WMI device methods using wmidev_invoke_method(). For each WMI method
> +invocation the WMI driver needs to provide the instance number and the method ID, as well as
> +a buffer with the method arguments and optionally a buffer for the results.
>
> -The maximum instance number can be retrieved during runtime using wmidev_instance_count().
> +The layout of said buffers is device-specific and described by the Binary MOF data associated
> +with a given WMI device. Said Binary MOF data also describes the method ID of a given WMI method
> +with the ``WmiMethodId`` qualifier. WMI devices exposing WMI methods usually expose only a single
> +instance (instance number 0), but in theory can expose multiple instances as well. In such a case
> +the number of instances can be retrieved using wmidev_instance_count().
>
> -Take a look at drivers/platform/x86/inspur_platform_profile.c for an example WMI method driver.
> +Take a look at drivers/platform/x86/intel/wmi/thunderbolt.c for an example WMI method driver.
>
> WMI data block drivers
> ----------------------
>
> -WMI drivers can query WMI device data blocks using wmidev_block_query(), the
> -structure of the returned ACPI object is again device-specific. Some WMI devices
> -also allow for setting data blocks using wmidev_block_set().
> +WMI drivers can query WMI data blocks using wmidev_query_block(), the layout of thereturned

(). The layout of the returned

> +buffer is again device-specific and described by the Binary MOF data. Some WMI data blocks are
> +also writeable and can be set using wmidev_set_block(). The number of data block instances can
> +again be retrieved using wmidev_instance_count().
>
> -The maximum instance number can also be retrieved using wmidev_instance_count().
> -
> -Take a look at drivers/platform/x86/intel/wmi/sbl-fw-update.c for an example
> -WMI data block driver.
> +Take a look at drivers/platform/x86/intel/wmi/sbl-fw-update.c for an example WMI data block driver.
>
> WMI event drivers
> -----------------
>
> -WMI drivers can receive WMI events via the notify() callback inside the struct wmi_driver.
> +WMI drivers can receive WMI events via the notify_new() callback inside the struct wmi_driver.
> The WMI subsystem will then take care of setting up the WMI event accordingly. Please note that
> -the structure of the ACPI object passed to this callback is device-specific, and freeing the
> -ACPI object is being done by the WMI subsystem, not the driver.
> +the layout of the buffer passed to this callback is device-specific, and freeing of the buffer
> +is being done by the WMI subsystem itself, not the driver.

is done by

>
> -The WMI driver core will take care that the notify() callback will only be called after
> +The WMI driver core will take care that the notify_new() callback will only be called after
> the probe() callback has been called, and that no events are being received by the driver
> right before and after calling its remove() or shutdown() callback.
>
> @@ -146,6 +145,36 @@ the ``no_notify_data`` flag inside struct wmi_driver should be set to ``true``.
>
> Take a look at drivers/platform/x86/xiaomi-wmi.c for an example WMI event driver.
>
> +Exchanging data with the WMI driver core
> +----------------------------------------
> +
> +WMI drivers can exchange data with the WMI driver core using struct wmi_buffer. The internal
> +structure of those buffers is device-specific and only known by the WMI driver. Because of this
> +the WMI driver itself is responsible for parsing and validating the data received from its
> +WMI device.
> +
> +The strcture of said buffers is described by the MOF data associated with the WMI device in

structure

> +question. When such a buffer contains multiple data items it usually makes sense to define a
> +C structure and use it during parsing. Since the WMI driver core guarantees that all buffers
> +received from a WMI device are aligned on a 8-byte boundary, WMI drivers can simply perform

on an 8-byte

> +a cast between the WMI buffer data and this C structure.
> +
> +This however should only be done after the size of the buffer was verified to be large enough
> +to hold the whole C structure. WMI drivers should reject undersized buffers as they are usually
> +send by the WMI device to signal an internal error. Oversized buffers however should be accepted

sent

> +to emulate the behavior of the Windows WMI implementation.
> +
> +When defining a C structure for parsing WMI buffers the alignment of the data items should be
> +respected. This is especially important for 64-bit integers as those have different alignments
> +on 64-bit (8-byte alignment) and 32-bit (4-byte alignment) architectures. It is thus a good idea
> +to manually specify the alignment of such data items or mark the whole structure as packed when
> +appropriate. Integer data items in general are little-endian integers and should be marked as
> +such using ``__le64`` and friends. When parsing WMI string data items the struct wmi_string should
> +be used as WMI strings have a different layout than C strings.
> +
> +See Documentation/wmi/acpi-interface.rst for more information regarding the binary format
> +of WMI data items.
> +
> Handling multiple WMI devices at once
> -------------------------------------
>
> @@ -170,6 +199,7 @@ Things to avoid
> When developing WMI drivers, there are a couple of things which should be avoided:
>
> - usage of the deprecated GUID-based WMI interface which uses GUIDs instead of WMI device structs
> +- usage of the deprecated ACPI-based WMI interface which uses ACPI objects instead of plain buffers
> - bypassing of the WMI subsystem when talking to WMI devices
> - WMI drivers which cannot be instantiated multiple times.
>

Otherwise LGTM. Thanks.

--
~Randy