1.. SPDX-License-Identifier: GPL-2.0-or-later
2
3============================================
4Dell DDV WMI interface driver (dell-wmi-ddv)
5============================================
6
7Introduction
8============
9
10Many Dell notebooks made after ~2020 support a WMI-based interface for
11retrieving various system data like battery temperature, ePPID, diagostic data
12and fan/thermal sensor data.
13
14This interface is likely used by the `Dell Data Vault` software on Windows,
15so it was called `DDV`. Currently the ``dell-wmi-ddv`` driver supports
16version 2 and 3 of the interface, with support for new interface versions
17easily added.
18
19.. warning:: The interface is regarded as internal by Dell, so no vendor
20             documentation is available. All knowledge was thus obtained by
21             trial-and-error, please keep that in mind.
22
23Dell ePPID (electronic Piece Part Identification)
24=================================================
25
26The Dell ePPID is used to uniquely identify components in Dell machines,
27including batteries. It has a form similar to `CC-PPPPPP-MMMMM-YMD-SSSS-FFF`
28and contains the following information:
29
30* Country code of origin (CC).
31* Part number with the first character being a filling number (PPPPPP).
32* Manufacture Identification (MMMMM).
33* Manufacturing Year/Month/Date (YMD) in base 36, with Y being the last digit
34  of the year.
35* Manufacture Sequence Number (SSSS).
36* Optional Firmware Version/Revision (FFF).
37
38The `eppidtool <https://pypi.org/project/eppidtool>`_ python utility can be used
39to decode and display this information.
40
41All information regarding the Dell ePPID was gathered using Dell support
42documentation and `this website <https://telcontar.net/KBK/Dell/date_codes>`_.
43
44WMI interface description
45=========================
46
47The WMI interface description can be decoded from the embedded binary MOF (bmof)
48data using the `bmfdec <https://github.com/pali/bmfdec>`_ utility:
49
50::
51
52 [WMI, Dynamic, Provider("WmiProv"), Locale("MS\\0x409"), Description("WMI Function"), guid("{8A42EA14-4F2A-FD45-6422-0087F7A7E608}")]
53 class DDVWmiMethodFunction {
54   [key, read] string InstanceName;
55   [read] boolean Active;
56
57   [WmiMethodId(1), Implemented, read, write, Description("Return Battery Design Capacity.")] void BatteryDesignCapacity([in] uint32 arg2, [out] uint32 argr);
58   [WmiMethodId(2), Implemented, read, write, Description("Return Battery Full Charge Capacity.")] void BatteryFullChargeCapacity([in] uint32 arg2, [out] uint32 argr);
59   [WmiMethodId(3), Implemented, read, write, Description("Return Battery Manufacture Name.")] void BatteryManufactureName([in] uint32 arg2, [out] string argr);
60   [WmiMethodId(4), Implemented, read, write, Description("Return Battery Manufacture Date.")] void BatteryManufactureDate([in] uint32 arg2, [out] uint32 argr);
61   [WmiMethodId(5), Implemented, read, write, Description("Return Battery Serial Number.")] void BatterySerialNumber([in] uint32 arg2, [out] uint32 argr);
62   [WmiMethodId(6), Implemented, read, write, Description("Return Battery Chemistry Value.")] void BatteryChemistryValue([in] uint32 arg2, [out] string argr);
63   [WmiMethodId(7), Implemented, read, write, Description("Return Battery Temperature.")] void BatteryTemperature([in] uint32 arg2, [out] uint32 argr);
64   [WmiMethodId(8), Implemented, read, write, Description("Return Battery Current.")] void BatteryCurrent([in] uint32 arg2, [out] uint32 argr);
65   [WmiMethodId(9), Implemented, read, write, Description("Return Battery Voltage.")] void BatteryVoltage([in] uint32 arg2, [out] uint32 argr);
66   [WmiMethodId(10), Implemented, read, write, Description("Return Battery Manufacture Access(MA code).")] void BatteryManufactureAceess([in] uint32 arg2, [out] uint32 argr);
67   [WmiMethodId(11), Implemented, read, write, Description("Return Battery Relative State-Of-Charge.")] void BatteryRelativeStateOfCharge([in] uint32 arg2, [out] uint32 argr);
68   [WmiMethodId(12), Implemented, read, write, Description("Return Battery Cycle Count")] void BatteryCycleCount([in] uint32 arg2, [out] uint32 argr);
69   [WmiMethodId(13), Implemented, read, write, Description("Return Battery ePPID")] void BatteryePPID([in] uint32 arg2, [out] string argr);
70   [WmiMethodId(14), Implemented, read, write, Description("Return Battery Raw Analytics Start")] void BatteryeRawAnalyticsStart([in] uint32 arg2, [out] uint32 argr);
71   [WmiMethodId(15), Implemented, read, write, Description("Return Battery Raw Analytics")] void BatteryeRawAnalytics([in] uint32 arg2, [out] uint32 RawSize, [out, WmiSizeIs("RawSize") : ToInstance] uint8 RawData[]);
72   [WmiMethodId(16), Implemented, read, write, Description("Return Battery Design Voltage.")] void BatteryDesignVoltage([in] uint32 arg2, [out] uint32 argr);
73   [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[]);
74   [WmiMethodId(18), Implemented, read, write, Description("Return Version.")] void ReturnVersion([in] uint32 arg2, [out] uint32 argr);
75   [WmiMethodId(32), Implemented, read, write, Description("Return Fan Sensor Information")] void FanSensorInformation([in] uint32 arg2, [out] uint32 RawSize, [out, WmiSizeIs("RawSize") : ToInstance] uint8 RawData[]);
76   [WmiMethodId(34), Implemented, read, write, Description("Return Thermal Sensor Information")] void ThermalSensorInformation([in] uint32 arg2, [out] uint32 RawSize, [out, WmiSizeIs("RawSize") : ToInstance] uint8 RawData[]);
77 };
78
79Each WMI method takes an ACPI buffer containing a 32-bit index as input argument,
80with the first 8 bit being used to specify the battery when using battery-related
81WMI methods. Other WMI methods may ignore this argument or interpret it
82differently. The WMI method output format varies:
83
84* if the function has only a single output, then an ACPI object
85  of the corresponding type is returned
86* if the function has multiple outputs, when an ACPI package
87  containing the outputs in the same order is returned
88
89The format of the output should be thoroughly checked, since many methods can
90return malformed data in case of an error.
91
92The data format of many battery-related methods seems to be based on the
93`Smart Battery Data Specification`, so unknown battery-related methods are
94likely to follow this standard in some way.
95
96WMI method GetBatteryDesignCapacity()
97-------------------------------------
98
99Returns the design capacity of the battery in mAh as an u16.
100
101WMI method BatteryFullCharge()
102------------------------------
103
104Returns the full charge capacity of the battery in mAh as an u16.
105
106WMI method BatteryManufactureName()
107-----------------------------------
108
109Returns the manufacture name of the battery as an ASCII string.
110
111WMI method BatteryManufactureDate()
112-----------------------------------
113
114Returns the manufacture date of the battery as an u16.
115The date is encoded in the following manner:
116
117- bits 0 to 4 contain the manufacture day.
118- bits 5 to 8 contain the manufacture month.
119- bits 9 to 15 contain the manufacture year biased by 1980.
120
121.. note::
122   The data format needs to be verified on more machines.
123
124WMI method BatterySerialNumber()
125--------------------------------
126
127Returns the serial number of the battery as an u16.
128
129WMI method BatteryChemistryValue()
130----------------------------------
131
132Returns the chemistry of the battery as an ASCII string.
133Known values are:
134
135- "Li-I" for Li-Ion
136
137WMI method BatteryTemperature()
138-------------------------------
139
140Returns the temperature of the battery in tenth degree kelvin as an u16.
141
142WMI method BatteryCurrent()
143---------------------------
144
145Returns the current flow of the battery in mA as an s16.
146Negative values indicate discharging.
147
148WMI method BatteryVoltage()
149---------------------------
150
151Returns the voltage flow of the battery in mV as an u16.
152
153WMI method BatteryManufactureAccess()
154-------------------------------------
155
156Returns a manufacture-defined value as an u16.
157
158WMI method BatteryRelativeStateOfCharge()
159-----------------------------------------
160
161Returns the capacity of the battery in percent as an u16.
162
163WMI method BatteryCycleCount()
164------------------------------
165
166Returns the cycle count of the battery as an u16.
167
168WMI method BatteryePPID()
169-------------------------
170
171Returns the ePPID of the battery as an ASCII string.
172
173WMI method BatteryeRawAnalyticsStart()
174--------------------------------------
175
176Performs an analysis of the battery and returns a status code:
177
178- ``0x0``: Success
179- ``0x1``: Interface not supported
180- ``0xfffffffe``: Error/Timeout
181
182.. note::
183   The meaning of this method is still largely unknown.
184
185WMI method BatteryeRawAnalytics()
186---------------------------------
187
188Returns a buffer usually containg 12 blocks of analytics data.
189Those blocks contain:
190- block number starting with 0 (u8)
191- 31 bytes of unknown data
192
193.. note::
194   The meaning of this method is still largely unknown.
195
196WMI method BatteryDesignVoltage()
197---------------------------------
198
199Returns the design voltage of the battery in mV as an u16.
200
201WMI method BatteryeRawAnalyticsABlock()
202---------------------------------------
203
204Returns a single block of analytics data, with the second byte
205of the index being used for selecting the block number.
206
207*Supported since WMI interface version 3!*
208
209.. note::
210   The meaning of this method is still largely unknown.
211
212WMI method ReturnVersion()
213--------------------------
214
215Returns the WMI interface version as an u32.
216
217WMI method FanSensorInformation()
218---------------------------------
219
220Returns a buffer containg fan sensor entries, terminated
221with a single ``0xff``.
222Those entries contain:
223
224- fan type (u8)
225- fan speed in RPM (little endian u16)
226
227WMI method ThermalSensorInformation()
228-------------------------------------
229
230Returns a buffer containing thermal sensor entries, terminated
231with a single ``0xff``.
232Those entries contain:
233
234- thermal type (u8)
235- current temperature (s8)
236- min. temperature (s8)
237- max. temperature (s8)
238- unknown field (u8)
239
240.. note::
241   TODO: Find out what the meaning of the last byte is.
242
243ACPI battery matching algorithm
244===============================
245
246The algorithm used to match ACPI batteries to indices is based on information
247which was found inside the logging messages of the OEM software.
248
249Basically for each new ACPI battery, the serial numbers of the batteries behind
250indices 1 till 3 are compared with the serial number of the ACPI battery.
251Since the serial number of the ACPI battery can either be encoded as a normal
252integer or as a hexadecimal value, both cases need to be checked. The first
253index with a matching serial number is then selected.
254
255A serial number of 0 indicates that the corresponding index is not associated
256with an actual battery, or that the associated battery is not present.
257
258Some machines like the Dell Inspiron 3505 only support a single battery and thus
259ignore the battery index. Because of this the driver depends on the ACPI battery
260hook mechanism to discover batteries.
261
262.. note::
263   The ACPI battery matching algorithm currently used inside the driver is
264   outdated and does not match the algorithm described above. The reasons for
265   this are differences in the handling of the ToHexString() ACPI opcode between
266   Linux and Windows, which distorts the serial number of ACPI batteries on many
267   machines. Until this issue is resolved, the driver cannot use the above
268   algorithm.
269
270Reverse-Engineering the DDV WMI interface
271=========================================
272
2731. Find a supported Dell notebook, usually made after ~2020.
2742. Dump the ACPI tables and search for the WMI device (usually called "ADDV").
2753. Decode the corresponding bmof data and look at the ASL code.
2764. Try to deduce the meaning of a certain WMI method by comparing the control
277   flow with other ACPI methods (_BIX or _BIF for battery related methods
278   for example).
2795. Use the built-in UEFI diagostics to view sensor types/values for fan/thermal
280   related methods (sometimes overwriting static ACPI data fields can be used
281   to test different sensor type values, since on some machines this data is
282   not reinitialized upon a warm reset).
283
284Alternatively:
285
2861. Load the ``dell-wmi-ddv`` driver, use the ``force`` module param
287   if necessary.
2882. Use the debugfs interface to access the raw fan/thermal sensor buffer data.
2893. Compare the data with the built-in UEFI diagnostics.
290
291In case the DDV WMI interface version available on your Dell notebook is not
292supported or you are seeing unknown fan/thermal sensors, please submit a
293bugreport on `bugzilla <https://bugzilla.kernel.org>`_ so they can be added
294to the ``dell-wmi-ddv`` driver.
295
296See Documentation/admin-guide/reporting-issues.rst for further information.
297