主頁 >  其他 > 嵌入式Linux開發19——Linux設備樹(萬字總結)

嵌入式Linux開發19——Linux設備樹(萬字總結)

2021-08-18 08:00:28 其他

??提示:本文參考《 Devicetree SpecificationV0.2.pdf 》、《Power_ePAPR_APPROVED_v1.12.pdf》、《IMX6UL參考手冊》以及正點原子的相關教程總結的學習筆記,萬字總結,水平有限,僅供參考,
??筆者偏嵌入式方向,故本文更多是關于實際開發中涉及的內容,

文章目錄

    • 設備樹的概念
    • DTS、 DTB 和 DTC
    • DTS語法
      • 1.dtsi頭檔案
      • 2.設備節點
      • 3.標準屬性
        • 3.1 compatible 屬性
        • 3.2 model屬性
        • 3.3 status 屬性
        • 3.4 #address-cells 和#size-cells 屬性
        • 3.5 reg 屬性
        • 3.6 ranges 屬性
      • 4.根節點compatible 屬性
    • 設備樹在系統中的體現
      • 1. 根節點“/”各個屬性
      • 2、根節點“/”各子節點
    • Linux 內核決議 DTB 檔案
    • 設備樹常用OF操作函式
      • 1. 查找節點的 OF 函式
        • 1.1 of_find_node_by_name 函式
        • 1.2 of_find_node_by_type 函式
        • 1.3 of_find_compatible_node 函式
        • 1.4 of_find_matching_node_and_match 函式
      • 2. 查找父/子節點的 OF 函式
        • 2.1 of_get_parent 函式
        • 2.2 of_get_next_child 函式
      • 3. 提取屬性值的 OF 函式
        • 3.1 of_find_property 函式
        • 3.2 of_property_count_elems_of_size 函式
        • 3.3 of_property_read_u32_index 函式
        • 3.4 of_property_read_u8_array 函式;of_property_read_u16_array 函式;of_property_read_u32_array 函式;of_property_read_u64_array 函式
        • 3.5 of_property_read_u8 函式;of_property_read_u16 函式;of_property_read_u32 函式;of_property_read_u64 函式
        • 3.6 of_property_read_string 函式
        • 3.7 of_n_addr_cells 函式
        • 3.8 of_n_size_cells 函式
      • 4. 其他常用的 OF 函式
        • 4.1 of_device_is_compatible 函式
        • 4.2 of_get_address 函式
        • 4.3 of_translate_address 函式
        • 4.4 of_address_to_resource 函式
        • 4.5 of_iomap 函式


設備樹的概念

??設備樹(Device Tree),將這個詞分開就是“設備”和“樹”,描述設備樹的檔案叫做 DTS(Device Tree Source),這個 DTS 檔案采用樹形結構描述板級設備,也就是開發板上的設備資訊,比如CPU 數量、 記憶體基地址、 IIC 介面上接了哪些設備、 SPI 介面上接了哪些設備等等,
??設備樹結構示意圖:
在這里插入圖片描述
??如圖所示,樹的主干就是系統總線, IIC 控制器、 GPIO 控制器、 SPI 控制器等都是接到系統主線上的分支,IIC 控制器有分為 IIC1 和 IIC2 兩種,其中 IIC1 上接了 FT5206 和 AT24C02這兩個 IIC 設備, IIC2 上只接了 MPU6050 這個設備, DTS 檔案的主要功能就是按照圖所示的結構來描述板子上的設備資訊,DTS 檔案描述設備資訊是有相應的語法規則要求的,稍后我們會詳細的講解 DTS 語法規則,
??隨著智能手機的發展,每年新出的 ARM 架構芯片少說都在數十、數百款, Linux 內核下板級資訊檔案將會成指數級增長!這些板級資訊檔案都是.c 或.h 檔案,都會被硬編碼進 Linux 內核中, 導致 Linux 內核“虛胖”,因此ARM 社區就引入了 PowerPC 等架構已經采用的設備樹(Flattened Device Tree),將這些描述板級硬體資訊的內容都從 Linux 內中分離開來,用一個專屬的檔案格式來描述,這個專屬的檔案就叫做設備樹,檔案擴展名為.dts, 一個 SOC 可以作出很多不同的板子,這些不同的板子肯定是有共同的資訊, 將這些共同的資訊提取出來作為一個通用的檔案,其他的.dts 檔案直接參考這個通用檔案即可,這個通用檔案就是.dtsi 檔案,類似于 C 語言中的頭檔案,一般.dts 描述板級資訊(也就是開發板上有哪些 IIC 設備、 SPI 設備等), .dtsi 描述 SOC 級資訊(也就是 SOC 有幾個 CPU、主頻是多少、各個外設控制器資訊等),

DTS、 DTB 和 DTC

??上一小節說了,設備樹源檔案擴展名為.dts,但是我們在前面移植 Linux 的時候卻一直在使用.dtb 檔案,那么 DTS 和 DTB 這兩個檔案是什么關系呢? DTS 是設備樹原始碼檔案, DTB 是將DTS 編譯以后得到的二進制檔案,將.c 檔案編譯為.o 需要用到 gcc 編譯器,那么將.dts 編譯為.dtb需要什么工具呢?需要用到 DTC 工具! DTC 工具原始碼在 Linux 內核的 scripts/dtc 目錄下,

DTS語法

1.dtsi頭檔案

