Linux 驱动-设备树
设备树格式
/ {
属性名 = "属性值","可以多个";
标签(通常是节点名简写): 字节点名@地址 {
属性名 = "属性值";
属性名 = [0x00 0x01];
属性名 = <1 2 3>;
};
}
&标签 {
属性名 = "向标签的节点追加内容";
};
特殊节点:
aliases { //为字节的设置别名
别名 = &标签;
}
chosen { //向内核传递参数
bootargs = "内核启动参数";
linux,stdout-path = "/plb/serial@84000000";
}
属性可以自定义也有一些标准属性:
- compatible = "用于设备匹配";
- model = "制造商和型号";
- status = "okay"(默认) or "disabled" or "fail" or "fail-sss"(sss是错误原因);
-
addres-cells = <2>
-
size-cells = <1>
- reg = <1 2 3> //父节点的#addres-cells 表示前2个是地址, #size-cells 表示地址后一个是大小, 每个数据叫一个cell,每个cell 32 bit.
- ranges = <子地址起始 对应的父地址起始 地址范围大小> //描述当前节点的子节点的地址和当前节点地址的映射关系
获取设备树信息
内核中使用struct device_node
表示设备节点,主要成员如下:
成员 | 描述 |
---|---|
name | 节点中属性为name的值 |
full_name | 节点的名字,在device_node结构体后面放一个字符串,full_name指向它 |
properties | 链表,连接该节点的所有属性 |
parent | 指向父节点 |
child | 指向子节点 |
sibling | 指向兄弟节点 |
使用of_
开头的函数:
查找节点
static inline struct device_node *of_find_compatible_node
(
struct device_node *from, //指定从哪个节点开始查找,如果设置为NULL表示从根节点开始查找
const char *type,
const char *compat)
static inline struct device_node *of_find_node_by_path
(const char *path)
static inline struct device_node *of_find_matching_node_and_match
(
struct device_node *from,
const struct of_device_id *matches,
const struct of_device_id **match)
static inline struct device_node *of_find_node_by_name
(struct device_node *from, const char *name)
static inline struct device_node *of_find_node_by_type
(struct device_node *from, const char *type)
查找父节点和子节点
static inline struct device_node *of_get_parent
(const struct device_node *node)
static inline struct device_node *of_get_next_child
(const struct device_node *node, struct device_node *prev)
查找属性
static inline struct property *of_find_property
(const struct device_node *np, const char *name, int *lenp)
内核用struct property
表示属性,主要成员如下:
成员 | 描述 |
---|---|
name | 属性名 |
length | 属性长度 |
value | 属性值 |
next | 下一个属性 |
读取属性值
static inline int of_property_read_string
(const struct device_node *np, const char *propname, const char **out_string)
static inline int of_property_read_string_index
(const struct device_node *np,
const char *propname,
int index, const char **output) //读取属性值的第index个字符串
static inline int of_property_read_u8_array
(const struct device_node *np,const char *propname, u8 *out_values, size_t sz)
static inline int of_property_read_u16_array
(const struct device_node *np,const char *propname, u32 *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)
判断属性是否存在
static inline bool of_property_read_bool
(const struct device_node *np, const char *propname)
读取地址
void __iomem *of_iomap
(struct device_node *np, int index) //自动读取reg属性并ioremap为内核虚拟地址
int of_address_to_resource
(struct device_node *dev, int index, struct resource *r)
编译和加载设备树
编译内核时会自动去编译设备树, 也可以单独编译
make dtbs
# 编译 dts 为 dtb
内核目录/scripts/dtc/dtc -I dts -O dtb -o xxx.dtb xxx.dts
使用make dtbs时会更加.config文件去编译对应的设备树, 以arm为列, arch/arm/boot/dts/目录下的makefile会根据某些条件去编译对应的设备树文件.
补充
/proc/device-tree 可以查看设备树信息
设备树被内核读取后会使用device_node
结构体表示, 根节点是of_root
.
并且有些device_node
会被转化成platform_device: 节点的compatile属性含有这些特殊的值(“simple-bus”,“simple-mfd”,“isa”,“arm,amba-bus”)之一, 它及其子节点会被转化成platform_device.