💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、星火、月之暗面及文生图 广告
# 设备树组成 ## 文件类型 ~~~ .dts 是ASCII的文本格式的设备树描述,一个.dts对应一个ARM设备,一般放在arch/arm/boot/dts下 .dtsi 类似c .h文件 是所有公用部分的提炼 dtb 被编译后的文件能够被linux识别 uboot也能识别 dtc是编译 .dts为.dtb的工具 dtc源码在 scripts/dtc/Makefile hostprogs-y:=dtc ubuntu安装dtc sudo apt-get install device-tree-complier soc被选中 dtc会被编译 例如: dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1012a-frdm.dtb dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1012a-qds.dtb dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1012a-rdb.dtb dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1043a-qds.dtb ~~~ ## 绑定 ~~~ 在 Documentation/devicetree/bindings下有绑定有设备绑定信息介绍 ~~~ ~~~ UBoot支持设备树 使能: #define CONFIG_OF_LIBFDT ~~~ # 根节点兼容 ~~~ compatible = "fsl,imx6ull-14x14-evk", "fsl,imx6ull"; static const char * const imx6ul_dt_compat[] __initconst = { "fsl,imx6ul", "fsl,imx6ull", "fsl,imx6ulz", NULL, }; DT_MACHINE_START(IMX6UL, "Freescale i.MX6 UltraLite (Device Tree)") .map_io = imx6ul_map_io, .init_irq = imx6ul_init_irq, .init_machine = imx6ul_init_machine, .init_late = imx6ul_init_late, .dt_compat = imx6ul_dt_compat, MACHINE_END of_machine_is_compatible(const char *compat) 判断具体电路板 ~~~ # 设备节点兼容 ~~~ static const struct of_device_id a1234_i2c_of_match[] = { {.compatible = "acme,a1234-i2c-bus", .data = (void *)&fns}, // .data附加数据 {}, } MODULE_DEVICE_TABLE(of, a1234_i2c_of_match); 热插拔设备自动加载驱动 usb pcie platform static struct platform_driver i2c_a1234_driver = { .driver = { .name = "a1234-i2c-bus", .owner = THIS_MODULE, .of_match_table = a1234_i2c_of_match } .probe = i2c_probe .remove = i2c_remove } module_platfrom_driver(i2c_a123_driver) 注册驱动到内核 ~~~ ## 展开module\_platfrom\_driver宏 ~~~ static int __init gpio_led_driver_init(void) { return platform_driver_register (&(gpio_led_driver)); } module_init(gpio_led_driver_init); static void __exit gpio_led_driver_exit(void) { platform_driver_unregister (&(gpio_led_driver) ); } module_exit(gpio_led_driver_exit); 展开后就是标准的注册和删除platfrom_driver ~~~ ## 一个驱动兼容多个设备 ~~~ 1. int of_device_is_compatible(const struct device_node *device, const char *compat) 查看设备兼容属性 2. 设备驱动附加数据 .data static const struct of_device_id a1234_i2c_of_match[] = { {.compatible = "acme,a1234-i2c-bus", .data = (void *)&fns}, // .data附加数据 {}, } ~~~ # 设备树常用OF操作函数 ~~~ 设备树描述了设备的详细信息,这些信息包括数字类型的、字符串类型的、数组类型的,我们在编写驱动的时候需要获取到这些信息。比如设备树使用 reg 属性描述了某个外设的寄存器地址为 0X02005482,长度为 0X400,我们在编写驱动的时候需要获取到reg属性的0X02005482和 0X400这两个值,然后初始化外设。Linux 内核给我们提供了一系列的函数来获取设备树中的节点或者属性信息,这一系列的函数都有一个统一的前缀“of\_”,所以在很多资料里面也被叫做 OF 函数。这些 OF 函数原型都定义在include/linux/of.h文件中。 ~~~ ## 查找节点的 OF 函数 ~~~ 设备都是以节点的形式“挂”到设备树上的,因此要想获取这个设备的其他属性信息,必 须先获取到这个设备的节点。Linux 内核使用 device_node 结构体来描述一个节点,此结构体定 义在文件 include/linux/of.h 中,定义如下: 示例代码 43.3.9.1 device_node 节点 struct device_node { const char *name; /* 节点名字 */ const char *type; /* 设备类型 */ phandle phandle; const char *full_name; /* 节点全名 */ struct fwnode_handle fwnode; struct property *properties; /* 属性 */ struct property *deadprops; /* removed 属性 */ struct device_node *parent; /* 父节点 */ struct device_node *child; /* 子节点 */ struct device_node *sibling; struct kobject kobj; 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 }; 与查找节点有关的 OF 函数有 5 个,我们依次来看一下 1. of_find_node_by_name 函数 of_find_node_by_name 函数通过节点名字查找指定的节点,函数原型如下: struct device_node *of_find_node_by_name(struct device_node *from, const char *name); 函数参数和返回值含义如下: from:开始查找的节点,如果为 NULL 表示从根节点开始查找整个设备树。 name:要查找的节点名字。 返回值:找到的节点,如果为 NULL 表示查找失败。 2 、of_find_node_by_type 函数 of_find_node_by_type 函数通过 device_type 属性查找指定的节点,函数原型如下: struct device_node *of_find_node_by_type(struct device_node *from, const char *type) 函数参数和返回值含义如下: from:开始查找的节点,如果为 NULL 表示从根节点开始查找整个设备树。 type:要查找的节点对应的 type 字符串,也就是 device_type 属性值。 返回值:找到的节点,如果为 NULL 表示查找失败。 3 、of_find_compatible_node 函数 of_find_compatible_node 函数根据 device_type 和 compatible 这两个属性查找指定的节点, 函数原型如下: struct device_node *of_find_compatible_node(struct device_node *from, const char *type, const char *compatible) 函数参数和返回值含义如下: from:开始查找的节点,如果为 NULL 表示从根节点开始查找整个设备树。 type:要查找的节点对应的 type 字符串,也就是 device_type 属性值,可以为 NULL,表示 忽略掉 device_type 属性。 compatible :要查找的节点所对应的 compatible 属性列表。 返回值:找到的节点,如果为 NULL 表示查找失败 4 、of_find_matching_node_and_match 函数 of_find_matching_node_and_match 函数通过 of_device_id 匹配表来查找指定的节点,函数原 型如下: 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) 函数参数和返回值含义如下: from:开始查找的节点,如果为 NULL 表示从根节点开始查找整个设备树。 matches:of_device_id 匹配表,也就是在此匹配表里面查找节点。 match :找到的匹配的 of_device_id。 返回值:找到的节点,如果为 NULL 表示查找失败 5 、of_find_node_by_path 函数 of_find_node_by_path 函数通过路径来查找指定的节点,函数原型如下: inline struct device_node *of_find_node_by_path(const char *path) 函数参数和返回值含义如下: path:带有全路径的节点名,可以使用节点的别名,比如“/backlight”就是 backlight 这个 节点的全路径。 返回值:找到的节点,如果为 NULL 表示查找失败 ~~~