0.引言
基于 ARM 內(nèi)核的 SoC 在引入設(shè)備樹技術(shù)之后,通過設(shè)備樹文件來描述不同的設(shè)備并匹配不同的驅(qū)動(dòng)代碼,使得一個(gè) kernel 鏡像文件可以支持多種設(shè)備。這種代碼可重用的思想不僅體現(xiàn)在設(shè)備樹文件中,在驅(qū)動(dòng)代碼中同樣也有所體現(xiàn)。
其中之一就是驅(qū)動(dòng)代碼中設(shè)備描述表-of_device_id。同一個(gè) IP 集成到不同 SoC 或者根據(jù)應(yīng)用場景激活不同功能,可以通過 of_device_id 這個(gè)數(shù)據(jù)結(jié)構(gòu)來實(shí)現(xiàn)。
對(duì)于同一個(gè) IP 集成到不同 SoC 的應(yīng)用場景而言,其寄存器基地址以及時(shí)鐘等參數(shù)可能不同,但是 IP 功能基本一樣。那么可以通過 of_device_id 里的不同 data 條目獲取對(duì)應(yīng)的參數(shù)信息。例如 exynos 的 dsi IP,在不同版本的 SoC 中基地址不同,定義了 5 種 SoC 類型。在 dsi probe 時(shí)獲取其在 SoC 中的基地址。
下面驅(qū)動(dòng)代碼表示該模塊需要支持多種不同時(shí)鐘頻率的初始化,可以定義一個(gè) of_device_id 表,根據(jù)匹配到的設(shè)備信息為每一種時(shí)鐘提供獨(dú)立的初始化函數(shù)。由 of_device_id_match_data 獲取到不同的 init_fn,按照不同的 dev.of_node,執(zhí)行 return init_fn(np);
以上應(yīng)用場景核心的數(shù)據(jù)結(jié)構(gòu)是 of_device_id,關(guān)鍵的處理函數(shù)是 of_device_get_match_data(),當(dāng)然,關(guān)于 of_device_id 的應(yīng)用場景不僅僅限于上面說的這兩種。
1.數(shù)據(jù)結(jié)構(gòu) of_device_id
of_device_id 數(shù)據(jù)結(jié)構(gòu)如下,定義在 mod_devicetable.h 中,組成也并不復(fù)雜。
1struct of_device_id {
2 char name[32];
3 char type[32];
4 char compatible[128];
5 const void *data;
6};
mod_devicetable.h 這個(gè)文件最初并沒有 of_device_id 這個(gè)數(shù)據(jù)結(jié)構(gòu),該文件的歷史暫時(shí)也只能查到 2005 年的 Linux-2.6.12-rc2
它的功能從最初的文件中也可以看到,主要是為 PCI 以及 USB 設(shè)備使用的,將設(shè)備的 vendor ID、subsystem ID、class 等信息提供給 scripts/table2alias.c,當(dāng)系統(tǒng)新插入一個(gè) PCI 或 USB 設(shè)備時(shí),用戶空間程序根據(jù)對(duì)應(yīng)的 vendor ID 等信息來加載對(duì)應(yīng)的驅(qū)動(dòng)程序。
2005 年 7 月 Linux-2.6.13-rc2 中提交了 of_match_id 這個(gè)數(shù)據(jù)結(jié)構(gòu)的代碼。
2.of_device_get_match_data()
函數(shù)原型位于 drivers/of/device.c
1const void *of_device_get_match_data(
2 const struct device *dev)
3{
4 const struct of_device_id *match;
5
6 match = of_match_device(xxx);
7 if (!match)
8 return NULL;
9
10 return match-》data;
11}
12EXPORT_SYMBOL(of_device_get_match_data);
這個(gè)函數(shù)的返回值類型可強(qiáng)制轉(zhuǎn)換成任何類型,取決于驅(qū)動(dòng)程序中例化數(shù)據(jù)結(jié)構(gòu) of_device_id data。當(dāng)然,由于 of_device_get_match_data 的函數(shù)返回值類型決定了不做強(qiáng)制類型轉(zhuǎn)換,也不會(huì)有問題。
代碼中增加下面的內(nèi)容,來追蹤 of_device_get_match_data 執(zhí)行流程。
#定義 of_device_id 并完成例化
#在 probe 函數(shù)中增加獲取數(shù)據(jù)的代碼
執(zhí)行結(jié)果顯示正確的獲取到了 of_device_id 各個(gè)成員例化的 value 值
#of_device_get_match_data() 代碼流程
有幾種情況是無法獲取到數(shù)據(jù)的
解析 dtb 之后未創(chuàng)建設(shè)備結(jié)點(diǎn)
驅(qū)動(dòng)代碼未實(shí)現(xiàn) of_device_id 設(shè)備表
of_device_id 成員 compatible、name、type 的值和設(shè)備樹中定義的同
基于模塊加載的并且可以熱插拔的驅(qū)動(dòng)程序,可以在系統(tǒng)啟動(dòng)后查看設(shè)備表信息。以定位出未獲取到設(shè)備表信息的故障原因。
3.查看設(shè)備表信息
能夠查看到設(shè)備表信息的一個(gè)前置條件是在定義 of_device_id 的時(shí)候,要將該設(shè)備表通過 MODULE_DEVICE_TABLE 來進(jìn)行聲明注冊(cè),否則在用戶空間是看不到的。其定義在/include/linux/module.h 中。type 可以是 of、usb、pci 等,name 為設(shè)備表的名字。
內(nèi)核中 scripts/mod/file2alias.c,用于將設(shè)備表導(dǎo)出到用戶空間 modules.alias 中,所以可以直接查看 modules.alias 文件。
也可以通過 modinfo 來查看 ko 文件符號(hào)信息!
設(shè)備表的定義如下,代碼定義了 name、type,那么設(shè)備樹里同樣也要定義:
刪除 MODULE_DEVICE_TABLE,modules.alias 里是沒有設(shè)備表信息的。
對(duì)于 of_device_id 而言,name、type、compatible 添加的方法:
#USB 設(shè)備表
1struct usb_device_id {
2 /* which fields to match against? */
3 __u16 match_flags;
4
5 /* Used for product specific matches; range is inclusive */
6 __u16 idVendor;
7 __u16 idProduct;
8 __u16 bcdDevice_lo;
9 __u16 bcdDevice_hi;
10
11 /* Used for device class matches */
12 __u8 bDeviceClass;
13 __u8 bDeviceSubClass;
14 __u8 bDeviceProtocol;
15
16 /* Used for interface class matches */
17 __u8 bInterfaceClass;
18 __u8 bInterfaceSubClass;
19 __u8 bInterfaceProtocol;
20
21 /* Used for vendor-specific interface matches */
22 __u8 bInterfaceNumber;
23
24 /* not matched against */
25 kernel_ulong_t driver_info
26 __attribute__((aligned(sizeof(kernel_ulong_t))));
27};
#PCI 設(shè)備表
1struct pci_device_id {
2 __u32 vendor, device; /* Vendor and device ID or PCI_ANY_ID*/
3 __u32 subvendor, subdevice; /* Subsystem ID‘s or PCI_ANY_ID */
4 __u32 class, class_mask; /* (class,subclass,prog-if) triplet */
5 kernel_ulong_t driver_data; /* Data private to the driver */
6};
對(duì)于這兩種類型的設(shè)備,導(dǎo)出的符號(hào)信息和普通設(shè)備也不一樣。
PCI 設(shè)備導(dǎo)出到用戶空間的設(shè)備信息:
導(dǎo)出 PCI 設(shè)備信息的代碼
USB 設(shè)備導(dǎo)出到用戶空間的設(shè)備信息:
導(dǎo)出 USB 設(shè)備信息的代碼
除了上面三種設(shè)備描述 table 之外,kernel 還提供了很多種其他的設(shè)備描述表,定義在 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
編輯:jq
-
ARM
+關(guān)注
關(guān)注
134文章
9347瀏覽量
377206 -
usb
+關(guān)注
關(guān)注
60文章
8175瀏覽量
272622 -
soc
+關(guān)注
關(guān)注
38文章
4385瀏覽量
222615 -
函數(shù)
+關(guān)注
關(guān)注
3文章
4379瀏覽量
64783
原文標(biāo)題:linux 驅(qū)動(dòng)程序的數(shù)據(jù)封裝
文章出處:【微信號(hào):gh_3980db2283cd,微信公眾號(hào):開關(guān)電源芯片】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
Linux環(huán)境再升級(jí):PLIN驅(qū)動(dòng)程序正式發(fā)布

RTC芯片有Linux PCA2131驅(qū)動(dòng)程序嗎?
適用于Oracle的ODBC驅(qū)動(dòng)程序
適用于Oracle的dbExpress驅(qū)動(dòng)程序

Linux驅(qū)動(dòng)程序程序員指南

pcie設(shè)備驅(qū)動(dòng)程序安裝步驟
Wilink8 Linux Wi-Fi驅(qū)動(dòng)程序R8.8版用戶指南

用于bq275xx電量計(jì)的WinCE/Linux驅(qū)動(dòng)程序

LSP 2.10 DaVinci Linux驅(qū)動(dòng)程序

評(píng)論