Linux设备树

文章目录

  • 1.设备树
    • 1.1什么是设备树?为什么需要设备树?
    • 1.2设备树和内核的关系
    • 1.3设备树的组成
    • 1.4节点的组成
    • 1.5属性的表示方式
    • 1.6节点添加
      • 1.6.1编写自己的设备节点
      • 1.6.2将设备节点添加到设备树文件中
      • 1.6.3编译设备树
      • 1.6.4将设备树文件拷贝到tftpboot下
      • 1.6.5重启开发板看现象
    • 1.7设备树节点获取函数
    • 1.8驱动获取设备节点的实例1
    • 1.9驱动获取设备节点的实例2
    • 1.10驱动获取设备节点的实例3

1.设备树

1.1什么是设备树?为什么需要设备树?

设备树:描述设备信息的一种树状方式。在linux内核的3.10版本前并没有使用
Linux设备树_第1张图片

设备树这种方式描述设备信息,而是通过文件的方式描述设备信息。在3.10内核版本

出现前利纳斯托瓦斯要求ARM社区整改设备信息的表述方式。ARM社区参考POWER PC设备

信息表述方式,引入了设备树。所以在3.10的内核版本之后所有ARM的内核表示设备信息

的方式都使用设备树。

dts -------------*.c

dtsi -------------*.h

​ |

​ DTC

​ |

​ --------------*.dtb

1.2设备树和内核的关系

设备树(Device Tree)是一种描述硬件的数据结构,在操作系统(OS)引导阶段进行设

备初始化(DTB文件在linux内核启动的时候内核解析),解析之后设备树就被放到内存在上

(逻辑结构:树状结构)。如果某个驱动需要使用设备信息,直接从设备树上获取对应的

设备信息即可。

1.3设备树的组成

参考:https://elinux.org/Device_Tree_Usage

设备树是节点属性的简单树结构。属性是键值对,节点可能同时包含属性和子节点。

1.4节点的组成

[@ ]

​ | |

节点名(设备类,最多31个字符) 设备的地址

eg1:

serial@101f1000{};

    设备树中同名的节点会被合并(相同的键值会覆盖前面的值,不同的键合并到一个节点中)

    节点可以取别名,node2就是mynode2的别名

    方式1:

    node2:mynode2@aabbccdd{

    ​ key1=“val1”;

    };

    方式2:

    aliases {

    node2= &mynode2@aabbccdd;

    };

    节点的引用(引用的节点需要放在根节点外)

    &node2{

    };

1.5属性的表示方式

  • 文本字符串(以空结尾)用双引号表示:

    • string-property = “a string”;

  • ‘Cells’ 是由尖括号分隔的 32 位无符号整数:

    • cell-property = <0xbeef 123 0xabcd1234>;

  • 二进制数据用方括号分隔(单字节的16进制表示形式):

    • binary-property = [01 23 45 67];

  • 不同表示的数据可以使用逗号连接在一起:

    • mixed-property = “a string”, [0x01 0x23 0x45 0x67], <0x12345678>;

1.6节点添加

1.6.1编写自己的设备节点

mynode@0x12345678{

​ string = “DC22041 everyone!!”;

​ uint = <0x11223344 0xaabbccdd>;

​ macaddr=[00 0c 29 7b f9 be];

​ mixed = “hello”,<0x112233>,[aa cc 00 12];

};

1.6.2将设备节点添加到设备树文件中

将上述的设备节点放在arch/arm/boot/dts/stm32mp157a-fsmp1a.dts
Linux设备树_第2张图片

1.6.3编译设备树

Linux设备树_第3张图片

1.6.4将设备树文件拷贝到tftpboot下

cp arch/arm/boot/dts/stm32mp157a-fsmp1a.dtb ~/tftpboot/

1.6.5重启开发板看现象

Linux设备树_第4张图片

1.7设备树节点获取函数

设备节点结构体:
struct device_node { //每个节点都会对应一个device_node结构体,它在内核中是树状结构
	const char *name;   // 节点的名称
	const char *full_name; //节点全名
	struct	property *properties;  // 属性健值对
	...
};

属性结构体:
struct property {
	char	*name;   // 键的名称
	int	length;      //值的长度
	void	*value;         // 键的值
	struct property *next;  // 单链表
};

查找节点API
struct device_node *of_find_node_by_path(const char *path)
 功能:通过节点的路径,查找到节点
 参数:
    @path  -节点的路径 "/mynode@0x12345678"
 返回值: 成功:设备节点的地址
         失败:NULL
struct device_node *of_find_node_by_name(struct device_node *from,                                    
    const char *name)
 功能:通过节点名查找指定节点
 参数:
	@from - 开始查找节点,如果为NULL,则从根节点开始
	@name - 节点名
 返回值:成功:得到节点的首地址
    	 失败:NULL 

获取属性
struct property *of_find_property(const struct device_node *np,
			  const char *name,int *lenp)