??和 C 語言一樣,設備樹也支持頭檔案,設備樹的頭檔案擴展名為.dtsi,一般.dtsi 檔案用于描述 SOC 的內部外設資訊,比如 CPU 架構、主頻、外設暫存器地址范圍,比如 UART、 IIC 等等,比如 imx6ull.dtsi 就是描述 I.MX6ULL 這顆 SOC 內部外設情況資訊的,內容如下:

10 #include <dt-bindings/clock/imx6ul-clock.h>
11 #include <dt-bindings/gpio/gpio.h>
12 #include <dt-bindings/interrupt-controller/arm-gic.h>
13 #include "imx6ull-pinfunc.h"
14 #include "imx6ull-pinfunc-snvs.h"
15 #include "skeleton.dtsi"
16
17 / {
18 aliases {
19 can0 = &flexcan1;
......
48 };
49
50 cpus {
51 #address-cells = <1>;
52 #size-cells = <0>;
53
54 cpu0: cpu@0 {
55 compatible = "arm,cortex-a7";
56 device_type = "cpu";
......
89 };
90 };
91
92 intc: interrupt-controller@00a01000 {
93 compatible = "arm,cortex-a7-gic";
94 #interrupt-cells = <3>;
95 interrupt-controller;
96 reg = <0x00a01000 0x1000>,
97 <0x00a02000 0x100>;
98 };
99
100 clocks {
101 #address-cells = <1>;
102 #size-cells = <0>;
103
104 ckil: clock@0 {
105 compatible = "fixed-clock";
106 reg = <0>;
107 #clock-cells = <0>;
108 clock-frequency = <32768>;
109 clock-output-names = "ckil";
110 };
......
135 };
136
137 soc {
138 #address-cells = <1>;
139 #size-cells = <1>;
140 compatible = "simple-bus";
141 interrupt-parent = <&gpc>;
142 ranges;
143
144 busfreq {
145 compatible = "fsl,imx_busfreq";
......
162 };
197
198 gpmi: gpmi-nand@01806000{
199 compatible = "fsl,imx6ull-gpmi-nand", "fsl, imx6ul-gpminand";
200 #address-cells = <1>;
201 #size-cells = <1>;
202 reg = <0x01806000 0x2000>, <0x01808000 0x4000>;
......
216 };
......
1177 };
1178 };

??第 54~89 行就是 cpu0 這個設備節點資訊,這個節點資訊描述了I.MX6ULL 這顆 SOC 所使用的 CPU 資訊,比如架構是 cortex-A7,頻率支持 996MHz、 792MHz、528MHz、396MHz 和 198MHz 等等,在 imx6ull.dtsi 檔案中不僅僅描述了 cpu0 這一個節點資訊,I.MX6ULL 這顆 SOC 所有的外設都描述的清清楚楚,比如 ecspi1~4、 uart1~8、 usbphy1~2、 i2c1~4等等,關于這些設備節點資訊的具體內容我們稍后在詳細的講解,

2.設備節點

??設備樹是采用樹形結構來描述板子上的設備資訊的檔案,每個設備都是一個節點,叫做設備節點,每個節點都通過一些屬性資訊來描述節點資訊,屬性就是鍵—值對,以下是從imx6ull.dtsi 檔案中縮減出來的設備樹檔案內容:

1 / {
2 aliases {
3 can0 = &flexcan1;
4 };
5 6
cpus {
7 #address-cells = <1>;
8 #size-cells = <0>;
9
10 cpu0: cpu@0 {
11 compatible = "arm,cortex-a7";
12 device_type = "cpu";
13 reg = <0>;
14 };
15 };
16
17 intc: interrupt-controller@00a01000 {
18 compatible = "arm,cortex-a7-gic";
19 #interrupt-cells = <3>;
20 interrupt-controller;
21 reg = <0x00a01000 0x1000>,
22 <0x00a02000 0x100>;
23 };
24 }

??第 1 行,“/”是根節點,每個設備樹檔案只有一個根節點,第 2、 6 和 17 行, aliases、 cpus 和 intc 是三個子節點,在設備樹中節點命名格式如下:

node-name@unit-address

??其中“node-name”是節點名字,為 ASCII 字串,節點名字應該能夠清晰的描述出節點的功能,比如“uart1”就表示這個節點是 UART1 外設,“unit-address”一般表示設備的地址或暫存器首地址,如果某個節點沒有地址或者暫存器的話“unit-address”可以不要,比如“cpu@0”、“interrupt-controller@00a01000”,
??還有另外一種形式:

label: node-name@unit-address

??引入 label 的目的就是為了方便訪問節點,可以直接通過&label 來訪問這個節點,比如通過&cpu0 就可以訪問“cpu@0”這個節點,而不需要輸入完整的節點名字,再比如節點 “intc:interrupt-controller@00a01000”,節點 label 是 intc,而節點名字就很長了,為“ interruptcontroller@00a01000”,很明顯通過&intc 來訪問“interrupt-controller@00a01000”這個節點要方便很多!
??每個節點都有不同屬性,不同的屬性又有不同的內容,屬性都是鍵值對,值可以為慷訓任意的位元組流,設備樹原始碼中常用的幾種資料形式如下所示:
??①、字串

compatible = "arm,cortex-a7";

??上述代碼設定 compatible 屬性的值為字串“arm,cortex-a7”,
??②、 32 位無符號整數

reg = <0>;

??上述代碼設定 reg 屬性的值為 0,
??③、字串串列
??屬性值也可以為字串串列,字串和字串之間采用“,”隔開,如下所示:

