![]() 在platform_device部分有簡單說明描述設備有兩種方法:一種是使用platform_device結構體來指定;另一種是使用設備樹來描述。 本篇筆記我們就來簡單地學習一下設備樹的一些知識。 什么是設備樹
設備樹簡單理解就是描述設備信息(資源)的一棵樹。設備樹(Device Tree)用代碼體現(xiàn)如下:
這些代碼被保存在.dts/dtsi后綴文件中,也即設備樹源文件 DTS(DeviceTree Source)。 這些源文件同我們的C代碼一樣,并不能直接使用的,而是得經過一個編譯過程生成機器可運行的二進制文件,如:
dts文件使用dtc工具編譯生成dtb文件,這個dtb文件就是內核可以使用的文件。例如我們的板子跑起來之后,我們系統(tǒng)使用的設備樹文件就存在目錄/boot下:
Linux為什么會引入設備樹? 在上一個實驗:【Linux筆記】LED驅動實驗(總線設備驅動模型)中我們使用了platform_device結構體來描述led設備(硬件資源)。既然已經有了描述設備的方法了,為什么還要引入設備樹呢? 因為Linux內核中有很多BSP(板級支持包),不同的BSP會包含著不同的描述設備的代碼(.c或.h文件)。 隨著芯片的發(fā)展,Linux內核中就包含著越來越多這些描述設備的代碼,導致Linux內核代碼會很臃腫。 這導致Linux之父Linus 大發(fā)雷霆:'this whole ARM thing is a f*cking pain in the ass'。 因此引入了設備樹文件,從而可精簡一些臃腫的C代碼。除此之外,.dts編譯生成.dtb文件的過程要比.c編譯生成驅動模塊、加載驅動模塊的過程要簡單很多,也更方便我們進行開發(fā)。 設備樹的語法 設備樹源文件也是需要根據一定規(guī)則來編寫的,同C語言一樣,也要遵循一些語法規(guī)則。下面簡單看一下設備樹的源碼結構及語法。
1、節(jié)點格式 label: node-name@unit-address
clock-frequency = <0x00000001 0x00000000>;
local-mac-address = [00 00 12 34 56 78]; // 每個byte使用2個16進制數來表示
“compatible”表示“兼容”,對于某個LED,內核中可能有A、B、C三個驅動都支持它,那可以這樣寫: led { model屬性與compatible屬性有些類似,但是有差別。compatible屬性是一個字符串列表,表示可以你的硬件兼容A、B、C等驅動;model用來準確地定義這個硬件是什么。 比如根節(jié)點中可以這樣寫: 從compatible屬性中可以知道它兼容哪些板,但是它到底是什么板?用model屬性來明確。 status 屬性看名字就知道是和設備狀態(tài)有關的, status 屬性值也是字符串,字符串是設備的狀態(tài)信息,可選的狀態(tài)如下所示:
格式: address-cells:address要用多少個32位數來表示; 下例中,address-cells為1,所以reg中用1個數來表示地址,即用0x80000000來表示地址;size-cells為1,所以reg中用1個數來表示大小,即用0x20000000表示大?。?/p> reg屬性的值,是一系列的“address size”,用多少個32位的數來表示address和size,由其父節(jié)點的# address-cells、#size-cells決定。示例: /dts-v1/; 過時了,建議不用。它的值是字符串,用來表示節(jié)點的名字。在跟platform_driver匹配時,優(yōu)先級最低。compatible屬性在匹配過程中,優(yōu)先級最高。 過時了,建議不用。它的值是字符串,用來表示節(jié)點的類型。在跟platform_driver匹配時,優(yōu)先級為中。compatible屬性在匹配過程中,優(yōu)先級最高。 用 / 標識根節(jié)點,如: 一般不需要我們設置,在 dtsi 文件中都定義好了,如: cpus { 芯片廠家不可能事先確定你的板子使用多大的內存,所以 memory 節(jié)點需要板廠設置,比如: 我們可以通過設備樹文件給內核傳入一些參數,這要在chosen節(jié)點中設置bootargs屬性: chosen { 操作設備樹的函數 Linux 內核給我們提供了一系列的函數來獲取設備樹中的節(jié)點或者屬性信息,這一系列的函數都有一個統(tǒng)一的前綴“of_”(“open firmware”即開放固件。),所以在很多資料里面也被叫做 OF 函數。
與查找節(jié)點有關的 OF 函數有 5 個: of_find_node_by_name 函數通過節(jié)點名字查找指定的節(jié)點,函數原型如下: of_find_node_by_type 函數通過 device_type 屬性查找指定的節(jié)點,函數原型如下: struct device_node *of_find_node_by_type(struct device_node *from, const char *type);of_find_compatible_node 函數根據 device_type 和 compatible 這兩個屬性查找指定的節(jié)點,函數原型如下: of_find_matching_node_and_match 函數通過 of_device_id 匹配表來查找指定的節(jié)點,函數原型如下: struct device_node *of_find_matching_node_and_match(struct device_node *from,const struct of_device_id *matches,const struct of_device_id **match);of_find_node_by_path 函數通過路徑來查找指定的節(jié)點,函數原型如下:
of_find_property 函數用于查找指定的屬性,函數原型如下: property *of_find_property(const struct device_node *np,const char *name,int *lenp);of_property_count_elems_of_size 函數用于獲取屬性中元素的數量,比如 reg 屬性值是一個數組,那么使用此函數可以獲取到這個數組的大小,此函數原型如下:
of_property_read_string 函數用于讀取屬性中字符串值,函數原型如下: int of_property_read_string(struct device_node *np,const char *propname,const char **out_string) |
|
|
來自: mynotebook > 《待分類》