Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

platform/x86: wmi: Add driver development guide

Since 2010, an LWN article covering WMI drivers exists:

https://lwn.net/Articles/391230/

Since the introduction of the modern bus-based interface
and other userspace tooling (bmfdec, lswmi, ...), this
article is outdated and causes people to still submit new
WMI drivers using the deprecated GUID-based interface.
Fix this by adding a short guide on how to develop WMI drivers
using the modern bus-based interface.

Signed-off-by: Armin Wolf <W_Armin@gmx.de>
Link: https://lore.kernel.org/r/20240402143059.8456-4-W_Armin@gmx.de
Reviewed-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>
Reviewed-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Hans de Goede <hdegoede@redhat.com>

authored by

Armin Wolf and committed by
Hans de Goede
a582a43e c5e160ff

+179
+178
Documentation/wmi/driver-development-guide.rst
··· 1 + .. SPDX-License-Identifier: GPL-2.0-or-later 2 + 3 + ============================ 4 + WMI driver development guide 5 + ============================ 6 + 7 + The WMI subsystem provides a rich driver API for implementing WMI drivers, 8 + documented at Documentation/driver-api/wmi.rst. This document will serve 9 + as an introductory guide for WMI driver writers using this API. It is supposed 10 + to be a successor to the original LWN article [1]_ which deals with WMI drivers 11 + using the deprecated GUID-based WMI interface. 12 + 13 + Obtaining WMI device information 14 + -------------------------------- 15 + 16 + Before developing an WMI driver, information about the WMI device in question 17 + must be obtained. The `lswmi <https://pypi.org/project/lswmi>`_ utility can be 18 + used to extract detailed WMI device information using the following command: 19 + 20 + :: 21 + 22 + lswmi -V 23 + 24 + The resulting output will contain information about all WMI devices available on 25 + a given machine, plus some extra information. 26 + 27 + In order to find out more about the interface used to communicate with a WMI device, 28 + the `bmfdec <https://github.com/pali/bmfdec>`_ utilities can be used to decode 29 + the Binary MOF (Managed Object Format) information used to describe WMI devices. 30 + The ``wmi-bmof`` driver exposes this information to userspace, see 31 + Documentation/wmi/devices/wmi-bmof.rst. 32 + 33 + In order to retrieve the decoded Binary MOF information, use the following command (requires root): 34 + 35 + :: 36 + 37 + ./bmf2mof /sys/bus/wmi/devices/05901221-D566-11D1-B2F0-00A0C9062910[-X]/bmof 38 + 39 + Sometimes, looking at the disassembled ACPI tables used to describe the WMI device 40 + helps in understanding how the WMI device is supposed to work. The path of the ACPI 41 + method associated with a given WMI device can be retrieved using the ``lswmi`` utility 42 + as mentioned above. 43 + 44 + Basic WMI driver structure 45 + -------------------------- 46 + 47 + The basic WMI driver is build around the struct wmi_driver, which is then bound 48 + to matching WMI devices using a struct wmi_device_id table: 49 + 50 + :: 51 + 52 + static const struct wmi_device_id foo_id_table[] = { 53 + { "936DA01F-9ABD-4D9D-80C7-02AF85C822A8", NULL }, 54 + { } 55 + }; 56 + MODULE_DEVICE_TABLE(wmi, foo_id_table); 57 + 58 + static struct wmi_driver foo_driver = { 59 + .driver = { 60 + .name = "foo", 61 + .probe_type = PROBE_PREFER_ASYNCHRONOUS, /* recommended */ 62 + .pm = pm_sleep_ptr(&foo_dev_pm_ops), /* optional */ 63 + }, 64 + .id_table = foo_id_table, 65 + .probe = foo_probe, 66 + .remove = foo_remove, /* optional, devres is preferred */ 67 + .notify = foo_notify, /* optional, for event handling */ 68 + .no_notify_data = true, /* optional, enables events containing no additional data */ 69 + .no_singleton = true, /* required for new WMI drivers */ 70 + }; 71 + module_wmi_driver(foo_driver); 72 + 73 + The probe() callback is called when the WMI driver is bound to a matching WMI device. Allocating 74 + driver-specific data structures and initialising interfaces to other kernel subsystems should 75 + normally be done in this function. 76 + 77 + The remove() callback is then called when the WMI driver is unbound from a WMI device. In order 78 + to unregister interfaces to other kernel subsystems and release resources, devres should be used. 79 + This simplifies error handling during probe and often allows to omit this callback entirely, see 80 + Documentation/driver-api/driver-model/devres.rst for details. 81 + 82 + Please note that new WMI drivers are required to be able to be instantiated multiple times, 83 + and are forbidden from using any deprecated GUID-based WMI functions. This means that the 84 + WMI driver should be prepared for the scenario that multiple matching WMI devices are present 85 + on a given machine. 86 + 87 + Because of this, WMI drivers should use the state container design pattern as described in 88 + Documentation/driver-api/driver-model/design-patterns.rst. 89 + 90 + WMI method drivers 91 + ------------------ 92 + 93 + WMI drivers can call WMI device methods using wmidev_evaluate_method(), the 94 + structure of the ACPI buffer passed to this function is device-specific and usually 95 + needs some tinkering to get right. Looking at the ACPI tables containing the WMI 96 + device usually helps here. The method id and instance number passed to this function 97 + are also device-specific, looking at the decoded Binary MOF is usually enough to 98 + find the right values. 99 + 100 + The maximum instance number can be retrieved during runtime using wmidev_instance_count(). 101 + 102 + Take a look at drivers/platform/x86/inspur_platform_profile.c for an example WMI method driver. 103 + 104 + WMI data block drivers 105 + ---------------------- 106 + 107 + WMI drivers can query WMI device data blocks using wmidev_block_query(), the 108 + structure of the returned ACPI object is again device-specific. Some WMI devices 109 + also allow for setting data blocks using wmidev_block_set(). 110 + 111 + The maximum instance number can also be retrieved using wmidev_instance_count(). 112 + 113 + Take a look at drivers/platform/x86/intel/wmi/sbl-fw-update.c for an example 114 + WMI data block driver. 115 + 116 + WMI event drivers 117 + ----------------- 118 + 119 + WMI drivers can receive WMI events via the notify() callback inside the struct wmi_driver. 120 + The WMI subsystem will then take care of setting up the WMI event accordingly. Please note that 121 + the structure of the ACPI object passed to this callback is device-specific, and freeing the 122 + ACPI object is being done by the WMI subsystem, not the driver. 123 + 124 + The WMI driver core will take care that the notify() callback will only be called after 125 + the probe() callback has been called, and that no events are being received by the driver 126 + right before and after calling its remove() callback. 127 + 128 + However WMI driver developers should be aware that multiple WMI events can be received concurrently, 129 + so any locking (if necessary) needs to be provided by the WMI driver itself. 130 + 131 + In order to be able to receive WMI events containing no additional event data, 132 + the ``no_notify_data`` flag inside struct wmi_driver should be set to ``true``. 133 + 134 + Take a look at drivers/platform/x86/xiaomi-wmi.c for an example WMI event driver. 135 + 136 + Handling multiple WMI devices at once 137 + ------------------------------------- 138 + 139 + There are many cases of firmware vendors using multiple WMI devices to control different aspects 140 + of a single physical device. This can make developing WMI drivers complicated, as those drivers 141 + might need to communicate with each other to present a unified interface to userspace. 142 + 143 + On such case involves a WMI event device which needs to talk to a WMI data block device or WMI 144 + method device upon receiving an WMI event. In such a case, two WMI drivers should be developed, 145 + one for the WMI event device and one for the other WMI device. 146 + 147 + The WMI event device driver has only one purpose: to receive WMI events, validate any additional 148 + event data and invoke a notifier chain. The other WMI driver adds itself to this notifier chain 149 + during probing and thus gets notified every time a WMI event is received. This WMI driver might 150 + then process the event further for example by using an input device. 151 + 152 + For other WMI device constellations, similar mechanisms can be used. 153 + 154 + Things to avoid 155 + --------------- 156 + 157 + When developing WMI drivers, there are a couple of things which should be avoided: 158 + 159 + - usage of the deprecated GUID-based WMI interface which uses GUIDs instead of WMI device structs 160 + - bypassing of the WMI subsystem when talking to WMI devices 161 + - WMI drivers which cannot be instantiated multiple times. 162 + 163 + Many older WMI drivers violate one or more points from this list. The reason for 164 + this is that the WMI subsystem evolved significantly over the last two decades, 165 + so there is a lot of legacy cruft inside older WMI drivers. 166 + 167 + New WMI drivers are also required to conform to the linux kernel coding style as specified in 168 + Documentation/process/coding-style.rst. The checkpatch utility can catch many common coding style 169 + violations, you can invoke it with the following command: 170 + 171 + :: 172 + 173 + ./scripts/checkpatch.pl --strict <path to driver file> 174 + 175 + References 176 + ========== 177 + 178 + .. [1] https://lwn.net/Articles/391230/
+1
Documentation/wmi/index.rst
··· 8 8 :maxdepth: 1 9 9 10 10 acpi-interface 11 + driver-development-guide 11 12 devices/index 12 13 13 14 .. only:: subproject and html