compatible = "fsl,imx6ull-gpmi-nand", "fsl, imx6ul-gpmi-nand";

??上述代碼設定屬性 compatible 的值為“fsl,imx6ull-gpmi-nand”和“fsl, imx6ul-gpmi-nand”,

3.標準屬性

??節點是由一堆的屬性組成,節點都是具體的設備,不同的設備需要的屬性不同,用戶可以自定義屬性,除了用戶自定義屬性,有很多屬性是標準屬性, Linux 下的很多外設驅動都會使用這些標準屬性,

3.1 compatible 屬性

??compatible 屬性也叫做“兼容性”屬性,這是非常重要的一個屬性! compatible 屬性的值是一個字串串列, compatible 屬性用于將設備和驅動系結起來,字串串列用于選擇設備所要使用的驅動程式, compatible 屬性的值格式如下所示:

"manufacturer,model"

??其中 manufacturer 表示廠商, model 一般是模塊對應的驅動名字,
??一般驅動程式檔案都會有一個 OF 匹配表,此 OF 匹配表保存著一些 compatible 值,如果設備節點的 compatible 屬性值和 OF 匹配表中的任何一個值相等,那么就表示設備可以使用這個驅動,

3.2 model屬性

??model 屬性值也是一個字串,一般 model 屬性描述設備模塊資訊,比如名字什么的,比如:

model = "wm8960-audio";

3.3 status 屬性

??status 屬性看名字就知道是和設備狀態有關的, status 屬性值也是字串,字串是設備的狀態資訊,可選的狀態如表所示:
在這里插入圖片描述

3.4 #address-cells 和#size-cells 屬性

??這兩個屬性的值都是無符號 32 位整形, #address-cells 和#size-cells 這兩個屬性可以用在任何擁有子節點的設備中,用于描述子節點的地址資訊, #address-cells 屬性值決定了子節點 reg 屬性中地址資訊所占用的字長(32 位), #size-cells 屬性值決定了子節點 reg 屬性中長度資訊所占的字長(32 位), #address-cells 和#size-cells 表明了子節點應該如何撰寫 reg 屬性值,一般 reg 屬性都是和地址有關的內容,和地址相關的資訊有兩種:起始地址和地址長度, reg 屬性的格式一為:

reg = <address1 length1 address2 length2 address3 length3……>

??每個“address length”組合表示一個地址范圍,其中 address 是起始地址, length 是地址長度, #address-cells 表明 address 這個資料所占用的字長, #size-cells 表明 length 這個資料所占用的字長,

3.5 reg 屬性

??reg 屬性前面已經提到過了, reg 屬性的值一般是(address, length)對, reg 屬性一般用于描述設備地址空間資源資訊,一般都是某個外設的暫存器地址范圍資訊,

3.6 ranges 屬性

??ranges屬性值可以為慷訓者按照(child-bus-address,parent-bus-address,length)格式撰寫的數字矩陣, ranges 是一個地址映射/轉換表, ranges 屬性每個專案由子地址、父地址和地址空間長度這三部分組成:
??child-bus-address:子總線地址空間的物理地址,由父節點的#address-cells 確定此物理地址所占用的字長,
??parent-bus-address: 父總線地址空間的物理地址,同樣由父節點的#address-cells 確定此物理地址所占用的字長,
??length: 子地址空間的長度,由父節點的#size-cells 確定此地址長度所占用的字長,
??如果 ranges 屬性值為空值,說明子地址空間和父地址空間完全相同,不需要進行地址轉換,對于我們所使用的 I.MX6ULL 來說,子地址空間和父地址空間完全相同,因此會在 imx6ull.dtsi中找到大量的值為空的 ranges 屬性,

4.根節點compatible 屬性

??每個節點都有 compatible 屬性,根節點“/”也不例外, imx6ull-emmc.dts 檔案中根節點的 compatible 屬性內容如下所示:

/ {
model = "Freescale i.MX6 ULL 14x14 EVK Board";
compatible = "fsl,imx6ull-14x14-evk", "fsl,imx6ull";..
}

??可以看出, compatible 有兩個值:“fsl,imx6ull-14x14-evk”和“fsl,imx6ull”,前面我們說了,設備節點的 compatible 屬性值是為了匹配 Linux 內核中的驅動程式,那么根節點中的 compatible屬性是為了做什么作業的? 通過根節點的 compatible 屬性可以知道我們所使用的設備,一般第一個值描述了所使用的硬體設備名字,比如這里使用的是“imx6ull-14x14-evk”這個設備,第二個值描述了設備所使用的 SOC,比如這里使用的是“imx6ull”這顆 SOC, Linux 內核會通過根節點的 compoatible 屬性查看是否支持此設備,如果支持的話設備就會啟動 Linux 內核,

設備樹在系統中的體現

??Linux 內核啟動的時候會決議設備樹中各個節點的資訊,并且在根檔案系統的/proc/devicetree 目錄下根據節點名字創建不同檔案夾:
在這里插入圖片描述
??以上就是就是目錄/proc/device-tree 目錄下的內容, /proc/device-tree 目錄下是根節點“/”的所有屬性和子節點,我們依次來看一下這些屬性和子節點,

1. 根節點“/”各個屬性

