Linux設備樹(3)——Linux內核對設備樹的處理

1、內核head.S對dtb的簡單處理node

Documentation/devicetree/usage-model.txt 中指定:linux

Linux uses DT data for three major purposes:
1) platform identification,
2) runtime configuration, and
3) device population.

內核對設備樹的處理也是分這三部分的。數組

1. 對於32bit的arm處理器,bootloader啓動內核時,會設置r0,r1,r2三個寄存器,
r0通常設置爲0;
r1通常設置爲machine id (在使用設備樹時該參數沒有被使用);
r2通常設置ATAGS(使用設備樹以前)或DTB的開始地址(使用設備樹以後)ide

bootloader給內核傳遞的參數時有2種方法:ATAGS 或 DTB函數

a. __lookup_processor_type : 使用匯編指令讀取CPU ID, 根據該ID找到對應的proc_info_list結構體(裏面含有這類CPU的初始化函數、信息)
b. __vet_atags : 判斷是否存在可用的ATAGS或DTB
c. __create_page_tables : 建立頁表, 即建立虛擬地址和物理地址的映射關係
d. __enable_mmu : 使能MMU, 之後就要使用虛擬地址了
e. __mmap_switched : 上述函數裏將會調用__mmap_switched
f. 把bootloader傳入的r2參數, 保存到變量__atags_pointer中
g. 調用C函數start_kernelspa

head.S/head-common.S :
把bootloader傳來的r1值, 賦給了C變量: __machine_arch_type
把bootloader傳來的r2值, 賦給了C變量: __atags_pointer // dtb首地址線程

對於32bit的arm處理器,machine_desc 使用 MACHINE_START 初始化,其 dt_compat 存儲的是 compatible 屬性數組,用於表示支持的單板。debug

u-boot 中也提供的對dtb文件進行操做的命令,爲 fdt, uboot 中全部的命令都是使用U_BOOT_CMD()來定義的,對應文件中有命令的使用註釋。指針

 

 

2、內核對設備樹中平臺信息的處理調試

a. 設備樹根節點的compatible屬性列出了一系列的字符串,表示它兼容的單板名,從「最兼容」到次之(體如今匹配順序上)。

b. 內核中有多個machine_desc,其中有 dt_compat 成員,它指向一個字符串數組,裏面表示該 machine_desc 支持哪些單板。

c. 使用設備樹根節點的 compatile 屬性的值,跟每個 machine_desc.dt_compat 比較,成績爲"吻合的compatile屬性值的位置",成績越低越匹配, 對應的 machine_desc 即被選中。

函數調用過程(arm平臺適合,可是不適合arm64平臺了):

