Linux驱动开发:设备树节点与属性

目录

1、设备节点(node)

2、属性(property)

3、节点的一些特性

4、节点的一些标准属性

4.1 compatible属性

4.2 model属性

4.3 status属性

4.4 reg属性

4.5 #address-cells和 #size-cells属性

5、device_node结构体

6、property结构体

7、 找到节点(device_node)的API

7.1 定义节点

7.2 of_find_node_by_path

7.3 of_find_node_by_name

7.4 of_find_compatible_node

8、根据节点(device_node)找到属性(property)的API

8.1 通过node中的properties属性找到值

8.2 of_find_property

8.3 of_property_read_string_index、of_property_read_string

8.4 of_property_read_u32_index

8.5 of_property_read_u8_array、of_property_read_u16_array...

8.6 of_n_addr_cells:获取#address-cells的值

8.7 of_n_size_cells:获取#size-cells的值

9、小知识


1、设备节点(node)

label : node-name @unit-address {

        properties definitions

        child nodes

};

label(标号):可以没有,label是为了更方便的引用这个node

unit-address:设备地址

properties:属性,属性由一个键值对组成,具体用法看第二小节

child nodes:子节点

2、属性(property)

属性实际上就是一个键值对,当然,也可以没有值,这代表的是一个标识。

1、字符串类型(" ")

string-property = "string";

2、无符号32位整数(< >)

cell-property = <0xFFFFFFFF>

cells-property = <1 2 3 4> //其中每个数都是一个uint32的数

3、字节序列([ ])一个字节的16进制表示的数

byte-property = [01 23 45 67]

3、节点的一些特性

3.1 在设备树如果有同名的节点会被合并,如果是属性名相同的话,后面的节点会覆盖前面的节点

node {

        property1 = "111";

        property2 = "222";

};

node {

        property2 = "333";

        property3 = "444";

};

合并后的节点:

node {

        property1 = "111";

        property2 = "333";

        property3 = "444";

};

3.2 取别名,取别的意义是方便给其他节点引用,取别名有两种办法

取别名方法一:

node : node_node@0xFFFFFFFF {

}

取别名方法二:

aliases {

        node_node = &node;

}

引用

&node {

        //要增加或者修改的内容

}

3.2 上述引用中其实可以用来删除节点

&node {

        /delete-property/property1

}

4、节点的一些标准属性

4.1 compatible属性

        compatible属性也叫做“兼容性”属性, compatible属性的值是一个字符串列表, compatible属性用于将设备和驱动绑定起来。字符串列表用于选择设备所要使用的驱动程序, compatible属性的值格式如下所示:

"manufacturer,model"

其中 manufacturer表示厂商, model一般是模块对应的驱动名字。

4.2 model属性

        model属性与compatible属性有些类似,但是有差别。compatible属性是一个字符串列表,表示可以你的硬件兼容A、B、C等驱动;model用来准确地定义这个硬件是什么。例如:

{

        compatible = "samsung,smdk2440", "samsung,mini2440";

        model = "jz2440_v3";

};

 它表示这个单板,可以兼容内核中的“smdk2440”,也兼容“mini2440”。

4.3 status属性

        dtsi文件中定义了很多设备,但是在你的板子上某些设备是没有的。这时你可以给这个设备节点添加一个status属性,设置为“disabled”,或者默认是disabled,要去开启他,就设置为"okay",例如:

&node {

        status = "disabled";

};

4.4 reg属性

        reg的本意是register,用来表示寄存器地址。但是在设备树里,它可以用来描述一段空间。反正对于ARM系统,寄存器和内存是统一编址的,即访问寄存器时用某块地址,访问内存时用某块地址,在访问方法上没有区别。reg属性的值,是一系列的“address size”,用多少个32位的数来表示address和size,由其父节点的#address-cells、#size-cells决定。例如:

/dts-v1/;

/ {

        #address-cells = <1>;

        #size-cells = <1>;

        memory {

                reg = <0x80000000 0x20000000>;

        };

};

4.5 #address-cells和 #size-cells属性

        cell指一个32位的数值,address-cells:address要用多少个32位数来表示;size-cells:size要用多少个32位数来表示。比如一段内存,怎么描述它的起始地址和大小?下例中,address-cells为1,所以reg中用1个数来表示地址,即用0x80000000来表示地址;size-cells为1,所以reg中用1个数来表示大小,即用0x20000000表示大小:

/ {

        #address-cells = <1>;

        #size-cells = <1>;

        memory {

                reg = <0x80000000 0x20000000>;

        };

};

5、device_node结构体

