2. Dell DDV WMI 接口驱动 (dell-wmi-ddv)¶
2.1. 简介¶
许多 2020 年之后生产的戴尔笔记本电脑都支持基于 WMI 的接口,用于检索各种系统数据,如电池温度、ePPID、诊断数据和风扇/散热传感器数据。
该接口可能被 Windows 上的 Dell Data Vault 软件使用,因此被称为 DDV。目前 dell-wmi-ddv
驱动程序支持接口的第 2 版和第 3 版,并且可以轻松添加对新接口版本的支持。
警告
该接口被戴尔视为内部接口,因此没有可用的供应商文档。所有知识都是通过试错获得的,请记住这一点。
2.2. Dell ePPID(电子部件标识)¶
Dell ePPID 用于唯一标识戴尔机器中的组件,包括电池。它的形式类似于 CC-PPPPPP-MMMMM-YMD-SSSS-FFF 并包含以下信息
原产国家代码 (CC)。
部件号,第一个字符是填充数字 (PPPPPP)。
制造商标识 (MMMMM)。
生产年份/月份/日期 (YMD),以 36 进制表示,Y 是年份的最后一位数字。
生产序列号 (SSSS)。
可选的固件版本/修订版 (FFF)。
可以使用 eppidtool python 实用程序来解码和显示此信息。
所有关于 Dell ePPID 的信息都是使用戴尔支持文档和此网站收集的。
2.3. WMI 接口描述¶
可以使用 bmfdec 实用程序从嵌入式二进制 MOF (bmof) 数据中解码 WMI 接口描述
[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[]);
};
每个 WMI 方法都接受一个包含 32 位索引的 ACPI 缓冲区作为输入参数,当使用电池相关的 WMI 方法时,前 8 位用于指定电池。其他 WMI 方法可能会忽略此参数或以不同的方式解释它。WMI 方法输出格式各不相同
如果该函数只有一个输出,则返回相应类型的 ACPI 对象
如果该函数有多个输出,则返回一个包含相同顺序输出的 ACPI 包
应彻底检查输出的格式,因为在发生错误的情况下,许多方法可能会返回格式错误的数据。
许多电池相关方法的数据格式似乎基于 Smart Battery Data Specification,因此未知的电池相关方法很可能以某种方式遵循此标准。
2.3.1. WMI 方法 GetBatteryDesignCapacity()¶
以 mAh 为单位返回电池的设计容量,作为 u16。
2.3.2. WMI 方法 BatteryFullCharge()¶
以 mAh 为单位返回电池的充满容量,作为 u16。
2.3.3. WMI 方法 BatteryManufactureName()¶
返回电池的制造商名称,作为 ASCII 字符串。
2.3.4. WMI 方法 BatteryManufactureDate()¶
返回电池的生产日期,作为 u16。日期以以下方式编码
位 0 到 4 包含生产日。
位 5 到 8 包含生产月。
位 9 到 15 包含生产年份,偏差为 1980 年。
2.3.5. WMI 方法 BatterySerialNumber()¶
返回电池的序列号,作为 u16。
2.3.6. WMI 方法 BatteryChemistryValue()¶
返回电池的化学成分,作为 ASCII 字符串。已知的值是
“Li-I”表示锂离子
2.3.7. WMI 方法 BatteryTemperature()¶
以十分之一度开尔文为单位返回电池的温度,作为 u16。
2.3.8. WMI 方法 BatteryCurrent()¶
以 mA 为单位返回电池的电流,作为 s16。负值表示放电。
2.3.9. WMI 方法 BatteryVoltage()¶
以 mV 为单位返回电池的电压,作为 u16。
2.3.10. WMI 方法 BatteryManufactureAccess()¶
返回电池的健康状况,作为 u16。健康状况以以下方式编码
第三个半字节包含一般故障模式
第四个半字节包含特定故障代码
有效的故障模式是
永久性故障 (
0x9
)过热故障 (
0xa
)过电流故障 (
0xb
)
所有其他故障模式都被认为是正常的。
以下故障代码对永久性故障有效
保险丝熔断 (
0x0
)电池单元不平衡 (
0x1
)过电压 (
0x2
)fet 故障 (
0x3
)
当电池发出永久性故障信号时,应忽略故障代码的最后两位。
以下故障代码对过热故障有效
充电开始时过热 (
0x5
)充电期间过热 (
0x7
)放电期间过热 (
0x8
)
以下故障代码对过电流故障有效
充电期间过电流 (
0x6
)放电期间过电流 (
0xb
)
2.3.11. WMI 方法 BatteryRelativeStateOfCharge()¶
以百分比形式返回电池容量,作为 u16。
2.3.12. WMI 方法 BatteryCycleCount()¶
返回电池的循环计数,作为 u16。
2.3.13. WMI 方法 BatteryePPID()¶
返回电池的 ePPID,作为 ASCII 字符串。
2.3.14. WMI 方法 BatteryeRawAnalyticsStart()¶
执行电池分析并返回状态代码
0x0
: 成功0x1
: 不支持接口0xfffffffe
: 错误/超时
注意
此方法的含义仍然很大程度上未知。
2.3.15. WMI 方法 BatteryeRawAnalytics()¶
返回一个缓冲区,通常包含 12 个块的分析数据。这些块包含
一个从 0 开始的块号 (u8)
31 字节的未知数据
注意
此方法的含义仍然很大程度上未知。
2.3.16. WMI 方法 BatteryDesignVoltage()¶
以 mV 为单位返回电池的设计电压,作为 u16。
2.3.17. WMI 方法 BatteryeRawAnalyticsABlock()¶
返回一个分析数据块,索引的第二个字节用于选择块号。
自 WMI 接口版本 3 起支持!
注意
此方法的含义仍然很大程度上未知。
2.3.18. WMI 方法 ReturnVersion()¶
返回 WMI 接口版本,作为 u32。
2.3.19. WMI 方法 FanSensorInformation()¶
返回一个包含风扇传感器条目的缓冲区,以单个 0xff
结尾。这些条目包含
风扇类型 (u8)
风扇转速,单位为 RPM(小端 u16)
2.3.20. WMI 方法 ThermalSensorInformation()¶
返回一个包含热传感器条目的缓冲区,以单个 0xff
结尾。这些条目包含
热类型 (u8)
当前温度 (s8)
最低温度 (s8)
最高温度 (s8)
未知字段 (u8)
注意
TODO:找出最后一个字节的含义。
2.4. ACPI 电池匹配算法¶
用于将 ACPI 电池与索引匹配的算法基于 OEM 软件日志消息中找到的信息。
基本上,对于每个新的 ACPI 电池,索引 1 到 3 后的电池序列号都与 ACPI 电池的序列号进行比较。由于 ACPI 电池的序列号可以编码为普通整数或十六进制值,因此需要检查两种情况。然后选择第一个具有匹配序列号的索引。
序列号 0 表示相应的索引未与实际电池关联,或者关联的电池不存在。
某些机器(如戴尔 Inspiron 3505)仅支持单个电池,因此忽略电池索引。因此,驱动程序依赖于 ACPI 电池挂钩机制来发现电池。
2.5. 逆向工程 DDV WMI 接口¶
找到一个受支持的戴尔笔记本电脑,通常是 2020 年之后生产的。
转储 ACPI 表并搜索 WMI 设备(通常称为“ADDV”)。
解码相应的 bmof 数据并查看 ASL 代码。
尝试通过将控制流与其他 ACPI 方法(例如电池相关方法的 _BIX 或 _BIF)进行比较来推断特定 WMI 方法的含义。
使用内置的 UEFI 诊断程序查看风扇/散热相关方法的传感器类型/值(有时覆盖静态 ACPI 数据字段可用于测试不同的传感器类型值,因为在某些机器上,此数据不会在热重置时重新初始化)。
或者
加载
dell-wmi-ddv
驱动程序,如有必要,使用force
模块参数。使用 debugfs 接口访问原始风扇/热传感器缓冲区数据。
将数据与内置的 UEFI 诊断程序进行比较。
如果您的戴尔笔记本电脑上提供的 DDV WMI 接口版本不受支持,或者您看到未知的风扇/热传感器,请在 bugzilla 上提交错误报告,以便可以将它们添加到 dell-wmi-ddv
驱动程序中。
有关更多信息,请参见报告问题。