??在上圖中,根節點屬性屬性表現為一個個的檔案(圖中細字體檔案),比如圖 43.5.1 中的“#address-cells”、“#size-cells”、“compatible”、“model”和“name”這 5 個檔案,它們在設備樹中就是根節點的 5個屬性,既然是檔案那么肯定可以查看其內容,輸入cat 命令來查看 model和 compatible 這兩個檔案的內容:
在這里插入圖片描述

2、根節點“/”各子節點

??各個檔案夾(圖中粗字體檔案夾)就是根節點“/”的各個子節點,比如“aliases”、“ backlight”、“ chosen”和“ clocks”等等,

Linux 內核決議 DTB 檔案

??Linux 內核在啟動的時候會決議 DTB 檔案,然后在/proc/device-tree 目錄下生成相應的設備樹節點檔案,接下來我們簡單分析一下 Linux 內核是如何決議 DTB 檔案的,流程圖如下所示:
在這里插入圖片描述

設備樹常用OF操作函式

??設備樹描述了設備的詳細資訊,這些資訊包括數字型別的、字串型別的、陣列型別的,我們在撰寫驅動的時候需要獲取到這些資訊,比如設備樹使用 reg 屬性描述了某個外設的暫存器地址為 0X02005482,長度為 0X400,我們在撰寫驅動的時候需要獲取到 reg 屬性的0X02005482 和 0X400 這兩個值,然后初始化外設, Linux 內核給我們提供了一系列的函式來獲取設備樹中的節點或者屬性資訊,這一系列的函式都有一個統一的前綴“of_”,所以在很多資料里面也被叫做 OF 函式,這些 OF 函式原型都定義在 include/linux/of.h 檔案中,

1. 查找節點的 OF 函式

??設備都是以節點的形式“掛”到設備樹上的,因此要想獲取這個設備的其他屬性資訊,必須先獲取到這個設備的節點, Linux 內核使用 device_node 結構體來描述一個節點,此結構體定義在檔案 include/linux/of.h 中,定義如下:

49 struct device_node {
50 const char *name; /* 節點名字 */
51 const char *type; /* 設備型別 */
52 phandle phandle;
53 const char *full_name; /* 節點全名 */
54 struct fwnode_handle fwnode;
55
56 struct property *properties; /* 屬性 */
57 struct property *deadprops; /* removed 屬性 */
58 struct device_node *parent; /* 父節點 */
59 struct device_node *child; /* 子節點 */
60 struct device_node *sibling;
61 struct kobject kobj;
62 unsigned long _flags;
63 void *data;
64 #if defined(CONFIG_SPARC)
65 const char *path_component_name;
66 unsigned int unique_id;
67 struct of_irq_controller *irq_trans;
68 #endif
69 };

??與查找節點有關的 OF 函式有 5 個,我們依次來看一下,

1.1 of_find_node_by_name 函式

??of_find_node_by_name 函式通過節點名字查找指定的節點,函式原型如下:

struct device_node *of_find_node_by_name(struct device_node *from,
const char *name);

??函式引數和回傳值含義如下:
??from:開始查找的節點,如果為 NULL 表示從根節點開始查找整個設備樹,
??name:要查找的節點名字,
??回傳值: 找到的節點,如果為 NULL 表示查找失敗,

1.2 of_find_node_by_type 函式

??of_find_node_by_type 函式通過 device_type 屬性查找指定的節點,函式原型如下:

struct device_node *of_find_node_by_type(struct device_node *from, const char *type)

??函式引數和回傳值含義如下:
??from:開始查找的節點,如果為 NULL 表示從根節點開始查找整個設備樹,
??type:要查找的節點對應的 type 字串,也就是 device_type 屬性值,
??回傳值: 找到的節點,如果為 NULL 表示查找失敗,

1.3 of_find_compatible_node 函式

??of_find_compatible_node 函式根據 device_type 和 compatible 這兩個屬性查找指定的節點,函式原型如下:

struct device_node *of_find_compatible_node(struct device_node *from,
const char *type,
const char *compatible)

1.4 of_find_matching_node_and_match 函式

??of_find_matching_node_and_match 函式通過 of_device_id 匹配表來查找指定的節點,函式原型如下:

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)

??函式引數和回傳值含義如下:
??from:開始查找的節點,如果為 NULL 表示從根節點開始查找整個設備樹,
??matches: of_device_id 匹配表,也就是在此匹配表里面查找節點,
??match: 找到的匹配的 of_device_id,
??回傳值: 找到的節點,如果為 NULL 表示查找失敗,
??1.5 of_find_node_by_path 函式
??of_find_node_by_path 函式通過路徑來查找指定的節點,函式原型如下:

inline struct device_node *of_find_node_by_path(const char *path)

??函式引數和回傳值含義如下:
??path:帶有全路徑的節點名,可以使用節點的別名,比如“/backlight”就是 backlight這個節點的全路徑,
??回傳值: 找到的節點,如果為 NULL 表示查找失敗,

2. 查找父/子節點的 OF 函式

2.1 of_get_parent 函式

??of_get_parent 函式用于獲取指定節點的父節點(如果有父節點的話),函式原型如下:

struct device_node *of_get_parent(const struct device_node *node)

??函式引數和回傳值含義如下:
??node:要查找的父節點的節點,
??回傳值: 找到的父節點,

2.2 of_get_next_child 函式

??of_get_next_child 函式用迭代的方式查找子節點,函式原型如下:

struct device_node *of_get_next_child(const struct device_node *node,
struct device_node *prev)

