179 lines
		
	
	
		
			7.8 KiB
		
	
	
	
		
			ReStructuredText
		
	
	
	
	
	
			
		
		
	
	
			179 lines
		
	
	
		
			7.8 KiB
		
	
	
	
		
			ReStructuredText
		
	
	
	
	
	
| .. 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.
 | |
| 
 | |
| 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[] = {
 | |
|          { "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 */
 | |
|         .notify = foo_notify,         /* optional, for event handling */
 | |
|         .no_notify_data = true,       /* optional, enables events containing no additional data */
 | |
|         .no_singleton = true,         /* required for new WMI drivers */
 | |
|   };
 | |
|   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.
 | |
| 
 | |
| Please note that new WMI drivers are required to be able to be instantiated multiple times,
 | |
| and are forbidden from using any deprecated GUID-based WMI functions. This means that the
 | |
| WMI driver should be prepared for the scenario that multiple matching WMI devices are present
 | |
| on a given machine.
 | |
| 
 | |
| Because of this, WMI drivers should use the state container design pattern as described in
 | |
| Documentation/driver-api/driver-model/design-patterns.rst.
 | |
| 
 | |
| WMI method drivers
 | |
| ------------------
 | |
| 
 | |
| WMI drivers can call WMI device methods using wmidev_evaluate_method(), the
 | |
| structure of the ACPI buffer passed to this function is device-specific and usually
 | |
| needs some tinkering to get right. Looking at the ACPI tables containing the WMI
 | |
| device usually helps here. The method id and instance number passed to this function
 | |
| are also device-specific, looking at the decoded Binary MOF is usually enough to
 | |
| find the right values.
 | |
| 
 | |
| The maximum instance number can be retrieved during runtime using wmidev_instance_count().
 | |
| 
 | |
| Take a look at drivers/platform/x86/inspur_platform_profile.c for an example WMI method driver.
 | |
| 
 | |
| WMI data block drivers
 | |
| ----------------------
 | |
| 
 | |
| WMI drivers can query WMI device data blocks using wmidev_block_query(), the
 | |
| structure of the returned ACPI object is again device-specific. Some WMI devices
 | |
| also allow for setting data blocks using wmidev_block_set().
 | |
| 
 | |
| The maximum instance number can also be retrieved using wmidev_instance_count().
 | |
| 
 | |
| Take a look at drivers/platform/x86/intel/wmi/sbl-fw-update.c for an example
 | |
| WMI data block driver.
 | |
| 
 | |
| WMI event drivers
 | |
| -----------------
 | |
| 
 | |
| WMI drivers can receive WMI events via the notify() callback inside the struct wmi_driver.
 | |
| The WMI subsystem will then take care of setting up the WMI event accordingly. Please note that
 | |
| the structure of the ACPI object passed to this callback is device-specific, and freeing the
 | |
| ACPI object is being done by the WMI subsystem, not the driver.
 | |
| 
 | |
| The WMI driver core will take care that the notify() 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() 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.
 | |
| 
 | |
| In order to be able to receive WMI events containing no additional event data,
 | |
| the ``no_notify_data`` flag inside struct wmi_driver should be set to ``true``.
 | |
| 
 | |
| Take a look at drivers/platform/x86/xiaomi-wmi.c for an example WMI event driver.
 | |
| 
 | |
| 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
 | |
| - 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/
 |