【轉載】Linux設備樹(Device Tree)機制

轉:Linux設備樹(Device Tree)機制

 

目錄html

1. 設備樹(Device Tree)基本概念及做用
2. 設備樹的組成和使用
  2.1. DTS和DTSI
  2.2. DTC
  2.3. DTB
  2.4. Bootloader
3. 設備樹中dts、dtsi文件的基本語法
  3.1. chosen node
  3.2. aliases node
  3.3. memory node
  3.4. 其餘節點
    3.4.1. Reg屬性
    3.4.2. Compatible屬性
    3.4.3. Interrupts屬性
    3.4.4. Ranges屬性
4. DTB相關結構
  4.1. Header
  4.2. 字符串塊
  4.3. memory reserve map
5. 解析DTB的函數及相關數據結構
  5.1. machine_desc結構
  5.2. 設備節點結構體
  5.3. 屬性結構體
  5.4. uboot下的相關結構體
6. DTB加載及解析過程
7. OF的API接口node

1. 設備樹(Device  Tree)基本概念及做用

在內核源碼中,存在大量對板級細節信息描述的代碼。這些代碼充斥在/arch/arm/plat-xxx和/arch/arm/mach-xxx目錄,對內核而言這些platform設備、resource、i2c_board_info、spi_board_info以及各類硬件的platform_data絕大多數純屬垃圾冗餘代碼。爲了解決這一問題,ARM內核版本3.x以後引入了原先在Power PC等其餘體系架構已經使用的Flattened Device Tree。linux

「A data structure by which bootloaders pass hardware layout to Linux in a device-independent manner, simplifying hardware probing.」開源文檔中對設備樹的描述是,一種描述硬件資源的數據結構,它經過bootloader將硬件資源傳給內核,使得內核和硬件資源描述相對獨立(也就是說*.dtb文件由Bootloader讀入內存,以後由內核來解析)。數組

Device Tree能夠描述的信息包括CPU的數量和類別、內存基地址和大小、總線和橋、外設鏈接、中斷控制器和中斷使用狀況、GPIO控制器和GPIO使用狀況、Clock控制器和Clock使用狀況。數據結構

另外,設備樹對於可熱插拔的熱備不進行具體描述,它只描述用於控制該熱插拔設備的控制器。架構

設備樹的主要優點:對於同一SOC的不一樣主板,只需更換設備樹文件.dtb便可實現不一樣主板的無差別支持,而無需更換內核文件。app

注:要使得3.x以後的內核支持使用設備樹,除了內核編譯時須要打開相對應的選項外,bootloader也須要支持將設備樹的數據結構傳給內核。ide

2. 設備樹的組成和使用