??函式引數和回傳值含義如下:
??node:父節點,
??prev:前一個子節點,也就是從哪一個子節點開始迭代的查找下一個子節點,可以設定為NULL,表示從第一個子節點開始,
??回傳值: 找到的下一個子節點,

3. 提取屬性值的 OF 函式

??節點的屬性資訊里面保存了驅動所需要的內容,因此對于屬性值的提取非常重要, Linux 內核中使用結構體 property 表示屬性,此結構體同樣定義在檔案 include/linux/of.h 中,內容如下:

35 struct property {
36 char *name; /* 屬性名字 */
37 int length; /* 屬性長度 */
38 void *value; /* 屬性值 */
39 struct property *next; /* 下一個屬性 */
40 unsigned long _flags;
41 unsigned int unique_id;
42 struct bin_attribute attr;
43 };

??Linux 內核也提供了提取屬性值的 OF 函式,我們依次來看一下,

3.1 of_find_property 函式

??of_find_property 函式用于查找指定的屬性,函式原型如下:

property *of_find_property(const struct device_node *np,
                            const char   *name,
                                     int   *lenp)

??函式引數和回傳值含義如下:
??np:設備節點,
??name: 屬性名字,
??lenp:屬性值的位元組數
??回傳值: 找到的屬性,

3.2 of_property_count_elems_of_size 函式

??of_property_count_elems_of_size 函式用于獲取屬性中元素的數量,比如 reg 屬性值是一個陣列,那么使用此函式可以獲取到這個陣列的大小,此函式原型如下:

int of_property_count_elems_of_size(const struct device_node *np,
                                    const char *propname,
                                    int elem_size)

??函式引數和回傳值含義如下:
??np:設備節點,
??proname: 需要統計元素數量的屬性名字,
??elem_size:元素長度,
??回傳值: 得到的屬性元素數量,

3.3 of_property_read_u32_index 函式

??of_property_read_u32_index 函式用于從屬性中獲取指定標號的 u32 型別資料值(無符號 32位),比如某個屬性有多個 u32 型別的值,那么就可以使用此函式來獲取指定標號的資料值,此函式原型如下:

int of_property_read_u32_index(const struct device_node *np,
const char *propname,
u32 index,
u32 *out_value)

??函式引數和回傳值含義如下:
??np:設備節點,
??proname: 要讀取的屬性名字,
??index:要讀取的值標號,
??out_value:讀取到的值
??回傳值: 0 讀取成功,負值,讀取失敗, -EINVAL 表示屬性不存在, -ENODATA 表示沒有要讀取的資料, -EOVERFLOW 表示屬性值串列太小,

3.4 of_property_read_u8_array 函式;of_property_read_u16_array 函式;of_property_read_u32_array 函式;of_property_read_u64_array 函式

??這 4 個函式分別是讀取屬性中 u8、 u16、 u32 和 u64 型別的陣列資料,比如大多數的 reg 屬性都是陣列資料,可以使用這 4 個函式一次讀取出 reg 屬性中的所有資料,這四個函式的原型如下:

int of_property_read_u8_array(const struct device_node *np,
const char *propname,
u8 *out_values,
size_t sz)
int of_property_read_u16_array(const struct device_node *np,
const char *propname,
u16 *out_values,
size_t sz)
int of_property_read_u32_array(const struct device_node *np,
const char *propname,
u32 *out_values,
size_t sz)
int of_property_read_u64_array(const struct device_node *np,
const char *propname,
u64 *out_values,
size_t sz)

??函式引數和回傳值含義如下:
??np:設備節點,
??proname: 要讀取的屬性名字,
??out_value:讀取到的陣列值,分別為 u8、 u16、 u32 和 u64,
??sz: 要讀取的陣列元素數量,
??回傳值: 0,讀取成功,負值,讀取失敗, -EINVAL 表示屬性不存在, -ENODATA 表示沒有要讀取的資料, -EOVERFLOW 表示屬性值串列太小,

3.5 of_property_read_u8 函式;of_property_read_u16 函式;of_property_read_u32 函式;of_property_read_u64 函式

??有些屬性只有一個整形值,這四個函式就是用于讀取這種只有一個整形值的屬性,分別用于讀取 u8、 u16、 u32 和 u64 型別屬性值,函式原型如下:

int of_property_read_u8(const struct device_node *np,
const char *propname,
u8 *out_value)
int of_property_read_u16(const struct device_node *np,
const char *propname,
u16 *out_value)
int of_property_read_u32(const struct device_node *np,
const char *propname,
u32 *out_value)
int of_property_read_u64(const struct device_node *np,
const char *propname,
u64 *out_value)

??函式引數和回傳值含義如下:
??np:設備節點,
??proname: 要讀取的屬性名字,
??out_value:讀取到的陣列值,
??回傳值: 0,讀取成功,負值,讀取失敗, -EINVAL 表示屬性不存在, -ENODATA 表示沒有要讀取的資料, -EOVERFLOW 表示屬性值串列太小,

3.6 of_property_read_string 函式

??of_property_read_string 函式用于讀取屬性中字串值,函式原型如下:

int of_property_read_string(struct device_node *np,
                            const char *propname,
                            const char **out_string)

??函式引數和回傳值含義如下:
??np:設備節點,
??proname: 要讀取的屬性名字,
??out_string:讀取到的字串值,
??回傳值: 0,讀取成功,負值,讀取失敗,

3.7 of_n_addr_cells 函式

??of_n_addr_cells 函式用于獲取#address-cells 屬性值,函式原型如下:

