linux/Documentation/wmi/devices/alienware-wmi.rst
Kurt Borja 6674c5a0ee
Documentation: alienware-wmi: Describe THERMAL_INFORMATION operation 0x02
This operation is used by alienware-wmi driver to avoid brute-forcing
operation 0x03.

Signed-off-by: Kurt Borja <kuurtb@gmail.com>
Reviewed-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
Link: https://lore.kernel.org/r/20241111183639.14726-1-kuurtb@gmail.com
Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
2024-11-16 16:50:54 +02:00

398 lines
14 KiB
ReStructuredText

.. SPDX-License-Identifier: GPL-2.0-or-later
==============================================
Dell AWCC WMI interface driver (alienware-wmi)
==============================================
Introduction
============
The WMI device WMAX has been implemented for many Alienware and Dell's G-Series
models. Throughout these models, two implementations have been identified. The
first one, used by older systems, deals with HDMI, brightness, RGB, amplifier
and deep sleep control. The second one used by newer systems deals primarily
with thermal, overclocking, and GPIO control.
It is suspected that the latter is used by Alienware Command Center (AWCC) to
manage manufacturer predefined thermal profiles. The alienware-wmi driver
exposes Thermal_Information and Thermal_Control methods through the Platform
Profile API to mimic AWCC's behavior.
This newer interface, named AWCCMethodFunction has been reverse engineered, as
Dell has not provided any official documentation. We will try to describe to the
best of our ability its discovered inner workings.
.. note::
The following method description may be incomplete and some operations have
different implementations between devices.
WMI interface description
-------------------------
The WMI interface description can be decoded from the embedded binary MOF (bmof)
data using the `bmfdec <https://github.com/pali/bmfdec>`_ utility:
::
[WMI, Dynamic, Provider("WmiProv"), Locale("MS\\0x409"), Description("WMI Function"), guid("{A70591CE-A997-11DA-B012-B622A1EF5492}")]
class AWCCWmiMethodFunction {
[key, read] string InstanceName;
[read] boolean Active;
[WmiMethodId(13), Implemented, read, write, Description("Return Overclocking Report.")] void Return_OverclockingReport([out] uint32 argr);
[WmiMethodId(14), Implemented, read, write, Description("Set OCUIBIOS Control.")] void Set_OCUIBIOSControl([in] uint32 arg2, [out] uint32 argr);
[WmiMethodId(15), Implemented, read, write, Description("Clear OC FailSafe Flag.")] void Clear_OCFailSafeFlag([out] uint32 argr);
[WmiMethodId(19), Implemented, read, write, Description("Get Fan Sensors.")] void GetFanSensors([in] uint32 arg2, [out] uint32 argr);
[WmiMethodId(20), Implemented, read, write, Description("Thermal Information.")] void Thermal_Information([in] uint32 arg2, [out] uint32 argr);
[WmiMethodId(21), Implemented, read, write, Description("Thermal Control.")] void Thermal_Control([in] uint32 arg2, [out] uint32 argr);
[WmiMethodId(23), Implemented, read, write, Description("MemoryOCControl.")] void MemoryOCControl([in] uint32 arg2, [out] uint32 argr);
[WmiMethodId(26), Implemented, read, write, Description("System Information.")] void SystemInformation([in] uint32 arg2, [out] uint32 argr);
[WmiMethodId(28), Implemented, read, write, Description("Power Information.")] void PowerInformation([in] uint32 arg2, [out] uint32 argr);
[WmiMethodId(32), Implemented, read, write, Description("FW Update GPIO toggle.")] void FWUpdateGPIOtoggle([in] uint32 arg2, [out] uint32 argr);
[WmiMethodId(33), Implemented, read, write, Description("Read Total of GPIOs.")] void ReadTotalofGPIOs([out] uint32 argr);
[WmiMethodId(34), Implemented, read, write, Description("Read GPIO pin Status.")] void ReadGPIOpPinStatus([in] uint32 arg2, [out] uint32 argr);
[WmiMethodId(35), Implemented, read, write, Description("Read Chassis Color.")] void ReadChassisColor([out] uint32 argr);
[WmiMethodId(36), Implemented, read, write, Description("Read Platform Properties.")] void ReadPlatformProperties([out] uint32 argr);
[WmiMethodId(37), Implemented, read, write, Description("Game Shift Status.")] void GameShiftStatus([in] uint32 arg2, [out] uint32 argr);
[WmiMethodId(128), Implemented, read, write, Description("Caldera SW installation.")] void CalderaSWInstallation([out] uint32 argr);
[WmiMethodId(129), Implemented, read, write, Description("Caldera SW is released.")] void CalderaSWReleased([out] uint32 argr);
[WmiMethodId(130), Implemented, read, write, Description("Caldera Connection Status.")] void CalderaConnectionStatus([in] uint32 arg2, [out] uint32 argr);
[WmiMethodId(131), Implemented, read, write, Description("Surprise Unplugged Flag Status.")] void SurpriseUnpluggedFlagStatus([out] uint32 argr);
[WmiMethodId(132), Implemented, read, write, Description("Clear Surprise Unplugged Flag.")] void ClearSurpriseUnpluggedFlag([out] uint32 argr);
[WmiMethodId(133), Implemented, read, write, Description("Cancel Undock Request.")] void CancelUndockRequest([out] uint32 argr);
[WmiMethodId(135), Implemented, read, write, Description("Devices in Caldera.")] void DevicesInCaldera([in] uint32 arg2, [out] uint32 argr);
[WmiMethodId(136), Implemented, read, write, Description("Notify BIOS for SW ready to disconnect Caldera.")] void NotifyBIOSForSWReadyToDisconnectCaldera([out] uint32 argr);
[WmiMethodId(160), Implemented, read, write, Description("Tobii SW installation.")] void TobiiSWinstallation([out] uint32 argr);
[WmiMethodId(161), Implemented, read, write, Description("Tobii SW Released.")] void TobiiSWReleased([out] uint32 argr);
[WmiMethodId(162), Implemented, read, write, Description("Tobii Camera Power Reset.")] void TobiiCameraPowerReset([out] uint32 argr);
[WmiMethodId(163), Implemented, read, write, Description("Tobii Camera Power On.")] void TobiiCameraPowerOn([out] uint32 argr);
[WmiMethodId(164), Implemented, read, write, Description("Tobii Camera Power Off.")] void TobiiCameraPowerOff([out] uint32 argr);
};
Some of these methods get quite intricate so we will describe them using
pseudo-code that vaguely resembles the original ASL code.
Methods not described in the following document have unknown behavior.
Argument Structure
------------------
All input arguments have type **uint32** and their structure is very similar
between methods. Usually, the first byte corresponds to a specific *operation*
the method performs, and the subsequent bytes correspond to *arguments* passed
to this *operation*. For example, if an operation has code 0x01 and requires an
ID 0xA0, the argument you would pass to the method is 0xA001.
Thermal Methods
===============
WMI method Thermal_Information([in] uint32 arg2, [out] uint32 argr)
-------------------------------------------------------------------
::
if BYTE_0(arg2) == 0x01:
argr = 1
if BYTE_0(arg2) == 0x02:
argr = SYSTEM_DESCRIPTION
if BYTE_0(arg2) == 0x03:
if BYTE_1(arg2) == 0x00:
argr = FAN_ID_0
if BYTE_1(arg2) == 0x01:
argr = FAN_ID_1
if BYTE_1(arg2) == 0x02:
argr = FAN_ID_2
if BYTE_1(arg2) == 0x03:
argr = FAN_ID_3
if BYTE_1(arg2) == 0x04:
argr = SENSOR_ID_CPU | 0x0100
if BYTE_1(arg2) == 0x05:
argr = SENSOR_ID_GPU | 0x0100
if BYTE_1(arg2) == 0x06:
argr = THERMAL_MODE_QUIET_ID
if BYTE_1(arg2) == 0x07:
argr = THERMAL_MODE_BALANCED_ID
if BYTE_1(arg2) == 0x08:
argr = THERMAL_MODE_BALANCED_PERFORMANCE_ID
if BYTE_1(arg2) == 0x09:
argr = THERMAL_MODE_PERFORMANCE_ID
if BYTE_1(arg2) == 0x0A:
argr = THERMAL_MODE_LOW_POWER_ID
if BYTE_1(arg2) == 0x0B:
argr = THERMAL_MODE_GMODE_ID
else:
argr = 0xFFFFFFFF
if BYTE_0(arg2) == 0x04:
if is_valid_sensor(BYTE_1(arg2)):
argr = SENSOR_TEMP_C
else:
argr = 0xFFFFFFFF
if BYTE_0(arg2) == 0x05:
if is_valid_fan(BYTE_1(arg2)):
argr = FAN_RPM()
if BYTE_0(arg2) == 0x06:
skip
if BYTE_0(arg2) == 0x07:
argr = 0
If BYTE_0(arg2) == 0x08:
if is_valid_fan(BYTE_1(arg2)):
argr = 0
else:
argr = 0xFFFFFFFF
if BYTE_0(arg2) == 0x09:
if is_valid_fan(BYTE_1(arg2)):
argr = FAN_UNKNOWN_STAT_0()
else:
argr = 0xFFFFFFFF
if BYTE_0(arg2) == 0x0A:
argr = THERMAL_MODE_BALANCED_ID
if BYTE_0(arg2) == 0x0B:
argr = CURRENT_THERMAL_MODE()
if BYTE_0(arg2) == 0x0C:
if is_valid_fan(BYTE_1(arg2)):
argr = FAN_UNKNOWN_STAT_1()
else:
argr = 0xFFFFFFFF
Operation 0x02 returns a *system description* buffer with the following
structure:
::
out[0] -> Number of fans
out[1] -> Number of sensors
out[2] -> 0x00
out[3] -> Number of thermal modes
Operation 0x03 list all available fan IDs, sensor IDs and thermal profile
codes in order, but different models may have different number of fans and
thermal profiles. These are the known ranges:
* Fan IDs: from 2 up to 4
* Sensor IDs: 2
* Thermal profile codes: from 1 up to 7
In total BYTE_1(ARG2) may range from 0x5 up to 0xD depending on the model.
WMI method Thermal_Control([in] uint32 arg2, [out] uint32 argr)
---------------------------------------------------------------
::
if BYTE_0(arg2) == 0x01:
if is_valid_thermal_profile(BYTE_1(arg2)):
SET_THERMAL_PROFILE(BYTE_1(arg2))
argr = 0
if BYTE_0(arg2) == 0x02:
if is_valid_fan(BYTE_1(arg2)):
SET_FAN_SPEED_MULTIPLIER(BYTE_2(arg2))
argr = 0
else:
argr = 0xFFFFFFFF
.. note::
While you can manually change the fan speed multiplier with this method,
Dell's BIOS tends to overwrite this changes anyway.
These are the known thermal profile codes:
::
CUSTOM 0x00
BALANCED_USTT 0xA0
BALANCED_PERFORMANCE_USTT 0xA1
COOL_USTT 0xA2
QUIET_USTT 0xA3
PERFORMANCE_USTT 0xA4
LOW_POWER_USTT 0xA5
QUIET 0x96
BALANCED 0x97
BALANCED_PERFORMANCE 0x98
PERFORMANCE 0x99
GMODE 0xAB
Usually if a model doesn't support the first four profiles they will support
the User Selectable Thermal Tables (USTT) profiles and vice-versa.
GMODE replaces PERFORMANCE in G-Series laptops.
WMI method GameShiftStatus([in] uint32 arg2, [out] uint32 argr)
---------------------------------------------------------------
::
if BYTE_0(arg2) == 0x1:
TOGGLE_GAME_SHIFT()
argr = GET_GAME_SHIFT_STATUS()
if BYTE_0(arg2) == 0x2:
argr = GET_GAME_SHIFT_STATUS()
Game Shift Status does not change the fan speed profile but it could be some
sort of CPU/GPU power profile. Benchmarks have not been done.
This method is only present on Dell's G-Series laptops and it's implementation
implies GMODE thermal profile is available, even if operation 0x03 of
Thermal_Information does not list it.
G-key on Dell's G-Series laptops also changes Game Shift status, so both are
directly related.
WMI method GetFanSensors([in] uint32 arg2, [out] uint32 argr)
-------------------------------------------------------------
::
if BYTE_0(arg2) == 0x1:
if is_valid_fan(BYTE_1(arg2)):
argr = 1
else:
argr = 0
if BYTE_0(arg2) == 0x2:
if is_valid_fan(BYTE_1(arg2)):
if BYTE_2(arg2) == 0:
argr == SENSOR_ID
else
argr == 0xFFFFFFFF
else:
argr = 0
Overclocking Methods
====================
.. warning::
These methods have not been tested and are only partially reverse
engineered.
WMI method Return_OverclockingReport([out] uint32 argr)
-------------------------------------------------------
::
CSMI (0xE3, 0x99)
argr = 0
CSMI is an unknown operation.
WMI method Set_OCUIBIOSControl([in] uint32 arg2, [out] uint32 argr)
-------------------------------------------------------------------
::
CSMI (0xE3, 0x99)
argr = 0
CSMI is an unknown operation.
WMI method Clear_OCFailSafeFlag([out] uint32 argr)
--------------------------------------------------
::
CSMI (0xE3, 0x99)
argr = 0
CSMI is an unknown operation.
WMI method MemoryOCControl([in] uint32 arg2, [out] uint32 argr)
---------------------------------------------------------------
AWCC supports memory overclocking, but this method is very intricate and has
not been deciphered yet.
GPIO methods
============
These methods are probably related to some kind of firmware update system,
through a GPIO device.
.. warning::
These methods have not been tested and are only partially reverse
engineered.
WMI method FWUpdateGPIOtoggle([in] uint32 arg2, [out] uint32 argr)
------------------------------------------------------------------
::
if BYTE_0(arg2) == 0:
if BYTE_1(arg2) == 1:
SET_PIN_A_HIGH()
else:
SET_PIN_A_LOW()
if BYTE_0(arg2) == 1:
if BYTE_1(arg2) == 1:
SET_PIN_B_HIGH()
else:
SET_PIN_B_LOW()
else:
argr = 1
WMI method ReadTotalofGPIOs([out] uint32 argr)
----------------------------------------------
::
argr = 0x02
WMI method ReadGPIOpPinStatus([in] uint32 arg2, [out] uint32 argr)
------------------------------------------------------------------
::
if BYTE_0(arg2) == 0:
argr = PIN_A_STATUS
if BYTE_0(arg2) == 1:
argr = PIN_B_STATUS
Other information Methods
=========================
WMI method ReadChassisColor([out] uint32 argr)
----------------------------------------------
::
argr = CHASSIS_COLOR_ID
Acknowledgements
================
Kudos to `AlexIII <https://github.com/AlexIII/tcc-g15>`_ for documenting
and testing available thermal profile codes.