start_kernel // init/main.c
    setup_arch(&command_line);  // arch/arm/kernel/setup.c
        mdesc = setup_machine_fdt(__atags_pointer);  // arch/arm/kernel/devtree.c
            /*將dtb文件佔用的內存預留起來(以後經過sysfs文件能夠dump)*/
            fixmap_remap_fdt(dt_phys);
                __fixmap_remap_fdt(dt_phys, &size, PAGE_KERNEL_RO);
                memblock_reserve(dt_phys, size);
            early_init_dt_verify(phys_to_virt(dt_phys)  // 判斷是否有效的dtb, drivers/of/ftd.c
                /*保存設備樹dtb文件起始地址*/
                initial_boot_params = params;
                    mdesc = of_flat_dt_match_machine(mdesc_best, arch_get_next_mach); //找到最匹配的machine_desc, drivers/of/ftd.c
                        while ((data = get_next_compat(&compat))) {
                            score = of_flat_dt_match(dt_root, compat);
                            if (score > 0 && score < best_score) {
                                best_data = data;
                                best_score = score;
                            }
                        }
                    
                    machine_desc = mdesc;

 

3、內核對設備樹中運行時配置信息的處理

1. 函數調用過程

start_kernel // init/main.c
    setup_arch(&command_line);  // arch/arm/kernel/setup.c
        mdesc = setup_machine_fdt(__atags_pointer);  // arch/arm/kernel/devtree.c
                    early_init_dt_scan_nodes();      // drivers/of/ftd.c
                        /*從「/chosen」(根節點下的chosen節點)下檢索各類信息*/
                        of_scan_flat_dt(early_init_dt_scan_chosen, boot_command_line);

                        /* Initialize {size,address}-cells info */
                        of_scan_flat_dt(early_init_dt_scan_root, NULL);

                        /* Setup memory, calling early_init_dt_add_memory_arch */
                        of_scan_flat_dt(early_init_dt_scan_memory, NULL);

a. /chosen 節點中 bootargs 屬性的值, 存入全局變量 boot_command_line
b. 將根節點的 #address-cells, #size-cells 屬性的值,存入全局變量 dt_root_addr_cells, dt_root_size_cells
c. 解析 /memory 中的 reg 屬性, 提取出"base, size", 最終調用 memblock_add(base, size);

2. dts文件中的每個 「{};」 都表示一個節點,都會對應構造一個 device_node 結構體,根節點也不例外。同級不一樣節點之間是兄弟的關係,包含節點是父子關係。

 

4、dtb轉換爲device_node(unflatten)的過程

1. 函數調用過程

setup_arch(char **cmdline_p)
    arm_memblock_init(mdesc); // arch/arm/kernel/setup.c
        early_init_fdt_reserve_self();
            //把DTB所佔區域保留下來, 即調用: memblock_reserve
            early_init_dt_reserve_memory_arch(__pa(initial_boot_params), fdt_totalsize(initial_boot_params), 0);           
        early_init_fdt_scan_reserved_mem();  // 根據dtb中的memreserve信息, 調用memblock_reserve
       /*非扁平化,也就是把dtb構形成樹的結構*/
    unflatten_device_tree(void)
        /*
         * 遍歷設備樹中每個node節點,而後構造device_node結構體,並生成其樹狀關係,
         * 根節點存在struct device_node of_root參數中。
         */
        __unflatten_device_tree(initial_boot_params, NULL, &of_root, early_init_dt_alloc_memory_arch, false);
            unflatten_dt_nodes(blob, NULL, dad, NULL);
                /*對設備樹中的全部節點都執行這個填充節點的函數*/
                populate_node
                    /*
                     * 這裏一塊把節點的名字長度allocl一塊兒分配了,節點的名字在device_node的末尾,
                     * 由device_node中的full_name指向。
                     */
                    unflatten_dt_alloc(mem, sizeof(struct device_node) + allocl, __alignof__(struct device_node));
                    np->full_name = fn = ((char *)np) + sizeof(*np);

                    /* 處理屬性,爲節點中的每個屬性都構造一個struct property結構 */
                    populate_properties(blob, offset, mem, np, pathp, dryrun);

2. 在DTB文件中,
dtb文件中,每個節點都以 TAG(FDT_BEGIN_NODE 即 0x00000001) 開始, 節點內部能夠嵌套其餘節點, 每個屬性都以 TAG(FDT_PROP即0x00000003)開始

3. dtb文件中的每個節點都轉換爲一個device_node結構體:

struct device_node {
    const char *name;  // 來自節點中的name屬性, 若是沒有該屬性, 則設爲"NULL"
    const char *type;  // 來自節點中的device_type屬性, 若是沒有該屬性, 則設爲"NULL"
    phandle phandle;
    const char *full_name;  //存儲節點的名字, node-name[@unit-address],實際上它是個指針,指向存在於這個結構體後面的名字。
    struct fwnode_handle fwnode;

    struct  property *properties;  // 節點的屬性
    struct  property *deadprops;    /* removed properties */
    struct  device_node *parent;   // 節點的父親
    struct  device_node *child;    // 節點的孩子(子節點)
    struct  device_node *sibling;  // 節點的兄弟(同級節點)
#if defined(CONFIG_OF_KOBJ)
    struct  kobject kobj;
#endif
    unsigned long _flags;
    void    *data;
#if defined(CONFIG_SPARC)
    const char *path_component_name;
    unsigned int unique_id;
    struct of_irq_controller *irq_trans;
#endif
};

4. device_node 結構體中有 properties, 用來表示該節點的屬性,每個屬性對應一個 property 結構體

struct property {
    char    *name;    // 屬性名字, 指向dtb文件中的字符串,好比reg, compatible等。
    int length;       // 屬性值的長度
    void    *value;   // 屬性值, 指向dtb文件中value所在位置, 數據仍以big endian存儲
    struct property *next;
#if defined(CONFIG_OF_DYNAMIC) || defined(CONFIG_SPARC)
    unsigned long _flags;
#endif
#if defined(CONFIG_OF_PROMTREE)
    unsigned int unique_id;
#endif
#if defined(CONFIG_OF_KOBJ)
    struct bin_attribute attr;
#endif
};

5. 這些device_node構成一棵樹, 根節點爲: of_root

 

5、device_node 轉換爲 platform_device

1. 轉換過程

dts -> dtb -> device_node -> platform_device

(1) 哪些 device_node 能夠轉換爲 platform_device

① 根節點下的含有 compatile 屬性的子節點。
② 若是一個結點的 compatile 屬性含有這些特殊的值("simple-bus","simple-mfd","isa","arm,amba-bus",定義在 of_default_bus_match_table 中)之一, 那麼它的子結點(需含compatile屬性)也能夠轉換爲platform_device。

(2) 怎麼轉換 ?
platform_device 中含有 resource 數組, 它來自 device_node 的 reg, interrupts 屬性;
platform_device.dev.of_node 指向 device_node,能夠經過它得到其餘屬性。

2. 根節點下的i2c, spi等節點會轉換爲平臺設備的設備端,i2c, spi等總線節點下的子節點, 應該交給對應的總線驅動程序來處理, 它們不該該被轉換爲 platform_device。

3. 小結:
(1) 內核函數 of_platform_default_populate_init, 遍歷 device_node 樹, 生成 platform_device。
(2) 並不是全部的 device_node 都會轉換爲 platform_device,只有如下的device_node會轉換:
① 該節點必須含有 compatible 屬性
② 須要是根節點的子節點(節點必須含有compatible屬性)纔會轉換
③ 含有特殊 compatible 屬性的節點的子節點(子節點必須含有compatible屬性,子節點的子節點纔會轉換),這些特殊的compatilbe屬性爲: "simple-bus","simple-mfd","isa","arm,amba-bus",定義在全局of_default_bus_match_table中。

4. 示例

/ {
      mytest {
            /*父節點中的"simple-bus"屬性會致使其子節點也會構建出平臺設備的設備端*/
          compatile = "mytest", "simple-bus";
          mytest@0 {
                compatile = "mytest_0";
          };
      };
      
      i2c {
          compatile = "samsung,i2c";
          at24c02 {
                compatile = "at24c02";                      
          };
      };

      spi {
          compatile = "samsung,spi";              
          flash@0 {
                compatible = "winbond,w25q32dw";
                spi-max-frequency = <25000000>;
                reg = <0>;
              };
      };
};

(1) 節點 /mytest 會被轉換爲 platform_device。因爲它兼容 "simple-bus", 它的子節點 /mytest/mytest@0 也會被轉換爲platform_device. 也就是說一個節點的 compatible 屬性中只要有 "simple-bus",其子節也會轉換爲 platform_device,若沒有是不會轉換的。
simple-bus 在usage-model中有介紹。

(2) /i2c 節點通常表示i2c控制器,它會被轉換爲platform_device,在內核中有對應的 platform_driver; 其子節點 /i2c/at24c02 節點不會被轉換爲 platform_device,它被如何處理徹底由父節點的 platform_driver 決定, 通常是被建立爲一個i2c_client。

(3) /spi 節點也相似, 它通常也是用來表示 SPI 控制器, 它會被轉換爲 platform_device, 在內核中有對應的 platform_driver; 其子節點 /spi/flash@0 不會被轉換爲 platform_device, 它被如何處理徹底由父節點的 platform_driver 決定, 通常是被建立爲一個spi_device。

5. device_node 節點轉化爲 platform_device 的函數調用過程

負責轉化的函數爲:

static int __init of_platform_default_populate_init(void) 
arch_initcall_sync(of_platform_default_populate_init);

內核中沒有直接對它的調用,而是使用放在".initcall3s.init"代碼段中,在內核啓動時進行 do_initcall_level 時調用這個函數。

arch_initcall_sync(of_platform_default_populate_init) 宏等效於:

static initcall_t __initcall_of_platform_default_populate_init3s __used
__attribute__((__section__(".initcall3s.init"))) = of_platform_default_populate_init;
start_kernel //init/main.c
    rest_init();
        pid = kernel_thread(kernel_init, NULL, CLONE_FS); /*建立kernel_init內核線程*/
                    kernel_init
                        kernel_init_freeable();
                            do_basic_setup();
                                do_initcalls();
                                    for (level = 0; level < ARRAY_SIZE(initcall_levels) - 1; level++)
                                        do_initcall_level(level);  //好比 do_initcall_level(3)
                                            for (fn = initcall_levels[3]; fn < initcall_levels[3+1]; fn++)
                                                do_one_initcall(initcall_from_entry(fn));  //就是調用"arch_initcall_sync(fn)"中定義的fn函數

生成platform_device的過程:

of_platform_default_populate_init //drivers/of/platform.c
    of_platform_default_populate(NULL, NULL, NULL);
        of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL)
            for_each_child_of_node(root, child) {
                rc = of_platform_bus_create(child, matches, lookup, parent, true); //調用過程看下面
                    of_platform_device_create_pdata
                        /*根據device_node節點的屬性設置platform_device的resource*/
                        dev = of_device_alloc(np, bus_id, parent);
                            if (num_irq || num_reg) {
                                res = kzalloc(sizeof(*res) * (num_irq + num_reg), GFP_KERNEL);
                                dev->num_resources = num_reg + num_irq;
                                dev->resource = res;
                                for (i = 0; i < num_reg; i++, res++) {
                                    rc = of_address_to_resource(np, i, res);
                                }
                            }
                    /*若父設備設備樹中的節點中compatible中沒有這個table裏面的字符,就不爲其子節點建立平臺設備了*/
                    if (!dev || !of_match_node(of_default_bus_match_table, bus))
                        return 0;

of_platform_bus_create的詳細調用過程(處理bus節點生成platform_devie, 並決定是否處理它的子節點):

of_platform_bus_create(bus, matches, ...)
    dev = of_platform_device_create_pdata(bus, bus_id, platform_data, parent);  // 生成bus節點的platform_device結構體
    /*
     * 若是父設備樹節點(一級節點)的compatile屬性不吻合of_default_bus_match_table表, 
     * 就不爲它的子節點(二級節點)建立platform_device結構。(這是個遞歸調用,也多是
     * 3、四級節點)。
     */
    if (!dev || !of_match_node(matches, bus))  
        return 0;
    
    for_each_child_of_node(bus, child) {    //取出每個子節點
        pr_debug("   create child: %pOF\n", child);
        /*
         * 若上面吻合就爲它的子節點也建立平臺設備的設備端, 這是一個遞歸調用。
         */
        rc = of_platform_bus_create(child, matches, lookup, &dev->dev, strict);
    }

 

6. I2C總線節點的處理過程:

/i2c 節點通常表示 i2c 控制器, 它會被轉換爲 platform_device, 在內核中有對應的 platform_driver; platform_driver 的 probe 函數中會調用 i2c_add_numbered_adapter:

i2c_add_numbered_adapter   // drivers/i2c/i2c-core-base.c
    __i2c_add_numbered_adapter
        i2c_register_adapter
            of_i2c_register_devices(adap);   // drivers/i2c/i2c-core-of.c
                for_each_available_child_of_node(bus, node) {
                    client = of_i2c_register_device(adap, node);
                        client = i2c_new_device(adap, &info);   //設備樹中的/i2c的子節點被轉換爲i2c_client
                            device_register(&client->dev);
                }

i2c觸摸板驅動(client驅動)的註冊過程:

mxt_init(void) //atmel_mxt_ts.c
    i2c_add_driver(&mxt_driver); //也就是i2c_register_driver(THIS_MODULE, driver)
        /*註冊返回時,驅動程序核心將爲全部匹配但未綁定的設備調用了probe()。*/
        driver_register(&driver->driver);
        /*遍歷已經存在的i2c適配器(每個i2c主機控制器都會註冊成一個i2c適配器)*/
        i2c_for_each_dev(driver, __process_new_driver);
            i2c_do_add_adapter(data, to_i2c_adapter(dev));s
                /*檢測該總線上支持的設備,並實例化它們*/
                i2c_detect(adap, driver);
                    i2c_detect_address(temp_client, driver);
                        client = i2c_new_device(adapter, &info);

 

7. SPI總線節點的處理過程:
/spi 節點通常表示 spi 控制器, 它會被轉換爲 platform_device, 在內核中有對應的 platform_driver; platform_driver的probe函數中會調用spi_register_master, 即spi_register_controller:

spi_register_controller    // drivers/spi/spi.c
    of_register_spi_devices    // drivers/spi/spi.c
        for_each_available_child_of_node(ctlr->dev.of_node, nc) {
            spi = of_register_spi_device(ctlr, nc);  // 設備樹中的spi子節點被轉換爲spi_device
                spi = spi_alloc_device(ctlr);
                rc = of_spi_parse_dt(ctlr, spi, nc);
                rc = spi_add_device(spi);
        }

 

8. 小結

  並非全部的 device_node 結構都能轉換成 platform_device 結構,好比根節點、choosen、memory 等對應的 device_node 就不會轉換爲platform_device 結構。通常只有根節點的子節點(一級子節點)才能轉化爲 platform_device 結構,子節點的子節點通常狀況下是不能夠轉換爲 platform_device 結構的,可是若其父節點的compatible屬性中指定了of_default_bus_match_table中的字符串,其子節點也是能夠轉化爲 platform_device 的。

/i2c 下的子節點是交由根節點下的i2c節點對應的 platform_driver 驅動的,子節點註冊成爲 i2c_client。spi總線的相似,其子節點註冊爲spi_device。

根節點下的子節點會註冊成爲平臺設備的設備端,根節點的子節點的子節點不會註冊成平臺設備,而是由其父節點的平臺驅動負責處理。

 

6、platform_device跟platform_driver的匹配

1. 註冊 platform_driver 的過程

platform_driver_register //drivers/base/platform.c
    __platform_driver_register
        drv->driver.probe = platform_drv_probe;
        driver_register
            //最終調用的是這個函數,i2c的和spi的也都是它
            bus_add_driver
                //把 platform_driver 放入 platform_bus_type 的driver鏈表中
                klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers);
                driver_attach
                    bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);  // 對於plarform_bus_type下的每個設備, 調用__driver_attach
                        __driver_attach
                            ret = driver_match_device(drv, dev);  // 判斷dev和drv是否匹配成功
                                return drv->bus->match ? drv->bus->match(dev, drv) : 1;  // 調用 platform_bus_type.match
                            driver_probe_device(drv, dev);
                                really_probe
                                    drv->probe  // platform_drv_probe
                                        platform_drv_probe
                                            struct platform_driver *drv = to_platform_driver(_dev->driver);
                                            drv->probe

