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 介面

  1. 找到一個受支援的戴爾筆記型電腦,通常是 2020 年之後生產的。

  2. 轉儲 ACPI 表並搜尋 WMI 裝置(通常稱為“ADDV”)。

  3. 解碼相應的 bmof 資料並檢視 ASL 程式碼。

  4. 嘗試透過將控制流與其他 ACPI 方法(例如電池相關方法的 _BIX 或 _BIF)進行比較來推斷特定 WMI 方法的含義。

  5. 使用內建的 UEFI 診斷程式檢視風扇/散熱相關方法的感測器型別/值(有時覆蓋靜態 ACPI 資料欄位可用於測試不同的感測器型別值,因為在某些機器上,此資料不會在熱重置時重新初始化)。

或者

  1. 載入 dell-wmi-ddv 驅動程式,如有必要,使用 force 模組引數。

  2. 使用 debugfs 介面訪問原始風扇/熱感測器緩衝區資料。

  3. 將資料與內建的 UEFI 診斷程式進行比較。

如果您的戴爾筆記型電腦上提供的 DDV WMI 介面版本不受支援,或者您看到未知的風扇/熱感測器,請在 bugzilla 上提交錯誤報告,以便可以將它們新增到 dell-wmi-ddv 驅動程式中。

有關更多資訊,請參見報告問題