設備樹包含DTC(device tree compiler),DTS(device tree source和DTB(device tree blob)。其對應關係如圖1-1所示:函數

 

 

圖1-1 DTS、DTC、DTB之間的關係工具

2.1. DTS和DTSI

*.dts文件是一種ASCII文本對Device Tree的描述,放置在內核的/arch/arm/boot/dts目錄。通常而言,一個*.dts文件對應一個ARM的machine。

*.dtsi文件做用:因爲一個SOC可能有多個不一樣的電路板,而每一個電路板擁有一個 *.dts。這些dts勢必會存在許多共同部分,爲了減小代碼的冗餘,設備樹將這些共同部分提煉保存在*.dtsi文件中,供不一樣的dts共同使用。*.dtsi的使用方法,相似於C語言的頭文件,在dts文件中須要進行include *.dtsi文件。固然,dtsi自己也支持include 另外一個dtsi文件。

2.2. DTC

DTC爲編譯工具,它能夠將.dts文件編譯成.dtb文件。DTC的源碼位於內核的scripts/dtc目錄,內核選中CONFIG_OF,編譯內核的時候,主機可執行程序DTC就會被編譯出來。 即scripts/dtc/Makefile中

hostprogs-y := dtc

always := $(hostprogs-y) 

在內核的arch/arm/boot/dts/Makefile中,若選中某種SOC,則與其對應相關的全部dtb文件都將編譯出來。在linux下,make dtbs可單獨編譯dtb。如下截取了TEGRA平臺的一部分。

ifeq ($(CONFIG_OF),y)

dtb-$(CONFIG_ARCH_TEGRA) += tegra20-harmony.dtb \

tegra30-beaver.dtb \

tegra114-dalmore.dtb \

tegra124-ardbeg.dtb 

2.3. DTB

DTC編譯*.dts生成的二進制文件(*.dtb),bootloader在引導內核時,會預先讀取*.dtb到內存,進而由內核解析。

2.4. Bootloader

Bootloader須要將設備樹在內存中的地址傳給內核。在ARM中經過bootm或bootz命令來進行傳遞。bootm [kernel_addr] [initrd_address] [dtb_address],其中kernel_addr爲內核鏡像的地址,initrd爲initrd的地址,dtb_address爲dtb所在的地址。若initrd_address爲空,則用「-」來代替。

3. 設備樹中dts、dtsi文件的基本語法

DTS的基本語法範例,如圖3-1 所示。

它包括一系列節點,以及描述節點的屬性。

「/」爲root節點。在一個.dts文件中,有且僅有一個root節點;在root節點下有「node1」,「node2」子節點,稱root爲「node1」和「node2」的parent節點,除了root節點外,每一個節點有且僅有一個parent;其中子節點node1下還存在子節點「child-nodel1」和「child-node2」。

注:若是看過內核/arch/arm/boot/dts目錄的讀者看到這可能有一個疑問。在每一個.dsti和.dts中都會存在一個「/」根節點,那麼若是在一個設備樹文件中include一個.dtsi文件,那麼豈不是存在多個「/」根節點了麼。其實否則,編譯器DTC在對.dts進行編譯生成dtb時,會對node進行合併操做,最終生成的dtb只有一個root node。Dtc會進行合併操做這一點從屬性上也能夠獲得驗證。這個稍後作講解。

在節點的{}裏面是描述該節點的屬性(property),即設備的特性。它的值是多樣化的:

1.它能夠是字符串string,如①;也多是字符串數組string-list,如②

2.它也能夠是32 bit unsigned integers,如cell⑧,整形用<>表示

3.它也能夠是binary data,如③,十六進制用[]表示

4.它也多是空,如⑦


圖3-1  DTS的基本語法範例

在/arch/arm/boot/dts/目錄中有一個文件skeleton.dtsi,該文件爲各ARM vendor共用的一些硬件定義信息。如下爲skeleton.dtsi的所有內容。

/ {

#address-cells = <1>;

#size-cells = <1>;

chosen { };

aliases { };

memory { device_type = "memory"; reg = <0 0>; };

};

如上,屬性# address-cells的值爲1,它表明以「/」根節點爲parent的子節點中,reg屬性中存在一個address值;#size-cells的值爲1,它表明以「\」 根節點爲parent的子節點中,reg屬性中存在一個size值。即父節點的# address-cells和#size-cells決定了子節點的address和size的長度;Reg的組織形式爲reg = 

下面列舉例子,對一些典型節點進行具體描述。

3.1. chosen node

chosen {

bootargs = "tegraid=40.0.0.00.00 vmalloc=256M video=tegrafb console=ttyS0,115200n8 earlyprintk";

};

chosen node 主要用來描述由系統指定的runtime parameter,它並無描述任何硬件設備節點信息。原先經過tag list傳遞的一些linux kernel運行的參數,能夠經過chosen節點來傳遞。如command line能夠經過bootargs這個property來傳遞。若是存在chosen node,它的parent節點必須爲「/」根節點。

3.3. aliases node

aliases {

i2c6 = &pca9546_i2c0;

i2c7 = &pca9546_i2c1;

i2c8 = &pca9546_i2c2;

i2c9 = &pca9546_i2c3;

};

aliases node用來定義別名,相似C++中引用。上面是一個在.dtsi中的典型應用,當使用i2c6時,也即便用pca9546_i2c0,使得引用節點變得簡單方便。例:當.dts  include 該.dtsi時,將i2c6的status屬性賦值爲okay,則代表該主板上的pca9546_i2c0處於enable狀態;反之,status賦值爲disabled,則代表該主板上的pca9546_i2c0處於disenable狀態。以下是引用的具體例子:

&i2c6 {--------------這裏&i2c6究竟是label仍是alias???

status = "okay";

};------------------在*.dtsi中大多默認爲設備爲disable,而後在*.dts中將其enable,進行重寫使能。

3.3. memory node

memory {

device_type = "memory";

reg = <0x00000000 0x20000000>; /* 512 MB */

};

對於memory node,device_type必須爲memory,由以前的描述能夠知道該memory node是以0x00000000爲起始地址,以0x20000000爲結束地址的512MB的空間。

通常而言,在.dts中不對memory進行描述,而是經過bootargs中相似521M@0x00000000的方式傳遞給內核。

3.4.  其餘節點

因爲其餘設備節點依據屬性進行描述,具備相似的形式。接下來的部分主要分析各類屬性的含義及做用,並結合相關的例子進行闡述。

3.4.1. Reg屬性

在device node 中,reg是描述memory-mapped IO register的offset和length。子節點的reg屬性address和length長度取決於父節點對應的#address-cells和#size-cells的值。例:

在上述的aips節點中,存在子節點spda。spda中的中reg爲<0x70000000 0x40000 >,其0x700000000爲address,0x40000爲size。這一點在圖3-1下有做介紹。

這裏補充的一點是:設備節點的名稱格式node-name@unit-address,節點名稱用node-name惟一標識,爲一個ASCII字符串。其中@unit-address爲可選項,能夠不做描述。unit-address的具體格式和設備掛載在哪一個bus上相關。如:cpu的unit-address從0開始編址,以此加1;本例中,aips爲0x70000000。

3.4.2. compatible屬性

在①中,compatible屬性爲string list,用來將設備匹配對應的driver驅動,優先級爲從左向右。本例中spba的驅動優先考慮「fsl,aips-bus」驅動;若沒有「fsl,aips-bus」驅動,則用字符串「simple-bus」來繼續尋找合適的驅動。即compatible實現了原先內核版本3.x以前,platform_device中.name的功能,至於具體的實現方法,本文後面會作講解。

注:對於「/」root節點,它也存在compatible屬性,用來匹配machine type。具體說明將在後面給出。

3.4.3. interrupts屬性

設備節點經過interrupt-parent來指定它所依附的中斷控制器,當節點沒有指定interrupt-parent時,則從parent節點中繼承。上面例子中,root節點的interrupt-parent = <&mic>。這裏使用了引用,即mic引用了②中的inrerrupt-controller @40008000;root節點的子節點並無指定interrupt-controller,如ahb、fab,它們均使用從根節點繼承過來的mic,即位於0x40008000的中斷控制器。

若子節點使用到中斷(中斷號、觸發方法等等),則需用interrupt屬性來指定,該屬性的數值長度受中斷控制器中#inrerrupt-controller值③控制,即interrupt屬性<>中數值的個數爲#inrerrupt-controller的值;本例中#inrerrupt-controller=<2>,於是④中interrupts的值爲<0x3d 0>形式,具體每一個數值的含義由驅動實現決定。

3.4.4. ranges屬性

ranges屬性爲地址轉換表,這在pcie中使用較爲常見,它代表了該設備在到parent節點中所對用的地址映射關係。ranges格式長度受當前節點#address-cell、parent節點#address-cells、當前節點#size-cell所控制。順序爲ranges=<前節點#address-cell, parent節點#address-cells , 當前節點#size-cell。在本例中,當前節點#address-cell=<1>,對應於⑤中的第一個0x20000000;parent節點#address-cells=<1>,對應於⑤中的第二個0x20000000;當前節點#size-cell=<1>,對應於⑤中的0x30000000。即ahb0節點所佔空間從0x20000000地址開始,對應於父節點的0x20000000地址開始的0x30000000地址空間大小。

注:對於相同名稱的節點,dtc會根據定義的前後順序進行合併,其相同屬性,取後定義的那個。

4. DTB相關結構

本節講下.dts編譯生成的dtb文件,其佈局結構。

DTB由三部分組成:頭(Header)、結構塊(device-tree structure)、字符串塊(string block)。下面將詳細介紹這三部分的內容。

4.1. Header

在\kernel\include\linux\of_fdt.h文件中有相關定義

 

4.2.device-tree structure

 

設備樹結構塊是一個線性化的結構體,是設備樹的主體,以節點的形式保存了主板上的設備信息。

在結構塊中,以宏OF_DT_BEGIN_NODE標誌一個節點的開始,以宏OF_DT_END_NODE標識一個節點的結束,整個結構塊以宏OF_DT_END (0x00000009)結束。在\kernel\include\linux\of_fdt.h中有相關定義,咱們把這些宏稱之爲token。

(1)FDT_BEGIN_NODE (0x00000001)。該token描述了一個node的開始位置,緊挨着該token的就是node name(包括unit address)

(2)FDT_END_NODE (0x00000002)。該token描述了一個node的結束位置。

(3)FDT_PROP (0x00000003)。該token描述了一個property的開始位置,該token以後是兩個u32的數據,分別是length和name offset。length表示該property value data的size。name offset表示該屬性字符串在device tree strings block的偏移值。length和name offset以後就是長度爲length具體的屬性值數據。

(4)FDT_NOP (0x00000004)。

(5)FDT_END (0x00000009)。該token標識了一個DTB的結束位置。

一個節點的結構以下:

(1)節點開始標誌:通常爲OF_DT_BEGIN_NODE(0x00000001)。

(2)節點路徑或者節點的單元名(version<3以節點路徑表示,version>=0x10以節點單元名錶示)

(3)填充字段(對齊到四字節)

(4)節點屬性。每一個屬性以宏OF_DT_PROP(0x00000003)開始,後面依次爲屬性值的字節長度(4字節)、屬性名稱在字符串塊中的偏移量(4字節)、屬性值和填充(對齊到四字節)。

(5)若是存在子節點,則定義子節點。

(6)節點結束標誌OF_DT_END_NODE(0x00000002)。

4.3. 字符串塊

經過節點的定義知道節點都有若干屬性,而不一樣的節點的屬性又有大量相同的屬性名稱,所以將這些屬性名稱提取出一張表,當節點須要應用某個屬性名稱時,直接在屬性名字段保存該屬性名稱在字符串塊中的偏移量。

4.4. memory reserve map

這個區域包括了若干的reserve memory描述符。每一個reserve memory描述符是由address和size組成。其中address和size都是用U64來描述。

有些系統,咱們也許會保留一些memory有特殊用途(例如DTB或者initrd image),或者在有些DSP+ARM的SOC platform上,有些memory被保留用於ARM和DSP進行信息交互。這些保留內存不會進入內存管理系統。

5. 解析DTB的函數及相關數據結構

5.1. machine_desc結構

內核將機器信息記錄爲machine_desc結構體(該定義在/arch/arm/include/asm/mach/arch.h),並保存在_arch_info_begin到_arch_info_end之間(_arch_info_begin,_arch_info_end爲虛擬地址,是編譯內核時指定的,此時mmu還未進行初始化。它其實經過彙編完成地址偏移操做)

machine_desc結構體用宏MACHINE_START進行定義,通常在/arch/arm/子目錄,與板級相關的文件中進行成員函數及變量的賦值。由linker將machine_desc彙集在.arch.info.init節區造成列表。

bootloader引導內核時,ARM寄存器r2會將.dtb的首地址傳給內核,內核根據該地址,解析.dtb中根節點的compatible屬性,將該屬性與內核中預先定義machine_desc結構體的dt_compat成員作匹配,獲得最匹配的一個machine_desc。

在代碼中,內核經過在start_kernel->setup_arch中調用setup_machine_fdt來實現上述功能,該函數的具體實現可參見/arch/arm/kernel/devtree.c。 

5.2. 設備節點結構體

1.

記錄節點信息的結構體。.dtb通過解析以後將以device_node列表的形式存儲節點信息。

5.3. 屬性結構體

device_node結構體中的成員結構體,用於描述節點屬性信息。

5.4. uboot下的相關結構體

首先咱們看下uboot用於記錄os、initrd、fdt信息的數據結構bootm_headers,其定義在/include/image.h中,這邊截取了其中與dtb相關的一小部分。

fit_hdr_fdt指向DTB設備樹鏡像的頭。

lmb爲uboot下的一種內存管理機制,全稱爲logical memory blocks。用於管理鏡像的內存。lmb所記錄的內存信息最終會傳遞給kernel。這裏對lmb不作展開描述。在/include/lmb.h和/lib/lmb.c中有對lmb的接口和定義的具體描述。有興趣的讀者能夠看下,所包含的代碼量很少。

6. DTB加載及解析過程

先從uboot裏的do_bootm出發,根據以前描述,DTB在內存中的地址經過bootm命令進行傳遞。在bootm中,它會根據所傳進來的DTB地址,對DTB所在內存作一系列操做,爲內核解析DTB提供保證。上圖爲對應的函數調用關係圖。

在do_bootm中,主要調用函數爲do_bootm_states,第四個參數爲bootm所要處理的階段和狀態。 

在do_bootm_states中,bootm_start會對lmb進行初始化操做,lmb所管理的物理內存塊有三種方式獲取。起始地址,優先級從上往下:

1. 環境變量「bootm_low」

2. 宏CONFIG_SYS_SDRAM_BASE(在tegra124中爲0x80000000)

3. gd->bd->bi_dram[0].start

大小:

1. 環境變量「bootm_size」

2. gd->bd->bi_dram[0].size

通過初始化以後,這塊內存就歸lmb所管轄。接着,調用bootm_find_os進行kernel鏡像的相關操做,這裏不具體闡述。

還記得以前講過bootm的三個參數麼,第一個參數內核地址已經被bootm_find_os處理,而接下來的兩個參數會在bootm_find_other中執行操做。

首先,bootm_find_other根據第二個參數找到ramdisk的地址,獲得ramdisk的鏡像;而後根據第三個參數獲得DTB鏡像,同檢查kernel和ramdisk鏡像同樣,檢查DTB鏡像也會進行一系列的校驗工做,若是校驗錯誤,將沒法正常啓動內核。另外,uboot在確認DTB鏡像無誤以後,會將該地址保存在環境變量「fdtaddr」中。

接着,uboot會把DTB鏡像reload一次,使得DTB鏡像所在的物理內存歸lmb所管理:①boot_fdt_add_mem_rsv_regions會將原先的內存DTB鏡像所在的內存置爲reserve,保證該段內存不會被其餘非法使用,保證接下來的reload數據是正確的;②boot_relocate_fdt會在bootmap區域中申請一塊未被使用的內存,接着將DTB鏡像內容複製到這塊區域(即歸lmb所管理的區域)

注:若環境變量中,指定「fdt_high」參數,則會根據該值,調用lmb_alloc_base函數來分配DTB鏡像reload的地址空間。若分配失敗,則會中止bootm操做。於是,不建議設置fdt_high參數。

接下來,do_bootm會根據內核的類型調用對應的啓動函數。與linux對應的是do_bootm_linux。

① boot_prep_linux

爲啓動後的kernel準備參數

② boot_jump_linux

以上是boot_jump_linux的片斷代碼,能夠看出:若使用DTB,則原先用來存儲ATAG的寄存器R2,將會用來存儲.dtb鏡像地址。

boot_jump_linux最後將調用kernel_entry,將.dtb鏡像地址傳給內核。

 

下面咱們來看下內核的處理部分:

在arch/arm/kernel/head.S中,有這樣一段:

_vet_atags定義在/arch/arm/kernel/head-common.S中,它主要對DTB鏡像作了一個簡單的校驗。

真正解析處理dbt的開始部分,是setup_arch->setup_machine_fdt。這部分的處理在第五部分的machine_mdesc中有說起。

如圖,是setup_machine_fdt中的解析過程。

解析chosen節點將對boot_command_line進行初始化。

解析根節點的{size,address}將對dt_root_size_cells,dt_root_addr_cells進行初始化。爲以後解析memory等其餘節點提供依據。

解析memory節點,將會把節點中描述的內存,加入memory的bank。爲以後的內存初始化提供條件。

 

解析設備樹在函數unflatten_device_tree中完成,它將.dtb解析成device_node結構(第五部分有其定義),並構成單項鍊表,以供OF的API接口使用。

下面主要結合代碼分析:/drivers/of/fdt.c

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

總的概括爲

① kernel入口處獲取到uboot傳過來的.dtb鏡像的基地址

② 經過early_init_dt_scan()函數來獲取kernel初始化時須要的bootargs和cmd_line等系統引導參數。

③ 調用unflatten_device_tree函數來解析dtb文件,構建一個由device_node結構鏈接而成的單向鏈表,並使用全局變量of_allnodes保存這個鏈表的頭指針。

④ 內核調用OF的API接口,獲取of_allnodes鏈表信息來初始化內核其餘子系統、設備等。

 

7. OF的API接口

OF的接口函數在/drivers/of/目錄下,有of_i2c.c、of_mdio.c、of_mtd.c、Adress.c等等

這裏將列出幾個經常使用的API接口。

 

1. 用來查找在dtb中的根節點

unsigned long __init of_get_flat_dt_root(void)

 

2. 根據deice_node結構的full_name參數,在全局鏈表of_allnodes中,查找合適的device_node

struct device_node *of_find_node_by_path(const char *path)

例如:

struct device_node *cpus;

cpus=of_find_node_by_path("/cpus");

 

3. 若from=NULL,則在全局鏈表of_allnodes中根據name查找合適的device_node

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

例如:

struct device_node *np;

np = of_find_node_by_name(NULL,"firewire");

 

4. 根據設備類型查找相應的device_node

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

例如:

struct device_node *tsi_pci;

tsi_pci= of_find_node_by_type(NULL,"pci");

 

5. 根據compatible字符串查找device_node

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

 

6. 根據節點屬性的name查找device_node

struct device_node *of_find_node_with_property(struct device_node *from,const char *prop_name)

 

7. 根據phandle查找device_node

struct device_node *of_find_node_by_phandle(phandle handle)

 

8. 根據alias的name得到設備id號

int of_alias_get_id(struct device_node *np, const char *stem)

 

9. device node計數增長/減小

struct device_node *of_node_get(struct device_node *node)

void of_node_put(struct device_node *node)

 

10. 根據property結構的name參數,在指定的device node中查找合適的property

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

 

11. 根據property結構的name參數,返回該屬性的屬性值

const void *of_get_property(const struct device_node *np, const char *name,int *lenp)

 

12. 根據compat參數與device node的compatible匹配,返回匹配度

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

 

13. 得到父節點的device node

struct device_node *of_get_parent(const struct device_node *node)

 

14. 將matches數組中of_device_id結構的name和type與device node的compatible和type匹配,返回匹配度最高的of_device_id結構

const struct of_device_id *of_match_node(const struct of_device_id *matches,const struct device_node *node)

 

15. 根據屬性名propname,讀出屬性值中的第index個u32數值給out_value

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

 

16. 根據屬性名propname,讀出該屬性的數組中sz個屬性值給out_values

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)

 

