xref: /linux/Documentation/wmi/devices/uniwill-laptop.rst (revision a34b0e4e21d6be3c3d620aa7f9dfbf0e9550c19e)
1.. SPDX-License-Identifier: GPL-2.0-or-later
2
3========================================
4Uniwill Notebook driver (uniwill-laptop)
5========================================
6
7Introduction
8============
9
10Many notebooks manufactured by Uniwill (either directly or as ODM) provide a EC interface
11for controlling various platform settings like sensors and fan control. This interface is
12used by the ``uniwill-laptop`` driver to map those features onto standard kernel interfaces.
13
14EC WMI interface description
15============================
16
17The EC WMI interface description can be decoded from the embedded binary MOF (bmof)
18data using the `bmfdec <https://github.com/pali/bmfdec>`_ utility:
19
20::
21
22  [WMI, Dynamic, Provider("WmiProv"), Locale("MS\\0x409"),
23   Description("Class used to operate methods on a ULong"),
24   guid("{ABBC0F6F-8EA1-11d1-00A0-C90629100000}")]
25  class AcpiTest_MULong {
26    [key, read] string InstanceName;
27    [read] boolean Active;
28
29    [WmiMethodId(1), Implemented, read, write, Description("Return the contents of a ULong")]
30    void GetULong([out, Description("Ulong Data")] uint32 Data);
31
32    [WmiMethodId(2), Implemented, read, write, Description("Set the contents of a ULong")]
33    void SetULong([in, Description("Ulong Data")] uint32 Data);
34
35    [WmiMethodId(3), Implemented, read, write,
36     Description("Generate an event containing ULong data")]
37    void FireULong([in, Description("WMI requires a parameter")] uint32 Hack);
38
39    [WmiMethodId(4), Implemented, read, write, Description("Get and Set the contents of a ULong")]
40    void GetSetULong([in, Description("Ulong Data")] uint64 Data,
41                     [out, Description("Ulong Data")] uint32 Return);
42
43    [WmiMethodId(5), Implemented, read, write,
44     Description("Get and Set the contents of a ULong for Dollby button")]
45    void GetButton([in, Description("Ulong Data")] uint64 Data,
46                   [out, Description("Ulong Data")] uint32 Return);
47  };
48
49Most of the WMI-related code was copied from the Windows driver samples, which unfortunately means
50that the WMI-GUID is not unique. This makes the WMI-GUID unusable for autoloading.
51
52WMI method GetULong()
53---------------------
54
55This WMI method was copied from the Windows driver samples and has no function.
56
57WMI method SetULong()
58---------------------
59
60This WMI method was copied from the Windows driver samples and has no function.
61
62WMI method FireULong()
63----------------------
64
65This WMI method allows to inject a WMI event with a 32-bit payload. Its primary purpose seems
66to be debugging.
67
68WMI method GetSetULong()
69------------------------
70
71This WMI method is used to communicate with the EC. The ``Data`` argument holds the following
72information (starting with the least significant byte):
73
741. 16-bit address
752. 16-bit data (set to ``0x0000`` when reading)
763. 16-bit operation (``0x0100`` for reading and ``0x0000`` for writing)
774. 16-bit reserved (set to ``0x0000``)
78
79The first 8 bits of the ``Return`` value contain the data returned by the EC when reading.
80The special value ``0xFEFEFEFE`` is used to indicate a communication failure with the EC.
81
82WMI method GetButton()
83----------------------
84
85This WMI method is not implemented on all machines and has an unknown purpose.
86
87Reverse-Engineering the EC WMI interface
88========================================
89
90.. warning:: Randomly poking the EC can potentially cause damage to the machine and other unwanted
91             side effects, please be careful.
92
93The EC behind the ``GetSetULong`` method is used by the OEM software supplied by the manufacturer.
94Reverse-engineering of this software is difficult since it uses an obfuscator, however some parts
95are not obfuscated. In this case `dnSpy <https://github.com/dnSpy/dnSpy>`_ could also be helpful.
96
97The EC can be accessed under Windows using powershell (requires admin privileges):
98
99::
100
101  > $obj = Get-CimInstance -Namespace root/wmi -ClassName AcpiTest_MULong | Select-Object -First 1
102  > Invoke-CimMethod -InputObject $obj -MethodName GetSetULong -Arguments @{Data = <input>}
103
104WMI event interface description
105===============================
106
107The WMI interface description can also be decoded from the embedded binary MOF (bmof)
108data:
109
110::
111
112  [WMI, Dynamic, Provider("WmiProv"), Locale("MS\\0x409"),
113   Description("Class containing event generated ULong data"),
114   guid("{ABBC0F72-8EA1-11d1-00A0-C90629100000}")]
115  class AcpiTest_EventULong : WmiEvent {
116    [key, read] string InstanceName;
117    [read] boolean Active;
118
119    [WmiDataId(1), read, write, Description("ULong Data")] uint32 ULong;
120  };
121
122Most of the WMI-related code was again copied from the Windows driver samples, causing this WMI
123interface to suffer from the same restrictions as the EC WMI interface described above.
124
125WMI event data
126--------------
127
128The WMI event data contains a single 32-bit value which is used to indicate various platform events.
129
130Reverse-Engineering the Uniwill WMI event interface
131===================================================
132
133The driver logs debug messages when receiving a WMI event. Thus enabling debug messages will be
134useful for finding unknown event codes.
135
136EC ACPI interface description
137=============================
138
139The ``INOU0000`` ACPI device is a virtual device used to access various hardware registers
140available on notebooks manufactured by Uniwill. Reading and writing those registers happens
141by calling ACPI control methods. The ``uniwill-laptop`` driver uses this device to communicate
142with the EC because the ACPI control methods are faster than the WMI methods described above.
143
144ACPI control methods used for reading registers take a single ACPI integer containing the address
145of the register to read and return a ACPI integer containing the data inside said register. ACPI
146control methods used for writing registers however take two ACPI integers, with the additional
147ACPI integer containing the data to be written into the register. Such ACPI control methods return
148nothing.
149
150System memory
151-------------
152
153System memory can be accessed with a granularity of either a single byte (``MMRB`` for reading and
154``MMWB`` for writing) or four bytes (``MMRD`` for reading and ``MMWD`` for writing). Those ACPI
155control methods are unused because they provide no benefit when compared to the native memory
156access functions provided by the kernel.
157
158EC RAM
159------
160
161The internal RAM of the EC can be accessed with a granularity of a single byte using the ``ECRR``
162(read) and ``ECRW`` (write) ACPI control methods, with the maximum register address being ``0xFFF``.
163The OEM software waits 6 ms after calling one of those ACPI control methods, likely to avoid
164overwhelming the EC when being connected over LPC.
165
166PCI config space
167----------------
168
169The PCI config space can be accessed with a granularity of four bytes using the ``PCRD`` (read) and
170``PCWD`` (write) ACPI control methods. The exact address format is unknown, and poking random PCI
171devices might confuse the PCI subsystem. Because of this those ACPI control methods are not used.
172
173IO ports
174--------
175
176IO ports can be accessed with a granularity of four bytes using the ``IORD`` (read) and ``IOWD``
177(write) ACPI control methods. Those ACPI control methods are unused because they provide no benefit
178when compared to the native IO port access functions provided by the kernel.
179
180CMOS RAM
181--------
182
183The CMOS RAM can be accessed with a granularity of a single byte using the ``RCMS`` (read) and
184``WCMS`` ACPI control methods. Using those ACPI methods might interfere with the native CMOS RAM
185access functions provided by the kernel due to the usage of indexed IO, so they are unused.
186
187Indexed IO
188----------
189
190Indexed IO with IO ports with a granularity of a single byte can be performed using the ``RIOP``
191(read) and ``WIOP`` (write) ACPI control methods. Those ACPI methods are unused because they
192provide no benifit when compared to the native IO port access functions provided by the kernel.
193
194Special thanks go to github user `pobrn` which developed the
195`qc71_laptop <https://github.com/pobrn/qc71_laptop>`_ driver on which this driver is partly based.
196The same is true for Tuxedo Computers, which developed the
197`tuxedo-drivers <https://gitlab.com/tuxedocomputers/development/packages/tuxedo-drivers>`_ package
198which also served as a foundation for this driver.
199