🔍
B站相應的視屏教程:
📌 內核:博文+視頻 - 從靜態綁定驅動模型到現代設備模型
主題:深入解析設備模型的數據流與匹配機制 —— 以 i.MX8M 與樹莓派為例的實戰對比
在上一節中,我們從驅動框架的歷史演進出發,分析了早期的靜態綁定驅動模型及其局限性,并逐步過渡到現代 Linux 設備模型架構。本節將聚焦于設備模型運行時的數據結構與匹配流程,結合實際平臺(NXP i.MX8M 與 Raspberry Pi),從設備樹的編寫、設備注冊、驅動匹配、probe 調用等多個角度展開,理論與實戰融合講解設備模型的本質運作方式。
📘 第一部分:設備模型的本質問題 —— 驅動如何找到設備?
在設備模型中,驅動程序不再"直接控制硬件",而是等待系統提供設備信息,再由總線驅動匹配機制完成“驅動與設備的配對”,最終執行 probe()
。
因此,理解設備模型的核心本質,就是要搞清楚:
“驅動是怎么和設備匹配的?設備又是怎么被注冊到系統中的?”
我們將通過 i.MX8M 和 Raspberry Pi 兩個平臺,來回答這個問題。
📘 第二部分:設備節點的來源 —— 設備樹(Device Tree)
? 什么是設備樹?
設備樹(DTS)是一種用于描述硬件信息的數據結構,編譯為 DTB 后在內核啟動初期被解析,生成內核中的 struct device_node
樹形結構。內核隨后根據設備樹中的節點內容,注冊相應的 platform_device
。
📎 i.MX8M 示例(LCDIF3 控制器)
lcdif3: lcd-controller@32fc6000 {compatible = "fsl,imx8mp-lcdif1";reg = <0x32fc6000 0x10000>;interrupts = <GIC_SPI 5 IRQ_TYPE_LEVEL_HIGH>;clocks = <&clk IMX8MP_CLK_MEDIA_APB_ROOT>, ...;status = "okay";
};
📌 內核會根據 compatible
字符串創建一個 platform_device
,名字類似 lcdif3.32fc6000
。
📎 Raspberry Pi 示例(I2C 控制器)
i2c1: i2c@7e804000 {compatible = "brcm,bcm2835-i2c";reg = <0x7e804000 0x1000>;interrupts = <2 21>;clock-frequency = <100000>;status = "okay";
};
設備樹被內核解析后,注冊為 platform_device
,后續等待匹配合適的驅動。
📘 第三部分:驅動如何聲明匹配信息?
驅動需要提供一個 of_match_table
,用于告訴設備模型:“我支持哪些設備”。
static const struct of_device_id lcdifv3_dt_ids[] = {{ .compatible = "fsl,imx8mp-lcdif1" },{ }
};
MODULE_DEVICE_TABLE(of, lcdifv3_dt_ids);static struct platform_driver lcdifv3_driver = {.probe = lcdifv3_probe,.remove = lcdifv3_remove,.driver = {.name = "imx-lcdifv3",.of_match_table = lcdifv3_dt_ids,},
};
🔍 注意:只有匹配成功,probe 才會被調用。
📘 第四部分:匹配過程是如何完成的?
? 匹配的參與者:
組件 | 數據結構 |
---|---|
設備 | struct platform_device |
驅動 | struct platform_driver |
匹配規則 | struct of_device_id[] |
總線中轉調度器 | struct bus_type |
? 匹配流程
- 設備樹解析階段,生成
platform_device
(如lcdif3
) - 驅動注冊時,添加到
platform_bus_type
的driver_list
- 內核自動遍歷設備與驅動,調用
bus_type->match()
- 匹配成功后:
- 設置
pdev->dev.driver = &driver
- 調用
driver->probe(pdev)
完成初始化
- 設置
📘 第五部分:數據結構流動分析(從 DTS 到 probe)
📌 流程圖:
DTS → of_node (設備樹節點)↓
of_platform_populate()↓
platform_device_register()↓
/sys/devices/platform/xxx ←→ /sys/bus/platform/devices/xxx↓
platform_bus_type.match()↓
platform_driver.probe()
📎 代碼對應點(以 LCDIF3 為例):
關鍵節點 | 對應代碼 |
---|---|
compatible = “fsl,imx8mp-lcdif1” | of_device_id 中匹配 |
reg/clocks 等資源 | of_address_to_resource() 等函數讀取 |
probe 中訪問資源 | platform_get_resource() / devm_ioremap_resource() |
📘 第六部分:i.MX8M vs 樹莓派平臺對比
對比維度 | NXP i.MX8M | Raspberry Pi |
---|---|---|
SoC 架構 | 多個 LCDIF 控制器 + VPU | Broadcom BCM283x |
DTS 中定義 | fsl,imx8mp-lcdif1 | brcm,bcm2835-i2c |
驅動模塊名 | imx-lcdifv3 | i2c-bcm2835 |
驅動結構 | 完整 platform_driver + match | 同樣采用 of_match_table 匹配 |
熱插拔支持 | 支持 runtime pm / suspend / resume | 同樣支持 PM、sysfs、modprobe 熱加載 |
📌 雖然 SoC 不同,但設備模型使用方式完全統一。
📘 第七部分:常見問題與調試技巧
? Q1: 為什么 probe 沒被調用?
- 沒有寫
of_match_table
compatible
寫錯,無法匹配- 驅動未被編譯進內核或未加載
status = "disabled"
導致設備未注冊
? Q2: 如何確認設備已注冊?
- 查看
/sys/bus/platform/devices/
- 使用
dmesg
檢查設備是否出現 - 加
dev_info()
等日志確認 probe 是否執行
? Q3: 如何查看匹配關系?
modinfo xxx.ko # 查看 compatible alias
ls /sys/bus/platform/drivers/xxx
📘 第八部分:實戰建議
- 永遠在驅動中寫上正確的
of_match_table
- 使用
devm_*
系列管理資源,避免內存泄漏 - 善用
dev_dbg()
、dev_err()
等接口打印調試信息 - 多觀察
/sys/
目錄,理解設備與驅動的 sysfs 映射關系 - 多平臺共享一個驅動時,合理利用
of_device_id.data
攜帶平臺定制參數
? 總結與回顧
本篇深入分析了設備模型中從 DTS → 設備注冊 → 驅動匹配 → probe 執行的完整過程。通過對比 i.MX8M 與樹莓派平臺,我們看到了設備模型在不同平臺間的通用性與強大抽象能力。
📌 核心關鍵詞:
- 設備樹注冊 → platform_device 創建
- 驅動注冊 → platform_driver with of_match_table
- 內核總線 → bus_type 匹配 → 調用 probe
這正是現代 Linux 驅動開發的標準范式。
下一篇我們將從 資源管理角度(時鐘、中斷、寄存器、GPIO)展開,講解 platform_get_resource()
、devm_*()
、of_property_read_*()
等函數在實際項目中的最佳使用方式。