一、设备树与驱动的匹配
1.设备树会被/scripts中的dtc可执行程序编译成二进制.dtb文件,之前设备树中的节点信息会以单链表的形式存储在这个.dtb文件中;驱动与设备树中compatible属性匹配上后,
驱动中的相应的node节点就映射在这个设备树节点上了,然后以这个node为参数调用of函数来解析这个设备树块上的信息为驱动所用。设备树中的信息是逐条进行获取的(?)
2.例如设备树中有如下定义:
flash_SY7803:flashlight {
compatible = "qcom,leds-gpio-flash";
status = "okay";
pinctrl-names = "flash_default";
pinctrl- = <&SY7803_default>;
qcom,flash-en = <&msm_gpio >;
qcom,flash-now = <&msm_gpio >;
qcom,op-seq = "flash_en", "flash_now";
qcom,torch-seq-val = < >;
qcom,flash-seq-val = < >;
linux,name = "flashlight"; //属性 linux,name
linux,default-trigger = "flashlight-trigger";
};
驱动中通过node接电来匹配设备树信息,例如:
struct device_node *node = pdev->dev.of_node;  //取得node  
rc = of_property_read_string(node, "linux,default-trigger", &temp_str);//temp_str="flashlight-trigger"
int rc = of_get_named_gpio(node, "qcom,flash-en", );//返回31,ARM中使用整形来表示引脚的 
rc = of_property_read_string(node, "linux,name", &flash_led->cdev.name);参数3指向:返回"flashlight"
rc = of_property_read_u32_array(node, "qcom,flash-seq-val",array_flash_seq, ); //获取整形数组,每个数组中有两个元素
rc = of_property_read_string_index(node, "qcom,op-seq", i, &seq_name);//i是索引,读取哪个字符串
更多相关函数见:include/linux/of.h

二、语法

1.node节点内描述的属性,value就是属性的值(任意字节数据,可以是整型、字符串、数组、等等)。描述行以“;”结束

2.节点的命名以字母、数字、_、等等符号构成,可以直接以设备名为节点名,也可以以“设备名@I/O地址”为节点名、“设备类型@I/O地址”为节点名,

3.子节点的节点名dm9000,节点路径/dm9000:

/{

...

dm9000{

...

};

...

};

节点名:dm9000,节点路径:/dm9000@80000000(类型表述也一样,例如:节点名ethernet,节点路径/ethernet@80000000)

/{

...

dm9000@80000000{

...

};

...

};

4.节点引用

节点名:demo,节点路径:/demo@80000000,引用路径:demo(等价/demo@80000000,解决路径名过长的问题)

/{

aliases {

demo = &demo;

};

...

demo:demo@80000000{

...

};

...

};

设备树中引用节点“/demo@80000000”的范例:

&demo{

...

};


5.节点查找

内核提供很多内核函数来查找(解析设备树)一个指定节点,可以按路径查找、按节点名查找、通过compatible属性查找等

  (1)路径查找:struct device_node *of_find_node_by_path(const char *path);

    补充:设备树的深度表示depth深度要为1,表示在根节点下(一般根节点/的depth为0)

  (2)节点名查找:struct device_node *of_find_node_by_name(struct device_node *from, const char *name);

  (3)通过compatible属性查找:struct device_node *of_find_compatible_node(struct device_node *from, const char *type, const char *compat);

  (4)设备ID表结构

  struct of_device_id {

    char name[32];        /*设备名*/

    char type[32];        /*设备类型*/

    char compatible[128]; /*用于与设备树compatible属性值匹配的字符串*/

    const void *data;     /*私有数据*/

  };


  /* 功能:通过compatible属性查找指定节点

  * 参数:

  * struct device_node *from - 指向开始路径的节点,如果为NULL,则从根节点开始

  * const struct of_device_id *matches - 指向设备ID表

  * 注意ID表必须以NULL结束

  * 范例: const struct of_device_id mydemo_of_match[] = {

  { .compatible = "fs4412,mydemo", },

  {}

  };

  */

  struct device_node *of_find_matching_node(struct device_node *from, const struct of_device_id *matches);


  (5)查找指定节点的子节点:struct device_node *of_get_child_by_name(const struct device_node *node, const char *name);

  (6)查找指定节点的父节点:device node struct device_node *of_get_parent(const struct device_node *node)

6.节点内容合并

  有时候,一个硬件设备的部分信息不会变化,但是部分信息是可能会变化的,就出现了节点内容合并。即:先编写好节点,仅仅描述部分属性值;使用者后加一部分属性值。

