裝置樹
-小白總結,謹慎參考
裝置樹是從軟體的角度描述硬體,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(相容性)