2. Dell DDV WMI 接口驱动 (dell-wmi-ddv)¶
2.1. 简介¶
许多在 2020 年之后生产的戴尔笔记本电脑支持基于 WMI 的接口,用于检索各种系统数据,如电池温度、ePPID、诊断数据和风扇/热传感器数据。
此接口很可能被 Windows 上的 Dell Data Vault 软件使用,因此被称为 DDV。目前,dell-wmi-ddv
驱动程序支持接口的第 2 版和第 3 版,并且可以轻松添加对新接口版本的支持。
警告
戴尔将此接口视为内部接口,因此没有可用的供应商文档。所有知识都是通过试错获得的,请记住这一点。
2.2. 戴尔 ePPID(电子零件标识)¶
戴尔 ePPID 用于唯一标识戴尔机器中的组件,包括电池。它的形式类似于 CC-PPPPPP-MMMMM-YMD-SSSS-FFF,包含以下信息
原产国代码 (CC)。
零件号,第一个字符为填充数字 (PPPPPP)。
制造商标识 (MMMMM)。
制造年份/月份/日期 (YMD),采用 36 进制,其中 Y 是年份的最后一位数字。
制造序列号 (SSSS)。
可选固件版本/修订版 (FFF)。
可以使用 eppidtool python 实用程序来解码和显示此信息。
有关戴尔 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 包,其中包含按相同顺序排列的输出
应彻底检查输出格式,因为许多方法在出现错误时可能会返回格式错误的数据。
许多与电池相关的方法的数据格式似乎基于 智能电池数据规范,因此未知的与电池相关的方法可能会以某种方式遵循此标准。
2.3.1. WMI 方法 GetBatteryDesignCapacity()¶
以 u16 形式返回电池的设计容量(以 mAh 为单位)。
2.3.2. WMI 方法 BatteryFullCharge()¶
以 u16 形式返回电池的满充电容量(以 mAh 为单位)。
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()¶
以 s16 形式返回电池的电流(以 mA 为单位)。负值表示放电。
2.3.9. WMI 方法 BatteryVoltage()¶
以 u16 形式返回电池的电压(以 mV 为单位)。
2.3.10. WMI 方法 BatteryManufactureAccess()¶
以 u16 形式返回制造商定义的值。
2.3.11. WMI 方法 BatteryRelativeStateOfCharge()¶
以 u16 形式返回电池容量的百分比。
2.3.12. WMI 方法 BatteryCycleCount()¶
以 u16 形式返回电池的循环次数。
2.3.13. WMI 方法 BatteryePPID()¶
以 ASCII 字符串形式返回电池的 ePPID。
2.3.14. WMI 方法 BatteryeRawAnalyticsStart()¶
执行电池分析并返回状态代码
0x0
:成功0x1
:不支持接口0xfffffffe
:错误/超时
注意
此方法的含义仍然很大程度上未知。
2.3.15. WMI 方法 BatteryeRawAnalytics()¶
返回一个缓冲区,通常包含 12 个分析数据块。这些块包含
以 0 开头的块号 (u8)
31 字节的未知数据
注意
此方法的含义仍然很大程度上未知。
2.3.16. WMI 方法 BatteryDesignVoltage()¶
以 u16 形式返回电池的设计电压(以 mV 为单位)。
2.3.17. WMI 方法 BatteryeRawAnalyticsABlock()¶
返回单个分析数据块,索引的第二个字节用于选择块号。
自 WMI 接口版本 3 起受支持!
注意
此方法的含义仍然很大程度上未知。
2.3.18. WMI 方法 ReturnVersion()¶
以 u32 形式返回 WMI 接口版本。
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 电池钩子机制来发现电池。
注意
驱动程序内部当前使用的 ACPI 电池匹配算法已过时,与上述算法不符。造成这种情况的原因是 Linux 和 Windows 之间对 ToHexString() ACPI 操作码的处理存在差异,这会扭曲许多机器上 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
驱动程序中。
有关更多信息,请参阅 报告问题。