struct device_node {
	const char *name;              //节点的名字 node
	const char *type;              //节点的全名 node@0x12345678
	struct	property *properties;  //节点内的属性,是一条链表
	struct	device_node *parent;   //父节点
	struct	device_node *child;    //子节点
	struct	device_node *sibling;  //兄弟节点
};

6、property结构体

struct property {
	char	*name;         //键
	int	length;            //值的长度
	void	*value;        //值
	struct property *next; //下一个键值对
};

7、 找到节点(device_node)的API

7.1 定义节点

mynode@0x12345678 {
    compatiable = "zgjl,mynode";
	string = "AAAAA";
	cell = <0x11223344>;
	byte = [01 23 24 56 78 9A];
	mixed = "BBBB",<0x12345678>,[01 02 03 04];
};

7.2 of_find_node_by_path

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

node = of_find_node_by_path("/mynode@0x12345678");

7.3 of_find_node_by_name

static inline struct device_node *of_find_node_by_name(struct device_node *from,
	const char *name)
//参数from表示从哪一个节点开始寻找,传入NULL表示从根节点开始寻找。

node = of_find_node_by_name(NULL,"mynode");

7.4 of_find_compatible_node

static inline struct device_node *of_find_compatible_node(
						struct device_node *from,
						const char *type,
						const char *compat)
//参数from表示从哪一个节点开始寻找,传入NULL表示从根节点开始寻找
//参数compat是一个字符串,用来指定compatible属性的值
//参数type是一个字符串,用来指定device_type属性的值,可以传入NULL

node = of_find_compatible_node(NULL,NULL,"zgjl,mynode");

8、根据节点(device_node)找到属性(property)的API

8.1 通过node中的properties属性找到值

//第一个是字符串,name是键,value是值
node->properties->name,(char *)node->properties->value

//第二个是32位无符号整数,__be32_to_cpup是大小端转化函数
node->properties->naxt->name,__be32_to_cpup(node->properties->next->value

8.2 of_find_property

static inline struct property *of_find_property(const struct device_node *np,
						const char *name,
						int *lenp)
//参数np表示节点,我们要在这个节点中找到名为name的属性。
//lenp用来保存这个属性的长度,即它的值的长度。

prop = of_find_property(node,"byte",&len); 
for (int i = 0; i < len; i++) {
	printk("name=%s,value=%#x\n","binint",*(char *)(prop->value+i));
}

8.3 of_property_read_string_index、of_property_read_string

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

static inline int of_property_read_string(const struct device_node *np,
					  const char *propname,
					  const char **out_string)
//np:设备节点。
//proname 要读取的属性名字。
//out_string:读取到的字符串值。

of_property_read_string_index(node,"string",0,&value);
printk("string = %s\n", value); 

8.4 of_property_read_u32_index

static inline int of_property_read_u32_index(const struct device_node *np,
			const char *propname, u32 index, u32 *out_value)
//np:设备节点。
//proname 要读取的属性名字。
//index:要读取的值标号。
//out_value:读取到的值

of_property_read_u32_index(node,"cell",0,&u32_val);
printk("cell = %#x\n", u32_val);

8.5 of_property_read_u8_array、of_property_read_u16_array...

static inline int of_property_read_u8_array(const struct device_node *np,
			const char *propname, u8 *out_values, size_t sz)
//np:设备节点。
//proname 要读取的属性名字。
//out_value:读取到的数组值,分别为 u8、 u16、 u32和 u64。
//sz 要读取的数组元素数量。
static inline int of_property_read_u16_array(const struct device_node *np,
			const char *propname, u16 *out_values, size_t sz)
static inline int of_property_read_u32_array(const struct device_node *np,
			const char *propname, u32 *out_values, size_t sz)
static inline int of_property_read_u64_array(const struct device_node *np,
			const char *propname, u64 *out_values, size_t sz)

of_property_read_u8_array(node,"binint",u8_arr,6);
	
for (int i = 0; i < 6; i++) {
	printk("u8_arr[%d] = %#x\n", i, u8_arr[i]);
}

8.6 of_n_addr_cells:获取#address-cells的值

int of_n_addr_cells(struct device_node *np)
{	
    const __be32 *ip;

	ip = of_get_property(np, "#address-cells", NULL);
	if (ip)
		return be32_to_cpup(ip);
}

8.7 of_n_size_cells:获取#size-cells的值

int of_n_size_cells(struct device_node *np)
{
	const __be32 *ip;
	
	ip = of_get_property(np, "#size-cells", NULL);
	if (ip)
		return be32_to_cpup(ip);
}

9、小知识

1、查看设备树

cd /sys/firmware/devicetree/base/

2、编译设备树文件

找到内核文件 make dtbs

3、设备树文件在 arch/arm/boot/dts 中

  • 2
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值