mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/chenhuacai/linux-loongson
synced 2025-08-28 18:10:32 +00:00

The health of a given battery is exposed over the Dell DDV WMI interface using the "BatteryManufactureAceess" WMI method. The resulting data contains, among other data, the health status of the battery. Expose this value to userspace using the power supply extension interface. Tested on a Dell Inspiron 3505. Signed-off-by: Armin Wolf <W_Armin@gmx.de> Link: https://lore.kernel.org/r/20250429003606.303870-4-W_Armin@gmx.de Reviewed-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com> Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
320 lines
13 KiB
ReStructuredText
320 lines
13 KiB
ReStructuredText
.. SPDX-License-Identifier: GPL-2.0-or-later
|
|
|
|
============================================
|
|
Dell DDV WMI interface driver (dell-wmi-ddv)
|
|
============================================
|
|
|
|
Introduction
|
|
============
|
|
|
|
Many Dell notebooks made after ~2020 support a WMI-based interface for
|
|
retrieving various system data like battery temperature, ePPID, diagnostic data
|
|
and fan/thermal sensor data.
|
|
|
|
This interface is likely used by the `Dell Data Vault` software on Windows,
|
|
so it was called `DDV`. Currently the ``dell-wmi-ddv`` driver supports
|
|
version 2 and 3 of the interface, with support for new interface versions
|
|
easily added.
|
|
|
|
.. warning:: The interface is regarded as internal by Dell, so no vendor
|
|
documentation is available. All knowledge was thus obtained by
|
|
trial-and-error, please keep that in mind.
|
|
|
|
Dell ePPID (electronic Piece Part Identification)
|
|
=================================================
|
|
|
|
The Dell ePPID is used to uniquely identify components in Dell machines,
|
|
including batteries. It has a form similar to `CC-PPPPPP-MMMMM-YMD-SSSS-FFF`
|
|
and contains the following information:
|
|
|
|
* Country code of origin (CC).
|
|
* Part number with the first character being a filling number (PPPPPP).
|
|
* Manufacture Identification (MMMMM).
|
|
* Manufacturing Year/Month/Date (YMD) in base 36, with Y being the last digit
|
|
of the year.
|
|
* Manufacture Sequence Number (SSSS).
|
|
* Optional Firmware Version/Revision (FFF).
|
|
|
|
The `eppidtool <https://pypi.org/project/eppidtool>`_ python utility can be used
|
|
to decode and display this information.
|
|
|
|
All information regarding the Dell ePPID was gathered using Dell support
|
|
documentation and `this website <https://telcontar.net/KBK/Dell/date_codes>`_.
|
|
|
|
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("{8A42EA14-4F2A-FD45-6422-0087F7A7E608}")]
|
|
class DDVWmiMethodFunction {
|
|
[key, read] string InstanceName;
|
|
[read] boolean Active;
|
|
|
|
[WmiMethodId(1), Implemented, read, write, Description("Return Battery Design Capacity.")] void BatteryDesignCapacity([in] uint32 arg2, [out] uint32 argr);
|
|
[WmiMethodId(2), Implemented, read, write, Description("Return Battery Full Charge Capacity.")] void BatteryFullChargeCapacity([in] uint32 arg2, [out] uint32 argr);
|
|
[WmiMethodId(3), Implemented, read, write, Description("Return Battery Manufacture Name.")] void BatteryManufactureName([in] uint32 arg2, [out] string argr);
|
|
[WmiMethodId(4), Implemented, read, write, Description("Return Battery Manufacture Date.")] void BatteryManufactureDate([in] uint32 arg2, [out] uint32 argr);
|
|
[WmiMethodId(5), Implemented, read, write, Description("Return Battery Serial Number.")] void BatterySerialNumber([in] uint32 arg2, [out] uint32 argr);
|
|
[WmiMethodId(6), Implemented, read, write, Description("Return Battery Chemistry Value.")] void BatteryChemistryValue([in] uint32 arg2, [out] string argr);
|
|
[WmiMethodId(7), Implemented, read, write, Description("Return Battery Temperature.")] void BatteryTemperature([in] uint32 arg2, [out] uint32 argr);
|
|
[WmiMethodId(8), Implemented, read, write, Description("Return Battery Current.")] void BatteryCurrent([in] uint32 arg2, [out] uint32 argr);
|
|
[WmiMethodId(9), Implemented, read, write, Description("Return Battery Voltage.")] void BatteryVoltage([in] uint32 arg2, [out] uint32 argr);
|
|
[WmiMethodId(10), Implemented, read, write, Description("Return Battery Manufacture Access(MA code).")] void BatteryManufactureAceess([in] uint32 arg2, [out] uint32 argr);
|
|
[WmiMethodId(11), Implemented, read, write, Description("Return Battery Relative State-Of-Charge.")] void BatteryRelativeStateOfCharge([in] uint32 arg2, [out] uint32 argr);
|
|
[WmiMethodId(12), Implemented, read, write, Description("Return Battery Cycle Count")] void BatteryCycleCount([in] uint32 arg2, [out] uint32 argr);
|
|
[WmiMethodId(13), Implemented, read, write, Description("Return Battery ePPID")] void BatteryePPID([in] uint32 arg2, [out] string argr);
|
|
[WmiMethodId(14), Implemented, read, write, Description("Return Battery Raw Analytics Start")] void BatteryeRawAnalyticsStart([in] uint32 arg2, [out] uint32 argr);
|
|
[WmiMethodId(15), Implemented, read, write, Description("Return Battery Raw Analytics")] void BatteryeRawAnalytics([in] uint32 arg2, [out] uint32 RawSize, [out, WmiSizeIs("RawSize") : ToInstance] uint8 RawData[]);
|
|
[WmiMethodId(16), Implemented, read, write, Description("Return Battery Design Voltage.")] void BatteryDesignVoltage([in] uint32 arg2, [out] uint32 argr);
|
|
[WmiMethodId(17), Implemented, read, write, Description("Return Battery Raw Analytics A Block")] void BatteryeRawAnalyticsABlock([in] uint32 arg2, [out] uint32 RawSize, [out, WmiSizeIs("RawSize") : ToInstance] uint8 RawData[]);
|
|
[WmiMethodId(18), Implemented, read, write, Description("Return Version.")] void ReturnVersion([in] uint32 arg2, [out] uint32 argr);
|
|
[WmiMethodId(32), Implemented, read, write, Description("Return Fan Sensor Information")] void FanSensorInformation([in] uint32 arg2, [out] uint32 RawSize, [out, WmiSizeIs("RawSize") : ToInstance] uint8 RawData[]);
|
|
[WmiMethodId(34), Implemented, read, write, Description("Return Thermal Sensor Information")] void ThermalSensorInformation([in] uint32 arg2, [out] uint32 RawSize, [out, WmiSizeIs("RawSize") : ToInstance] uint8 RawData[]);
|
|
};
|
|
|
|
Each WMI method takes an ACPI buffer containing a 32-bit index as input argument,
|
|
with the first 8 bit being used to specify the battery when using battery-related
|
|
WMI methods. Other WMI methods may ignore this argument or interpret it
|
|
differently. The WMI method output format varies:
|
|
|
|
* if the function has only a single output, then an ACPI object
|
|
of the corresponding type is returned
|
|
* if the function has multiple outputs, when an ACPI package
|
|
containing the outputs in the same order is returned
|
|
|
|
The format of the output should be thoroughly checked, since many methods can
|
|
return malformed data in case of an error.
|
|
|
|
The data format of many battery-related methods seems to be based on the
|
|
`Smart Battery Data Specification`, so unknown battery-related methods are
|
|
likely to follow this standard in some way.
|
|
|
|
WMI method GetBatteryDesignCapacity()
|
|
-------------------------------------
|
|
|
|
Returns the design capacity of the battery in mAh as an u16.
|
|
|
|
WMI method BatteryFullCharge()
|
|
------------------------------
|
|
|
|
Returns the full charge capacity of the battery in mAh as an u16.
|
|
|
|
WMI method BatteryManufactureName()
|
|
-----------------------------------
|
|
|
|
Returns the manufacture name of the battery as an ASCII string.
|
|
|
|
WMI method BatteryManufactureDate()
|
|
-----------------------------------
|
|
|
|
Returns the manufacture date of the battery as an u16.
|
|
The date is encoded in the following manner:
|
|
|
|
- bits 0 to 4 contain the manufacture day.
|
|
- bits 5 to 8 contain the manufacture month.
|
|
- bits 9 to 15 contain the manufacture year biased by 1980.
|
|
|
|
WMI method BatterySerialNumber()
|
|
--------------------------------
|
|
|
|
Returns the serial number of the battery as an u16.
|
|
|
|
WMI method BatteryChemistryValue()
|
|
----------------------------------
|
|
|
|
Returns the chemistry of the battery as an ASCII string.
|
|
Known values are:
|
|
|
|
- "Li-I" for Li-Ion
|
|
|
|
WMI method BatteryTemperature()
|
|
-------------------------------
|
|
|
|
Returns the temperature of the battery in tenth degree kelvin as an u16.
|
|
|
|
WMI method BatteryCurrent()
|
|
---------------------------
|
|
|
|
Returns the current flow of the battery in mA as an s16.
|
|
Negative values indicate discharging.
|
|
|
|
WMI method BatteryVoltage()
|
|
---------------------------
|
|
|
|
Returns the voltage flow of the battery in mV as an u16.
|
|
|
|
WMI method BatteryManufactureAccess()
|
|
-------------------------------------
|
|
|
|
Returns the health status of the battery as a u16.
|
|
The health status encoded in the following manner:
|
|
|
|
- the third nibble contains the general failure mode
|
|
- the fourth nibble contains the specific failure code
|
|
|
|
Valid failure modes are:
|
|
|
|
- permanent failure (``0x9``)
|
|
- overheat failure (``0xa``)
|
|
- overcurrent failure (``0xb``)
|
|
|
|
All other failure modes are to be considered normal.
|
|
|
|
The following failure codes are valid for a permanent failure:
|
|
|
|
- fuse blown (``0x0``)
|
|
- cell imbalance (``0x1``)
|
|
- overvoltage (``0x2``)
|
|
- fet failure (``0x3``)
|
|
|
|
The last two bits of the failure code are to be ignored when the battery
|
|
signals a permanent failure.
|
|
|
|
The following failure codes a valid for a overheat failure:
|
|
|
|
- overheat at start of charging (``0x5``)
|
|
- overheat during charging (``0x7``)
|
|
- overheat during discharging (``0x8``)
|
|
|
|
The following failure codes are valid for a overcurrent failure:
|
|
|
|
- overcurrent during charging (``0x6``)
|
|
- overcurrent during discharging (``0xb``)
|
|
|
|
WMI method BatteryRelativeStateOfCharge()
|
|
-----------------------------------------
|
|
|
|
Returns the capacity of the battery in percent as an u16.
|
|
|
|
WMI method BatteryCycleCount()
|
|
------------------------------
|
|
|
|
Returns the cycle count of the battery as an u16.
|
|
|
|
WMI method BatteryePPID()
|
|
-------------------------
|
|
|
|
Returns the ePPID of the battery as an ASCII string.
|
|
|
|
WMI method BatteryeRawAnalyticsStart()
|
|
--------------------------------------
|
|
|
|
Performs an analysis of the battery and returns a status code:
|
|
|
|
- ``0x0``: Success
|
|
- ``0x1``: Interface not supported
|
|
- ``0xfffffffe``: Error/Timeout
|
|
|
|
.. note::
|
|
The meaning of this method is still largely unknown.
|
|
|
|
WMI method BatteryeRawAnalytics()
|
|
---------------------------------
|
|
|
|
Returns a buffer usually containing 12 blocks of analytics data.
|
|
Those blocks contain:
|
|
|
|
- a block number starting with 0 (u8)
|
|
- 31 bytes of unknown data
|
|
|
|
.. note::
|
|
The meaning of this method is still largely unknown.
|
|
|
|
WMI method BatteryDesignVoltage()
|
|
---------------------------------
|
|
|
|
Returns the design voltage of the battery in mV as an u16.
|
|
|
|
WMI method BatteryeRawAnalyticsABlock()
|
|
---------------------------------------
|
|
|
|
Returns a single block of analytics data, with the second byte
|
|
of the index being used for selecting the block number.
|
|
|
|
*Supported since WMI interface version 3!*
|
|
|
|
.. note::
|
|
The meaning of this method is still largely unknown.
|
|
|
|
WMI method ReturnVersion()
|
|
--------------------------
|
|
|
|
Returns the WMI interface version as an u32.
|
|
|
|
WMI method FanSensorInformation()
|
|
---------------------------------
|
|
|
|
Returns a buffer containing fan sensor entries, terminated
|
|
with a single ``0xff``.
|
|
Those entries contain:
|
|
|
|
- fan type (u8)
|
|
- fan speed in RPM (little endian u16)
|
|
|
|
WMI method ThermalSensorInformation()
|
|
-------------------------------------
|
|
|
|
Returns a buffer containing thermal sensor entries, terminated
|
|
with a single ``0xff``.
|
|
Those entries contain:
|
|
|
|
- thermal type (u8)
|
|
- current temperature (s8)
|
|
- min. temperature (s8)
|
|
- max. temperature (s8)
|
|
- unknown field (u8)
|
|
|
|
.. note::
|
|
TODO: Find out what the meaning of the last byte is.
|
|
|
|
ACPI battery matching algorithm
|
|
===============================
|
|
|
|
The algorithm used to match ACPI batteries to indices is based on information
|
|
which was found inside the logging messages of the OEM software.
|
|
|
|
Basically for each new ACPI battery, the serial numbers of the batteries behind
|
|
indices 1 till 3 are compared with the serial number of the ACPI battery.
|
|
Since the serial number of the ACPI battery can either be encoded as a normal
|
|
integer or as a hexadecimal value, both cases need to be checked. The first
|
|
index with a matching serial number is then selected.
|
|
|
|
A serial number of 0 indicates that the corresponding index is not associated
|
|
with an actual battery, or that the associated battery is not present.
|
|
|
|
Some machines like the Dell Inspiron 3505 only support a single battery and thus
|
|
ignore the battery index. Because of this the driver depends on the ACPI battery
|
|
hook mechanism to discover batteries.
|
|
|
|
Reverse-Engineering the DDV WMI interface
|
|
=========================================
|
|
|
|
1. Find a supported Dell notebook, usually made after ~2020.
|
|
2. Dump the ACPI tables and search for the WMI device (usually called "ADDV").
|
|
3. Decode the corresponding bmof data and look at the ASL code.
|
|
4. Try to deduce the meaning of a certain WMI method by comparing the control
|
|
flow with other ACPI methods (_BIX or _BIF for battery related methods
|
|
for example).
|
|
5. Use the built-in UEFI diagnostics to view sensor types/values for fan/thermal
|
|
related methods (sometimes overwriting static ACPI data fields can be used
|
|
to test different sensor type values, since on some machines this data is
|
|
not reinitialized upon a warm reset).
|
|
|
|
Alternatively:
|
|
|
|
1. Load the ``dell-wmi-ddv`` driver, use the ``force`` module param
|
|
if necessary.
|
|
2. Use the debugfs interface to access the raw fan/thermal sensor buffer data.
|
|
3. Compare the data with the built-in UEFI diagnostics.
|
|
|
|
In case the DDV WMI interface version available on your Dell notebook is not
|
|
supported or you are seeing unknown fan/thermal sensors, please submit a
|
|
bugreport on `bugzilla <https://bugzilla.kernel.org>`_ so they can be added
|
|
to the ``dell-wmi-ddv`` driver.
|
|
|
|
See Documentation/admin-guide/reporting-issues.rst for further information.
|