2. 註冊 platform_device 的過程

platform_device_register
    platform_device_add
        device_add
            bus_add_device
                //把 platform_device 放入 platform_bus_type 的device鏈表中
                klist_add_tail(&dev->p->knode_bus, &bus->p->klist_devices); 
            bus_probe_device(dev);
                device_initial_probe
                    __device_attach
                        //對於plarform_bus_type下的每個driver, 調用 __device_attach_driver
                        ret = bus_for_each_drv(dev->bus, NULL, &data, __device_attach_driver);
                            __device_attach_driver
                                ret = driver_match_device(drv, dev);
                                    return drv->bus->match ? drv->bus->match(dev, drv) : 1; //調用platform_bus_type.match
                                driver_probe_device

匹配函數是platform_bus_type.match,即platform_match,由這個函數可知匹配過程按優先順序羅列以下:
a. 比較 platform_dev.driver_override 和 platform_driver.drv->name
b. 比較 platform_dev.dev.of_node的compatible屬性 和 platform_driver.drv->of_match_table
c. 比較 platform_dev.name 和 platform_driver.id_table
d. 比較 platform_dev.name 和 platform_driver.drv->name
有一個成功, 即匹配成功,以後dev再也不參與匹配了。


3. 範圍更廣一些的總線設備模型:

