summaryrefslogtreecommitdiffstats
path: root/Documentation/wmi
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2026-08-30 09:22:00 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2026-08-30 09:22:00 -0700
commit034dd340b08be1f2f0477ad16131d609f9dbd53c (patch)
tree2536f4b2d7893ccd916b5abdf3c454ad6edc03c2 /Documentation/wmi
downloadlinux-stable-034dd340b08be1f2f0477ad16131d609f9dbd53c.tar.gz
linux-stable-034dd340b08be1f2f0477ad16131d609f9dbd53c.zip
Merge tag 'trace-v7.3-2' of git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-tracegrafted
Pull tracing fixes from Steven Rostedt: - Fix error output of boot instance creation failure Currently if a boot instance creation fails, instead of printing out the name of the instance that failed, it prints "(null)". That is because it prints "cur_str" that had already been processed by strsep(). Print the saved name instead. While at it, print the error code of the failure. - Fix use-after-free for same named historgrams Histograms can be named so that they can be used in multiple events. But if the named histogram has a variable attached, the second event that uses the named histogram which duplicates it and needs to free the original after duplication leaves the old variable in place and still visible. If another histogram uses than variable, it will use the stale one which will try to reference the freed duplicate histogram and crash the kernel. Free the duplicate variables along with the duplicated histogram data. - Check return value of kthread_run() in event self test The events self tests uses a kthread for testing but does not check if it succeeded in creating a kthread. If the kthread creation were to fail, the code will still try to call kthread_stop() on the error returned. - Fix race between reading trace_pipe and updating subbuffer size If a user is reading the trace_pipe file at the same time they update the ring buffer sub-buffer size, can cause the trace_pipe read to read stale data. Add trace_access_lock() around updating the ring buffer sub-buffer size. - Fix eventfs_inode on failure path in creation of the events directory In the creation of the "events" directory, if after allocating the eventfs_inode a failure is detected, it calls cleanup_ei() which calls free_ei(). The free_ei() will test if eventfs_inode being freed has no children. It is a bug if it does. But on the failure case of the creation of the "events" directory, the children lists have not yet been initialized and the free will trigger a warning because list_empty() on an uninitialized list returns false. Move the initialization into init_ei() where it makes more sense and makes sure that a created eventfs_inode has its lists initialized upon creation. - Check return value of kthread_run() in ftrace direct sample code The sample code that shows how to use the ftrace direct calls does not test the return of kthread_run() to see if it succeeds. Return a failure if the kthread_run() doesn't succeed. - Clear user events state on fork in case of alloc failure On fork, the child gets a pointer to the parent's user events state. It makes a copy of it then updates the child's pointer to it. But if the allocation fails, the duplication function leaves the child with a pointer to its parent's descriptor. When the child cleans up its data, it will free the parent's descriptor while the parent is still using it. In the duplication function, set the child's user_event_mm to NULL before testing if the allocation succeeded, and when it exits it will not free the parent's descriptor. - Fix retry exhaustion in simple ring buffer reader swap simple_ring_buffer_swap_reader_page() starts with retry set to 8 and post-decrements it only after a failed link replacement. On the final attempt, a successful replacement leaves retry at zero, while a failed replacement leaves it at -1. But the check for success expects the retry value to be non-zero and exits with an error on zero. This is the opposite result. Fix it. - Fail nicely when the remote swap_reader_page() returns an error Currently, if the swap_reader_page() of a remote buffer fails, it triggers a WARN_ON_ONCE() and continues normally. Instead, have it exit with an error and a pr_warn() print instead of a full WARNING. * tag 'trace-v7.3-2' of git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace: ring-buffer: Stop remote reader update when page swap fails tracing: Fix retry exhaustion in simple ring buffer reader swap tracing/user_events: Clear copied tracing state before fork duplication samples/ftrace: Fix kthread_stop() on ERR_PTR in ftrace-direct-multi-modify samples/ftrace: Fix kthread_stop() on ERR_PTR in ftrace-direct-modify eventfs: Initialize ei->children and ei->list in init_ei() tracing: Fix use-after-free in trace_pipe read on sub-buffer order change tracing: Fix crash passing ERR_PTR to kthread_stop() tracing: Fix use-after-free with same-name named triggers tracing: Fix logged instance name on creation failure
Diffstat (limited to 'Documentation/wmi')
-rw-r--r--Documentation/wmi/acpi-interface.rst174
-rw-r--r--Documentation/wmi/devices/alienware-wmi.rst322
-rw-r--r--Documentation/wmi/devices/bitland-mifs-wmi.rst207
-rw-r--r--Documentation/wmi/devices/dell-wmi-ddv.rst319
-rw-r--r--Documentation/wmi/devices/index.rst15
-rw-r--r--Documentation/wmi/devices/lenovo-wmi-gamezone.rst202
-rw-r--r--Documentation/wmi/devices/lenovo-wmi-other.rst167
-rw-r--r--Documentation/wmi/devices/msi-wmi-platform.rst198
-rw-r--r--Documentation/wmi/devices/uniwill-laptop.rst198
-rw-r--r--Documentation/wmi/devices/wmi-bmof.rst25
-rw-r--r--Documentation/wmi/driver-development-guide.rst225
-rw-r--r--Documentation/wmi/index.rst12
12 files changed, 2064 insertions, 0 deletions
diff --git a/Documentation/wmi/acpi-interface.rst b/Documentation/wmi/acpi-interface.rst
new file mode 100644
index 000000000..4657101c5
--- /dev/null
+++ b/Documentation/wmi/acpi-interface.rst
@@ -0,0 +1,174 @@
+.. SPDX-License-Identifier: GPL-2.0-or-later
+
+==================
+ACPI WMI interface
+==================
+
+The ACPI WMI interface is a proprietary extension of the ACPI specification made
+by Microsoft to allow hardware vendors to embed WMI (Windows Management Instrumentation)
+objects inside their ACPI firmware. Typical functions implemented over ACPI WMI
+are hotkey events on modern notebooks and configuration of BIOS options.
+
+PNP0C14 ACPI device
+-------------------
+
+Discovery of WMI objects is handled by defining ACPI devices with a PNP ID
+of ``PNP0C14``. These devices will contain a set of ACPI buffers and methods
+used for mapping and execution of WMI methods and/or queries. If there exist
+multiple of such devices, then each device is required to have a
+unique ACPI UID.
+
+_WDG buffer
+-----------
+
+The ``_WDG`` buffer is used to discover WMI objects and is required to be
+static. Its internal structure consists of data blocks with a size of 20 bytes,
+containing the following data:
+
+======= =============== =====================================================
+Offset Size (in bytes) Content
+======= =============== =====================================================
+0x00 16 128 bit Variant 2 object GUID.
+0x10 2 2 character method ID or single byte notification ID.
+0x12 1 Object instance count.
+0x13 1 Object flags.
+======= =============== =====================================================
+
+The WMI object flags control whether the method or notification ID is used:
+
+- 0x1: Data block is expensive to collect.
+- 0x2: Data block contains WMI methods.
+- 0x4: Data block contains ASCIZ string.
+- 0x8: Data block describes a WMI event, use notification ID instead
+ of method ID.
+
+Each WMI object GUID can appear multiple times inside a system.
+The method/notification ID is used to construct the ACPI method names used for
+interacting with the WMI object.
+
+WQxx ACPI methods
+-----------------
+
+If a data block does not contain WMI methods, then its content can be retrieved
+by this required ACPI method. The last two characters of the ACPI method name
+are the method ID of the data block to query. Their single parameter is an
+integer describing the instance which should be queried. This parameter can be
+omitted if the data block contains only a single instance.
+
+WSxx ACPI methods
+-----------------
+
+Similar to the ``WQxx`` ACPI methods, except that it is optional and takes an
+additional buffer as its second argument. The instance argument also cannot
+be omitted.
+
+WMxx ACPI methods
+-----------------
+
+Used for executing WMI methods associated with a data block. The last two
+characters of the ACPI method name are the method ID of the data block
+containing the WMI methods. Their first parameter is a integer describing the
+instance which methods should be executed. The second parameter is an integer
+describing the WMI method ID to execute, and the third parameter is a buffer
+containing the WMI method parameters. If the data block is marked as containing
+an ASCIZ string, then this buffer should contain an ASCIZ string. The ACPI
+method will return the result of the executed WMI method.
+
+WExx ACPI methods
+-----------------
+
+Used for optionally enabling/disabling WMI events, the last two characters of
+the ACPI method are the notification ID of the data block describing the WMI
+event as hexadecimal value. Their first parameter is an integer with a value
+of 0 if the WMI event should be disabled, other values will enable
+the WMI event.
+
+Those ACPI methods are always called even for WMI events not registered as
+being expensive to collect to match the behavior of the Windows driver.
+
+WCxx ACPI methods
+-----------------
+Similar to the ``WExx`` ACPI methods, except that instead of WMI events it controls
+data collection of data blocks registered as being expensive to collect. Thus the
+last two characters of the ACPI method name are the method ID of the data block
+to enable/disable.
+
+Those ACPI methods are also called before setting data blocks to match the
+behavior of the Windows driver.
+
+_WED ACPI method
+----------------
+
+Used to retrieve additional WMI event data, its single parameter is a integer
+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
+consumption by the ACPI firmware. Additionally, any data returned by the various ACPI methods needs
+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 an unsigned 16-bit little endian integer specifying 2 bytes
+ the length of the string data in bytes, followed by the string data
+ encoded as UTF-16LE with **optional** NULL termination and padding.
+ Keep in mind that some firmware implementations might depend on the
+ terminating NULL character to be present. Also the padding should
+ always be performed with NULL characters.
+``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 bytes
+``uint16`` Unsigned 16-bit little endian integer. 2 bytes
+``sint32`` Signed 32-bit little endian integer. 4 bytes
+``uint32`` Unsigned 32-bit little endian integer. 4 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.mmmmmmsutc* 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
+ 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 NULL character
+ 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/devices/alienware-wmi.rst b/Documentation/wmi/devices/alienware-wmi.rst
new file mode 100644
index 000000000..1d9d43e2e
--- /dev/null
+++ b/Documentation/wmi/devices/alienware-wmi.rst
@@ -0,0 +1,322 @@
+.. SPDX-License-Identifier: GPL-2.0-or-later
+
+==============================================
+Dell AWCC WMI interface driver (alienware-wmi)
+==============================================
+
+Introduction
+============
+
+The WMI device WMAX has been implemented for many Alienware and Dell's G-Series
+models. Throughout these models, two implementations have been identified. The
+first one, used by older systems, deals with HDMI, brightness, RGB, amplifier
+and deep sleep control. The second one used by newer systems deals primarily
+with thermal control and overclocking.
+
+It is suspected that the latter is used by Alienware Command Center (AWCC) to
+manage manufacturer predefined thermal profiles. The alienware-wmi driver
+exposes Thermal_Information and Thermal_Control methods through the Platform
+Profile API to mimic AWCC's behavior.
+
+This newer interface, named AWCCMethodFunction has been reverse engineered, as
+Dell has not provided any official documentation. We will try to describe to the
+best of our ability its discovered inner workings.
+
+.. note::
+ The following method description may be incomplete and some operations have
+ different implementations between devices.
+
+WMI interface description
+-------------------------
+
+The WMI interface description can be decoded from the embedded binary MOF (bmof)
+data using the `bmfdec <https://github.com/pali/bmfdec>`_ utility:
+
+::
+
+ [WMI, Dynamic, Provider("WmiProv"), Locale("MS\\0x409"), Description("WMI Function"), guid("{A70591CE-A997-11DA-B012-B622A1EF5492}")]
+ class AWCCWmiMethodFunction {
+ [key, read] string InstanceName;
+ [read] boolean Active;
+
+ [WmiMethodId(13), Implemented, read, write, Description("Return Overclocking Report.")] void Return_OverclockingReport([out] uint32 argr);
+ [WmiMethodId(14), Implemented, read, write, Description("Set OCUIBIOS Control.")] void Set_OCUIBIOSControl([in] uint32 arg2, [out] uint32 argr);
+ [WmiMethodId(15), Implemented, read, write, Description("Clear OC FailSafe Flag.")] void Clear_OCFailSafeFlag([out] uint32 argr);
+ [WmiMethodId(19), Implemented, read, write, Description("Get Fan Sensors.")] void GetFanSensors([in] uint32 arg2, [out] uint32 argr);
+ [WmiMethodId(20), Implemented, read, write, Description("Thermal Information.")] void Thermal_Information([in] uint32 arg2, [out] uint32 argr);
+ [WmiMethodId(21), Implemented, read, write, Description("Thermal Control.")] void Thermal_Control([in] uint32 arg2, [out] uint32 argr);
+ [WmiMethodId(23), Implemented, read, write, Description("MemoryOCControl.")] void MemoryOCControl([in] uint32 arg2, [out] uint32 argr);
+ [WmiMethodId(26), Implemented, read, write, Description("System Information.")] void SystemInformation([in] uint32 arg2, [out] uint32 argr);
+ [WmiMethodId(28), Implemented, read, write, Description("Power Information.")] void PowerInformation([in] uint32 arg2, [out] uint32 argr);
+ [WmiMethodId(32), Implemented, read, write, Description("FW Update GPIO toggle.")] void FWUpdateGPIOtoggle([in] uint32 arg2, [out] uint32 argr);
+ [WmiMethodId(33), Implemented, read, write, Description("Read Total of GPIOs.")] void ReadTotalofGPIOs([out] uint32 argr);
+ [WmiMethodId(34), Implemented, read, write, Description("Read GPIO pin Status.")] void ReadGPIOpPinStatus([in] uint32 arg2, [out] uint32 argr);
+ [WmiMethodId(35), Implemented, read, write, Description("Read Chassis Color.")] void ReadChassisColor([out] uint32 argr);
+ [WmiMethodId(36), Implemented, read, write, Description("Read Platform Properties.")] void ReadPlatformProperties([out] uint32 argr);
+ [WmiMethodId(37), Implemented, read, write, Description("Game Shift Status.")] void GameShiftStatus([in] uint32 arg2, [out] uint32 argr);
+ [WmiMethodId(128), Implemented, read, write, Description("Caldera SW installation.")] void CalderaSWInstallation([out] uint32 argr);
+ [WmiMethodId(129), Implemented, read, write, Description("Caldera SW is released.")] void CalderaSWReleased([out] uint32 argr);
+ [WmiMethodId(130), Implemented, read, write, Description("Caldera Connection Status.")] void CalderaConnectionStatus([in] uint32 arg2, [out] uint32 argr);
+ [WmiMethodId(131), Implemented, read, write, Description("Surprise Unplugged Flag Status.")] void SurpriseUnpluggedFlagStatus([out] uint32 argr);
+ [WmiMethodId(132), Implemented, read, write, Description("Clear Surprise Unplugged Flag.")] void ClearSurpriseUnpluggedFlag([out] uint32 argr);
+ [WmiMethodId(133), Implemented, read, write, Description("Cancel Undock Request.")] void CancelUndockRequest([out] uint32 argr);
+ [WmiMethodId(135), Implemented, read, write, Description("Devices in Caldera.")] void DevicesInCaldera([in] uint32 arg2, [out] uint32 argr);
+ [WmiMethodId(136), Implemented, read, write, Description("Notify BIOS for SW ready to disconnect Caldera.")] void NotifyBIOSForSWReadyToDisconnectCaldera([out] uint32 argr);
+ [WmiMethodId(160), Implemented, read, write, Description("Tobii SW installation.")] void TobiiSWinstallation([out] uint32 argr);
+ [WmiMethodId(161), Implemented, read, write, Description("Tobii SW Released.")] void TobiiSWReleased([out] uint32 argr);
+ [WmiMethodId(162), Implemented, read, write, Description("Tobii Camera Power Reset.")] void TobiiCameraPowerReset([out] uint32 argr);
+ [WmiMethodId(163), Implemented, read, write, Description("Tobii Camera Power On.")] void TobiiCameraPowerOn([out] uint32 argr);
+ [WmiMethodId(164), Implemented, read, write, Description("Tobii Camera Power Off.")] void TobiiCameraPowerOff([out] uint32 argr);
+ };
+
+Methods not described in the following document have unknown behavior.
+
+Argument Structure
+------------------
+
+All input arguments have type **uint32** and their structure is very similar
+between methods. Usually, the first byte corresponds to a specific *operation*
+the method performs, and the subsequent bytes correspond to *arguments* passed
+to this *operation*. For example, if an operation has code 0x01 and requires an
+ID 0xA0, the argument you would pass to the method is 0xA001.
+
+
+Thermal Methods
+===============
+
+WMI method GetFanSensors([in] uint32 arg2, [out] uint32 argr)
+-------------------------------------------------------------
+
++--------------------+------------------------------------+--------------------+
+| Operation (Byte 0) | Description | Arguments |
++====================+====================================+====================+
+| 0x01 | Get the number of temperature | - Byte 1: Fan ID |
+| | sensors related with a fan ID | |
++--------------------+------------------------------------+--------------------+
+| 0x02 | Get the temperature sensor IDs | - Byte 1: Fan ID |
+| | related to a fan sensor ID | - Byte 2: Index |
++--------------------+------------------------------------+--------------------+
+
+WMI method Thermal_Information([in] uint32 arg2, [out] uint32 argr)
+-------------------------------------------------------------------
+
++--------------------+------------------------------------+--------------------+
+| Operation (Byte 0) | Description | Arguments |
++====================+====================================+====================+
+| 0x01 | Unknown. | - None |
++--------------------+------------------------------------+--------------------+
+| 0x02 | Get system description number with | - None |
+| | the following structure: | |
+| | | |
+| | - Byte 0: Number of fans | |
+| | - Byte 1: Number of temperature | |
+| | sensors | |
+| | - Byte 2: Unknown | |
+| | - Byte 3: Number of thermal | |
+| | profiles | |
++--------------------+------------------------------------+--------------------+
+| 0x03 | List an ID or resource at a given | - Byte 1: Index |
+| | index. Fan IDs, temperature IDs, | |
+| | unknown IDs and thermal profile | |
+| | IDs are listed in that exact | |
+| | order. | |
+| | | |
+| | Operation 0x02 is used to know | |
+| | which indexes map to which | |
+| | resources. | |
+| | | |
+| | **Returns:** ID at a given index | |
++--------------------+------------------------------------+--------------------+
+| 0x04 | Get the current temperature for a | - Byte 1: Sensor |
+| | given temperature sensor. | ID |
++--------------------+------------------------------------+--------------------+
+| 0x05 | Get the current RPM for a given | - Byte 1: Fan ID |
+| | fan. | |
++--------------------+------------------------------------+--------------------+
+| 0x06 | Get fan speed percentage. (not | - Byte 1: Fan ID |
+| | implemented in every model) | |
++--------------------+------------------------------------+--------------------+
+| 0x07 | Unknown. | - Unknown |
++--------------------+------------------------------------+--------------------+
+| 0x08 | Get minimum RPM for a given FAN | - Byte 1: Fan ID |
+| | ID. | |
++--------------------+------------------------------------+--------------------+
+| 0x09 | Get maximum RPM for a given FAN | - Byte 1: Fan ID |
+| | ID. | |
++--------------------+------------------------------------+--------------------+
+| 0x0A | Get balanced thermal profile ID. | - None |
++--------------------+------------------------------------+--------------------+
+| 0x0B | Get current thermal profile ID. | - None |
++--------------------+------------------------------------+--------------------+
+| 0x0C | Get current `boost` value for a | - Byte 1: Fan ID |
+| | given fan ID. | |
++--------------------+------------------------------------+--------------------+
+
+WMI method Thermal_Control([in] uint32 arg2, [out] uint32 argr)
+---------------------------------------------------------------
+
++--------------------+------------------------------------+--------------------+
+| Operation (Byte 0) | Description | Arguments |
++====================+====================================+====================+
+| 0x01 | Activate a given thermal profile. | - Byte 1: Thermal |
+| | | profile ID |
++--------------------+------------------------------------+--------------------+
+| 0x02 | Set a `boost` value for a given | - Byte 1: Fan ID |
+| | fan ID. | - Byte 2: Boost |
++--------------------+------------------------------------+--------------------+
+
+These are the known thermal profile codes:
+
++------------------------------+----------+------+
+| Thermal Profile | Type | ID |
++==============================+==========+======+
+| Custom | Special | 0x00 |
++------------------------------+----------+------+
+| G-Mode | Special | 0xAB |
++------------------------------+----------+------+
+| Quiet | Legacy | 0x96 |
++------------------------------+----------+------+
+| Balanced | Legacy | 0x97 |
++------------------------------+----------+------+
+| Balanced Performance | Legacy | 0x98 |
++------------------------------+----------+------+
+| Performance | Legacy | 0x99 |
++------------------------------+----------+------+
+| Balanced | USTT | 0xA0 |
++------------------------------+----------+------+
+| Balanced Performance | USTT | 0xA1 |
++------------------------------+----------+------+
+| Cool | USTT | 0xA2 |
++------------------------------+----------+------+
+| Quiet | USTT | 0xA3 |
++------------------------------+----------+------+
+| Performance | USTT | 0xA4 |
++------------------------------+----------+------+
+| Low Power | USTT | 0xA5 |
++------------------------------+----------+------+
+
+If a model supports the User Selectable Thermal Tables (USTT) profiles, it will
+not support the Legacy profiles and vice-versa.
+
+Every model supports the CUSTOM (0x00) thermal profile. GMODE replaces
+PERFORMANCE in G-Series laptops.
+
+WMI method GameShiftStatus([in] uint32 arg2, [out] uint32 argr)
+---------------------------------------------------------------
+
++--------------------+------------------------------------+--------------------+
+| Operation (Byte 0) | Description | Arguments |
++====================+====================================+====================+
+| 0x01 | Toggle *Game Shift*. | - None |
++--------------------+------------------------------------+--------------------+
+| 0x02 | Get *Game Shift* status. | - None |
++--------------------+------------------------------------+--------------------+
+
+Game Shift Status does not change the fan speed profile but it could be some
+sort of CPU/GPU power profile. Benchmarks have not been done.
+
+This method is only present on Dell's G-Series laptops and it's implementation
+implies GMODE thermal profile is available, even if operation 0x03 of
+Thermal_Information does not list it.
+
+G-key on Dell's G-Series laptops also changes Game Shift status, so both are
+directly related.
+
+Overclocking Methods
+====================
+
+WMI method MemoryOCControl([in] uint32 arg2, [out] uint32 argr)
+---------------------------------------------------------------
+
+AWCC supports memory overclocking, but this method is very intricate and has
+not been deciphered yet.
+
+GPIO control Methods
+====================
+
+Alienware and Dell G Series devices with the AWCC interface usually have an
+embedded STM32 RGB lighting controller with USB/HID capabilities. It's vendor ID
+is ``187c`` while it's product ID may vary from model to model.
+
+The control of two GPIO pins of this MCU is exposed as WMI methods for debugging
+purposes.
+
++--------------+--------------------------------------------------------------+
+| Pin | Description |
++==============+===============================+==============================+
+| 0 | Device Firmware Update (DFU) | **HIGH**: Enables DFU mode |
+| | mode pin. | on next MCU boot. |
+| | +------------------------------+
+| | | **LOW**: Disables DFU mode |
+| | | on next MCU boot. |
++--------------+-------------------------------+------------------------------+
+| 1 | Negative Reset (NRST) pin. | **HIGH**: MCU is ON. |
+| | | |
+| | +------------------------------+
+| | | **LOW**: MCU is OFF. |
+| | | |
++--------------+-------------------------------+------------------------------+
+
+See :ref:`acknowledgements` for more information on this MCU.
+
+.. note::
+ Some GPIO control methods break the usual argument structure and take a
+ **Pin number** instead of an operation on the first byte.
+
+WMI method FWUpdateGPIOtoggle([in] uint32 arg2, [out] uint32 argr)
+------------------------------------------------------------------
+
++--------------------+------------------------------------+--------------------+
+| Operation (Byte 0) | Description | Arguments |
++====================+====================================+====================+
+| Pin number | Set the pin status | - Byte 1: Pin |
+| | | status |
++--------------------+------------------------------------+--------------------+
+
+WMI method ReadTotalofGPIOs([out] uint32 argr)
+----------------------------------------------
+
++--------------------+------------------------------------+--------------------+
+| Operation (Byte 0) | Description | Arguments |
++====================+====================================+====================+
+| N/A | Get the total number of GPIOs | - None |
++--------------------+------------------------------------+--------------------+
+
+.. note::
+ Due to how WMI methods are implemented on the firmware level, this method
+ requires a dummy uint32 input argument when invoked.
+
+WMI method ReadGPIOpPinStatus([in] uint32 arg2, [out] uint32 argr)
+------------------------------------------------------------------
+
++--------------------+------------------------------------+--------------------+
+| Operation (Byte 0) | Description | Arguments |
++====================+====================================+====================+
+| Pin number | Get the pin status | - None |
++--------------------+------------------------------------+--------------------+
+
+.. note::
+ There known firmware bug in some laptops where reading the status of a pin
+ also flips it.
+
+Other information Methods
+=========================
+
+WMI method ReadChassisColor([out] uint32 argr)
+----------------------------------------------
+
+Returns the chassis color internal ID.
+
+.. _acknowledgements:
+
+Acknowledgements
+================
+
+Kudos to
+
+* `AlexIII <https://github.com/AlexIII/tcc-g15>`_
+* `T-Troll <https://github.com/T-Troll/alienfx-tools/>`_
+* `Gabriel Marcano <https://gabriel.marcanobrady.family/blog/2024/12/16/dell-g5-5505-se-acpi-or-figuring-out-how-to-reset-the-rgb-controller/>`_
+
+for documenting and testing some of this device's functionality, making it
+possible to generalize this driver.
diff --git a/Documentation/wmi/devices/bitland-mifs-wmi.rst b/Documentation/wmi/devices/bitland-mifs-wmi.rst
new file mode 100644
index 000000000..9e86ecc29
--- /dev/null
+++ b/Documentation/wmi/devices/bitland-mifs-wmi.rst
@@ -0,0 +1,207 @@
+.. SPDX-License-Identifier: GPL-2.0-or-later
+
+========================================
+Bitland MIFS driver (bitland-mifs-wmi)
+========================================
+
+Introduction
+============
+
+
+EC WMI interface description
+============================
+
+The EC WMI interface description can be decoded from the embedded binary MOF (bmof)
+data using the `bmfdec <https://github.com/pali/bmfdec>`_ utility:
+
+::
+
+ class WMIEvent : __ExtrinsicEvent {
+ };
+
+ [WMI, Dynamic, Provider("WmiProv"), Locale("MS\\0x40A"), Description("Root WMI HID_EVENT20"), guid("{46c93e13-ee9b-4262-8488-563bca757fef}")]
+ class HID_EVENT20 : WmiEvent {
+ [key, read] string InstanceName;
+ [read] boolean Active;
+ [WmiDataId(1), read, write, Description("Package Data")] uint8 EventDetail[8];
+ };
+
+ [WMI, Dynamic, Provider("WmiProv"), Locale("MS\\0x40A"), Description("Root WMI HID_EVENT21"), guid("{fa78e245-2c0f-4ca1-91cf-15f34e474850}")]
+ class HID_EVENT21 : WmiEvent {
+ [key, read] string InstanceName;
+ [read] boolean Active;
+ [WmiDataId(1), read, write, Description("Package Data")] uint8 EventDetail[8];
+ };
+
+ [WMI, Dynamic, Provider("WmiProv"), Locale("MS\\0x40A"), Description("Root WMI HID_EVENT22"), guid("{1dceaf0a-4d63-44bb-bd0c-0d6281bfddc5}")]
+ class HID_EVENT22 : WmiEvent {
+ [key, read] string InstanceName;
+ [read] boolean Active;
+ [WmiDataId(1), read, write, Description("Package Data")] uint8 EventDetail[8];
+ };
+
+ [WMI, Dynamic, Provider("WmiProv"), Locale("MS\\0x40A"), Description("Root WMI HID_EVENT23"), guid("{3f9e3c26-b077-4f86-91f5-37ff64d8c7ed}")]
+ class HID_EVENT23 : WmiEvent {
+ [key, read] string InstanceName;
+ [read] boolean Active;
+ [WmiDataId(1), read, write, Description("Package Data")] uint8 EventDetail[8];
+ };
+
+ [WMI, Dynamic, provider("WmiProv"), Locale("MS\\0x409"), Description("Class used to operate firmware interface"), guid("{b60bfb48-3e5b-49e4-a0e9-8cffe1b3434b}")]
+ class MICommonInterface {
+ [key, read] string InstanceName;
+ [read] boolean Active;
+
+ [WmiMethodId(1), Implemented, read, write, Description("Method used to support system functions.")] void MiInterface([in, Description("WMI Interface")] uint8 InData[32], [out] uint8 OutData[30], [out] uint16 Reserved);
+ };
+
+Reverse-Engineering the EC WMI interface
+========================================
+
+The OEM software can be download from `this link <https://iknow.lenovo.com.cn/detail/429447>`_
+
+Nothing is obfuscated, In this case, `ILSpy <https://github.com/icsharpcode/ILSpy>`_ could be helpful.
+
+WMI Methods (MICommonInterface)
+========================================
+
+The ``MICommonInterface`` class (GUID: ``{b60bfb48-3e5b-49e4-a0e9-8cffe1b3434b}``)
+is the primary control interface. It uses a 32-byte buffer for both input
+(``InData``) and output (``OutData``).
+
+Method Structure
+----------------
+
+The data packet follows a standardized format:
+
++----------+------------------------------------------------------------------+
+| Byte | Description |
++==========+==================================================================+
+| 1 | Method Type: Get (0xFA / 250) or Set (0xFB / 251) |
++----------+------------------------------------------------------------------+
+| 3 | Command ID (Method Name) |
++----------+------------------------------------------------------------------+
+| 4 - 31 | Arguments (for Set) or Return Data (for Get) |
++----------+------------------------------------------------------------------+
+
+
+Command IDs
+-----------
+
+The following Command IDs are used in the third byte of the buffer:
+
++----------+-----------------------+------------------------------------------+
+| ID | Name | Values / Description |
++==========+=======================+==========================================+
+| 8 | SystemPerMode | 0: Balance, 1: Performance, 2: Quiet, |
+| | | 3: Full-speed |
++----------+-----------------------+------------------------------------------+
+| 9 | GPUMode | 0: Hybrid, 1: Discrete, 2: UMA |
++----------+-----------------------+------------------------------------------+
+| 10 | KeyboardType | 0: White, 1: Single RGB, 2: Zone RGB |
++----------+-----------------------+------------------------------------------+
+| 11 | FnLock | 0: Off, 1: On |
++----------+-----------------------+------------------------------------------+
+| 12 | TPLock | 0: Unlock, 1: Lock (Touchpad) |
++----------+-----------------------+------------------------------------------+
+| 13 | CPUGPUSYSFanSpeed | Returns 12 bytes of fan data: |
+| | | Bytes 4-5: CPU Fan RPM (Little Endian) |
+| | | Bytes 6-7: GPU Fan RPM (Little Endian) |
+| | | Bytes 10-11: SYS Fan RPM (Little Endian) |
++----------+-----------------------+------------------------------------------+
+| 16 | RGBKeyboardMode | 0: Off, 1: Auto Cyclic, 2: Fixed, |
+| | | 3: Custom |
++----------+-----------------------+------------------------------------------+
+| 17 | RGBKeyboardColor | Bytes 4, 5, 6: Red, Green, Blue values |
++----------+-----------------------+------------------------------------------+
+| 18 | RGBKeyboardBrightness | 0-10: Brightness Levels, 128: Auto |
++----------+-----------------------+------------------------------------------+
+| 19 | SystemAcType | 1: Type-C, 2: Circular Hole (DC) |
++----------+-----------------------+------------------------------------------+
+| 20 | MaxFanSpeedSwitch | Byte 4: Fan Type (0: CPU/GPU, 1: SYS) |
+| | | Byte 5: State (0: Off, 1: On) |
++----------+-----------------------+------------------------------------------+
+| 21 | MaxFanSpeed | Sets manual fan speed duty cycle |
++----------+-----------------------+------------------------------------------+
+| 22 | CPUThermometer | Returns CPU Temperature |
++----------+-----------------------+------------------------------------------+
+
+WMI Events (HID_EVENT20)
+========================
+
+The driver listens for events from the ``HID_EVENT20`` class
+(GUID: ``{46c93e13-ee9b-4262-8488-563bca757fef}``). These events are triggered
+by hotkeys or system state changes (e.g., plugging in AC power).
+
+Event Structure
+---------------
+
+The event data is provided in an 8-byte array (``EventDetail``):
+
++----------+------------------------------------------------------------------+
+| Byte | Description |
++==========+==================================================================+
+| 0 | Event Type (Always 0x01 for HotKey/Notification) |
++----------+------------------------------------------------------------------+
+| 1 | Event ID (Corresponds to the Command IDs above) |
++----------+------------------------------------------------------------------+
+| 2 | Value (The new state or value of the feature) |
++----------+------------------------------------------------------------------+
+
+Common Event IDs:
+-----------------
+
+Note: reserved event ids are not listed there
+
++----------+------------------------------------------------------------------+
+| Event Id | Description |
++==========+==================================================================+
+| 4 | AirPlane mode change |
++----------+------------------------------------------------------------------+
+| 5 | Keyboard brightness change |
++----------+------------------------------------------------------------------+
+| 6 | Touchpad state (enabled/disabled) change |
++----------+------------------------------------------------------------------+
+| 7 | FnLock state (enabled/disabled) change |
++----------+------------------------------------------------------------------+
+| 8 | Keyboard mode change |
++----------+------------------------------------------------------------------+
+| 9 | CapsLock state change |
++----------+------------------------------------------------------------------+
+| 13 | NumLock state change |
++----------+------------------------------------------------------------------+
+| 14 | ScrollLock state change |
++----------+------------------------------------------------------------------+
+| 15 | Performance plan change |
++----------+------------------------------------------------------------------+
+| 25 | Display refresh rate change |
++----------+------------------------------------------------------------------+
+| 33 | Super key lock state (enabled/disabled) change |
++----------+------------------------------------------------------------------+
+| 35 | Open control center key |
++----------+------------------------------------------------------------------+
+
+Implementation Details
+======================
+
+Performance Modes
+-----------------
+Changing the performance mode via Command ID 0x08 (SystemPerMode) affects the
+power limits (PL1/PL2) and fan curves managed by the Embedded Controller (EC).
+Note that the "Full-speed" and "Performance" mode (1, 3) is typically only
+available when the system is connected to a DC power source (not USB-C/PD).
+
+In the driver implementation, switch to performance/full-speed mode without
+DC power connected will throw the EOPNOTSUPP error.
+
+Graphics Switching
+------------------
+The ``GPUMode`` (0x09) allows switching between Hybrid (Muxless) and Discrete
+(Muxed) graphics. Changing this value usually requires a system reboot to
+take effect in the BIOS/Firmware.
+
+Fan Control
+-----------
+The system supports both automatic EC control and manual overrides. Command ID
+0x14 (``MaxFanSpeedSwitch``) is used to toggle manual control, while ID 0x15
+sets the actual PWM duty cycle.
diff --git a/Documentation/wmi/devices/dell-wmi-ddv.rst b/Documentation/wmi/devices/dell-wmi-ddv.rst
new file mode 100644
index 000000000..109d4c5c9
--- /dev/null
+++ b/Documentation/wmi/devices/dell-wmi-ddv.rst
@@ -0,0 +1,319 @@
+.. SPDX-License-Identifier: GPL-2.0-or-later
+
+============================================
+Dell DDV WMI interface driver (dell-wmi-ddv)
+============================================
+
+Introduction
+============
+
+Many Dell notebooks made after ~2020 support a WMI-based interface for
+retrieving various system data like battery temperature, ePPID, diagnostic data
+and fan/thermal sensor data.
+
+This interface is likely used by the `Dell Data Vault` software on Windows,
+so it was called `DDV`. Currently the ``dell-wmi-ddv`` driver supports
+version 2 and 3 of the interface, with support for new interface versions
+easily added.
+
+.. warning:: The interface is regarded as internal by Dell, so no vendor
+ documentation is available. All knowledge was thus obtained by
+ trial-and-error, please keep that in mind.
+
+Dell ePPID (electronic Piece Part Identification)
+=================================================
+
+The Dell ePPID is used to uniquely identify components in Dell machines,
+including batteries. It has a form similar to `CC-PPPPPP-MMMMM-YMD-SSSS-FFF`
+and contains the following information:
+
+* Country code of origin (CC).
+* Part number with the first character being a filling number (PPPPPP).
+* Manufacture Identification (MMMMM).
+* Manufacturing Year/Month/Date (YMD) in base 36, with Y being the last digit
+ of the year.
+* Manufacture Sequence Number (SSSS).
+* Optional Firmware Version/Revision (FFF).
+
+The `eppidtool <https://pypi.org/project/eppidtool>`_ python utility can be used
+to decode and display this information.
+
+All information regarding the Dell ePPID was gathered using Dell support
+documentation and `this website <https://telcontar.net/KBK/Dell/date_codes>`_.
+
+WMI interface description
+=========================
+
+The WMI interface description can be decoded from the embedded binary MOF (bmof)
+data using the `bmfdec <https://github.com/pali/bmfdec>`_ utility:
+
+::
+
+ [WMI, Dynamic, Provider("WmiProv"), Locale("MS\\0x409"), Description("WMI Function"), guid("{8A42EA14-4F2A-FD45-6422-0087F7A7E608}")]
+ class DDVWmiMethodFunction {
+ [key, read] string InstanceName;
+ [read] boolean Active;
+
+ [WmiMethodId(1), Implemented, read, write, Description("Return Battery Design Capacity.")] void BatteryDesignCapacity([in] uint32 arg2, [out] uint32 argr);
+ [WmiMethodId(2), Implemented, read, write, Description("Return Battery Full Charge Capacity.")] void BatteryFullChargeCapacity([in] uint32 arg2, [out] uint32 argr);
+ [WmiMethodId(3), Implemented, read, write, Description("Return Battery Manufacture Name.")] void BatteryManufactureName([in] uint32 arg2, [out] string argr);
+ [WmiMethodId(4), Implemented, read, write, Description("Return Battery Manufacture Date.")] void BatteryManufactureDate([in] uint32 arg2, [out] uint32 argr);
+ [WmiMethodId(5), Implemented, read, write, Description("Return Battery Serial Number.")] void BatterySerialNumber([in] uint32 arg2, [out] uint32 argr);
+ [WmiMethodId(6), Implemented, read, write, Description("Return Battery Chemistry Value.")] void BatteryChemistryValue([in] uint32 arg2, [out] string argr);
+ [WmiMethodId(7), Implemented, read, write, Description("Return Battery Temperature.")] void BatteryTemperature([in] uint32 arg2, [out] uint32 argr);
+ [WmiMethodId(8), Implemented, read, write, Description("Return Battery Current.")] void BatteryCurrent([in] uint32 arg2, [out] uint32 argr);
+ [WmiMethodId(9), Implemented, read, write, Description("Return Battery Voltage.")] void BatteryVoltage([in] uint32 arg2, [out] uint32 argr);
+ [WmiMethodId(10), Implemented, read, write, Description("Return Battery Manufacture Access(MA code).")] void BatteryManufactureAceess([in] uint32 arg2, [out] uint32 argr);
+ [WmiMethodId(11), Implemented, read, write, Description("Return Battery Relative State-Of-Charge.")] void BatteryRelativeStateOfCharge([in] uint32 arg2, [out] uint32 argr);
+ [WmiMethodId(12), Implemented, read, write, Description("Return Battery Cycle Count")] void BatteryCycleCount([in] uint32 arg2, [out] uint32 argr);
+ [WmiMethodId(13), Implemented, read, write, Description("Return Battery ePPID")] void BatteryePPID([in] uint32 arg2, [out] string argr);
+ [WmiMethodId(14), Implemented, read, write, Description("Return Battery Raw Analytics Start")] void BatteryeRawAnalyticsStart([in] uint32 arg2, [out] uint32 argr);
+ [WmiMethodId(15), Implemented, read, write, Description("Return Battery Raw Analytics")] void BatteryeRawAnalytics([in] uint32 arg2, [out] uint32 RawSize, [out, WmiSizeIs("RawSize") : ToInstance] uint8 RawData[]);
+ [WmiMethodId(16), Implemented, read, write, Description("Return Battery Design Voltage.")] void BatteryDesignVoltage([in] uint32 arg2, [out] uint32 argr);
+ [WmiMethodId(17), Implemented, read, write, Description("Return Battery Raw Analytics A Block")] void BatteryeRawAnalyticsABlock([in] uint32 arg2, [out] uint32 RawSize, [out, WmiSizeIs("RawSize") : ToInstance] uint8 RawData[]);
+ [WmiMethodId(18), Implemented, read, write, Description("Return Version.")] void ReturnVersion([in] uint32 arg2, [out] uint32 argr);
+ [WmiMethodId(32), Implemented, read, write, Description("Return Fan Sensor Information")] void FanSensorInformation([in] uint32 arg2, [out] uint32 RawSize, [out, WmiSizeIs("RawSize") : ToInstance] uint8 RawData[]);
+ [WmiMethodId(34), Implemented, read, write, Description("Return Thermal Sensor Information")] void ThermalSensorInformation([in] uint32 arg2, [out] uint32 RawSize, [out, WmiSizeIs("RawSize") : ToInstance] uint8 RawData[]);
+ };
+
+Each WMI method takes an ACPI buffer containing a 32-bit index as input argument,
+with the first 8 bit being used to specify the battery when using battery-related
+WMI methods. Other WMI methods may ignore this argument or interpret it
+differently. The WMI method output format varies:
+
+* if the function has only a single output, then an ACPI object
+ of the corresponding type is returned
+* if the function has multiple outputs, when an ACPI package
+ containing the outputs in the same order is returned
+
+The format of the output should be thoroughly checked, since many methods can
+return malformed data in case of an error.
+
+The data format of many battery-related methods seems to be based on the
+`Smart Battery Data Specification`, so unknown battery-related methods are
+likely to follow this standard in some way.
+
+WMI method GetBatteryDesignCapacity()
+-------------------------------------
+
+Returns the design capacity of the battery in mAh as an u16.
+
+WMI method BatteryFullCharge()
+------------------------------
+
+Returns the full charge capacity of the battery in mAh as an u16.
+
+WMI method BatteryManufactureName()
+-----------------------------------
+
+Returns the manufacture name of the battery as an ASCII string.
+
+WMI method BatteryManufactureDate()
+-----------------------------------
+
+Returns the manufacture date of the battery as an u16.
+The date is encoded in the following manner:
+
+- bits 0 to 4 contain the manufacture day.
+- bits 5 to 8 contain the manufacture month.
+- bits 9 to 15 contain the manufacture year biased by 1980.
+
+WMI method BatterySerialNumber()
+--------------------------------
+
+Returns the serial number of the battery as an u16.
+
+WMI method BatteryChemistryValue()
+----------------------------------
+
+Returns the chemistry of the battery as an ASCII string.
+Known values are:
+
+- "Li-I" for Li-Ion
+
+WMI method BatteryTemperature()
+-------------------------------
+
+Returns the temperature of the battery in tenth degree kelvin as an u16.
+
+WMI method BatteryCurrent()
+---------------------------
+
+Returns the current flow of the battery in mA as an s16.
+Negative values indicate discharging.
+
+WMI method BatteryVoltage()
+---------------------------
+
+Returns the voltage flow of the battery in mV as an u16.
+
+WMI method BatteryManufactureAccess()
+-------------------------------------
+
+Returns the health status of the battery as a u16.
+The health status encoded in the following manner:
+
+ - the third nibble contains the general failure mode
+ - the fourth nibble contains the specific failure code
+
+Valid failure modes are:
+
+ - permanent failure (``0x9``)
+ - overheat failure (``0xa``)
+ - overcurrent failure (``0xb``)
+
+All other failure modes are to be considered normal.
+
+The following failure codes are valid for a permanent failure:
+
+ - fuse blown (``0x0``)
+ - cell imbalance (``0x1``)
+ - overvoltage (``0x2``)
+ - fet failure (``0x3``)
+
+The last two bits of the failure code are to be ignored when the battery
+signals a permanent failure.
+
+The following failure codes a valid for a overheat failure:
+
+ - overheat at start of charging (``0x5``)
+ - overheat during charging (``0x7``)
+ - overheat during discharging (``0x8``)
+
+The following failure codes are valid for a overcurrent failure:
+
+ - overcurrent during charging (``0x6``)
+ - overcurrent during discharging (``0xb``)
+
+WMI method BatteryRelativeStateOfCharge()
+-----------------------------------------
+
+Returns the capacity of the battery in percent as an u16.
+
+WMI method BatteryCycleCount()
+------------------------------
+
+Returns the cycle count of the battery as an u16.
+
+WMI method BatteryePPID()
+-------------------------
+
+Returns the ePPID of the battery as an ASCII string.
+
+WMI method BatteryeRawAnalyticsStart()
+--------------------------------------
+
+Performs an analysis of the battery and returns a status code:
+
+- ``0x0``: Success
+- ``0x1``: Interface not supported
+- ``0xfffffffe``: Error/Timeout
+
+.. note::
+ The meaning of this method is still largely unknown.
+
+WMI method BatteryeRawAnalytics()
+---------------------------------
+
+Returns a buffer usually containing 12 blocks of analytics data.
+Those blocks contain:
+
+- a block number starting with 0 (u8)
+- 31 bytes of unknown data
+
+.. note::
+ The meaning of this method is still largely unknown.
+
+WMI method BatteryDesignVoltage()
+---------------------------------
+
+Returns the design voltage of the battery in mV as an u16.
+
+WMI method BatteryeRawAnalyticsABlock()
+---------------------------------------
+
+Returns a single block of analytics data, with the second byte
+of the index being used for selecting the block number.
+
+*Supported since WMI interface version 3!*
+
+.. note::
+ The meaning of this method is still largely unknown.
+
+WMI method ReturnVersion()
+--------------------------
+
+Returns the WMI interface version as an u32.
+
+WMI method FanSensorInformation()
+---------------------------------
+
+Returns a buffer containing fan sensor entries, terminated
+with a single ``0xff``.
+Those entries contain:
+
+- fan type (u8)
+- fan speed in RPM (little endian u16)
+
+WMI method ThermalSensorInformation()
+-------------------------------------
+
+Returns a buffer containing thermal sensor entries, terminated
+with a single ``0xff``.
+Those entries contain:
+
+- thermal type (u8)
+- current temperature (s8)
+- min. temperature (s8)
+- max. temperature (s8)
+- unknown field (u8)
+
+.. note::
+ TODO: Find out what the meaning of the last byte is.
+
+ACPI battery matching algorithm
+===============================
+
+The algorithm used to match ACPI batteries to indices is based on information
+which was found inside the logging messages of the OEM software.
+
+Basically for each new ACPI battery, the serial numbers of the batteries behind
+indices 1 till 3 are compared with the serial number of the ACPI battery.
+Since the serial number of the ACPI battery can either be encoded as a normal
+integer or as a hexadecimal value, both cases need to be checked. The first
+index with a matching serial number is then selected.
+
+A serial number of 0 indicates that the corresponding index is not associated
+with an actual battery, or that the associated battery is not present.
+
+Some machines like the Dell Inspiron 3505 only support a single battery and thus
+ignore the battery index. Because of this the driver depends on the ACPI battery
+hook mechanism to discover batteries.
+
+Reverse-Engineering the DDV WMI interface
+=========================================
+
+1. Find a supported Dell notebook, usually made after ~2020.
+2. Dump the ACPI tables and search for the WMI device (usually called "ADDV").
+3. Decode the corresponding bmof data and look at the ASL code.
+4. Try to deduce the meaning of a certain WMI method by comparing the control
+ flow with other ACPI methods (_BIX or _BIF for battery related methods
+ for example).
+5. Use the built-in UEFI diagnostics to view sensor types/values for fan/thermal
+ related methods (sometimes overwriting static ACPI data fields can be used
+ to test different sensor type values, since on some machines this data is
+ not reinitialized upon a warm reset).
+
+Alternatively:
+
+1. Load the ``dell-wmi-ddv`` driver, use the ``force`` module param
+ if necessary.
+2. Use the debugfs interface to access the raw fan/thermal sensor buffer data.
+3. Compare the data with the built-in UEFI diagnostics.
+
+In case the DDV WMI interface version available on your Dell notebook is not
+supported or you are seeing unknown fan/thermal sensors, please submit a
+bugreport on `bugzilla <https://bugzilla.kernel.org>`_ so they can be added
+to the ``dell-wmi-ddv`` driver.
+
+See Documentation/admin-guide/reporting-issues.rst for further information.
diff --git a/Documentation/wmi/devices/index.rst b/Documentation/wmi/devices/index.rst
new file mode 100644
index 000000000..b0a9b4229
--- /dev/null
+++ b/Documentation/wmi/devices/index.rst
@@ -0,0 +1,15 @@
+.. SPDX-License-Identifier: GPL-2.0-or-later
+
+=============================
+Driver-specific Documentation
+=============================
+
+This section provides information about various devices supported by
+the Linux kernel, their protocols and driver details.
+
+.. toctree::
+ :maxdepth: 1
+ :numbered:
+ :glob:
+
+ *
diff --git a/Documentation/wmi/devices/lenovo-wmi-gamezone.rst b/Documentation/wmi/devices/lenovo-wmi-gamezone.rst
new file mode 100644
index 000000000..1769ad3d5
--- /dev/null
+++ b/Documentation/wmi/devices/lenovo-wmi-gamezone.rst
@@ -0,0 +1,202 @@
+.. SPDX-License-Identifier: GPL-2.0-or-later
+
+==========================================================
+Lenovo WMI Interface Gamezone Driver (lenovo-wmi-gamezone)
+==========================================================
+
+Introduction
+============
+The Lenovo WMI gamezone interface is broken up into multiple GUIDs,
+The primary "Gamezone" GUID provides advanced features such as fan
+profiles and overclocking. It is paired with multiple event GUIDs
+and data block GUIDs that provide context for the various methods.
+
+Gamezone Data
+-------------
+
+WMI GUID ``887B54E3-DDDC-4B2C-8B88-68A26A8835D0``
+
+The Gamezone Data WMI interface provides platform-profile and fan curve
+settings for devices that fall under the "Gaming Series" of Lenovo devices.
+It uses a notifier chain to inform other Lenovo WMI interface drivers of the
+current platform profile when it changes. The currently set profile can be
+determined by the user on the hardware by looking at the color of the power
+or profile LED, depending on the model.
+
+The following platform profiles are supported:
+ - low-power, blue LED
+ - balanced, white LED
+ - performance, red LED
+ - max-power, purple LED
+ - custom, purple LED
+
+Extreme Mode
+~~~~~~~~~~~~~~~~~~~~
+Some newer Lenovo "Gaming Series" laptops have an "Extreme Mode" profile
+enabled in their BIOS. When available, this mode will be represented by the
+max-power platform profile.
+
+For a subset of these devices the "Extreme Mode" profile is incomplete in
+the BIOS and setting it will cause undefined behavior. A BIOS bug quirk table
+is provided to ensure these devices cannot set "Extreme Mode" from the driver.
+
+Custom Profile
+~~~~~~~~~~~~~~
+The custom profile represents a hardware mode on Lenovo devices that enables
+user modifications to Package Power Tracking (PPT) and fan curve settings.
+When an attribute exposed by the Other Mode WMI interface is to be modified,
+the Gamezone driver must first be switched to the "custom" profile manually,
+or the setting will have no effect. If another profile is set from the list
+of supported profiles, the BIOS will override any user PPT settings when
+switching to that profile.
+
+Gamezone Thermal Mode Event
+---------------------------
+
+WMI GUID ``D320289E-8FEA-41E0-86F9-911D83151B5F``
+
+The Gamezone Thermal Mode Event interface notifies the system when the platform
+profile has changed, either through the hardware event (Fn+Q for laptops or
+Legion + Y for Go Series), or through the Gamezone WMI interface. This event is
+implemented in the Lenovo WMI Events driver (lenovo-wmi-events).
+
+
+WMI interface description
+=========================
+
+The WMI interface description can be decoded from the embedded binary MOF (bmof)
+data using the `bmfdec <https://github.com/pali/bmfdec>`_ utility:
+
+::
+
+ [WMI, Dynamic, Provider("WmiProv"), Locale("MS\\0x409"), Description("LENOVO_GAMEZONE_DATA class"), guid("{887B54E3-DDDC-4B2C-8B88-68A26A8835D0}")]
+ class LENOVO_GAMEZONE_DATA {
+ [key, read] string InstanceName;
+ [read] boolean Active;
+
+ [WmiMethodId(4), Implemented, Description("Is SupportGpu OverClock")] void IsSupportGpuOC([out, Description("Is SupportGpu OverClock")] uint32 Data);
+ [WmiMethodId(11), Implemented, Description("Get AslCode Version")] void GetVersion ([out, Description("AslCode version")] UINT32 Data);
+ [WmiMethodId(12), Implemented, Description("Fan cooling capability")] void IsSupportFanCooling([out, Description("Fan cooling capability")] UINT32 Data);
+ [WmiMethodId(13), Implemented, Description("Set Fan cooling on/off")] void SetFanCooling ([in, Description("Set Fan cooling on/off")] UINT32 Data);
+ [WmiMethodId(14), Implemented, Description("cpu oc capability")] void IsSupportCpuOC ([out, Description("cpu oc capability")] UINT32 Data);
+ [WmiMethodId(15), Implemented, Description("bios has overclock capability")] void IsBIOSSupportOC ([out, Description("bios has overclock capability")] UINT32 Data);
+ [WmiMethodId(16), Implemented, Description("enable or disable overclock in bios")] void SetBIOSOC ([in, Description("enable or disable overclock in bios")] UINT32 Data);
+ [WmiMethodId(18), Implemented, Description("Get CPU temperature")] void GetCPUTemp ([out, Description("Get CPU temperature")] UINT32 Data);
+ [WmiMethodId(19), Implemented, Description("Get GPU temperature")] void GetGPUTemp ([out, Description("Get GPU temperature")] UINT32 Data);
+ [WmiMethodId(20), Implemented, Description("Get Fan cooling on/off status")] void GetFanCoolingStatus ([out, Description("Get Fan cooling on/off status")] UINT32 Data);
+ [WmiMethodId(21), Implemented, Description("EC support disable windows key capability")] void IsSupportDisableWinKey ([out, Description("EC support disable windows key capability")] UINT32 Data);
+ [WmiMethodId(22), Implemented, Description("Set windows key disable/enable")] void SetWinKeyStatus ([in, Description("Set windows key disable/enable")] UINT32 Data);
+ [WmiMethodId(23), Implemented, Description("Get windows key disable/enable status")] void GetWinKeyStatus ([out, Description("Get windows key disable/enable status")] UINT32 Data);
+ [WmiMethodId(24), Implemented, Description("EC support disable touchpad capability")] void IsSupportDisableTP ([out, Description("EC support disable touchpad capability")] UINT32 Data);
+ [WmiMethodId(25), Implemented, Description("Set touchpad disable/enable")] void SetTPStatus ([in, Description("Set touchpad disable/enable")] UINT32 Data);
+ [WmiMethodId(26), Implemented, Description("Get touchpad disable/enable status")] void GetTPStatus ([out, Description("Get touchpad disable/enable status")] UINT32 Data);
+ [WmiMethodId(30), Implemented, Description("Get Keyboard feature list")] void GetKeyboardfeaturelist ([out, Description("Get Keyboard feature list")] UINT32 Data);
+ [WmiMethodId(31), Implemented, Description("Get Memory OC Information")] void GetMemoryOCInfo ([out, Description("Get Memory OC Information")] UINT32 Data);
+ [WmiMethodId(32), Implemented, Description("Water Cooling feature capability")] void IsSupportWaterCooling ([out, Description("Water Cooling feature capability")] UINT32 Data);
+ [WmiMethodId(33), Implemented, Description("Set Water Cooling status")] void SetWaterCoolingStatus ([in, Description("Set Water Cooling status")] UINT32 Data);
+ [WmiMethodId(34), Implemented, Description("Get Water Cooling status")] void GetWaterCoolingStatus ([out, Description("Get Water Cooling status")] UINT32 Data);
+ [WmiMethodId(35), Implemented, Description("Lighting feature capability")] void IsSupportLightingFeature ([out, Description("Lighting feature capability")] UINT32 Data);
+ [WmiMethodId(36), Implemented, Description("Set keyboard light off or on to max")] void SetKeyboardLight ([in, Description("keyboard light off or on switch")] UINT32 Data);
+ [WmiMethodId(37), Implemented, Description("Get keyboard light on/off status")] void GetKeyboardLight ([out, Description("Get keyboard light on/off status")] UINT32 Data);
+ [WmiMethodId(38), Implemented, Description("Get Macrokey scan code")] void GetMacrokeyScancode ([in, Description("Macrokey index")] UINT32 idx, [out, Description("Scan code")] UINT32 scancode);
+ [WmiMethodId(39), Implemented, Description("Get Macrokey count")] void GetMacrokeyCount ([out, Description("Macrokey count")] UINT32 Data);
+ [WmiMethodId(40), Implemented, Description("Support G-Sync feature")] void IsSupportGSync ([out, Description("Support G-Sync feature")] UINT32 Data);
+ [WmiMethodId(41), Implemented, Description("Get G-Sync Status")] void GetGSyncStatus ([out, Description("Get G-Sync Status")] UINT32 Data);
+ [WmiMethodId(42), Implemented, Description("Set G-Sync Status")] void SetGSyncStatus ([in, Description("Set G-Sync Status")] UINT32 Data);
+ [WmiMethodId(43), Implemented, Description("Support Smart Fan feature")] void IsSupportSmartFan ([out, Description("Support Smart Fan feature")] UINT32 Data);
+ [WmiMethodId(44), Implemented, Description("Set Smart Fan Mode")] void SetSmartFanMode ([in, Description("Set Smart Fan Mode")] UINT32 Data);
+ [WmiMethodId(45), Implemented, Description("Get Smart Fan Mode")] void GetSmartFanMode ([out, Description("Get Smart Fan Mode")] UINT32 Data);
+ [WmiMethodId(46), Implemented, Description("Get Smart Fan Setting Mode")] void GetSmartFanSetting ([out, Description("Get Smart Setting Mode")] UINT32 Data);
+ [WmiMethodId(47), Implemented, Description("Get Power Charge Mode")] void GetPowerChargeMode ([out, Description("Get Power Charge Mode")] UINT32 Data);
+ [WmiMethodId(48), Implemented, Description("Get Gaming Product Info")] void GetProductInfo ([out, Description("Get Gaming Product Info")] UINT32 Data);
+ [WmiMethodId(49), Implemented, Description("Over Drive feature capability")] void IsSupportOD ([out, Description("Over Drive feature capability")] UINT32 Data);
+ [WmiMethodId(50), Implemented, Description("Get Over Drive status")] void GetODStatus ([out, Description("Get Over Drive status")] UINT32 Data);
+ [WmiMethodId(51), Implemented, Description("Set Over Drive status")] void SetODStatus ([in, Description("Set Over Drive status")] UINT32 Data);
+ [WmiMethodId(52), Implemented, Description("Set Light Control Owner")] void SetLightControlOwner ([in, Description("Set Light Control Owner")] UINT32 Data);
+ [WmiMethodId(53), Implemented, Description("Set DDS Control Owner")] void SetDDSControlOwner ([in, Description("Set DDS Control Owner")] UINT32 Data);
+ [WmiMethodId(54), Implemented, Description("Get the flag of restore OC value")] void IsRestoreOCValue ([in, Description("Clean this flag")] UINT32 idx, [out, Description("Restore oc value flag")] UINT32 Data);
+ [WmiMethodId(55), Implemented, Description("Get Real Thremal Mode")] void GetThermalMode ([out, Description("Real Thremal Mode")] UINT32 Data);
+ [WmiMethodId(56), Implemented, Description("Get the OC switch status in BIOS")] void GetBIOSOCMode ([out, Description("OC Mode")] UINT32 Data);
+ [WmiMethodId(59), Implemented, Description("Get hardware info support version")] void GetHardwareInfoSupportVersion ([out, Description("version")] UINT32 Data);
+ [WmiMethodId(60), Implemented, Description("Get Cpu core 0 max frequency")] void GetCpuFrequency ([out, Description("frequency")] UINT32 Data);
+ [WmiMethodId(62), Implemented, Description("Check the Adapter type fit for OC")] void IsACFitForOC ([out, Description("AC check result")] UINT32 Data);
+ [WmiMethodId(63), Implemented, Description("Is support IGPU mode")] void IsSupportIGPUMode ([out, Description("IGPU modes")] UINT32 Data);
+ [WmiMethodId(64), Implemented, Description("Get IGPU Mode Status")] void GetIGPUModeStatus([out, Description("IGPU Mode Status")] UINT32 Data);
+ [WmiMethodId(65), Implemented, Description("Set IGPU Mode")] void SetIGPUModeStatus([in, Description("IGPU Mode")] UINT32 mode, [out, Description("return code")] UINT32 Data);
+ [WmiMethodId(66), Implemented, Description("Notify DGPU Status")] void NotifyDGPUStatus([in, Description("DGPU status")] UINT32 status, [out, Description("return code")] UINT32 Data);
+ [WmiMethodId(67), Implemented, Description("Is changed Y log")] void IsChangedYLog([out, Description("Is changed Y Log")] UINT32 Data);
+ [WmiMethodId(68), Implemented, Description("Get DGPU Hardwawre ID")] void GetDGPUHWId([out, Description("Get DGPU Hardware ID")] string Data);
+ };
+
+ [WMI, Dynamic, Provider("WmiProv"), Locale("MS\\0x409"), Description("Definition of CPU OC parameter list"), guid("{B7F3CA0A-ACDC-42D2-9217-77C6C628FBD2}")]
+ class LENOVO_GAMEZONE_CPU_OC_DATA {
+ [key, read] string InstanceName;
+ [read] boolean Active;
+
+ [WmiDataId(1), read, Description("OC tune id.")] uint32 Tuneid;
+ [WmiDataId(2), read, Description("Default value.")] uint32 DefaultValue;
+ [WmiDataId(3), read, Description("OC Value.")] uint32 OCValue;
+ [WmiDataId(4), read, Description("Min Value.")] uint32 MinValue;
+ [WmiDataId(5), read, Description("Max Value.")] uint32 MaxValue;
+ [WmiDataId(6), read, Description("Scale Value.")] uint32 ScaleValue;
+ [WmiDataId(7), read, Description("OC Order id.")] uint32 OCOrderid;
+ [WmiDataId(8), read, Description("NON-OC Order id.")] uint32 NOCOrderid;
+ [WmiDataId(9), read, Description("Delay time in ms.")] uint32 Interval;
+ };
+
+ [WMI, Dynamic, Provider("WmiProv"), Locale("MS\\0x409"), Description("Definition of GPU OC parameter list"), guid("{887B54E2-DDDC-4B2C-8B88-68A26A8835D0}")]
+ class LENOVO_GAMEZONE_GPU_OC_DATA {
+ [key, read] string InstanceName;
+ [read] boolean Active;
+
+ [WmiDataId(1), read, Description("P-State ID.")] uint32 PStateID;
+ [WmiDataId(2), read, Description("CLOCK ID.")] uint32 ClockID;
+ [WmiDataId(3), read, Description("Default value.")] uint32 defaultvalue;
+ [WmiDataId(4), read, Description("OC Offset freqency.")] uint32 OCOffsetFreq;
+ [WmiDataId(5), read, Description("OC Min offset value.")] uint32 OCMinOffset;
+ [WmiDataId(6), read, Description("OC Max offset value.")] uint32 OCMaxOffset;
+ [WmiDataId(7), read, Description("OC Offset Scale.")] uint32 OCOffsetScale;
+ [WmiDataId(8), read, Description("OC Order id.")] uint32 OCOrderid;
+ [WmiDataId(9), read, Description("NON-OC Order id.")] uint32 NOCOrderid;
+ };
+
+ [WMI, Dynamic, Provider("WmiProv"), Locale("MS\\0x409"), Description("Fancooling finish event"), guid("{BC72A435-E8C1-4275-B3E2-D8B8074ABA59}")]
+ class LENOVO_GAMEZONE_FAN_COOLING_EVENT: WMIEvent {
+ [key, read] string InstanceName;
+ [read] boolean Active;
+
+ [WmiDataId(1), read, Description("Fancooling clean finish event")] uint32 EventId;
+ };
+
+ [WMI, Dynamic, Provider("WmiProv"), Locale("MS\\0x409"), Description("Smart Fan mode change event"), guid("{D320289E-8FEA-41E0-86F9-611D83151B5F}")]
+ class LENOVO_GAMEZONE_SMART_FAN_MODE_EVENT: WMIEvent {
+ [key, read] string InstanceName;
+ [read] boolean Active;
+
+ [WmiDataId(1), read, Description("Smart Fan Mode change event")] uint32 mode;
+ [WmiDataId(2), read, Description("version of FN+Q")] uint32 version;
+ };
+
+ [WMI, Dynamic, Provider("WmiProv"), Locale("MS\\0x409"), Description("Smart Fan setting mode change event"), guid("{D320289E-8FEA-41E1-86F9-611D83151B5F}")]
+ class LENOVO_GAMEZONE_SMART_FAN_SETTING_EVENT: WMIEvent {
+ [key, read] string InstanceName;
+ [read] boolean Active;
+
+ [WmiDataId(1), read, Description("Smart Fan Setting mode change event")] uint32 mode;
+ };
+
+ [WMI, Dynamic, Provider("WmiProv"), Locale("MS\\0x409"), Description("POWER CHARGE MODE Change EVENT"), guid("{D320289E-8FEA-41E0-86F9-711D83151B5F}")]
+ class LENOVO_GAMEZONE_POWER_CHARGE_MODE_EVENT: WMIEvent {
+ [key, read] string InstanceName;
+ [read] boolean Active;
+
+ [WmiDataId(1), read, Description("POWER CHARGE MODE Change EVENT")] uint32 mode;
+ };
+
+ [WMI, Dynamic, Provider("WmiProv"), Locale("MS\\0x409"), Description("Thermal Mode Real Mode change event"), guid("{D320289E-8FEA-41E0-86F9-911D83151B5F}")]
+ class LENOVO_GAMEZONE_THERMAL_MODE_EVENT: WMIEvent {
+ [key, read] string InstanceName;
+ [read] boolean Active;
+
+ [WmiDataId(1), read, Description("Thermal Mode Real Mode")] uint32 mode;
+ };
diff --git a/Documentation/wmi/devices/lenovo-wmi-other.rst b/Documentation/wmi/devices/lenovo-wmi-other.rst
new file mode 100644
index 000000000..011054d64
--- /dev/null
+++ b/Documentation/wmi/devices/lenovo-wmi-other.rst
@@ -0,0 +1,167 @@
+.. SPDX-License-Identifier: GPL-2.0-or-later
+
+===========================================================
+Lenovo WMI Interface Other Mode Driver (lenovo-wmi-other)
+===========================================================
+
+Introduction
+============
+Lenovo WMI Other Mode interface is broken up into multiple GUIDs,
+The primary Other Mode interface provides advanced power tuning features
+such as Package Power Tracking (PPT). It is paired with multiple data block
+GUIDs that provide context for the various methods.
+
+
+Other Mode
+----------
+
+WMI GUID ``DC2A8805-3A8C-41BA-A6F7-092E0089CD3B``
+
+The Other Mode WMI interface uses the firmware_attributes class to expose
+various WMI attributes provided by the interface in the sysfs. This enables
+CPU and GPU power limit tuning as well as various other attributes for
+devices that fall under the "Gaming Series" of Lenovo devices. Each
+attribute exposed by the Other Mode interface has corresponding
+capability data blocks which allow the driver to probe details about the
+attribute. Each attribute has multiple pages, one for each of the platform
+profiles managed by the Gamezone interface. Attributes are exposed in sysfs
+under the following path:
+
+::
+
+ /sys/class/firmware-attributes/lenovo-wmi-other/attributes/<attribute>/
+
+Additionally, this driver also exports attributes to HWMON.
+
+LENOVO_CAPABILITY_DATA_00
+-------------------------
+
+WMI GUID ``362A3AFE-3D96-4665-8530-96DAD5BB300E``
+
+The LENOVO_CAPABILITY_DATA_00 interface provides various information that
+does not rely on the gamezone thermal mode.
+
+The following HWMON attributes are implemented:
+ - fanX_div: internal RPM divisor
+ - fanX_input: current RPM
+ - fanX_target: target RPM (tunable, 0=auto)
+
+Due to the internal RPM divisor, the current/target RPMs are rounded down to
+its nearest multiple. The divisor itself is not necessary to be a power of two.
+
+LENOVO_CAPABILITY_DATA_01
+-------------------------
+
+WMI GUID ``7A8F5407-CB67-4D6E-B547-39B3BE018154``
+
+The LENOVO_CAPABILITY_DATA_01 interface provides various information that
+relies on the gamezone thermal mode, including power limits of integrated
+CPU and GPU components.
+
+Each attribute has the following properties:
+ - current_value
+ - default_value
+ - display_name
+ - max_value
+ - min_value
+ - scalar_increment
+ - type
+
+The following firmware-attributes are implemented:
+ - cpu_temp: CPU Thermal Load Limit
+ - dgpu_boost_clk: Dedicated GPU Boost Clock
+ - dgpu_didvid: Dedicated GPU Device Identifier and Vendor Identifier
+ - dgpu_enable: Dedicated GPU Enabled Status
+ - gpu_mode: GPU Mode by Power Limit
+ - gpu_nv_ac_offset: Nvidia GPU AC Total Processing Power Baseline Offset
+ - gpu_nv_bpl: Nvidia GPU Base Power Limit
+ - gpu_nv_cpu_boost: Nvidia GPU to CPU Dynamic Boost Limit
+ - gpu_nv_ctgp: Nvidia GPU Configurable Total Graphics Power
+ - gpu_nv_ppab: Nvidia GPU Power Performance Aware Boost Limit
+ - gpu_temp: GPU Thermal Load Limit
+ - ppt_cpu_cl: CPU Cross Loading Power Limit
+ - ppt_pl1_apu_spl: Platform Profile Tracking APU Sustained Power Limit
+ - ppt_pl1_spl: Platform Profile Tracking Sustained Power Limit
+ - ppt_pl1_spl_cl: Platform Profile Tracking Cross Loading Sustained Power Limit
+ - ppt_pl1_tau: Exceed Duration for Platform Profile Tracking Sustained Power Limit
+ - ppt_pl2_sppt: Platform Profile Tracking Slow Package Power Tracking
+ - ppt_pl2_sppt_cl: Platform Profile Tracking Cross Loading Slow Package Tracking
+ - ppt_pl3_fppt: Platform Profile Tracking Fast Package Power Tracking
+ - ppt_pl3_fppt_cl: Platform Profile Tracking Cross Loading Fast Package Power Tracking
+ - ppt_pl4_ipl: Platform Profile Tracking Instantaneous Power Limit
+ - ppt_pl4_ipl_cl: Platform Profile Tracking Cross Loading Instantaneous Power Limit
+
+LENOVO_FAN_TEST_DATA
+-------------------------
+
+WMI GUID ``B642801B-3D21-45DE-90AE-6E86F164FB21``
+
+The LENOVO_FAN_TEST_DATA interface provides reference data for self-test of
+cooling fans.
+
+The following HWMON attributes are implemented:
+ - fanX_max: maximum RPM
+ - fanX_min: minimum RPM
+
+WMI interface description
+=========================
+
+The WMI interface description can be decoded from the embedded binary MOF (bmof)
+data using the `bmfdec <https://github.com/pali/bmfdec>`_ utility:
+
+::
+
+ [WMI, Dynamic, Provider("WmiProv"), Locale("MS\\0x409"), Description("LENOVO_OTHER_METHOD class"), guid("{dc2a8805-3a8c-41ba-a6f7-092e0089cd3b}")]
+ class LENOVO_OTHER_METHOD {
+ [key, read] string InstanceName;
+ [read] boolean Active;
+
+ [WmiMethodId(17), Implemented, Description("Get Feature Value ")] void GetFeatureValue([in] uint32 IDs, [out] uint32 value);
+ [WmiMethodId(18), Implemented, Description("Set Feature Value ")] void SetFeatureValue([in] uint32 IDs, [in] uint32 value);
+ [WmiMethodId(19), Implemented, Description("Get Data By Command ")] void GetDataByCommand([in] uint32 IDs, [in] uint32 Command, [out] uint32 DataSize, [out, WmiSizeIs("DataSize")] uint32 Data[]);
+ [WmiMethodId(99), Implemented, Description("Get Data By Package for TAC")] void GetDataByPackage([in, Max(40)] uint8 Input[], [out] uint32 DataSize, [out, WmiSizeIs("DataSize")] uint8 Data[]);
+ };
+
+ [WMI, Dynamic, Provider("WmiProv"), Locale("MS\\0x409"), Description("LENOVO CAPABILITY DATA 00"), guid("{362a3afe-3d96-4665-8530-96dad5bb300e}")]
+ class LENOVO_CAPABILITY_DATA_00 {
+ [key, read] string InstanceName;
+ [read] boolean Active;
+
+ [WmiDataId(1), read, Description(" IDs.")] uint32 IDs;
+ [WmiDataId(2), read, Description("Capability.")] uint32 Capability;
+ [WmiDataId(3), read, Description("Capability Default Value.")] uint32 DefaultValue;
+ };
+
+ [WMI, Dynamic, Provider("WmiProv"), Locale("MS\\0x409"), Description("LENOVO CAPABILITY DATA 01"), guid("{7a8f5407-cb67-4d6e-b547-39b3be018154}")]
+ class LENOVO_CAPABILITY_DATA_01 {
+ [key, read] string InstanceName;
+ [read] boolean Active;
+
+ [WmiDataId(1), read, Description(" IDs.")] uint32 IDs;
+ [WmiDataId(2), read, Description("Capability.")] uint32 Capability;
+ [WmiDataId(3), read, Description("Default Value.")] uint32 DefaultValue;
+ [WmiDataId(4), read, Description("Step.")] uint32 Step;
+ [WmiDataId(5), read, Description("Minimum Value.")] uint32 MinValue;
+ [WmiDataId(6), read, Description("Maximum Value.")] uint32 MaxValue;
+ };
+
+ [WMI, Dynamic, Provider("WmiProv"), Locale("MS\\0x409"), Description("LENOVO CAPABILITY DATA 02"), guid("{bbf1f790-6c2f-422b-bc8c-4e7369c7f6ab}")]
+ class LENOVO_CAPABILITY_DATA_02 {
+ [key, read] string InstanceName;
+ [read] boolean Active;
+
+ [WmiDataId(1), read, Description(" IDs.")] uint32 IDs;
+ [WmiDataId(2), read, Description("Capability.")] uint32 Capability;
+ [WmiDataId(3), read, Description("Data Size.")] uint32 DataSize;
+ [WmiDataId(4), read, Description("Default Value"), WmiSizeIs("DataSize")] uint8 DefaultValue[];
+ };
+
+ [WMI, Dynamic, Provider("WmiProv"), Locale("MS\\0x409"), Description("Definition of Fan Test Data"), guid("{B642801B-3D21-45DE-90AE-6E86F164FB21}")]
+ class LENOVO_FAN_TEST_DATA {
+ [key, read] string InstanceName;
+ [read] boolean Active;
+ [WmiDataId(1), read, Description("Mode.")] uint32 NumOfFans;
+ [WmiDataId(2), read, Description("Fan ID."), WmiSizeIs("NumOfFans")] uint32 FanId[];
+ [WmiDataId(3), read, Description("Maximum Fan Speed."), WmiSizeIs("NumOfFans")] uint32 FanMaxSpeed[];
+ [WmiDataId(4), read, Description("Minumum Fan Speed."), WmiSizeIs("NumOfFans")] uint32 FanMinSpeed[];
+ };
diff --git a/Documentation/wmi/devices/msi-wmi-platform.rst b/Documentation/wmi/devices/msi-wmi-platform.rst
new file mode 100644
index 000000000..73197b319
--- /dev/null
+++ b/Documentation/wmi/devices/msi-wmi-platform.rst
@@ -0,0 +1,198 @@
+.. SPDX-License-Identifier: GPL-2.0-or-later
+
+===================================================
+MSI WMI Platform Features driver (msi-wmi-platform)
+===================================================
+
+Introduction
+============
+
+Many MSI notebooks support various features like reading fan sensors. This features are controlled
+by the embedded controller, with the ACPI firmware exposing a standard ACPI WMI interface on top
+of the embedded controller interface.
+
+WMI interface description
+=========================
+
+The WMI interface description can be decoded from the embedded binary MOF (bmof)
+data using the `bmfdec <https://github.com/pali/bmfdec>`_ utility:
+
+::
+
+ [WMI, Locale("MS\0x409"),
+ Description("This class contains the definition of the package used in other classes"),
+ guid("{ABBC0F60-8EA1-11d1-00A0-C90629100000}")]
+ class Package {
+ [WmiDataId(1), read, write, Description("16 bytes of data")] uint8 Bytes[16];
+ };
+
+ [WMI, Locale("MS\0x409"),
+ Description("This class contains the definition of the package used in other classes"),
+ guid("{ABBC0F63-8EA1-11d1-00A0-C90629100000}")]
+ class Package_32 {
+ [WmiDataId(1), read, write, Description("32 bytes of data")] uint8 Bytes[32];
+ };
+
+ [WMI, Dynamic, Provider("WmiProv"), Locale("MS\0x409"),
+ Description("Class used to operate methods on a package"),
+ guid("{ABBC0F6E-8EA1-11d1-00A0-C90629100000}")]
+ class MSI_ACPI {
+ [key, read] string InstanceName;
+ [read] boolean Active;
+
+ [WmiMethodId(1), Implemented, read, write, Description("Return the contents of a package")]
+ void GetPackage([out, id(0)] Package Data);
+
+ [WmiMethodId(2), Implemented, read, write, Description("Set the contents of a package")]
+ void SetPackage([in, id(0)] Package Data);
+
+ [WmiMethodId(3), Implemented, read, write, Description("Return the contents of a package")]
+ void Get_EC([out, id(0)] Package_32 Data);
+
+ [WmiMethodId(4), Implemented, read, write, Description("Set the contents of a package")]
+ void Set_EC([in, id(0)] Package_32 Data);
+
+ [WmiMethodId(5), Implemented, read, write, Description("Return the contents of a package")]
+ void Get_BIOS([in, out, id(0)] Package_32 Data);
+
+ [WmiMethodId(6), Implemented, read, write, Description("Set the contents of a package")]
+ void Set_BIOS([in, out, id(0)] Package_32 Data);
+
+ [WmiMethodId(7), Implemented, read, write, Description("Return the contents of a package")]
+ void Get_SMBUS([in, out, id(0)] Package_32 Data);
+
+ [WmiMethodId(8), Implemented, read, write, Description("Set the contents of a package")]
+ void Set_SMBUS([in, out, id(0)] Package_32 Data);
+
+ [WmiMethodId(9), Implemented, read, write, Description("Return the contents of a package")]
+ void Get_MasterBattery([in, out, id(0)] Package_32 Data);
+
+ [WmiMethodId(10), Implemented, read, write, Description("Set the contents of a package")]
+ void Set_MasterBattery([in, out, id(0)] Package_32 Data);
+
+ [WmiMethodId(11), Implemented, read, write, Description("Return the contents of a package")]
+ void Get_SlaveBattery([in, out, id(0)] Package_32 Data);
+
+ [WmiMethodId(12), Implemented, read, write, Description("Set the contents of a package")]
+ void Set_SlaveBattery([in, out, id(0)] Package_32 Data);
+
+ [WmiMethodId(13), Implemented, read, write, Description("Return the contents of a package")]
+ void Get_Temperature([in, out, id(0)] Package_32 Data);
+
+ [WmiMethodId(14), Implemented, read, write, Description("Set the contents of a package")]
+ void Set_Temperature([in, out, id(0)] Package_32 Data);
+
+ [WmiMethodId(15), Implemented, read, write, Description("Return the contents of a package")]
+ void Get_Thermal([in, out, id(0)] Package_32 Data);
+
+ [WmiMethodId(16), Implemented, read, write, Description("Set the contents of a package")]
+ void Set_Thermal([in, out, id(0)] Package_32 Data);
+
+ [WmiMethodId(17), Implemented, read, write, Description("Return the contents of a package")]
+ void Get_Fan([in, out, id(0)] Package_32 Data);
+
+ [WmiMethodId(18), Implemented, read, write, Description("Set the contents of a package")]
+ void Set_Fan([in, out, id(0)] Package_32 Data);
+
+ [WmiMethodId(19), Implemented, read, write, Description("Return the contents of a package")]
+ void Get_Device([in, out, id(0)] Package_32 Data);
+
+ [WmiMethodId(20), Implemented, read, write, Description("Set the contents of a package")]
+ void Set_Device([in, out, id(0)] Package_32 Data);
+
+ [WmiMethodId(21), Implemented, read, write, Description("Return the contents of a package")]
+ void Get_Power([in, out, id(0)] Package_32 Data);
+
+ [WmiMethodId(22), Implemented, read, write, Description("Set the contents of a package")]
+ void Set_Power([in, out, id(0)] Package_32 Data);
+
+ [WmiMethodId(23), Implemented, read, write, Description("Return the contents of a package")]
+ void Get_Debug([in, out, id(0)] Package_32 Data);
+
+ [WmiMethodId(24), Implemented, read, write, Description("Set the contents of a package")]
+ void Set_Debug([in, out, id(0)] Package_32 Data);
+
+ [WmiMethodId(25), Implemented, read, write, Description("Return the contents of a package")]
+ void Get_AP([in, out, id(0)] Package_32 Data);
+
+ [WmiMethodId(26), Implemented, read, write, Description("Set the contents of a package")]
+ void Set_AP([in, out, id(0)] Package_32 Data);
+
+ [WmiMethodId(27), Implemented, read, write, Description("Return the contents of a package")]
+ void Get_Data([in, out, id(0)] Package_32 Data);
+
+ [WmiMethodId(28), Implemented, read, write, Description("Set the contents of a package")]
+ void Set_Data([in, out, id(0)] Package_32 Data);
+
+ [WmiMethodId(29), Implemented, read, write, Description("Return the contents of a package")]
+ void Get_WMI([out, id(0)] Package_32 Data);
+ };
+
+Due to a peculiarity in how Windows handles the ``CreateByteField()`` ACPI operator (errors only
+happen when a invalid byte field is ultimately accessed), all methods require a 32 byte input
+buffer, even if the Binary MOF says otherwise.
+
+The input buffer contains a single byte to select the subfeature to be accessed and 31 bytes of
+input data, the meaning of which depends on the subfeature being accessed.
+
+The output buffer contains a single byte which signals success or failure (``0x00`` on failure)
+and 31 bytes of output data, the meaning if which depends on the subfeature being accessed.
+
+.. note::
+ The ACPI control method responsible for handling the WMI method calls is not thread-safe.
+ This is a firmware bug that needs to be handled inside the driver itself.
+
+WMI method Get_EC()
+-------------------
+
+Returns embedded controller information, the selected subfeature does not matter. The output
+data contains a flag byte and a 28 byte controller firmware version string.
+
+The first 4 bits of the flag byte contain the minor version of the embedded controller interface,
+with the next 2 bits containing the major version of the embedded controller interface.
+
+The 7th bit signals if the embedded controller page changed (exact meaning is unknown), and the
+last bit signals if the platform is a Tigerlake platform.
+
+The MSI software seems to only use this interface when the last bit is set.
+
+WMI method Get_Fan()
+--------------------
+
+Fan speed sensors can be accessed by selecting subfeature ``0x00``. The output data contains
+up to four 16-bit fan speed readings in big-endian format. Most machines do not support all
+four fan speed sensors, so the remaining reading are hardcoded to ``0x0000``.
+
+The fan RPM readings can be calculated with the following formula:
+
+ RPM = 480000 / <fan speed reading>
+
+If the fan speed reading is zero, then the fan RPM is zero too.
+
+WMI method Get_WMI()
+--------------------
+
+Returns the version of the ACPI WMI interface, the selected subfeature does not matter.
+The output data contains two bytes, the first one contains the major version and the last one
+contains the minor revision of the ACPI WMI interface.
+
+The MSI software seems to only use this interface when the major version is greater than two.
+
+Reverse-Engineering the MSI WMI Platform interface
+==================================================
+
+.. warning:: Randomly poking the embedded controller interface can potentially cause damage
+ to the machine and other unwanted side effects, please be careful.
+
+The underlying embedded controller interface is used by the ``msi-ec`` driver, and it seems
+that many methods just copy a part of the embedded controller memory into the output buffer.
+
+This means that the remaining WMI methods can be reverse-engineered by looking which part of
+the embedded controller memory is accessed by the ACPI AML code. The driver also supports a
+debugfs interface for directly executing WMI methods. Additionally, any safety checks regarding
+unsupported hardware can be disabled by loading the module with ``force=true``.
+
+More information about the MSI embedded controller interface can be found at the
+`msi-ec project <https://github.com/BeardOverflow/msi-ec>`_.
+
+Special thanks go to github user `glpnk` for showing how to decode the fan speed readings.
diff --git a/Documentation/wmi/devices/uniwill-laptop.rst b/Documentation/wmi/devices/uniwill-laptop.rst
new file mode 100644
index 000000000..65583b239
--- /dev/null
+++ b/Documentation/wmi/devices/uniwill-laptop.rst
@@ -0,0 +1,198 @@
+.. SPDX-License-Identifier: GPL-2.0-or-later
+
+========================================
+Uniwill Notebook driver (uniwill-laptop)
+========================================
+
+Introduction
+============
+
+Many notebooks manufactured by Uniwill (either directly or as ODM) provide a EC interface
+for controlling various platform settings like sensors and fan control. This interface is
+used by the ``uniwill-laptop`` driver to map those features onto standard kernel interfaces.
+
+EC WMI interface description
+============================
+
+The EC WMI interface description can be decoded from the embedded binary MOF (bmof)
+data using the `bmfdec <https://github.com/pali/bmfdec>`_ utility:
+
+::
+
+ [WMI, Dynamic, Provider("WmiProv"), Locale("MS\\0x409"),
+ Description("Class used to operate methods on a ULong"),
+ guid("{ABBC0F6F-8EA1-11d1-00A0-C90629100000}")]
+ class AcpiTest_MULong {
+ [key, read] string InstanceName;
+ [read] boolean Active;
+
+ [WmiMethodId(1), Implemented, read, write, Description("Return the contents of a ULong")]
+ void GetULong([out, Description("Ulong Data")] uint32 Data);
+
+ [WmiMethodId(2), Implemented, read, write, Description("Set the contents of a ULong")]
+ void SetULong([in, Description("Ulong Data")] uint32 Data);
+
+ [WmiMethodId(3), Implemented, read, write,
+ Description("Generate an event containing ULong data")]
+ void FireULong([in, Description("WMI requires a parameter")] uint32 Hack);
+
+ [WmiMethodId(4), Implemented, read, write, Description("Get and Set the contents of a ULong")]
+ void GetSetULong([in, Description("Ulong Data")] uint64 Data,
+ [out, Description("Ulong Data")] uint32 Return);
+
+ [WmiMethodId(5), Implemented, read, write,
+ Description("Get and Set the contents of a ULong for Dollby button")]
+ void GetButton([in, Description("Ulong Data")] uint64 Data,
+ [out, Description("Ulong Data")] uint32 Return);
+ };
+
+Most of the WMI-related code was copied from the Windows driver samples, which unfortunately means
+that the WMI-GUID is not unique. This makes the WMI-GUID unusable for autoloading.
+
+WMI method GetULong()
+---------------------
+
+This WMI method was copied from the Windows driver samples and has no function.
+
+WMI method SetULong()
+---------------------
+
+This WMI method was copied from the Windows driver samples and has no function.
+
+WMI method FireULong()
+----------------------
+
+This WMI method allows to inject a WMI event with a 32-bit payload. Its primary purpose seems
+to be debugging.
+
+WMI method GetSetULong()
+------------------------
+
+This WMI method is used to communicate with the EC. The ``Data`` argument holds the following
+information (starting with the least significant byte):
+
+1. 16-bit address
+2. 16-bit data (set to ``0x0000`` when reading)
+3. 16-bit operation (``0x0100`` for reading and ``0x0000`` for writing)
+4. 16-bit reserved (set to ``0x0000``)
+
+The first 8 bits of the ``Return`` value contain the data returned by the EC when reading.
+The special value ``0xFEFEFEFE`` is used to indicate a communication failure with the EC.
+
+WMI method GetButton()
+----------------------
+
+This WMI method is not implemented on all machines and has an unknown purpose.
+
+Reverse-Engineering the EC WMI interface
+========================================
+
+.. warning:: Randomly poking the EC can potentially cause damage to the machine and other unwanted
+ side effects, please be careful.
+
+The EC behind the ``GetSetULong`` method is used by the OEM software supplied by the manufacturer.
+Reverse-engineering of this software is difficult since it uses an obfuscator, however some parts
+are not obfuscated. In this case `dnSpy <https://github.com/dnSpy/dnSpy>`_ could also be helpful.
+
+The EC can be accessed under Windows using powershell (requires admin privileges):
+
+::
+
+ > $obj = Get-CimInstance -Namespace root/wmi -ClassName AcpiTest_MULong | Select-Object -First 1
+ > Invoke-CimMethod -InputObject $obj -MethodName GetSetULong -Arguments @{Data = <input>}
+
+WMI event interface description
+===============================
+
+The WMI interface description can also be decoded from the embedded binary MOF (bmof)
+data:
+
+::
+
+ [WMI, Dynamic, Provider("WmiProv"), Locale("MS\\0x409"),
+ Description("Class containing event generated ULong data"),
+ guid("{ABBC0F72-8EA1-11d1-00A0-C90629100000}")]
+ class AcpiTest_EventULong : WmiEvent {
+ [key, read] string InstanceName;
+ [read] boolean Active;
+
+ [WmiDataId(1), read, write, Description("ULong Data")] uint32 ULong;
+ };
+
+Most of the WMI-related code was again copied from the Windows driver samples, causing this WMI
+interface to suffer from the same restrictions as the EC WMI interface described above.
+
+WMI event data
+--------------
+
+The WMI event data contains a single 32-bit value which is used to indicate various platform events.
+
+Reverse-Engineering the Uniwill WMI event interface
+===================================================
+
+The driver logs debug messages when receiving a WMI event. Thus enabling debug messages will be
+useful for finding unknown event codes.
+
+EC ACPI interface description
+=============================
+
+The ``INOU0000`` ACPI device is a virtual device used to access various hardware registers
+available on notebooks manufactured by Uniwill. Reading and writing those registers happens
+by calling ACPI control methods. The ``uniwill-laptop`` driver uses this device to communicate
+with the EC because the ACPI control methods are faster than the WMI methods described above.
+
+ACPI control methods used for reading registers take a single ACPI integer containing the address
+of the register to read and return a ACPI integer containing the data inside said register. ACPI
+control methods used for writing registers however take two ACPI integers, with the additional
+ACPI integer containing the data to be written into the register. Such ACPI control methods return
+nothing.
+
+System memory
+-------------
+
+System memory can be accessed with a granularity of either a single byte (``MMRB`` for reading and
+``MMWB`` for writing) or four bytes (``MMRD`` for reading and ``MMWD`` for writing). Those ACPI
+control methods are unused because they provide no benefit when compared to the native memory
+access functions provided by the kernel.
+
+EC RAM
+------
+
+The internal RAM of the EC can be accessed with a granularity of a single byte using the ``ECRR``
+(read) and ``ECRW`` (write) ACPI control methods, with the maximum register address being ``0xFFF``.
+The OEM software waits 6 ms after calling one of those ACPI control methods, likely to avoid
+overwhelming the EC when being connected over LPC.
+
+PCI config space
+----------------
+
+The PCI config space can be accessed with a granularity of four bytes using the ``PCRD`` (read) and
+``PCWD`` (write) ACPI control methods. The exact address format is unknown, and poking random PCI
+devices might confuse the PCI subsystem. Because of this those ACPI control methods are not used.
+
+IO ports
+--------
+
+IO ports can be accessed with a granularity of four bytes using the ``IORD`` (read) and ``IOWD``
+(write) ACPI control methods. Those ACPI control methods are unused because they provide no benefit
+when compared to the native IO port access functions provided by the kernel.
+
+CMOS RAM
+--------
+
+The CMOS RAM can be accessed with a granularity of a single byte using the ``RCMS`` (read) and
+``WCMS`` ACPI control methods. Using those ACPI methods might interfere with the native CMOS RAM
+access functions provided by the kernel due to the usage of indexed IO, so they are unused.
+
+Indexed IO
+----------
+
+Indexed IO with IO ports with a granularity of a single byte can be performed using the ``RIOP``
+(read) and ``WIOP`` (write) ACPI control methods. Those ACPI methods are unused because they
+provide no benefit when compared to the native IO port access functions provided by the kernel.
+
+Special thanks go to github user `pobrn` which developed the
+`qc71_laptop <https://github.com/pobrn/qc71_laptop>`_ driver on which this driver is partly based.
+The same is true for Tuxedo Computers, which developed the
+`tuxedo-drivers <https://gitlab.com/tuxedocomputers/development/packages/tuxedo-drivers>`_ package
+which also served as a foundation for this driver.
diff --git a/Documentation/wmi/devices/wmi-bmof.rst b/Documentation/wmi/devices/wmi-bmof.rst
new file mode 100644
index 000000000..ca1ee9a29
--- /dev/null
+++ b/Documentation/wmi/devices/wmi-bmof.rst
@@ -0,0 +1,25 @@
+.. SPDX-License-Identifier: GPL-2.0-only
+
+==============================
+WMI embedded Binary MOF driver
+==============================
+
+Introduction
+============
+
+Many machines embed WMI Binary MOF (Managed Object Format) metadata used to
+describe the details of their ACPI WMI interfaces. The data can be decoded
+with tools like `bmfdec <https://github.com/pali/bmfdec>`_ to obtain a
+human readable WMI interface description, which is useful for developing
+new WMI drivers.
+
+The Binary MOF data can be retrieved from the ``bmof`` sysfs attribute of the
+associated WMI device. Please note that multiple WMI devices containing Binary
+MOF data can exist on a given system.
+
+WMI interface
+=============
+
+The Binary MOF WMI device is identified by the WMI GUID ``05901221-D566-11D1-B2F0-00A0C9062910``.
+The Binary MOF can be obtained by doing a WMI data block query. The result is
+then returned as an ACPI buffer with a variable size.
diff --git a/Documentation/wmi/driver-development-guide.rst b/Documentation/wmi/driver-development-guide.rst
new file mode 100644
index 000000000..6290c448f
--- /dev/null
+++ b/Documentation/wmi/driver-development-guide.rst
@@ -0,0 +1,225 @@
+.. SPDX-License-Identifier: GPL-2.0-or-later
+
+============================
+WMI driver development guide
+============================
+
+The WMI subsystem provides a rich driver API for implementing WMI drivers,
+documented at Documentation/driver-api/wmi.rst. This document will serve
+as an introductory guide for WMI driver writers using this API. It is supposed
+to be a successor to the original LWN article [1]_ which deals with WMI drivers
+using the deprecated GUID-based WMI interface.
+
+Obtaining WMI device information
+--------------------------------
+
+Before developing an WMI driver, information about the WMI device in question
+must be obtained. The `lswmi <https://pypi.org/project/lswmi>`_ utility can be
+used to extract detailed WMI device information using the following command:
+
+::
+
+ lswmi -V
+
+The resulting output will contain information about all WMI devices available on
+a given machine, plus some extra information.
+
+In order to find out more about the interface used to communicate with a WMI device,
+the `bmfdec <https://github.com/pali/bmfdec>`_ utilities can be used to decode
+the Binary MOF (Managed Object Format) information used to describe WMI devices.
+The ``wmi-bmof`` driver exposes this information to userspace, see
+Documentation/wmi/devices/wmi-bmof.rst.
+
+In order to retrieve the decoded Binary MOF information, use the following command (requires root):
+
+::
+
+ ./bmf2mof /sys/bus/wmi/devices/05901221-D566-11D1-B2F0-00A0C9062910[-X]/bmof
+
+Sometimes, looking at the disassembled ACPI tables used to describe the WMI device
+helps in understanding how the WMI device is supposed to work. The path of the ACPI
+method associated with a given WMI device can be retrieved using the ``lswmi`` utility
+as mentioned above.
+
+If you are attempting to port a driver to Linux and are working on a Windows
+system, `WMIExplorer <https://github.com/vinaypamnani/wmie2>`_ can be useful
+for inspecting available WMI methods and invoking them directly.
+
+Basic WMI driver structure
+--------------------------
+
+The basic WMI driver is build around the struct wmi_driver, which is then bound
+to matching WMI devices using a struct wmi_device_id table:
+
+::
+
+ static const struct wmi_device_id foo_id_table[] = {
+ /* Using only uppercase letters is recommended */
+ { "936DA01F-9ABD-4D9D-80C7-02AF85C822A8", NULL },
+ { }
+ };
+ MODULE_DEVICE_TABLE(wmi, foo_id_table);
+
+ static struct wmi_driver foo_driver = {
+ .driver = {
+ .name = "foo",
+ .probe_type = PROBE_PREFER_ASYNCHRONOUS, /* recommended */
+ .pm = pm_sleep_ptr(&foo_dev_pm_ops), /* optional */
+ },
+ .id_table = foo_id_table,
+ .probe = foo_probe,
+ .remove = foo_remove, /* optional, devres is preferred */
+ .shutdown = foo_shutdown, /* optional, called during shutdown */
+ .notify_new = foo_notify, /* optional, for event handling */
+ .min_event_size = X, /* optional, simplifies event payload size verification */
+ .no_singleton = true, /* required for new WMI drivers */
+ };
+ module_wmi_driver(foo_driver);
+
+The probe() callback is called when the WMI driver is bound to a matching WMI device. Allocating
+driver-specific data structures and initialising interfaces to other kernel subsystems should
+normally be done in this function.
+
+The remove() callback is then called when the WMI driver is unbound from a WMI device. In order
+to unregister interfaces to other kernel subsystems and release resources, devres should be used.
+This simplifies error handling during probe and often allows to omit this callback entirely, see
+Documentation/driver-api/driver-model/devres.rst for details.
+
+The shutdown() callback is called during shutdown, reboot or kexec. Its sole purpose is to disable
+the WMI device and put it in a well-known state for the WMI driver to pick up later after reboot
+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 or ACPI-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.
+
+Because of this, WMI drivers should use the state container design pattern as described in
+Documentation/driver-api/driver-model/design-patterns.rst.
+
+.. warning:: Using both GUID-based and non-GUID-based functions for querying WMI data blocks and
+ handling WMI events simultaneously on the same device is guaranteed to corrupt the
+ WMI device state and might lead to erratic behaviour.
+
+WMI method drivers
+------------------
+
+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. When calling WMI
+methods that do not return any values, wmidev_invoke_procedure() should be used instead.
+
+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/intel/wmi/thunderbolt.c for an example WMI method driver.
+
+WMI data block drivers
+----------------------
+
+WMI drivers can query WMI data blocks using wmidev_query_block(), 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().
+
+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_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 layout of the buffer passed to this callback is device-specific, and freeing of the buffer
+is done by the WMI subsystem itself, not the driver.
+
+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.
+
+However WMI driver developers should be aware that multiple WMI events can be received concurrently,
+so any locking (if necessary) needs to be provided by the WMI driver itself.
+
+The WMI driver can furthermore instruct the WMI driver core to automatically reject WMI events
+that contain a undersized event payload by populating the ``min_event_size`` field inside
+struct wmi_driver. Setting this field to 0 will thus enable the WMI driver to receive WMI events
+without any event payload.
+
+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 structure of said buffers is described by the MOF data associated with the WMI device in
+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 an 8-byte boundary, WMI drivers can simply perform
+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
+sent by the WMI device to signal an internal error. Oversized buffers however should be accepted
+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
+-------------------------------------
+
+There are many cases of firmware vendors using multiple WMI devices to control different aspects
+of a single physical device. This can make developing WMI drivers complicated, as those drivers
+might need to communicate with each other to present a unified interface to userspace.
+
+On such case involves a WMI event device which needs to talk to a WMI data block device or WMI
+method device upon receiving an WMI event. In such a case, two WMI drivers should be developed,
+one for the WMI event device and one for the other WMI device.
+
+The WMI event device driver has only one purpose: to receive WMI events, validate any additional
+event data and invoke a notifier chain. The other WMI driver adds itself to this notifier chain
+during probing and thus gets notified every time a WMI event is received. This WMI driver might
+then process the event further for example by using an input device.
+
+For other WMI device constellations, similar mechanisms can be used.
+
+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.
+
+Many older WMI drivers violate one or more points from this list. The reason for
+this is that the WMI subsystem evolved significantly over the last two decades,
+so there is a lot of legacy cruft inside older WMI drivers.
+
+New WMI drivers are also required to conform to the linux kernel coding style as specified in
+Documentation/process/coding-style.rst. The checkpatch utility can catch many common coding style
+violations, you can invoke it with the following command:
+
+::
+
+ ./scripts/checkpatch.pl --strict <path to driver file>
+
+References
+==========
+
+.. [1] https://lwn.net/Articles/391230/
diff --git a/Documentation/wmi/index.rst b/Documentation/wmi/index.rst
new file mode 100644
index 000000000..56016078f
--- /dev/null
+++ b/Documentation/wmi/index.rst
@@ -0,0 +1,12 @@
+.. SPDX-License-Identifier: GPL-2.0-or-later
+
+=============
+WMI Subsystem
+=============
+
+.. toctree::
+ :maxdepth: 1
+
+ acpi-interface
+ driver-development-guide
+ devices/index