linux驅動-裝置樹
裝置樹
-小白總結,謹慎參考
裝置樹是從軟體的角度描述硬體,DTS是裝置樹原始檔。DTC是負責將DTS轉換成DTB,DTB是DTS的二進位制形式,供機器使用。
裝置樹,首先是一個樹形結構,除了根節點外其他子節點都有唯一的父節點,節點下可以有子節點和屬性。屬性由名字和值組成。裝置樹僅僅是軟體開發人員為了描述硬體而做的一個近似標識而已。系統中的每個裝置都對應著裝置樹的一個節點。
基於platform匯流排的驅動分析:
在裝置驅動模型中,匯流排負責將裝置和驅動繫結。在系統每註冊一個裝置的時候,會尋找與之匹配的驅動;相反的,在系統每註冊一個驅動的時候,會尋找與之匹配的裝置,而匹配由匯流排完成。
1.Platform匯流排驅動的工作流程:
1.提供並註冊platform_device/裝置節點
2.提供並註冊platform_driver
3.當platform匯流排內的mach函式會不停的匹配driver和device(老核心是根據driver內的id、name元素;新核心是根據of_match_table中的compatible)
4.一旦匹配成功,則呼叫driver的probe(探測)函式開始正式執行驅動程式碼
2. platform匯流排驅動的獨立性和適應性
一個platform匯流排驅動程式可以對應多個裝置,並且裝置的變化也不會影響驅動。這是如何實現的呢?
簡單的說,這是一種類似傳參的機制。裝置將底層資訊(比如暫存器資訊、使用到的中斷號、裝置名稱等)傳遞給驅動,驅動本身程式碼不用變,只需要根據引數操作底層,便可適應裝置的變化
現代驅動設計理念就是演算法和資料分離,驅動原始碼中不攜帶資料,只負責演算法(對硬體的操作方法),這樣最大程度保持驅動的獨立性和適應性
具體的實現方法是:老核心中,platform_device包含了一個device結構體,其內部有一個void *platform_data; 使用者可以在裡面存放各種底層資訊。當driver的probe(探測)函式執行時,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版本之後的核心,platform、i2c、spi等裝置不再需要在mach-xxx中註冊,驅動程式將直接和裝置樹裡面的裝置節點進行匹配,是通過裝置節點中的compatible (相容性)來與裝置節點進行匹配的。
常見屬性的設定和獲取:
當修改或編寫驅動時,常常需要修改gpio、時鐘、中斷等等引數,以前都是在mach-xxx中的device設定的,現在則要在節點裡設定,然後驅動用特殊的API來獲取
屬性的獲取常常在probe函式中進行,但是獲取屬性之前,最重要的是,確定哪個節點觸發了驅動。如果一個驅動對應多個節點,那驅動可以通過
int of_device_is_compatible(const struct device_node *device, const char *name)來判斷當前節點是否包含指定的compatible(相容性)