設備端註冊或驅動端註冊都會觸發匹配,匹配是使用 bus_type.match(),匹配上後會調用 bus_type.probe(),bus的probe()中會調用
驅動的probe().

(1) 驅動端註冊觸發的匹配過程:

driver_register(struct device_driver *drv)
    bus_add_driver(struct device_driver *drv) //drivers/base/bus.c
        driver_attach(struct device_driver *drv) //drivers/base/dd.c
            bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);
                __driver_attach(struct device *dev, void *data)
                    /*調用drv->bus->match(dev, drv)來匹配dev和drv,匹配上後調用下面的probe()流程*/
                    driver_match_device(drv, dev);
                    /*
                     * 只有當這個dev->driver爲空的時候才進行匹配,也就是說一旦dev匹配到drv後就
                     * 再也不參與匹配過程了。
                     */
                    if (!dev->driver)
                    driver_probe_device(struct device_driver *drv, struct device *dev)    //drivers/base/dd.c
                        really_probe    //drivers/base/dd.c
                            if (dev->bus->probe) {
                                /*先回去調用bus的probe,在bus的probe中再調用驅動的probe.*/
                                ret = dev->bus->probe(dev);
                            } else if (drv->probe) {
                                /*若bus的probe不存在,則直接調用驅動的probe.*/
                                ret = drv->probe(dev);
                            }

