1. 程式人生 > >linux驅動-裝置樹

linux驅動-裝置樹

裝置樹

-小白總結,謹慎參考

裝置樹是從軟體的角度描述硬體,DTS是裝置樹原始檔。DTC是負責將DTS轉換成DTB,DTBDTS的二進位制形式,供機器使用。

裝置樹,首先是一個樹形結構,除了根節點外其他子節點都有唯一的父節點,節點下可以有子節點屬性。屬性由名字組成。裝置樹僅僅是軟體開發人員為了描述硬體而做的一個近似標識而已。系統中的每個裝置都對應著裝置樹的一個節點

基於platform匯流排的驅動分析:
在裝置驅動模型中,匯流排負責將裝置和驅動繫結。在系統每註冊一個裝置的時候,會尋找與之匹配的驅動;相反的,在系統每註冊一個驅動的時候,會尋找與之匹配的裝置,而匹配由匯流排完成。

1.Platform匯流排驅動的工作流程:

1.提供並註冊platform_device/裝置節點

2.提供並註冊platform_driver

3.platform匯流排內的mach函式會不停的匹配driverdevice(老核心是根據driver內的idname元素;新核心是根據of_match_table中的compatible

4.一旦匹配成功,則呼叫driverprobe(探測)函式開始正式執行驅動程式碼

2. platform匯流排驅動的獨立性和適應性

一個platform匯流排驅動程式可以對應多個裝置,並且裝置的變化也不會影響驅動。這是如何實現的呢?

簡單的說,這是一種類似傳參的機制。裝置將底層資訊(比如暫存器資訊、使用到的中斷號、裝置名稱等)傳遞給驅動,驅動本身程式碼不用變,只需要根據引數操作底層,便可適應裝置的變化

現代驅動設計理念就是演算法和資料分離,驅動原始碼中不攜帶資料,只負責演算法(對硬體的操作方法),這樣最大程度保持驅動的獨立性和適應性

具體的實現方法是:老核心中,platform_device包含了一個device結構體,其內部有一個void *platform_data; 使用者可以在裡面存放各種底層資訊。當driverprobe(探測)函式執行時,platform_device會作為引數傳進去,這樣驅動就能夠間接的得到這個void *platform_data,從而據此操作硬體;新核心則直接在裝置節點屬性中存放資料,驅動通過API讀取節點裡的資料:

老版本設備註冊:

 

驅動編寫:

 

紅線部分:引數資訊傳遞到驅動

3.新核心下的匯流排驅動:裝置樹


對於驅動本身來說,主要是platform裝置不再需要在mach-xxx中註冊,而是直接以節點形式定義在裝置樹中。platform裝置可以直接定義在dts的根節點內。

驅動程式將直接和裝置樹裡的裝置節點進行配對,是通過裝置節點中的compatible(相容性)來與裝置節點進行配對的。具體方法是定義一個of_match_table,只要裡面的compatible與裝置節點裡的compatible相同,那麼就觸發probe函式

有關裝置的私有資料,新核心不再使用plat_data了,而是直接在節點中定義各種屬性,然後在驅動中用特定的API獲取,詳見裝置樹詳解

4.裝置樹結構:

基本構造:

{}包圍起來的結構稱之為節點,dts中最開頭的/ {},稱為根節點。節點的標準結構[email protected]{}xxx是節點的名字,

yyy則不是必須的,其值為節點的地址(暫存器地址或其他地址),比如i2c1:[email protected]中的就是一個i2c控制器的暫存器基地址,

rtc: [email protected]中的就是這個rtc裝置的i2c地址

屬性:地址:

有關節點的地址,比如[email protected],雖然它在名字後面跟了地址,但是正式的設定是在reg屬性中設定的

比如:reg = <0x021a0000 0x4000>; reg的格式通常為<address length>0x021a0000是暫存器基地址,0x4000是長度。

屬性:相容性:

如果一個節點是裝置節點,那麼它一定要有compatible(相容性),因為這將作為 驅動和裝置(裝置節點)的匹配依據,compatible(相容性)的值可以有不止一個字元串以滿足不同的需求,系統啟動後,將根據根節點的compatible來判斷cpu資訊,並由 此進行初始化

核心與節點的匹配:

首先,核心需要知道dtb檔案的地址,這是uboot告訴核心的,核心知曉dtb的文件地址後,那麼驅動就可以通過一些API任意獲取裝置樹的內部資訊

對於3.x版本之後的核心,platformi2cspi等裝置不再需要在mach-xxx中註冊,驅動程式將直接和裝置樹裡面的裝置節點進行匹配,是通過裝置節點中的compatible (相容性)來與裝置節點進行匹配的。

常見屬性的設定和獲取:

當修改或編寫驅動時,常常需要修改gpio、時鐘、中斷等等引數,以前都是在mach-xxx中的device設定的,現在則要在節點裡設定,然後驅動用特殊的API來獲取

屬性的獲取常常在probe函式中進行,但是獲取屬性之前,最重要的是,確定哪個節點觸發了驅動。如果一個驅動對應多個節點,那驅動可以通過

int of_device_is_compatible(const struct device_node *device, const char *name)來判斷當前節點是否包含指定的compatible(相容性)