Linux驱动程序的数据封装
引言
0
基于ARM內核的SoC在引入設備樹技術之后,通過設備樹文件來描述不同的設備并匹配不同的驅動代碼,使得一個kernel鏡像文件可以支持多種設備。這種代碼可重用的思想不僅體現在設備樹文件中,在驅動代碼中同樣也有所體現。其中之一就是驅動代碼中設備描述表-of_device_id。同一個IP集成到不同SoC或者根據應用場景激活不同功能,可以通過of_device_id這個數據結構來實現。
對于同一個IP集成到不同SoC的應用場景而言,其寄存器基地址以及時鐘等參數可能不同,但是IP功能基本一樣。那么可以通過of_device_id里的不同data條目獲取對應的參數信息。例如exynos的dsi IP,在不同版本的SoC中基地址不同,定義了5種SoC類型。在dsi probe時獲取其在SoC中的基地址。
下面驅動代碼表示該模塊需要支持多種不同時鐘頻率的初始化,可以定義一個of_device_id表,根據匹配到的設備信息為每一種時鐘提供獨立的初始化函數。由of_device_id_match_data獲取到不同的init_fn,按照不同的dev.of_node,執行return init_fn(np);
以上應用場景核心的數據結構是of_device_id,關鍵的處理函數是of_device_get_match_data(),當然,關于of_device_id的應用場景不僅僅限于上面說的這兩種。
數據結構of_device_id
1
of_device_id數據結構如下,定義在mod_devicetable.h中,組成也并不復雜。
1struct?of_device_id?{ 2????char????name[32]; 3????char????type[32]; 4????char????compatible[128]; 5????const?void?*data; 6};mod_devicetable.h這個文件最初并沒有of_device_id這個數據結構,該文件的歷史暫時也只能查到2005年的Linux-2.6.12-rc2
它的功能從最初的文件中也可以看到,主要是為PCI以及USB設備使用的,將設備的vendor ID、subsystem ID、class等信息提供給scripts/table2alias.c,當系統新插入一個PCI或USB設備時,用戶空間程序根據對應的vendor ID等信息來加載對應的驅動程序。
2005年7月Linux-2.6.13-rc2中提交了of_match_id這個數據結構的代碼。
???????? of_device_get_match_data()
2
函數原型位于drivers/of/device.c
1const?void?*of_device_get_match_data(2????const?struct?device?*dev)3{4????const?struct?of_device_id?*match;56????match?=?of_match_device(xxx);7????if?(!match)8????????return?NULL;9 10????return?match->data; 11} 12EXPORT_SYMBOL(of_device_get_match_data);這個函數的返回值類型可強制轉換成任何類型,取決于驅動程序中例化數據結構of_device_id data。當然,由于of_device_get_match_data的函數返回值類型決定了不做強制類型轉換,也不會有問題。
代碼中增加下面的內容,來追蹤of_device_get_match_data執行流程。
#定義of_device_id并完成例化
#在probe函數中增加獲取數據的代碼
執行結果顯示正確的獲取到了of_device_id各個成員例化的value值
#of_device_get_match_data()代碼流程
有幾種情況是無法獲取到數據的
##解析dtb之后未創建設備結點
##驅動代碼未實現of_device_id設備表
##of_device_id成員compatible、name、type的值和設備樹中定義的同
基于模塊加載的并且可以熱插拔的驅動程序,可以在系統啟動后查看設備表信息。以定位出未獲取到設備表信息的故障原因。
查看設備表信息
3
能夠查看到設備表信息的一個前置條件是在定義of_device_id的時候,要將該設備表通過MODULE_DEVICE_TABLE來進行聲明注冊,否則在用戶空間是看不到的。其定義在/include/linux/module.h中。type可以是of、usb、pci等,name為設備表的名字。
內核中scripts/mod/file2alias.c,用于將設備表導出到用戶空間modules.alias中,所以可以直接查看modules.alias文件。
也可以通過modinfo來查看ko文件符號信息
設備表的定義如下,代碼定義了name、type,那么設備樹里同樣也要定義:
刪除MODULE_DEVICE_TABLE,modules.alias里是沒有設備表信息的。
對于of_device_id而言,name、type、compatible添加的方法:
#USB設備表
#PCI設備表
對于這兩種類型的設備,導出的符號信息和普通設備也不一樣。
PCI設備導出到用戶空間的設備信息:
導出PCI設備信息的代碼
USB設備導出到用戶空間的設備信息:
導出USB設備信息的代碼
除了上面三種設備描述table之外,kernel還提供了很多種其他的設備描述表,定義在include/linux/mod_devicetable.h
mod_devicetable.h的commit log:
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/log/include/linux/mod_devicetable.h
推薦閱讀:
專輯|Linux文章匯總
專輯|程序人生
專輯|C語言
我的知識小密圈
關注公眾號,后臺回復「1024」獲取學習資料網盤鏈接。
歡迎點贊,關注,轉發,在看,您的每一次鼓勵,我都將銘記于心~
總結
以上是生活随笔為你收集整理的Linux驱动程序的数据封装的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: BROTHER 废墨清零教学
- 下一篇: 图解分析 Linux 网络包发送过程