int of_n_addr_cells(struct device_node *np)

??函式引數和回傳值含義如下:
??np:設備節點,
??回傳值: 獲取到的#address-cells 屬性值,

3.8 of_n_size_cells 函式

??of_size_cells 函式用于獲取#size-cells 屬性值,函式原型如下:

int of_n_size_cells(struct device_node *np)

??函式引數和回傳值含義如下:
??np:設備節點,
??回傳值: 獲取到的#size-cells 屬性值,

4. 其他常用的 OF 函式

4.1 of_device_is_compatible 函式

??of_device_is_compatible 函式用于查看節點的 compatible 屬性是否有包含 compat 指定的字串,也就是檢查設備節點的兼容性,函式原型如下:

int of_device_is_compatible(const struct device_node *device,
const char *compat)

??函式引數和回傳值含義如下:
??device:設備節點,
??compat:要查看的字串,
??回傳值: 0,節點的 compatible 屬性中不包含 compat 指定的字串; 正數,節點的 compatible屬性中包含 compat 指定的字串,

4.2 of_get_address 函式

??of_get_address 函式用于獲取地址相關屬性,主要是“reg”或者“assigned-addresses”屬性值,函式原型如下:

const __be32 *of_get_address(struct device_node *dev,
                             int index,
                             u64 *size,
                             unsigned int *flags)

??函式引數和回傳值含義如下:
??dev:設備節點,
??index:要讀取的地址標號,
??size:地址長度,
??flags:引數,比如 IORESOURCE_IO、 IORESOURCE_MEM 等
??回傳值: 讀取到的地址資料首地址,為 NULL 的話表示讀取失敗,

4.3 of_translate_address 函式

??of_translate_address 函式負責將從設備樹讀取到的地址轉換為物理地址,函式原型如下:

u64 of_translate_address(struct device_node *dev,
                         const __be32 *in_addr)

??函式引數和回傳值含義如下:
??dev:設備節點,
??in_addr:要轉換的地址,
??回傳值: 得到的物理地址,如果為 OF_BAD_ADDR 的話表示轉換失敗,

4.4 of_address_to_resource 函式

??IIC、 SPI、 GPIO 等這些外設都有對應的暫存器,這些暫存器其實就是一組記憶體空間, Linux內核使用 resource 結構體來描述一段記憶體空間,“resource”翻譯出來就是“資源”,因此用 resource結構體描述的都是設備資源資訊, resource 結構體定義在檔案 include/linux/ioport.h 中,定義如下:

struct resource {
resource_size_t start;
resource_size_t end;
const char *name;
unsigned long flags;
struct resource *parent, *sibling, *child;
};

??對于 32 位的 SOC 來說, resource_size_t 是 u32 型別的,其中 start 表示開始地址, end 表示結束地址, name 是這個資源的名字, flags 是資源標志位,一般表示資源型別,可選的資源標志定義在檔案 include/linux/ioport.h 中,如下所示:

1 #define IORESOURCE_BITS 0x000000ff
2 #define IORESOURCE_TYPE_BITS 0x00001f00
3 #define IORESOURCE_IO 0x00000100
4 #define IORESOURCE_MEM 0x00000200
5 #define IORESOURCE_REG 0x00000300
6 #define IORESOURCE_IRQ 0x00000400
7 #define IORESOURCE_DMA 0x00000800
8 #define IORESOURCE_BUS 0x00001000
9 #define IORESOURCE_PREFETCH 0x00002000
10 #define IORESOURCE_READONLY 0x00004000
11 #define IORESOURCE_CACHEABLE 0x00008000
12 #define IORESOURCE_RANGELENGTH 0x00010000
13 #define IORESOURCE_SHADOWABLE 0x00020000
14 #define IORESOURCE_SIZEALIGN 0x00040000
15 #define IORESOURCE_STARTALIGN 0x00080000
16 #define IORESOURCE_MEM_64 0x00100000
17 #define IORESOURCE_WINDOW 0x00200000
18 #define IORESOURCE_MUXED 0x00400000
19 #define IORESOURCE_EXCLUSIVE 0x08000000
20 #define IORESOURCE_DISABLED 0x10000000
21 #define IORESOURCE_UNSET 0x20000000
22 #define IORESOURCE_AUTO 0x40000000
23 #define IORESOURCE_BUSY 0x80000000

??大 家 一 般 最 常 見 的 資 源 標 志 就 是 IORESOURCE_MEM 、 IORESOURCE_REG 和IORESOURCE_IRQ 等,接下來我們回到 of_address_to_resource 函式,此函式看名字像是從設備樹里面提取資源值,但是本質上就是將 reg 屬性值,然后將其轉換為 resource 結體型別,函式原型如下所示:

int of_address_to_resource(struct device_node *dev,
int index,
struct resource *r)

??函式引數和回傳值含義如下:
??dev:設備節點,
??index:地址資源標號,
??r:得到的 resource 型別的資源值,
??回傳值: 0,成功;負值,失敗,

4.5 of_iomap 函式

??of_iomap 函式用于直接記憶體映射,以前我們會通過 ioremap 函式來完成物理地址到虛擬地址的映射,采用設備樹以后就可以直接通過 of_iomap 函式來獲取記憶體地址所對應的虛擬地址,不需要使用 ioremap 函式了,當然了,你也可以使用 ioremap 函式來完成物理地址到虛擬地址的記憶體映射,只是在采用設備樹以后,大部分的驅動都使用 of_iomap 函式了, of_iomap 函式本質上也是將 reg 屬性中地址資訊轉換為虛擬地址,如果 reg 屬性有多段的話,可以通過 index 引數指定要完成記憶體映射的是哪一段, of_iomap 函式原型如下:

