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中最開頭的/ {},稱爲根節點。節點的標準結構xxx@yyy{}xxx是節點的名字,

yyy則不是必須的,其值爲節點的地址(寄存器地址或其他地址),比如i2c1:i2c@021a0000中的就是一個i2c控制器的寄存器基地址,

rtc: pcf8523@68中的就是這個rtc設備的i2c地址

屬性:地址:

有關節點的地址,比如i2c@021a0000,雖然它在名字後面跟了地址,但是正式的設置是在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(兼容性)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章