xref: /linux/Documentation/wmi/devices/msi-wmi-platform.rst (revision 8499899816fd79aefdfa923ed3fb5a15b0a62757)
1.. SPDX-License-Identifier: GPL-2.0-or-later
2
3===================================================
4MSI WMI Platform Features driver (msi-wmi-platform)
5===================================================
6
7Introduction
8============
9
10Many MSI notebooks support various features like reading fan sensors. This features are controlled
11by the embedded controller, with the ACPI firmware exposing a standard ACPI WMI interface on top
12of the embedded controller interface.
13
14WMI interface description
15=========================
16
17The 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, Locale("MS\0x409"),
23   Description("This class contains the definition of the package used in other classes"),
24   guid("{ABBC0F60-8EA1-11d1-00A0-C90629100000}")]
25  class Package {
26    [WmiDataId(1), read, write, Description("16 bytes of data")] uint8 Bytes[16];
27  };
28
29  [WMI, Locale("MS\0x409"),
30   Description("This class contains the definition of the package used in other classes"),
31   guid("{ABBC0F63-8EA1-11d1-00A0-C90629100000}")]
32  class Package_32 {
33    [WmiDataId(1), read, write, Description("32 bytes of data")] uint8 Bytes[32];
34  };
35
36  [WMI, Dynamic, Provider("WmiProv"), Locale("MS\0x409"),
37   Description("Class used to operate methods on a package"),
38   guid("{ABBC0F6E-8EA1-11d1-00A0-C90629100000}")]
39  class MSI_ACPI {
40    [key, read] string InstanceName;
41    [read] boolean Active;
42
43    [WmiMethodId(1), Implemented, read, write, Description("Return the contents of a package")]
44    void GetPackage([out, id(0)] Package Data);
45
46    [WmiMethodId(2), Implemented, read, write, Description("Set the contents of a package")]
47    void SetPackage([in, id(0)] Package Data);
48
49    [WmiMethodId(3), Implemented, read, write, Description("Return the contents of a package")]
50    void Get_EC([out, id(0)] Package_32 Data);
51
52    [WmiMethodId(4), Implemented, read, write, Description("Set the contents of a package")]
53    void Set_EC([in, id(0)] Package_32 Data);
54
55    [WmiMethodId(5), Implemented, read, write, Description("Return the contents of a package")]
56    void Get_BIOS([in, out, id(0)] Package_32 Data);
57
58    [WmiMethodId(6), Implemented, read, write, Description("Set the contents of a package")]
59    void Set_BIOS([in, out, id(0)] Package_32 Data);
60
61    [WmiMethodId(7), Implemented, read, write, Description("Return the contents of a package")]
62    void Get_SMBUS([in, out, id(0)] Package_32 Data);
63
64    [WmiMethodId(8), Implemented, read, write, Description("Set the contents of a package")]
65    void Set_SMBUS([in, out, id(0)] Package_32 Data);
66
67    [WmiMethodId(9), Implemented, read, write, Description("Return the contents of a package")]
68    void Get_MasterBattery([in, out, id(0)] Package_32 Data);
69
70    [WmiMethodId(10), Implemented, read, write, Description("Set the contents of a package")]
71    void Set_MasterBattery([in, out, id(0)] Package_32 Data);
72
73    [WmiMethodId(11), Implemented, read, write, Description("Return the contents of a package")]
74    void Get_SlaveBattery([in, out, id(0)] Package_32 Data);
75
76    [WmiMethodId(12), Implemented, read, write, Description("Set the contents of a package")]
77    void Set_SlaveBattery([in, out, id(0)] Package_32 Data);
78
79    [WmiMethodId(13), Implemented, read, write, Description("Return the contents of a package")]
80    void Get_Temperature([in, out, id(0)] Package_32 Data);
81
82    [WmiMethodId(14), Implemented, read, write, Description("Set the contents of a package")]
83    void Set_Temperature([in, out, id(0)] Package_32 Data);
84
85    [WmiMethodId(15), Implemented, read, write, Description("Return the contents of a package")]
86    void Get_Thermal([in, out, id(0)] Package_32 Data);
87
88    [WmiMethodId(16), Implemented, read, write, Description("Set the contents of a package")]
89    void Set_Thermal([in, out, id(0)] Package_32 Data);
90
91    [WmiMethodId(17), Implemented, read, write, Description("Return the contents of a package")]
92    void Get_Fan([in, out, id(0)] Package_32 Data);
93
94    [WmiMethodId(18), Implemented, read, write, Description("Set the contents of a package")]
95    void Set_Fan([in, out, id(0)] Package_32 Data);
96
97    [WmiMethodId(19), Implemented, read, write, Description("Return the contents of a package")]
98    void Get_Device([in, out, id(0)] Package_32 Data);
99
100    [WmiMethodId(20), Implemented, read, write, Description("Set the contents of a package")]
101    void Set_Device([in, out, id(0)] Package_32 Data);
102
103    [WmiMethodId(21), Implemented, read, write, Description("Return the contents of a package")]
104    void Get_Power([in, out, id(0)] Package_32 Data);
105
106    [WmiMethodId(22), Implemented, read, write, Description("Set the contents of a package")]
107    void Set_Power([in, out, id(0)] Package_32 Data);
108
109    [WmiMethodId(23), Implemented, read, write, Description("Return the contents of a package")]
110    void Get_Debug([in, out, id(0)] Package_32 Data);
111
112    [WmiMethodId(24), Implemented, read, write, Description("Set the contents of a package")]
113    void Set_Debug([in, out, id(0)] Package_32 Data);
114
115    [WmiMethodId(25), Implemented, read, write, Description("Return the contents of a package")]
116    void Get_AP([in, out, id(0)] Package_32 Data);
117
118    [WmiMethodId(26), Implemented, read, write, Description("Set the contents of a package")]
119    void Set_AP([in, out, id(0)] Package_32 Data);
120
121    [WmiMethodId(27), Implemented, read, write, Description("Return the contents of a package")]
122    void Get_Data([in, out, id(0)] Package_32 Data);
123
124    [WmiMethodId(28), Implemented, read, write, Description("Set the contents of a package")]
125    void Set_Data([in, out, id(0)] Package_32 Data);
126
127    [WmiMethodId(29), Implemented, read, write, Description("Return the contents of a package")]
128    void Get_WMI([out, id(0)] Package_32 Data);
129  };
130
131Due to a peculiarity in how Windows handles the ``CreateByteField()`` ACPI operator (errors only
132happen when a invalid byte field is ultimately accessed), all methods require a 32 byte input
133buffer, even if the Binary MOF says otherwise.
134
135The input buffer contains a single byte to select the subfeature to be accessed and 31 bytes of
136input data, the meaning of which depends on the subfeature being accessed.
137
138The output buffer contains a single byte which signals success or failure (``0x00`` on failure)
139and 31 bytes of output data, the meaning if which depends on the subfeature being accessed.
140
141.. note::
142   The ACPI control method responsible for handling the WMI method calls is not thread-safe.
143   This is a firmware bug that needs to be handled inside the driver itself.
144
145WMI method Get_EC()
146-------------------
147
148Returns embedded controller information, the selected subfeature does not matter. The output
149data contains a flag byte and a 28 byte controller firmware version string.
150
151The first 4 bits of the flag byte contain the minor version of the embedded controller interface,
152with the next 2 bits containing the major version of the embedded controller interface.
153
154The 7th bit signals if the embedded controller page changed (exact meaning is unknown), and the
155last bit signals if the platform is a Tigerlake platform.
156
157The MSI software seems to only use this interface when the last bit is set.
158
159WMI method Get_Fan()
160--------------------
161
162Fan speed sensors can be accessed by selecting subfeature ``0x00``. The output data contains
163up to four 16-bit fan speed readings in big-endian format. Most machines do not support all
164four fan speed sensors, so the remaining reading are hardcoded to ``0x0000``.
165
166The fan RPM readings can be calculated with the following formula:
167
168        RPM = 480000 / <fan speed reading>
169
170If the fan speed reading is zero, then the fan RPM is zero too.
171
172WMI method Get_WMI()
173--------------------
174
175Returns the version of the ACPI WMI interface, the selected subfeature does not matter.
176The output data contains two bytes, the first one contains the major version and the last one
177contains the minor revision of the ACPI WMI interface.
178
179The MSI software seems to only use this interface when the major version is greater than two.
180
181Reverse-Engineering the MSI WMI Platform interface
182==================================================
183
184.. warning:: Randomly poking the embedded controller interface can potentially cause damage
185             to the machine and other unwanted side effects, please be careful.
186
187The underlying embedded controller interface is used by the ``msi-ec`` driver, and it seems
188that many methods just copy a part of the embedded controller memory into the output buffer.
189
190This means that the remaining WMI methods can be reverse-engineered by looking which part of
191the embedded controller memory is accessed by the ACPI AML code. The driver also supports a
192debugfs interface for directly executing WMI methods. Additionally, any safety checks regarding
193unsupported hardware can be disabled by loading the module with ``force=true``.
194
195More information about the MSI embedded controller interface can be found at the
196`msi-ec project <https://github.com/BeardOverflow/msi-ec>`_.
197
198Special thanks go to github user `glpnk` for showing how to decode the fan speed readings.
199