void __iomem *of_iomap(struct device_node *np,
                       int index)

??函式引數和回傳值含義如下:
??np:設備節點,
??index: reg 屬性中要完成記憶體映射的段,如果 reg 屬性只有一段的話 index 就設定為 0,
??回傳值: 經過記憶體映射后的虛擬記憶體首地址,如果為 NULL 的話表示記憶體映射失敗,
??關于設備樹常用的 OF 函式就先講解到這里, Linux 內核中關于設備樹的 OF 函式不僅僅只有前面講的這幾個,還有很多 OF 函式我們并沒有講解,這些沒有講解的 OF 函式要結合具體的驅動,比如獲取中斷號的 OF 函式、獲取 GPIO 的 OF 函式等等,這些 OF 函式我們在后面的驅動實驗中再詳細的講解,

轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/294470.html

標籤:其他

上一篇:Linux云計算-使用 MyCat 實作 MySQL 主從讀寫分離

下一篇:【資料結構】一篇文章學懂并查集+LRU Cache,拿來吧你!

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 網閘典型架構簡述

    網閘架構一般分為兩種:三主機的三系統架構網閘和雙主機的2+1架構網閘。 三主機架構分別為內端機、外端機和仲裁機。三機無論從軟體和硬體上均各自獨立。首先從硬體上來看,三機都用各自獨立的主板、記憶體及存盤設備。從軟體上來看,三機有各自獨立的作業系統。這樣能達到完全的三機獨立。對于“2+1”系統,“2”分為 ......

    uj5u.com 2020-09-10 02:00:44 more
  • 如何從xshell上傳檔案到centos linux虛擬機里

    如何從xshell上傳檔案到centos linux虛擬機里及:虛擬機CentOs下執行 yum -y install lrzsz命令,出現錯誤:鏡像無法找到軟體包 前言 一、安裝lrzsz步驟 二、上傳檔案 三、遇到的問題及解決方案 總結 前言 提示:其實很簡單,往虛擬機上安裝一個上傳檔案的工具 ......

    uj5u.com 2020-09-10 02:00:47 more
  • 一、SQLMAP入門

    一、SQLMAP入門 1、判斷是否存在注入 sqlmap.py -u 網址/id=1 id=1不可缺少。當注入點后面的引數大于兩個時。需要加雙引號, sqlmap.py -u "網址/id=1&uid=1" 2、判斷文本中的請求是否存在注入 從文本中加載http請求,SQLMAP可以從一個文本檔案中 ......

    uj5u.com 2020-09-10 02:00:50 more
  • Metasploit 簡單使用教程

    metasploit 簡單使用教程 浩先生, 2020-08-28 16:18:25 分類專欄: kail 網路安全 linux 文章標簽: linux資訊安全 編輯 著作權 metasploit 使用教程 前言 一、Metasploit是什么? 二、準備作業 三、具體步驟 前言 Msfconsole ......

    uj5u.com 2020-09-10 02:00:53 more
  • 游戲逆向之驅動層與用戶層通訊

    驅動層代碼: #pragma once #include <ntifs.h> #define add_code CTL_CODE(FILE_DEVICE_UNKNOWN,0x800,METHOD_BUFFERED,FILE_ANY_ACCESS) /* 更多游戲逆向視頻www.yxfzedu.com ......

    uj5u.com 2020-09-10 02:00:56 more
  • 北斗電力時鐘(北斗授時服務器)讓網路資料更精準

    北斗電力時鐘(北斗授時服務器)讓網路資料更精準 北斗電力時鐘(北斗授時服務器)讓網路資料更精準 京準電子科技官微——ahjzsz 近幾年,資訊技術的得了快速發展,互聯網在逐漸普及,其在人們生活和生產中都得到了廣泛應用,并且取得了不錯的應用效果。計算機網路資訊在電力系統中的應用,一方面使電力系統的運行 ......

    uj5u.com 2020-09-10 02:01:03 more
  • 【CTF】CTFHub 技能樹 彩蛋 writeup

    ?碎碎念 CTFHub:https://www.ctfhub.com/ 筆者入門CTF時時剛開始刷的是bugku的舊平臺,后來才有了CTFHub。 感覺不論是網頁UI設計,還是題目質量,賽事跟蹤,工具軟體都做得很不錯。 而且因為獨到的金幣制度的確讓人有一種想去刷題賺金幣的感覺。 個人還是非常喜歡這個 ......

    uj5u.com 2020-09-10 02:04:05 more
  • 02windows基礎操作

    我學到了一下幾點 Windows系統目錄結構與滲透的作用 常見Windows的服務詳解 Windows埠詳解 常用的Windows注冊表詳解 hacker DOS命令詳解(net user / type /md /rd/ dir /cd /net use copy、批處理 等) 利用dos命令制作 ......

    uj5u.com 2020-09-10 02:04:18 more
  • 03.Linux基礎操作

    我學到了以下幾點 01Linux系統介紹02系統安裝,密碼啊破解03Linux常用命令04LAMP 01LINUX windows: win03 8 12 16 19 配置不繁瑣 Linux:redhat,centos(紅帽社區版),Ubuntu server,suse unix:金融機構,證券,銀 ......

    uj5u.com 2020-09-10 02:04:30 more
  • 05HTML

    01HTML介紹 02頭部標簽講解03基礎標簽講解04表單標簽講解 HTML前段語言 js1.了解代碼2.根據代碼 懂得挖掘漏洞 (POST注入/XSS漏洞上傳)3.黑帽seo 白帽seo 客戶網站被黑帽植入劫持代碼如何處理4.熟悉html表單 <html><head><title>TDK標題,描述 ......

    uj5u.com 2020-09-10 02:04:36 more