對於i2c平臺設備,其bus爲 i2c_bus_type,i2c_bus_type.probe = i2c_device_probe:

i2c_device_probe
    if (driver->probe)
            status = driver->probe(client, i2c_match_id(driver->id_table, client));

只要 device_driver 在註冊的時候指定好 bus,以後引用的都是這個bus裏面的函數.


(2) 設備端註冊觸發匹配過程:

device_register(struct device *dev) //drivers/base/core.c
    device_add(dev);
        bus_add_device(dev);
            /*將device添加到bus的klist_devices鏈表中*/
            klist_add_tail(&dev->p->knode_bus, &bus->p->klist_devices);
            kobject_uevent(&dev->kobj, KOBJ_ADD);
            bus_probe_device(dev);
                if (bus->p->drivers_autoprobe)
                    device_initial_probe(dev); //drivers/base/dd.c
                        __device_attach(dev, true);
                            /*對bus上的每個驅動都與device匹配*/
                            bus_for_each_drv(dev->bus, NULL, &data, __device_attach_driver);
                                __device_attach_driver
                                    driver_match_device(drv, dev);
                                    driver_probe_device(drv, dev); /*接下來的處理流程和drv匹配dev是同樣的了*/

 

7、內核中設備樹的操做函數

dtb -> device_node -> platform_device

