<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          整理了一份Linux設(shè)備樹基礎(chǔ)知識(shí)!

          共 7440字,需瀏覽 15分鐘

           ·

          2022-07-04 15:06

              關(guān)注、星標(biāo)公眾號,直達(dá)精彩內(nèi)容

          來源:百問網(wǎng)+正點(diǎn)原子


          前言

          在platform_device部分有簡單說明描述設(shè)備有兩種方法:一種是使用platform_device結(jié)構(gòu)體來指定;另一種是使用設(shè)備樹來描述。

          本篇筆記我們就來簡單地學(xué)習(xí)一下設(shè)備樹的一些知識(shí)。

          什么是設(shè)備樹

          設(shè)備樹簡單理解就是描述設(shè)備信息(資源)的一棵樹。設(shè)備樹(Device Tree)用代碼體現(xiàn)如下:


          這些代碼被保存在.dts/dtsi后綴文件中,也即設(shè)備樹源文件 DTS(DeviceTree Source)

          這些源文件同我們的C代碼一樣,并不能直接使用的,而是得經(jīng)過一個(gè)編譯過程生成機(jī)器可運(yùn)行的二進(jìn)制文件,如:


          dts文件使用dtc工具編譯生成dtb文件,這個(gè)dtb文件就是內(nèi)核可以使用的文件。例如我們的板子跑起來之后,我們系統(tǒng)使用的設(shè)備樹文件就存在目錄/boot下:

          Linux為什么會(huì)引入設(shè)備樹?

          在上一個(gè)實(shí)驗(yàn):【Linux筆記】LED驅(qū)動(dòng)實(shí)驗(yàn)(總線設(shè)備驅(qū)動(dòng)模型)中我們使用了platform_device結(jié)構(gòu)體來描述led設(shè)備(硬件資源)。既然已經(jīng)有了描述設(shè)備的方法了,為什么還要引入設(shè)備樹呢?

          因?yàn)長inux內(nèi)核中有很多BSP(板級支持包),不同的BSP會(huì)包含著不同的描述設(shè)備的代碼(.c或.h文件)。

          隨著芯片的發(fā)展,Linux內(nèi)核中就包含著越來越多這些描述設(shè)備的代碼,導(dǎo)致Linux內(nèi)核代碼會(huì)很臃腫。

          這導(dǎo)致Linux之父Linus 大發(fā)雷霆:"this whole ARM thing is a f*cking pain in the ass"。

          因此引入了設(shè)備樹文件,從而可精簡一些臃腫的C代碼。除此之外,.dts編譯生成.dtb文件的過程要比.c編譯生成驅(qū)動(dòng)模塊、加載驅(qū)動(dòng)模塊的過程要簡單很多,也更方面我們進(jìn)行開發(fā)。

          設(shè)備樹的語法

          設(shè)備樹源文件也是需要根據(jù)一定規(guī)則來編寫的,同C語言一樣,也要遵循一些語法規(guī)則。下面簡單看一下設(shè)備樹的源碼結(jié)構(gòu)及語法。

          先看一個(gè)設(shè)備樹示例:

          1、節(jié)點(diǎn)格式

          label: node-name@unit-address

          其中:

          label:標(biāo)號

          node-name:節(jié)點(diǎn)名字

          unit-address:單元地址

          label 是標(biāo)號,可以省略。label 的作用是為了方便地引用 node。比如:


          可以使用下面 2 種方法來修改 uart@fe001000 這個(gè) node:

          2、屬性格式

          簡單地說, properties 就是“name=value”, value 有多種取值方式。示例:

          • 一個(gè)32位的數(shù)據(jù),用尖括號包圍起來,如
          interrupts = <17 0xc>;   
          • 一個(gè)64位數(shù)據(jù)(使用2個(gè)32位數(shù)據(jù)表示),用尖括號包圍起來,如:
          clock-frequency = <0x00000001 0x00000000>;   
          • 有結(jié)束符的字符串,用雙引號包圍起來,如:
          compatible = "simple-bus";   
          • 字節(jié)序列,用中括號包圍起來,如:
          local-mac-address = [00 00 12 34 56 78]; // 每個(gè)byte使用2個(gè)16進(jìn)制數(shù)來表示   
          local-mac-address = [000012345678];      // 每個(gè)byte使用2個(gè)16進(jìn)制數(shù)來表示   
          • 可以是各種值的組合,用逗號隔開,如:
          compatible = "ns16550""ns8250";   
          example = <0xf00f0000 19>, "a strange property format";   

          3、一些標(biāo)準(zhǔn)屬性

          (1) compatible 屬性

          “compatible”表示“兼容”,對于某個(gè)LED,內(nèi)核中可能有A、B、C三個(gè)驅(qū)動(dòng)都支持它,那可以這樣寫:

          led {   
           compatible = “A”, “B”, “C”;   
          };  

          內(nèi)核啟動(dòng)時(shí),就會(huì)為這個(gè)LED按這樣的優(yōu)先順序?yàn)樗业津?qū)動(dòng)程序:A、B、C。

          (2)model 屬性

          model屬性與compatible屬性有些類似,但是有差別。compatible屬性是一個(gè)字符串列表,表示可以你的硬件兼容A、B、C等驅(qū)動(dòng);model用來準(zhǔn)確地定義這個(gè)硬件是什么。

          比如根節(jié)點(diǎn)中可以這樣寫:

          / {   
              compatible = "samsung,smdk2440""samsung,mini2440";   
              model = "jz2440_v3";   
          };  

          它表示這個(gè)單板,可以兼容內(nèi)核中的“smdk2440”,也兼容“mini2440”。

          從compatible屬性中可以知道它兼容哪些板,但是它到底是什么板?用model屬性來明確。

          (3)status 屬性

          status 屬性看名字就知道是和設(shè)備狀態(tài)有關(guān)的, status 屬性值也是字符串,字符串是設(shè)備的狀態(tài)信息,可選的狀態(tài)如下所示:

          (4)#address-cells 和#size-cells 屬性

          格式:

          address-cells:address要用多少個(gè)32位數(shù)來表示;   
          size-cells:size要用多少個(gè)32位數(shù)來表示。 

          比如一段內(nèi)存,怎么描述它的起始地址和大小?

          下例中,address-cells為1,所以reg中用1個(gè)數(shù)來表示地址,即用0x80000000來表示地址;size-cells為1,所以reg中用1個(gè)數(shù)來表示大小,即用0x20000000表示大小:

          / {   
              # address-cells = <1>;   
              # size-cells = <1>;   
              memory {   
               reg = <0x80000000 0x20000000>;   
              };   
          };   

          (5)reg 屬性

          reg屬性的值,是一系列的“address size”,用多少個(gè)32位的數(shù)來表示address和size,由其父節(jié)點(diǎn)的# address-cells、#size-cells決定。示例:

          /dts-v1/;   
          / {   
              # address-cells = <1>;   
              # size-cells = <1>;   
              memory {   
               reg = <0x80000000 0x20000000>;   
              };   
          };   

          (7)name 屬性

          過時(shí)了,建議不用。它的值是字符串,用來表示節(jié)點(diǎn)的名字。在跟platform_driver匹配時(shí),優(yōu)先級最低。compatible屬性在匹配過程中,優(yōu)先級最高。

          (8)device_type 屬性

          過時(shí)了,建議不用。它的值是字符串,用來表示節(jié)點(diǎn)的類型。在跟platform_driver匹配時(shí),優(yōu)先級為中。compatible屬性在匹配過程中,優(yōu)先級最高。

          3、常用的節(jié)點(diǎn)

          (1)根節(jié)點(diǎn)

          用 / 標(biāo)識(shí)根節(jié)點(diǎn),如:

          /dts-v1/;   
          / {   
              model = "SMDK24440";   
              compatible = "samsung,smdk2440";   

              # address-cells = <1>;   
              # size-cells = <1>;   
          };   

          (2)CPU節(jié)點(diǎn)

          一般不需要我們設(shè)置,在 dtsi 文件中都定義好了,如:

          cpus {   
              # address-cells = <1>;   
              # size-cells = <0>;   

              cpu0: cpu@0 {   
               .......   
              }   
          };   

          (3)memory 節(jié)點(diǎn)

          芯片廠家不可能事先確定你的板子使用多大的內(nèi)存,所以 memory 節(jié)點(diǎn)需要板廠設(shè)置,比如:

          memory {   
           reg = <0x80000000 0x20000000>;   
          }; 

          (4)chosen 節(jié)點(diǎn)

          我們可以通過設(shè)備樹文件給內(nèi)核傳入一些參數(shù),這要在chosen節(jié)點(diǎn)中設(shè)置bootargs屬性:

          chosen {   
           bootargs = "noinitrd root=/dev/mtdblock4 rw init=/linuxrc console=ttySAC0,115200";   
          };   

          操作設(shè)備樹的函數(shù)

          Linux 內(nèi)核給我們提供了一系列的函數(shù)來獲取設(shè)備樹中的節(jié)點(diǎn)或者屬性信息,這一系列的函數(shù)都有一個(gè)統(tǒng)一的前綴“of_”(“open firmware”即開放固件。),所以在很多資料里面也被叫做 OF 函數(shù)。

          1、節(jié)點(diǎn)相關(guān)操作函數(shù)

          Linux 內(nèi)核使用 device_node 結(jié)構(gòu)體來描述一個(gè)節(jié)點(diǎn),此結(jié)構(gòu)體定義在文件 include/linux/of.h 中,定義如下:

          與查找節(jié)點(diǎn)有關(guān)的 OF 函數(shù)有 5 個(gè):

          (1) of_find_node_by_name 函數(shù)

          of_find_node_by_name 函數(shù)通過節(jié)點(diǎn)名字查找指定的節(jié)點(diǎn),函數(shù)原型如下:

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

          (2) of_find_node_by_type 函數(shù)

          of_find_node_by_type 函數(shù)通過 device_type 屬性查找指定的節(jié)點(diǎn),函數(shù)原型如下:

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

          (3) of_find_compatible_node 函數(shù)

          of_find_compatible_node 函數(shù)根據(jù) device_type 和 compatible 這兩個(gè)屬性查找指定的節(jié)點(diǎn),函數(shù)原型如下:

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

          (4)of_find_matching_node_and_match 函數(shù)

          of_find_matching_node_and_match 函數(shù)通過 of_device_id 匹配表來查找指定的節(jié)點(diǎn),函數(shù)原型如下:

          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);

          (5)of_find_node_by_path 函數(shù)

          of_find_node_by_path 函數(shù)通過路徑來查找指定的節(jié)點(diǎn),函數(shù)原型如下:

          inline struct device_node *of_find_node_by_path(const char *path);

          2、提取屬性值的 OF 函數(shù)

          Linux 內(nèi)核中使用結(jié)構(gòu)體 property 表示屬性,此結(jié)構(gòu)體同樣定義在文件 include/linux/of.h 中,內(nèi)容如下:

          Linux 內(nèi)核也提供了提取屬性值的 OF 函數(shù) :

          (1) of_find_property 函數(shù)

          of_find_property 函數(shù)用于查找指定的屬性,函數(shù)原型如下:

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

          (2)of_property_count_elems_of_size 函數(shù)

          of_property_count_elems_of_size 函數(shù)用于獲取屬性中元素的數(shù)量,比如 reg 屬性值是一個(gè)數(shù)組,那么使用此函數(shù)可以獲取到這個(gè)數(shù)組的大小,此函數(shù)原型如下:

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

          (3)讀取 u8、 u16、 u32 和 u64 類型的數(shù)組數(shù)據(jù)

          (4)讀取 u8、 u16、 u32 和 u64 類型屬性值

          (5)of_property_read_string 函數(shù)

          of_property_read_string 函數(shù)用于讀取屬性中字符串值,函數(shù)原型如下:

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

          版權(quán)聲明:本文來源網(wǎng)絡(luò),免費(fèi)傳達(dá)知識(shí),版權(quán)歸原作者所有。如涉及作品版權(quán)問題,請聯(lián)系我進(jìn)行刪除。

          ????????????????  END  ???????????????

          關(guān)注我的微信公眾號,回復(fù)“加群”按規(guī)則加入技術(shù)交流群。


          點(diǎn)擊“閱讀原文”查看更多分享,歡迎點(diǎn)分享、收藏、點(diǎn)贊、在看。

          瀏覽 98
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  艹逼视频在线免费观看 | 国内自拍区 | 男人天堂v在线 | 久久青草视频 | 成人在线18 |