~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/Documentation/wmi/driver-development-guide.rst

Version: ~ [ linux-6.11-rc3 ] ~ [ linux-6.10.4 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.45 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.104 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.164 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.223 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.281 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.319 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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/

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php