1. include/linux/目錄下有不少of開頭的頭文件:

// (1) 處理DTB的
of_fdt.h           // dtb文件的相關操做函數, 咱們通常用不到, 由於dtb文件在內核中已經被轉換爲device_node樹(它更易於使用)

// (2) 處理device_node的
of.h               // 提供設備樹的通常處理函數, 好比 of_property_read_u32(讀取某個屬性的u32值), of_get_child_count(獲取某個device_node的子節點數)
of_address.h       // 地址相關的函數, 好比 of_get_address(得到reg屬性中的addr, size值)
of_match_device(從matches數組中取出與當前設備最匹配的一項)
of_dma.h           // 設備樹中DMA相關屬性的函數
of_gpio.h          // GPIO相關的函數
of_graph.h         // GPU相關驅動中用到的函數, 從設備樹中得到GPU信息
of_iommu.h         // 不多用到
of_irq.h           // 中斷相關的函數
of_mdio.h          // MDIO (Ethernet PHY) API
of_net.h           // OF helpers for network devices. 
of_pci.h           // PCI相關函數
of_pdt.h           // 不多用到
of_reserved_mem.h  // reserved_mem的相關函數

// (3) 處理 platform_device的,在將 device_node --> platform_device 的過程當中大量使用
 
of_platform.h      // 把device_node轉換爲platform_device時用到的函數, 
                   // 好比of_device_alloc(根據device_node分配設置platform_device), 
                   //     of_find_device_by_node (根據device_node查找到platform_device),
                   //     of_platform_bus_probe (處理device_node及它的子節點)
of_device.h        // 設備相關的函數, 好比 of_match_device

2. 設備樹中的下面的操做使用的應該是handle,有兩個值,表示能夠引用兩類中斷。
interrupts = <0xA 0x8>

 

8、在根文件系統中查看設備樹(有助於調試)

1. /sys/firmware/fdt // 原始dtb文件

hexdump -C /sys/firmware/fdt    //打印出原始的dtb文件

2. /sys/firmware/devicetree // 以目錄結構程現的dtb文件

根節點對應其中的base目錄, 每個節點對應一個目錄, 每個屬性對應一個文件。

3. /sys/devices/platform // 顯示系統中全部的platform_device, 有來自設備樹的, 也有來有.c文件中註冊的。
對於來自設備樹的platform_device,其sys文件路徑下有of_node節點(反向也成立)。能夠進入 /sys/devices/platform/<設備名>/of_node 查看它的設備樹屬性

能夠根據這個目錄判斷平臺設備的設備端有沒有被建立。也能夠經過有無 of_node 節點來判斷是否是經過設備樹節點產生的平臺設備。

4. /proc/device-tree 是連接文件, 指向 /sys/firmware/devicetree/base

相關文章
相關標籤/搜索