在同级路径下,节点名相同的“两个”节点实际是一个节点。

/*参考板(评估板)的已经编写好的node节点*/

/{

  node{

    item1=value;

  };

};

/*移植者添加的node节点*/

/{

  node{

    item2=value;

  };

};

等价于:

/{

  node{

    item1=value;

    item2=value;

  };

};


7.节点内容替换

  有时候,一个硬件设备的部分属性信息可能会变化,但是设备树里面已经描述了所有的属性值,使用者可以添加已有的属性值,以替换原有的属性值,就出现了节点内容替换。

另外,节点的内容即使不会变化,但是可能不会使用。在同级路径下,节点名相同的“两个”节点实际是一个节点。

(1)内容替换的常见形式之一:替换

/*参考板的已经编写好的node节点*/

/{

  node{

    item=value1;

  };

};

/*移植者添加的node节点*/

/{

  node{

    item=value2;

  };

};

等价于:

/{

  node{

    item=value2; //前者的赋值被后者覆盖掉了

  };

};

(2)内容替换的常见形式之二:叠加并替换

/*参考板的已经编写好的node节点*/

/{

  node{

    item=value;

    status = "disabled";

  };

};

/*移植者添加的node节点*/

/{

  node{

    status = "okay";

  };

};

等价于:

/{

  node{

    item=value;

    status = "okay";

  };

};


8.节点内容引用

  有时候,一个节点需要使用到别的节点的属性值,就需要引用的概念。有时候在设备树编写时,要替换节点属性值,或是合并节点的属性值,也会使用引用。

(1)引用节点完成属性值的替换及合并:

/*参考板的已经编写好的node节点*/

/{

  node:node@80000000{

    item1=value;

    status = "disabled";

  };

};

/*移植者添加的node节点*/

&node{

  item2=value;

  status = "okay";

};

等价于:

/{

  node : node@80000000{

    item1=value;

    item2=value;

    status = "okay";

  };

};

(2)节点引用另一个节点:

/*参考板的已经编写好的node节点*/

/{

  node:node@80000000{

    item=value;

  };

};

/*移植者添加的demo节点*/

/{

  demo{

    item=<&node>;  /*这个是什么意思?希望知道的回答一下*/

  };

};

说明:demo节点的属性item引用了节点的node的属性值,具体怎么使用node节点的属性值,在属性章节进行讨论。

9.删除节点

应用条件:通常DTS中包含了多个平台的描述文件,且多个平台会共享一些通用的dtsi。这些dtsi的节点对于指定的平台来说,其节点未必全部需要,因此就需要将不需要的节点进行裁剪或者DISABLE。节点删除就是实现这个作用。

语法如下:
/delete-node/ 节点名;

例如在dra7.dtsi里面定义了rtc的节点,但是在自己的产品中不想使用这个RTC,而使用其他的rtc:

dra7.dtsi 相关内容如下:

/ {
...
ocp {
...
rtc: rtc@ {
compatible = "ti,am3352-rtc";
reg = <0x48838000 0x100>;
interrupts = <GIC_SPI IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI IRQ_TYPE_LEVEL_HIGH>;
ti,hwmods = "rtcss";
clocks = <&sys_32k_ck>;
property1 = <>;
property2;
};
};
};

在am572x-xxx.dts,中删除:

#include "dra7.dtsi"

/ {
...
ocp {
/delete-node/ rtc@;
};
};

10.删除属性

#include "dra7.dtsi"
... &rtc {
/delete-property/ property1;
/delete-property/ property2;
};

三、典型节点

1.chosen节点
  chosen 节点并不代表一个真实的设备,只是作为一个为固件和操作系统之间传递数据的地方,比如引导参数。chosen 节点里的数据也不代表硬件。通常,chosen 节点在.dts 源文件中为空,并在启动时填充。在我们的示例系统中,固件可以往 chosen 节点添加以下信息:
chosen {
    bootargs = "root=/dev/nfs rw nfsroot=192.168.1.1 console=ttyS0,115200"; //节点属性
    linux,initrd-start = <0x85500000>; //节点属性
    linux,initrd-end = <0x855a3212>; //节点属性
};
2.memory节点     
  memory节点用于描述目标板上物理内存范围,一般称作/memory节点,可以有一个或多个。当有多个节点时,需要后跟单元地址予以区分;只有一个单元地址时,可以不写单元地址,默认为0。此节点包含板上物理内存的属性,一般要指定device_type(固定为"memory")和reg属性。其中reg的属性值以<起始地址 空间大小>的形式给出,如下示例中目标板内存起始地址为0x80000000,大小为0x20000000字节。 
