Linux 设备树: of_property_match_string 的用法与工作原理

前言

  • 当前新版本的 Linux 内核 设备驱动框架,与设备树(Device Tree)结合密切,整体 设备树的设备驱动框架,比较的庞大,但又非常的经典。

  • 一个个的 设备树解析函数,都是前人【智慧】的结晶,了解 设备树的实现,了解设备树的解析,对Linux 设备驱动开发非常有利,并且可以大大提高开发编码能力

  • 虽然Linux 内核庞大、开源,但是Linux 内核各个模块的实现都是经典,非常适合学习深造

设备树节点与设备树属性

  • 通过 include\linux\of.h 可以获取 设备树节点 struct device_node 与设备树节点属性 struct property 的定义

  • 这里需要特别了解 设备树节点属性:属性name = 属性value,属性value 可能是一个字符串的列表,比如

	i2c1: i2c@fea90000 {
		compatible = "rockchip,rk3588-i2c", "rockchip,rk3399-i2c";
		reg = <0x0 0xfea90000 0x0 0x1000>;
		clocks = <&cru CLK_I2C1>, <&cru PCLK_I2C1>;
		clock-names = "i2c", "pclk";
		interrupts = <GIC_SPI 318 IRQ_TYPE_LEVEL_HIGH>;
		pinctrl-names = "default";
		pinctrl-0 = <&i2c1m0_xfer>;
		resets = <&cru SRST_I2C1>, <&cru SRST_P_I2C1>;
		reset-names = "i2c", "apb";
		#address-cells = <1>;
		#size-cells = <0>;
		status = "disabled";
	};
  • 这里 compatibleclock-names reset-names 都有两个 属性值,比如 reset-names = "i2c", "apb";

  • 这里需要确认 reset-names = "i2c", "apb"; 这种 多个属性值的具体 内存储存方式,用于理解如何解析这样的设备树属性,比如分别获取其中的属性,也就是 "i2c", "apb" ,分别得到 "i2c""apb"

property 的 dtb 存储方式

  • 可能大家认为 reset-names = "i2c", "apb"; 在 dtb 中就是 这样的字符串存储,其实 dtb 的生成,有 dtc 的一套复杂的规则决定,这里 属性 name 可能只是一个索引,作为公用的字符串,而属性值如果是 字符串列表(多个字符串),比如 "i2c", "apb",引号不需要,并且 中间的分隔符是 \0,而不是 逗号 ,

  • 这样拆解字符串列表,就不再是以 逗号分隔,而是 字符串结束符 \0 进行分隔,这就需要获取整个字符串的长度【字节数】,这个 设备树属性 的 长度是 struct property 中的 int length; 成员

struct property {
	char	*name;
	int	length;   /* 属性 value 的长度(字节数) */
	void	*value;
	struct property *next;
#if defined(CONFIG_OF_DYNAMIC) || defined(CONFIG_SPARC)
	unsigned long _flags;
#endif
#if defined(CONFIG_OF_PROMTREE)
	unsigned int unique_id;
#endif
#if defined(CONFIG_OF_KOBJ)
	struct bin_attribute attr;
#endif
};

在这里插入图片描述

在这里插入图片描述

of_property_match_string 解析

  • 明白了设备树 属性值(property -> value)字符串列表的储存方式后,解析起来就明白多了,这里有个字符串列表 【index】索引的概念,比如第一个,第二个字符串

  • Linux 内核 drivers\of\property.cof_property_match_string 的实现代码如下

/**
 * of_property_match_string() - Find string in a list and return index
 * @np: pointer to node containing string list property
 * @propname: string list property name
 * @string: pointer to string to search for in string list
 *
 * This function searches a string list property and returns the index
 * of a specific string value.
 */
int of_property_match_string(const struct device_node *np, const char *propname,
			     const char *string)
{
	const struct property *prop = of_find_property(np, propname, NULL);
	size_t l;
	int i;
	const char *p, *end;

	if (!prop)
		return -EINVAL;
	if (!prop->value)
		return -ENODATA;

	p = prop->value;
	end = p + prop->length;

	for (i = 0; p < end; i++, p += l) {
		l = strnlen(p, end - p) + 1;
		if (p + l > end)
			return -EILSEQ;
		pr_debug("comparing %s with %s\n", string, p);
		if (strcmp(string, p) == 0)
			return i; /* Found it; return index */
	}
	return -ENODATA;
}
  • 这里入参: 设备树节点,设备树属性 name,就可以查找这个设备树属性 property。

  • 查找到设备树属性 property不是目的,目的就是 查找 设备树属性值 是否匹配,给定一个字符串,是否存在于 字符串列表中,返回字符串列表的索引 index

  • 举个例子: reset-names = "i2c", "apb";,这里查找 "apb" 是否存在,这里存在,就是返回了 index,比如是 1(索引以 0 作为起始)

  • 这里有个经典的字符串列表匹配的算法,就是 通过 总长度,获取整个字符串列表的结束地址,

  • prop->length 就是这个设备树属性 value,也就是 字符串列表的总长度(字节数)

	p = prop->value;
	end = p + prop->length;
  • 利用了 字符串操作函数都是以 NULL(\0) 作为结束,因此通过获取 单个字符串的 长度,利用指针的加减法(地址加减),就可以逐个判断分隔出来的 单个字符是否匹配

  • 这里 strnlen 用的比较的经典,获取到的其实就是第一次 遇到 字符串结束符 NULL(\0)之前的长度。

小结

  • 这个 of_property_match_string 实现原理比较的经典,当然与 设备树节点属性值的存储有关系,也就是 属性值是字符串列表时,字符串列表的分隔符是 【NULL 或者 \0】,这用于字符串列表的拆解

  • 有些设备树属性确实有多个属性值,有的是数值型的,有的是字符串列表型的,需要解析匹配并获取 匹配值的 索引值。

相关推荐

  1. 决策基础:定义工作原理

    2024-03-24 17:20:03       41 阅读
  2. linux】sed

    2024-03-24 17:20:03       34 阅读
  3. HTTP 协议格式 Fiddler 工具

    2024-03-24 17:20:03       30 阅读
  4. Redis:原理、概念、实例解析

    2024-03-24 17:20:03       28 阅读
  5. linux 中date 命令

    2024-03-24 17:20:03       54 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-03-24 17:20:03       94 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-03-24 17:20:03       100 阅读
  3. 在Django里面运行非项目文件

    2024-03-24 17:20:03       82 阅读
  4. Python语言-面向对象

    2024-03-24 17:20:03       91 阅读

热门阅读

  1. MySQL 之简单查询

    2024-03-24 17:20:03       38 阅读
  2. ES6—Symbol详解

    2024-03-24 17:20:03       33 阅读
  3. Oracle to_char可以转换哪些类型的数据

    2024-03-24 17:20:03       39 阅读
  4. 2.windows ubuntu子系统配置

    2024-03-24 17:20:03       41 阅读
  5. 2023天梯赛

    2024-03-24 17:20:03       41 阅读
  6. 长链接与短链接的理解

    2024-03-24 17:20:03       33 阅读
  7. Mockito.when返回的list长度为0问题解决方法

    2024-03-24 17:20:03       35 阅读
  8. 用I/O口模拟IIC总线协议遇到的一些问题

    2024-03-24 17:20:03       36 阅读
  9. 对原型模式的理解

    2024-03-24 17:20:03       47 阅读