17. 根據屬性名propname,讀出該屬性的u64屬性值

int of_property_read_u64(const struct device_node *np, const char *propname,u64 *out_value)

 

18. 根據屬性名propname,讀出該屬性的字符串屬性值

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

 

19. 根據屬性名propname,讀出該字符串屬性值數組中的第index個字符串

int of_property_read_string_index(struct device_node *np, const char *propname,int index, const char **output)

 

20. 讀取屬性名propname中,字符串屬性值的個數

int of_property_count_strings(struct device_node *np, const char *propname)

 

21. 讀取該設備的第index個irq號

unsigned int irq_of_parse_and_map(struct device_node *dev, int index)

 

22. 讀取該設備的第index個irq號,並填充一個irq資源結構體

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

 

23. 獲取該設備的irq個數

int of_irq_count(struct device_node *dev)

 

24. 獲取設備寄存器地址,並填充寄存器資源結構體

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

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

 

25. 獲取通過映射的寄存器虛擬地址

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

 

24. 根據device_node查找返回該設備對應的platform_device結構

struct platform_device *of_find_device_by_node(struct device_node *np)

 

25. 根據device node,bus id以及父節點建立該設備的platform_device結構

struct platform_device *of_device_alloc(struct device_node *np,const char *bus_id,struct device *parent)

static struct platform_device *of_platform_device_create_pdata(struct device_node *np,const char *bus_id,

void *platform_data,struct device *parent)

 

26. 遍歷of_allnodes中的節點掛接到of_platform_bus_type總線上,因爲此時of_platform_bus_type總線上尚未驅動,因此此時不進行匹配

int of_platform_bus_probe(struct device_node *root,const struct of_device_id *matches,struct device *parent)

相關文章
相關標籤/搜索