memory {
    device_type = "memory";
    reg = <0x80000000 0x20000000>;
};
四、OF提供的常用API函数
OF提供的函数主要集中在drivers/of/目录下,有address.c,base.c,device.c,fdt.c,irq.c,platform.c等等
. 用来查找在dtb中的根节点
unsigned long __init of_get_flat_dt_root(void) . 根据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"); . 若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"); . 根据设备类型查找相应的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"); . 根据compatible字符串查找device_node
struct device_node *of_find_compatible_node(struct device_node *from,const char *type, const char *compatible) . 根据节点属性的name查找device_node
struct device_node *of_find_node_with_property(struct device_node *from,const char *prop_name) . 根据phandle查找device_node
struct device_node *of_find_node_by_phandle(phandle handle) . 根据alias的name获得设备id号
int of_alias_get_id(struct device_node *np, const char *stem) . device node计数增加/减少
struct device_node *of_node_get(struct device_node *node)
void of_node_put(struct device_node *node) . 根据property结构的name参数,在指定的device node中查找合适的property
struct property *of_find_property(const struct device_node *np,const char *name,int *lenp) . 根据property结构的name参数,返回该属性的属性值
const void *of_get_property(const struct device_node *np, const char *name,int *lenp) . 根据compat参数与device node的compatible匹配,返回匹配度
int of_device_is_compatible(const struct device_node *device,const char *compat) . 获得父节点的device node
struct device_node *of_get_parent(const struct device_node *node) . 将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) . 根据属性名propname,读出属性值中的第index个u32数值给out_value
int of_property_read_u32_index(const struct device_node *np,const char *propname,u32 index, u32 *out_value) . 根据属性名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) . 根据属性名propname,读出该属性的u64属性值
int of_property_read_u64(const struct device_node *np, const char *propname,u64 *out_value) . 根据属性名propname,读出该属性的字符串属性值
int of_property_read_string(struct device_node *np, const char *propname,const char **out_string) . 根据属性名propname,读出该字符串属性值数组中的第index个字符串
int of_property_read_string_index(struct device_node *np, const char *propname,int index, const char **output) . 读取属性名propname中,字符串属性值的个数
int of_property_count_strings(struct device_node *np, const char *propname) . 读取该设备的第index个irq号
unsigned int irq_of_parse_and_map(struct device_node *dev, int index) . 读取该设备的第index个irq号,并填充一个irq资源结构体
int of_irq_to_resource(struct device_node *dev, int index, struct resource *r) . 获取该设备的irq个数
int of_irq_count(struct device_node *dev) . 获取设备寄存器地址,并填充寄存器资源结构体
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) . 获取经过映射的寄存器虚拟地址
void __iomem *of_iomap(struct device_node *np, int index) . 根据device_node查找返回该设备对应的platform_device结构
struct platform_device *of_find_device_by_node(struct device_node *np) . 根据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) . 遍历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) . 遍历of_allnodes中的所有节点,生成并初始化platform_device结构
int of_platform_populate(struct device_node *root,const struct of_device_id *matches, const struct of_dev_auxdata *lookup,
struct device *parent)

参考1:http://blog.csdn.net/u013377887/article/details/52966198

参考2:http://www.embedu.org/Column/3910.html

例如在dra7.dtsi里面定义了rtc的节点,但是在自己的产品中不想使用这个RTC,而使用其他的rtc:
dra7.dtsi 相关内容如下:
/ {    ...    ocp {        ...        rtc: rtc@48838000 {            compatible = "ti,am3352-rtc";            reg = <0x48838000 0x100>;            interrupts = <GIC_SPI 217 IRQ_TYPE_LEVEL_HIGH>,     <GIC_SPI 217 IRQ_TYPE_LEVEL_HIGH>;            ti,hwmods = "rtcss";            clocks = <&sys_32k_ck>;            property1 = <1>;            property2;        };    };};
在am572x-xxx.dts,中删除:
#include "dra7.dtsi" / {    ...    ocp {        /delete-node/ rtc@48838000;    };};

