19c0beb6bSArmin Wolf.. SPDX-License-Identifier: GPL-2.0-or-later 29c0beb6bSArmin Wolf 39c0beb6bSArmin Wolf=================================================== 49c0beb6bSArmin WolfMSI WMI Platform Features driver (msi-wmi-platform) 59c0beb6bSArmin Wolf=================================================== 69c0beb6bSArmin Wolf 79c0beb6bSArmin WolfIntroduction 89c0beb6bSArmin Wolf============ 99c0beb6bSArmin Wolf 109c0beb6bSArmin WolfMany MSI notebooks support various features like reading fan sensors. This features are controlled 119c0beb6bSArmin Wolfby the embedded controller, with the ACPI firmware exposing a standard ACPI WMI interface on top 129c0beb6bSArmin Wolfof the embedded controller interface. 139c0beb6bSArmin Wolf 149c0beb6bSArmin WolfWMI interface description 159c0beb6bSArmin Wolf========================= 169c0beb6bSArmin Wolf 179c0beb6bSArmin WolfThe WMI interface description can be decoded from the embedded binary MOF (bmof) 189c0beb6bSArmin Wolfdata using the `bmfdec <https://github.com/pali/bmfdec>`_ utility: 199c0beb6bSArmin Wolf 209c0beb6bSArmin Wolf:: 219c0beb6bSArmin Wolf 229c0beb6bSArmin Wolf [WMI, Locale("MS\0x409"), 239c0beb6bSArmin Wolf Description("This class contains the definition of the package used in other classes"), 249c0beb6bSArmin Wolf guid("{ABBC0F60-8EA1-11d1-00A0-C90629100000}")] 259c0beb6bSArmin Wolf class Package { 269c0beb6bSArmin Wolf [WmiDataId(1), read, write, Description("16 bytes of data")] uint8 Bytes[16]; 279c0beb6bSArmin Wolf }; 289c0beb6bSArmin Wolf 299c0beb6bSArmin Wolf [WMI, Locale("MS\0x409"), 309c0beb6bSArmin Wolf Description("This class contains the definition of the package used in other classes"), 319c0beb6bSArmin Wolf guid("{ABBC0F63-8EA1-11d1-00A0-C90629100000}")] 329c0beb6bSArmin Wolf class Package_32 { 339c0beb6bSArmin Wolf [WmiDataId(1), read, write, Description("32 bytes of data")] uint8 Bytes[32]; 349c0beb6bSArmin Wolf }; 359c0beb6bSArmin Wolf 369c0beb6bSArmin Wolf [WMI, Dynamic, Provider("WmiProv"), Locale("MS\0x409"), 379c0beb6bSArmin Wolf Description("Class used to operate methods on a package"), 389c0beb6bSArmin Wolf guid("{ABBC0F6E-8EA1-11d1-00A0-C90629100000}")] 399c0beb6bSArmin Wolf class MSI_ACPI { 409c0beb6bSArmin Wolf [key, read] string InstanceName; 419c0beb6bSArmin Wolf [read] boolean Active; 429c0beb6bSArmin Wolf 439c0beb6bSArmin Wolf [WmiMethodId(1), Implemented, read, write, Description("Return the contents of a package")] 449c0beb6bSArmin Wolf void GetPackage([out, id(0)] Package Data); 459c0beb6bSArmin Wolf 469c0beb6bSArmin Wolf [WmiMethodId(2), Implemented, read, write, Description("Set the contents of a package")] 479c0beb6bSArmin Wolf void SetPackage([in, id(0)] Package Data); 489c0beb6bSArmin Wolf 499c0beb6bSArmin Wolf [WmiMethodId(3), Implemented, read, write, Description("Return the contents of a package")] 509c0beb6bSArmin Wolf void Get_EC([out, id(0)] Package_32 Data); 519c0beb6bSArmin Wolf 529c0beb6bSArmin Wolf [WmiMethodId(4), Implemented, read, write, Description("Set the contents of a package")] 539c0beb6bSArmin Wolf void Set_EC([in, id(0)] Package_32 Data); 549c0beb6bSArmin Wolf 559c0beb6bSArmin Wolf [WmiMethodId(5), Implemented, read, write, Description("Return the contents of a package")] 569c0beb6bSArmin Wolf void Get_BIOS([in, out, id(0)] Package_32 Data); 579c0beb6bSArmin Wolf 589c0beb6bSArmin Wolf [WmiMethodId(6), Implemented, read, write, Description("Set the contents of a package")] 599c0beb6bSArmin Wolf void Set_BIOS([in, out, id(0)] Package_32 Data); 609c0beb6bSArmin Wolf 619c0beb6bSArmin Wolf [WmiMethodId(7), Implemented, read, write, Description("Return the contents of a package")] 629c0beb6bSArmin Wolf void Get_SMBUS([in, out, id(0)] Package_32 Data); 639c0beb6bSArmin Wolf 649c0beb6bSArmin Wolf [WmiMethodId(8), Implemented, read, write, Description("Set the contents of a package")] 659c0beb6bSArmin Wolf void Set_SMBUS([in, out, id(0)] Package_32 Data); 669c0beb6bSArmin Wolf 679c0beb6bSArmin Wolf [WmiMethodId(9), Implemented, read, write, Description("Return the contents of a package")] 689c0beb6bSArmin Wolf void Get_MasterBattery([in, out, id(0)] Package_32 Data); 699c0beb6bSArmin Wolf 709c0beb6bSArmin Wolf [WmiMethodId(10), Implemented, read, write, Description("Set the contents of a package")] 719c0beb6bSArmin Wolf void Set_MasterBattery([in, out, id(0)] Package_32 Data); 729c0beb6bSArmin Wolf 739c0beb6bSArmin Wolf [WmiMethodId(11), Implemented, read, write, Description("Return the contents of a package")] 749c0beb6bSArmin Wolf void Get_SlaveBattery([in, out, id(0)] Package_32 Data); 759c0beb6bSArmin Wolf 769c0beb6bSArmin Wolf [WmiMethodId(12), Implemented, read, write, Description("Set the contents of a package")] 779c0beb6bSArmin Wolf void Set_SlaveBattery([in, out, id(0)] Package_32 Data); 789c0beb6bSArmin Wolf 799c0beb6bSArmin Wolf [WmiMethodId(13), Implemented, read, write, Description("Return the contents of a package")] 809c0beb6bSArmin Wolf void Get_Temperature([in, out, id(0)] Package_32 Data); 819c0beb6bSArmin Wolf 829c0beb6bSArmin Wolf [WmiMethodId(14), Implemented, read, write, Description("Set the contents of a package")] 839c0beb6bSArmin Wolf void Set_Temperature([in, out, id(0)] Package_32 Data); 849c0beb6bSArmin Wolf 859c0beb6bSArmin Wolf [WmiMethodId(15), Implemented, read, write, Description("Return the contents of a package")] 869c0beb6bSArmin Wolf void Get_Thermal([in, out, id(0)] Package_32 Data); 879c0beb6bSArmin Wolf 889c0beb6bSArmin Wolf [WmiMethodId(16), Implemented, read, write, Description("Set the contents of a package")] 899c0beb6bSArmin Wolf void Set_Thermal([in, out, id(0)] Package_32 Data); 909c0beb6bSArmin Wolf 919c0beb6bSArmin Wolf [WmiMethodId(17), Implemented, read, write, Description("Return the contents of a package")] 929c0beb6bSArmin Wolf void Get_Fan([in, out, id(0)] Package_32 Data); 939c0beb6bSArmin Wolf 949c0beb6bSArmin Wolf [WmiMethodId(18), Implemented, read, write, Description("Set the contents of a package")] 959c0beb6bSArmin Wolf void Set_Fan([in, out, id(0)] Package_32 Data); 969c0beb6bSArmin Wolf 979c0beb6bSArmin Wolf [WmiMethodId(19), Implemented, read, write, Description("Return the contents of a package")] 989c0beb6bSArmin Wolf void Get_Device([in, out, id(0)] Package_32 Data); 999c0beb6bSArmin Wolf 1009c0beb6bSArmin Wolf [WmiMethodId(20), Implemented, read, write, Description("Set the contents of a package")] 1019c0beb6bSArmin Wolf void Set_Device([in, out, id(0)] Package_32 Data); 1029c0beb6bSArmin Wolf 1039c0beb6bSArmin Wolf [WmiMethodId(21), Implemented, read, write, Description("Return the contents of a package")] 1049c0beb6bSArmin Wolf void Get_Power([in, out, id(0)] Package_32 Data); 1059c0beb6bSArmin Wolf 1069c0beb6bSArmin Wolf [WmiMethodId(22), Implemented, read, write, Description("Set the contents of a package")] 1079c0beb6bSArmin Wolf void Set_Power([in, out, id(0)] Package_32 Data); 1089c0beb6bSArmin Wolf 1099c0beb6bSArmin Wolf [WmiMethodId(23), Implemented, read, write, Description("Return the contents of a package")] 1109c0beb6bSArmin Wolf void Get_Debug([in, out, id(0)] Package_32 Data); 1119c0beb6bSArmin Wolf 1129c0beb6bSArmin Wolf [WmiMethodId(24), Implemented, read, write, Description("Set the contents of a package")] 1139c0beb6bSArmin Wolf void Set_Debug([in, out, id(0)] Package_32 Data); 1149c0beb6bSArmin Wolf 1159c0beb6bSArmin Wolf [WmiMethodId(25), Implemented, read, write, Description("Return the contents of a package")] 1169c0beb6bSArmin Wolf void Get_AP([in, out, id(0)] Package_32 Data); 1179c0beb6bSArmin Wolf 1189c0beb6bSArmin Wolf [WmiMethodId(26), Implemented, read, write, Description("Set the contents of a package")] 1199c0beb6bSArmin Wolf void Set_AP([in, out, id(0)] Package_32 Data); 1209c0beb6bSArmin Wolf 1219c0beb6bSArmin Wolf [WmiMethodId(27), Implemented, read, write, Description("Return the contents of a package")] 1229c0beb6bSArmin Wolf void Get_Data([in, out, id(0)] Package_32 Data); 1239c0beb6bSArmin Wolf 1249c0beb6bSArmin Wolf [WmiMethodId(28), Implemented, read, write, Description("Set the contents of a package")] 1259c0beb6bSArmin Wolf void Set_Data([in, out, id(0)] Package_32 Data); 1269c0beb6bSArmin Wolf 1279c0beb6bSArmin Wolf [WmiMethodId(29), Implemented, read, write, Description("Return the contents of a package")] 1289c0beb6bSArmin Wolf void Get_WMI([out, id(0)] Package_32 Data); 1299c0beb6bSArmin Wolf }; 1309c0beb6bSArmin Wolf 1319c0beb6bSArmin WolfDue to a peculiarity in how Windows handles the ``CreateByteField()`` ACPI operator (errors only 1329c0beb6bSArmin Wolfhappen when a invalid byte field is ultimately accessed), all methods require a 32 byte input 1336e73c490SLuis Felipe Hernandezbuffer, even if the Binary MOF says otherwise. 1349c0beb6bSArmin Wolf 1359c0beb6bSArmin WolfThe input buffer contains a single byte to select the subfeature to be accessed and 31 bytes of 1369c0beb6bSArmin Wolfinput data, the meaning of which depends on the subfeature being accessed. 1379c0beb6bSArmin Wolf 1386e73c490SLuis Felipe HernandezThe output buffer contains a single byte which signals success or failure (``0x00`` on failure) 1399c0beb6bSArmin Wolfand 31 bytes of output data, the meaning if which depends on the subfeature being accessed. 1409c0beb6bSArmin Wolf 141*baf2f2c2SArmin Wolf.. note:: 142*baf2f2c2SArmin Wolf The ACPI control method responsible for handling the WMI method calls is not thread-safe. 143*baf2f2c2SArmin Wolf This is a firmware bug that needs to be handled inside the driver itself. 144*baf2f2c2SArmin Wolf 1459c0beb6bSArmin WolfWMI method Get_EC() 1469c0beb6bSArmin Wolf------------------- 1479c0beb6bSArmin Wolf 1489c0beb6bSArmin WolfReturns embedded controller information, the selected subfeature does not matter. The output 1499c0beb6bSArmin Wolfdata contains a flag byte and a 28 byte controller firmware version string. 1509c0beb6bSArmin Wolf 1519c0beb6bSArmin WolfThe first 4 bits of the flag byte contain the minor version of the embedded controller interface, 1529c0beb6bSArmin Wolfwith the next 2 bits containing the major version of the embedded controller interface. 1539c0beb6bSArmin Wolf 1546e73c490SLuis Felipe HernandezThe 7th bit signals if the embedded controller page changed (exact meaning is unknown), and the 1559c0beb6bSArmin Wolflast bit signals if the platform is a Tigerlake platform. 1569c0beb6bSArmin Wolf 1579c0beb6bSArmin WolfThe MSI software seems to only use this interface when the last bit is set. 1589c0beb6bSArmin Wolf 1599c0beb6bSArmin WolfWMI method Get_Fan() 1609c0beb6bSArmin Wolf-------------------- 1619c0beb6bSArmin Wolf 1629c0beb6bSArmin WolfFan speed sensors can be accessed by selecting subfeature ``0x00``. The output data contains 1639c0beb6bSArmin Wolfup to four 16-bit fan speed readings in big-endian format. Most machines do not support all 1649c0beb6bSArmin Wolffour fan speed sensors, so the remaining reading are hardcoded to ``0x0000``. 1659c0beb6bSArmin Wolf 1669c0beb6bSArmin WolfThe fan RPM readings can be calculated with the following formula: 1679c0beb6bSArmin Wolf 1689c0beb6bSArmin Wolf RPM = 480000 / <fan speed reading> 1699c0beb6bSArmin Wolf 1709c0beb6bSArmin WolfIf the fan speed reading is zero, then the fan RPM is zero too. 1719c0beb6bSArmin Wolf 1729c0beb6bSArmin WolfWMI method Get_WMI() 1739c0beb6bSArmin Wolf-------------------- 1749c0beb6bSArmin Wolf 1759c0beb6bSArmin WolfReturns the version of the ACPI WMI interface, the selected subfeature does not matter. 1769c0beb6bSArmin WolfThe output data contains two bytes, the first one contains the major version and the last one 1779c0beb6bSArmin Wolfcontains the minor revision of the ACPI WMI interface. 1789c0beb6bSArmin Wolf 1799c0beb6bSArmin WolfThe MSI software seems to only use this interface when the major version is greater than two. 1809c0beb6bSArmin Wolf 1819c0beb6bSArmin WolfReverse-Engineering the MSI WMI Platform interface 1829c0beb6bSArmin Wolf================================================== 1839c0beb6bSArmin Wolf 1849c0beb6bSArmin Wolf.. warning:: Randomly poking the embedded controller interface can potentially cause damage 1859c0beb6bSArmin Wolf to the machine and other unwanted side effects, please be careful. 1869c0beb6bSArmin Wolf 1879c0beb6bSArmin WolfThe underlying embedded controller interface is used by the ``msi-ec`` driver, and it seems 1889c0beb6bSArmin Wolfthat many methods just copy a part of the embedded controller memory into the output buffer. 1899c0beb6bSArmin Wolf 1909c0beb6bSArmin WolfThis means that the remaining WMI methods can be reverse-engineered by looking which part of 1919c0beb6bSArmin Wolfthe embedded controller memory is accessed by the ACPI AML code. The driver also supports a 1929c0beb6bSArmin Wolfdebugfs interface for directly executing WMI methods. Additionally, any safety checks regarding 1939c0beb6bSArmin Wolfunsupported hardware can be disabled by loading the module with ``force=true``. 1949c0beb6bSArmin Wolf 1959c0beb6bSArmin WolfMore information about the MSI embedded controller interface can be found at the 1969c0beb6bSArmin Wolf`msi-ec project <https://github.com/BeardOverflow/msi-ec>`_. 1979c0beb6bSArmin Wolf 1989c0beb6bSArmin WolfSpecial thanks go to github user `glpnk` for showing how to decode the fan speed readings. 199