功能:已知设备节点的地址,根据键的名称,查找出键值
参数:
    @np     -设备节点的地址
    @name   -键的名称
	@lenp   -获取到的值的字符串长度
返回值:成功 属性健值对的指针
        出错 NULL
    
static inline int of_property_read_u8_array(const struct device_node *np,
			const char *propname, u8 *out_values, size_t sz)
功能: 得到属性值中指定标号的8位数组的值
参数:
	@np        - 设备节点指针
	@propname  - 属性名称
	@out_values- 输出数据的首地址
	@sz        - 成员个数
返回值: 成功返回0,出错错误码   
    
int of_property_read_u32_array(const struct device_node *np,      
                         const char *propname,
                         u32 *out_values, size_t sz)
功能: 得到属性值中指定标号的32位数组的值
参数:
	@np        - 设备节点指针
	@propname  - 属性名称
	@out_values- 输出数据的首地址
	@sz        - 成员个数
返回值: 成功返回0,出错错误码
    
int of_property_read_string(struct device_node *np, const char *propname,
			const char **out_string)
功能:已知字符串属性健值对的名称,得到字符串的值
参数:
      np         -设备节点的地址
      propname   -属性健值对的名称
	  out_string -填充字符串的值
返回值:成功0,出错错误码

1.8驱动获取设备节点的实例1

#include 
#include 
#include 
/*
mynode@0x12345678{
	string = "DC22041 everyone!!";
	uint   = <0x11223344 0xaabbccdd>;
	macaddr=[00 0c 29 7b f9 be];
	mixed = "hello",<0x112233>,[aa cc 00 12];
};
*/
struct device_node* node;
static int __init mynode_init(void)
{
    //通过路径获取节点
    node = of_find_node_by_path("/mynode@0x12345678");
    if (node == NULL) {
        printk("get node error\n");
        return -ENODATA;
    }

    printk("name=%s,value = %s\n", node->properties->name,
        (char*)node->properties->value);
    printk("name=%s,value1 = %#x,value2=%#x\n", node->properties->next->name,
        __be32_to_cpup(node->properties->next->value),
        __be32_to_cpup(node->properties->next->value+4));
    //__be32_to_cpup:将大端转化为小端(32bit)
    return 0;
}
static void __exit mynode_exit(void)
{
}
module_init(mynode_init);
module_exit(mynode_exit);
MODULE_LICENSE("GPL");

1.9驱动获取设备节点的实例2

#include 
#include 
#include 
/*
mynode@0x12345678{
	string = "DC22041 everyone!!";
	uint   = <0x11223344 0xaabbccdd>;
	macaddr=[00 0c 29 7b f9 be];
	mixed = "hello",<0x112233>,[aa cc 00 12];
};
*/
struct device_node* node;
struct property *p;
static int __init mynode_init(void)
{
    int len,i;
    //通过路径获取节点
    node = of_find_node_by_path("/mynode@0x12345678");
    if (node == NULL) {
        printk("get node error\n");
        return -ENODATA;
    }
    p = of_find_property(node,"mixed",&len);
    if(p == NULL){
        printk("get property error\n");
        return -ENODATA;
    }

    printk("%s\n",(char *)p->value);
    printk("%#x\n",__be32_to_cpup(p->value+6));
    for(i=0;i<4;i++){
        printk("%#x\n",*(unsigned char *)(p->value+10+i));
    }

    return 0;
}
static void __exit mynode_exit(void)
{
}
module_init(mynode_init);
module_exit(mynode_exit);
MODULE_LICENSE("GPL");

1.10驱动获取设备节点的实例3

#include 
#include 
#include 
/*
mynode@0x12345678{
	string = "DC22041 everyone!!";
	uint   = <0x11223344 0xaabbccdd>;
	macaddr=[00 0c 29 7b f9 be];
	mixed = "hello",<0x112233>,[aa cc 00 12];
};
*/
struct device_node* node;
struct property* p;
static int __init mynode_init(void)
{
    int  i;
    const char* out_string;
    u32 d32[2];
    u8 d8[6];
    //通过路径获取节点
    node = of_find_node_by_path("/mynode@0x12345678");
    if (node == NULL) {
        printk("get node error\n");
        return -ENODATA;
    }

    of_property_read_string(node, "string", &out_string);
    printk("string = %s\n", out_string);

    of_property_read_u32_array(node, "uint", d32, 2);
    for (i = 0; i < 2; i++) {
        printk("uint[%d] = %#x\n", i, d32[i]);
    }

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

    return 0;
}
static void __exit mynode_exit(void)
{
}
module_init(mynode_init);
module_exit(mynode_exit);
MODULE_LICENSE("GPL");
   for (i = 0; i < 2; i++) {
        printk("uint[%d] = %#x\n", i, d32[i]);
    }

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

    return 0;
}
static void __exit mynode_exit(void)
{
}
module_init(mynode_init);
module_exit(mynode_exit);
MODULE_LICENSE("GPL");

你可能感兴趣的:(linux,java,运维)