最新发布
  • 2023年最新微信小程式抓包教程

    01 開門見山 隔一個月發一篇文章,不過分。 首先回顧一下《微信系結手機號資料庫被脫庫事件》,我也是第一時間得知了這個訊息,然后跟蹤了整件事情的經過。下面是這起事件的相關截圖以及近日流出的一萬條資料樣本: 個人認為這件事也沒什么,還不如關注一下之前45億快遞資料查詢渠道疑似在近日復活的訊息。 訊息是 ......

    uj5u.com 2023-04-20 08:48:24 more
  • web3 產品介紹:metamask 錢包 使用最多的瀏覽器插件錢包

    Metamask錢包是一種基于區塊鏈技術的數字貨幣錢包,它允許用戶在安全、便捷的環境下管理自己的加密資產。Metamask錢包是以太坊生態系統中最流行的錢包之一,它具有易于使用、安全性高和功能強大等優點。 本文將詳細介紹Metamask錢包的功能和使用方法。 一、 Metamask錢包的功能 數字資 ......

    uj5u.com 2023-04-20 08:47:46 more
  • vulnhub_Earth

    前言 靶機地址->>>vulnhub_Earth 攻擊機ip:192.168.20.121 靶機ip:192.168.20.122 參考文章 https://www.cnblogs.com/Jing-X/archive/2022/04/03/16097695.html https://www.cnb ......

    uj5u.com 2023-04-20 07:46:20 more
  • 從4k到42k,軟體測驗工程師的漲薪史,給我看哭了

    清明節一過,盲猜大家已經無心上班,在數著日子準備過五一,但一想到銀行卡里的余額……瞬間心情就不美麗了。最近,2023年高校畢業生就業調查顯示,本科畢業月平均起薪為5825元。調查一出,便有很多同學表示自己又被平均了。看著這一資料,不免讓人想到前不久中國青年報的一項調查:近六成大學生認為畢業10年內會 ......

    uj5u.com 2023-04-20 07:44:00 more
  • 最新版本 Stable Diffusion 開源 AI 繪畫工具之中文自動提詞篇

    🎈 標簽生成器 由于輸入正向提示詞 prompt 和反向提示詞 negative prompt 都是使用英文,所以對學習母語的我們非常不友好 使用網址:https://tinygeeker.github.io/p/ai-prompt-generator 這個網址是為了讓大家在使用 AI 繪畫的時候 ......

    uj5u.com 2023-04-20 07:43:36 more
  • 漫談前端自動化測驗演進之路及測驗工具分析

    隨著前端技術的不斷發展和應用程式的日益復雜,前端自動化測驗也在不斷演進。隨著 Web 應用程式變得越來越復雜,自動化測驗的需求也越來越高。如今,自動化測驗已經成為 Web 應用程式開發程序中不可或缺的一部分,它們可以幫助開發人員更快地發現和修復錯誤,提高應用程式的性能和可靠性。 ......

    uj5u.com 2023-04-20 07:43:16 more
  • CANN開發實踐:4個DVPP記憶體問題的典型案例解讀

    摘要:由于DVPP媒體資料處理功能對存放輸入、輸出資料的記憶體有更高的要求(例如,記憶體首地址128位元組對齊),因此需呼叫專用的記憶體申請介面,那么本期就分享幾個關于DVPP記憶體問題的典型案例,并給出原因分析及解決方法。 本文分享自華為云社區《FAQ_DVPP記憶體問題案例》,作者:昇騰CANN。 DVPP ......

    uj5u.com 2023-04-20 07:43:03 more
  • msf學習

    msf學習 以kali自帶的msf為例 一、msf核心模塊與功能 msf模塊都放在/usr/share/metasploit-framework/modules目錄下 1、auxiliary 輔助模塊,輔助滲透(埠掃描、登錄密碼爆破、漏洞驗證等) 2、encoders 編碼器模塊,主要包含各種編碼 ......

    uj5u.com 2023-04-20 07:42:59 more
  • Halcon軟體安裝與界面簡介

    1. 下載Halcon17版本到到本地 2. 雙擊安裝包后 3. 步驟如下 1.2 Halcon軟體安裝 界面分為四大塊 1. Halcon的五個助手 1) 影像采集助手:與相機連接,設定相機引數,采集影像 2) 標定助手:九點標定或是其它的標定,生成標定檔案及內參外參,可以將像素單位轉換為長度單位 ......

    uj5u.com 2023-04-20 07:42:17 more
  • 在MacOS下使用Unity3D開發游戲

    第一次發博客,先發一下我的游戲開發環境吧。 去年2月份買了一臺MacBookPro2021 M1pro(以下簡稱mbp),這一年來一直在用mbp開發游戲。我大致分享一下我的開發工具以及使用體驗。 1、Unity 官網鏈接: https://unity.cn/releases 我一般使用的Apple ......

    uj5u.com 2023-04-20 07:40:19 more