Linux设备树使用(二)的更多相关文章

  1. linux设备树语法

    设备树语法及绑定 概述 Device Tree是一种用来描述硬件的数据结构,类似板级描述语言,起源于OpenFirmware(OF). 就ARM平台来说,设备树文件存放在arch/arm/boot/d ...

  2. Linux设备树语法详解

    概念 Linux内核从3.x开始引入设备树的概念,用于实现驱动代码与设备信息相分离.在设备树出现以前,所有关于设备的具体信息都要写在驱动里,一旦外围设备变化,驱动代码就要重写.引入了设备树之后,驱动代 ...

  3. Linux设备树语法详解【转】

    转自:http://www.cnblogs.com/xiaojiang1025/p/6131381.html 概念 Linux内核从3.x开始引入设备树的概念,用于实现驱动代码与设备信息相分离.在设备 ...

  4. 宋牧春: Linux设备树文件结构与解析深度分析(2) 【转】

    转自:https://mp.weixin.qq.com/s/WPZSElF3OQPMGqdoldm07A 作者简介 宋牧春,linux内核爱好者,喜欢阅读各种开源代码(uboot.linux.ucos ...

  5. linux 设备树【转】

    转自:http://blog.csdn.net/chenqianleo/article/details/77779439 [-] linux 设备树 为什么要使用设备树Device Tree 设备树的 ...

  6. 【转载】Linux设备树(Device Tree)机制

    转:Linux设备树(Device Tree)机制   目录 1. 设备树(Device Tree)基本概念及作用2. 设备树的组成和使用 2.1. DTS和DTSI 2.2. DTC 2.3. DT ...

  7. Linux设备树学习

    1.概念 设备树用于实现驱动代码与设备信息相分离.驱动代码只负责处理驱动的逻辑而关于设备的具体信息存放到设备树文件中.(dts文件,编译后为dtb文件).一个dts文件对应一个ARM的machine, ...

  8. 我眼中的Linux设备树(二 节点)

    二 节点(node)的表示首先说节点的表示方法,除了根节点只用一个斜杠"/"表示外,其他节点的表示形式如"node-name@unit-address".@前边 ...

  9. Linux设备树(二 节点)

    二 节点(node)的表示 首先说节点的表示方法,除了根节点只用一个斜杠“/”表示外,其他节点的表示形式如“node-name@unit-address”.@前边是节点名字,后边是节点地址.节点名字的 ...

随机推荐

  1. Win7 默认.lnk打开方式全是别的程序 还原的办法

    Xu言: no zuo no die~ 今天,一个朋友问我,他电脑桌面上点任何东西都是提示下载... - -||| 本以为是中毒了,然后上去看了一眼..发现他自己把所有.lnk 的默认打开方式选择了搜 ...

  2. 20170621xlVBA跨表转换数据

    Sub 跨表转置() Dim Wb As Workbook Dim Sht As Worksheet Dim oSht As Worksheet Dim Rng As Range Dim Index ...

  3. Jzzhu and Numbers CodeForces - 449D (高维前缀和,容斥)

    大意: 给定集合a, 求a的按位与和等于0的非空子集数. 首先由容斥可以得到 $ans = \sum \limits_{0\le x <2^{20}} (-1)^{\alpha} f_x$, 其 ...

  4. SSH 反向代理

    SSH反向代理 被控制端没有NAT或者没有静态公网IP,把本端一台服务器映射到外网给远端SSH进来,建立SSH反向隧道. 先映射本端机器到外网  nat server 2222to22 protoco ...

  5. 浅析postgresql数据库事务及行锁特征

    开源数据库领域,postgresql以其优越的性能.功能及良好的稳定性排名首位可谓当之无愧,尤其是对高并发的支持可谓匠心独具.而优越的性能和稳定性,究其根本无非是良好的基础架构,本文将对其性能和稳定性 ...

  6. 算法笔记——C/C++语言基础篇(已完结)

    开始系统学习算法,希望自己能够坚持下去,期间会把常用到的算法写进此博客,便于以后复习,同时希望能够给初学者提供一定的帮助,手敲难免存在错误,欢迎评论指正,共同学习.博客也可能会引用别人写的代码,如有引 ...

  7. Sql Server中集合的操作(并集、差集、交集)学习

    首先我们做一下测试数据 1.创建测试数据 --创建人员表1-- create table Person1 ( Uid ,) primary key, Name ) not null ) --创建人员表 ...

  8. Openwrt working with patches in the build system (8)

    Reference :https://openwrt.org/docs/guide-developer/build-system/use-patches-with-buildsystem exampl ...

  9. jquery组件和插件写法

    <!doctype html> <html> <head> <meta charset="utf-8"> <meta name ...

  10. js 实现智能输入数字

    <!doctype html> <html> <head> <meta charset="utf-8"> <meta name ...