Linux驅動之設備樹的基礎知識
前期知識
1. 如何編寫一個簡單的Linux驅動(一)——驅動的基本框架
2. 如何編寫一個簡單的Linux驅動(二)——設備操作集file_operations
3. 如何編寫一個簡單的Linux驅動(三)——完善設備驅動
前言
在前面的文章中,我們只介紹了如何對驅動和設備節點進行操作,並沒有涉及到對具體硬體設備的操作。從本篇開始,將介紹對硬體設備的操作。這裡,我們要引入一個新的概念——設備樹。
在學習Linux驅動時,我們一般會用到ARM開發板。ARM開發板的廠商有很多,我們熟知的有正點原子、迅為、友善之臂、天嵌等等。我們可以想像這樣一種場景,每家開發板廠商都自己開發板載設備的驅動,即使使用同一款處理器,但每款板子的廠商對於板載硬體的定義是不相同的,為了板載硬體能夠正常工作,每家廠商都會根據自己的板載硬體來設計不同於其他廠商的驅動,並將其提交到ARM社區,ARM社區再將它們添加到Linux內核。顯然,隨著使用Linux的設備越來越多,這些驅動就像是一層層的sh*t一樣,糊在Linux內核上,導致Linux內核越來越臃腫。
在幾年前,ARM社區真的是這麼做的,這就惹惱了大神Linus,於是Linus就給ARM社區來了套素質N連。於是,ARM社區學習了PowerPC的模式,把設備從內核中獨立出來,形成設備樹。
1.什麼是設備樹
設備樹是用來描述板級設備的文件,板子上所有的設備資訊都彙集在這一個文件中,如圖。

系統匯流排是設備樹的主幹;CAN控制器、GPIO控制器等是系統匯流排的分支;GPIOA、CAN1、IIC1是更進一步的分支;GPIOA1、AT24C02、MCP2515就是具體設備。這樣將設備按照類別組成一棵樹,就組成了一整棵設備樹。我們可以在系統的”proc/device-tree”目錄下看到系統的設備樹資訊。
2.DTS文件和DTSI文件
設備樹源文件一般包括兩種,dts文件和dtsi文件,dtsi文件是dts文件的頭文件,此外,dts文件還可以像C語言那樣包含.h格式的頭文件。就像下面這樣。
//這是一個dts文件
/dts-v1/; //這條語句必須有
#include "xxx.h" //像C語言一樣包含.h頭文件
#include "xxxx.dtsi" //包含dtsi頭文件
...
...
需要注意的是,在dts文件中,文件開始處的/dts-v1/;語句是必備的。可以看到,dts文件在包含頭文件方面和C語言十分相似,都使用#include。
dtsi文件一般用來描述較為通用的SOC級別的資訊,比如CPU資訊,外設控制器資訊、主頻資訊等等。而dts文件則用來描述具象化的外設資訊,例如要把GPIOA1用作按鍵,就需要在dts文件中進行描述。
3.設備樹源文件分析
3.1根節點和普通節點
/{}; 是根節點,其他的node_name{}; 是普通節點。當某個結點在多個關聯文件中都出現時,不會產生衝突,出現的後者會對前者作為補充;如果後者與前者有相同的屬性,則後者的屬性會覆蓋掉前者的屬性。
比如:在dtsi頭文件中有對adc的描述
adc: adc@126C0000 {
compatible = "samsung,exynos-adc-v1";
reg = <0x126C0000 0x100>;
interrupt-parent = <&combiner>;
interrupts = <10 3>;
clocks = <&clock CLK_TSADC>;
clock-names = "adc";
#io-channel-cells = <1>;
io-channel-ranges;
samsung,syscon-phandle = <&pmu_system_controller>;
status = "disabled"; //adc不工作
};
可以在dts文件中對adc描述進行追加
&adc {
/*vdd-supply = <&ldo3_reg>;*/
status = "okay"; //覆蓋頭文件中的status,使能adc
};
3.2特殊的設備節點
aliases節點:用於保存其他節點的別名。chosen節點:該節點並不是一個真的設備,它的主要功能是幫助uboot向內核傳遞數據,最主要的參數是bootargs參數。
3.3設備節點的命名
設備節點的命名方式有三種。
node-name{};; node-name是結點名稱。node-name@unit-address{};:unit-address是設備地址或暫存器首地址。label: node-name@unit-address{};:label是節點標籤,可以使用&label快捷地訪問節點。
3.4設備樹節點的標準屬性
- 根節點的
compatible屬性:用於標識設備樹能否與Linux內核匹配,該屬性值的一半格式為"廠商,板子名稱"。 - 普通節點的
compatible屬性:指兼容性。該屬性值的一般格式為"廠商,設備驅動名"。如果Linux內核中的匹配表中有與compatible屬性中的值相同的值,則該Linux內核可以使用該設備驅動。當驅動的兼容性資訊與設備樹的compatible屬性匹配後,會運行驅動程式碼里的probe函數。 status屬性:標識設備可用(「okay」)還是不可用(「disabled」)。當然也有其他的值。#address-cells和#size-cells屬性:用於標明該如何編寫reg屬性值。#address-cells用於標明reg屬性中address所佔字長數,size-cells用於標明length所佔的字長數。reg屬性:該屬性的格式一般為reg = <address,length, address,length,…>,address表示其實地址,length表示地址長度,一般用於記憶體中(也可以用於其他設備)。例:
#address-cells = <2>; //起始地址佔兩個字長
#size-cells = <1>; //地址長度佔一個字長
reg = <0x400080,0x600040,0x4000>; //表示0x400080和0x600040是起始地址,地址長度為0x4000
4. 驅動程式如何獲取設備樹資訊
Linux內核的"linux/of.h"文件中提供了一系列以of開頭的函數,其中包含了可以獲取設備樹資訊的函數。
5.DTS、DTB和DTC
dts是設備樹源文件的一種格式,dtb是設備樹文件編譯後形成的二進位文件的格式,dtc是用來編譯設備樹文件的編譯工具。


