https://biscuitos.github.io/blog/DTS-of_property_read_string_index/

源码分析

of_property_read_string_index
of_property_read_string_index
|
|---of_property_read_string_helper
|
|---of_find_property
|
|---of_find_property
|
|---__of_find_property
|
|---of_prop_cmp

平台: ARM32

linux: 3.10/4.18/5.0

函数作用:从 string-list 属性中,读出第 N 个字符串。

of_property_read_string_index
/**
* of_property_read_string_index() - Find and read a string from a multiple
* strings property.
* @np: device node from which the property value is to be read.
* @propname: name of the property to be searched.
* @index: index of the string in the list of strings
* @out_string: pointer to null terminated return string, modified only if
* return value is 0.
*
* Search for a property in a device tree node and retrieve a null
* terminated string value (pointer to data, not a copy) in the list of strings
* contained in that property.
* Returns 0 on success, -EINVAL if the property does not exist, -ENODATA if
* property does not have a value, and -EILSEQ if the string is not
* null-terminated within the length of the property data.
*
* The out_string pointer is modified only if a valid string can be decoded.
*/
static inline int of_property_read_string_index(struct device_node *np,
const char *propname,
int index, const char **output)
{
int rc = of_property_read_string_helper(np, propname, output, 1, index);
return rc < 0 ? rc : 0;
}

参数 np 指向设备节点;propname 指向属性名字;output 参数用于存储指定的字符 串;index 用于指定字符串在 string-list 中的索引。

函数直接调用 of_property_read_string_helper() 函数获得多个字符串。

of_property_read_string_helper
/**
* of_property_read_string_util() - Utility helper for parsing string properties
* @np: device node from which the property value is to be read.
* @propname: name of the property to be searched.
* @out_strs: output array of string pointers.
* @sz: number of array elements to read.
* @skip: Number of strings to skip over at beginning of list.
*
* Don't call this function directly. It is a utility helper for the
* of_property_read_string*() family of functions.
*/
int of_property_read_string_helper(struct device_node *np, const char *propname,
const char **out_strs, size_t sz, int skip)
{
struct property *prop = of_find_property(np, propname, NULL);
int l = 0, i = 0;
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 && (!out_strs || i < skip + sz); i++, p += l) {
l = strnlen(p, end - p) + 1;
if (p + l > end)
return -EILSEQ;
if (out_strs && i >= skip)
*out_strs++ = p;
}
i -= skip;
return i <= 0 ? -ENODATA : i;
}
EXPORT_SYMBOL_GPL(of_property_read_string_helper);

参数 np 指向设备节点;propname 指向属性名字;out_strs 参数用于存储指定的字符 串;sz 参数指定了读取字符串的数量;skip 参数指定了从第几个字符串开始读取。

函数首先调用 of_find_property() 函数获得 propname 对应的属性,然后对获得的属性 和属性值进行有效性检查,检查不过直接返回错误;如果检查通过,接着计算属性的结束 地址后,使用 for 循环遍历属性的值,并且跳过 skip 对应的地址,然后将字符串都存 储在 out_strs 参数里。

of_find_property
struct property *of_find_property(const struct device_node *np,
const char *name,
int *lenp)
{
struct property *pp;
unsigned long flags; raw_spin_lock_irqsave(&devtree_lock, flags);
pp = __of_find_property(np, name, lenp);
raw_spin_unlock_irqrestore(&devtree_lock, flags); return pp;
}
EXPORT_SYMBOL(of_find_property);

参数 np 指向一个 device_node;name 参数表示需要查看属性的名字;lenp 用于存储 属性长度。

函数通过调用 raw_spin_lock_irqsave() 函数加锁之后,就直接调用 __of_find_property() 函数。__of_find_property() 函数用于查找并返回属性名字与 name 一致的属性。调用完 __of_find_property() 函数之后,调用 raw_spin_unlock_irqrestore() 函数解锁。最后返回 property 结构。

__of_find_property
static struct property *__of_find_property(const struct device_node *np,
const char *name, int *lenp)
{
struct property *pp; if (!np)
return NULL; for (pp = np->properties; pp; pp = pp->next) {
if (of_prop_cmp(pp->name, name) == 0) {
if (lenp)
*lenp = pp->length;
break;
}
} return pp;
}

由于每个 device_node 包含一个名为 properties 的成员,properties 是一个单链表的 表头,这个单链表包含了该节点的所有属性,函数通过使用 for 循环遍历这个链表,以 此遍历节点所包含的所有属性。每遍历一个属性就会调用 of_prop_cmp() 函数, of_prop_cmp() 函数用于对比两个字符串是否相等,如果相等返回 0. 因此,当遍历到 的属性的名字与参数 name 一致,那么定义为找到了指定的属性。此时,如果 lenp 不 为 NULL,那么会将属性的长度即 length 存储到 lenp 指向的地址。


实践

实践目的是在 DTS 文件中构建一个私有节点,私有节点包含一个 string-list 属性,属 性里面包含了多个字符串,然后通过of_property_read_string_index() 函数读取第 N 个字符串,函数定义如下:

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

这个函数经常用用于读取 string-list 属性中的第 N 个字符。

本文实践基于 Linux 4.20.8 arm32 平台,开发者可以参考如下文章快速搭建一个 调试环境:

Establish Linux 4.20.8 on ARM32

DTS 文件

由于使用的平台是 ARM32,所以在源码 /arch/arm/boot/dts 目录下创建一个 DTSI 文 件,在 root 节点之下创建一个名为 DTS_demo 的子节点。节点包含名为 BiscutisOS-strings 的属性,属性值为 “uboot”, “kernel”, “rootfs”, “BiscuitOS” 四个字符串。具体内容如下:

/*
* DTS Demo Code
*
* (C) 2019.01.06 <buddy.zhang@aliyun.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
/ {
DTS_demo {
compatible = "DTS_demo, BiscuitOS";
status = "okay";
BiscuitOS-strings = "uboot", "kernel", "rootfs", "BiscuitOS";
};
};

创建完毕之后,将其保存并命名为 DTS_demo.dtsi。然后开发者在 Linux 4.20.8 的源 码中,找到 arch/arm/boot/dts/vexpress-v2p-ca9.dts 文件,然后在文件开始地方添 加如下内容:

#include "DTS_demo.dtsi"

编写 DTS 对应驱动

准备好 DTSI 文件之后,开发者编写一个简单的驱动,这个驱动作为 DTS_demo 的设备 驱动,在 DTS 机制遍历时会调用匹配成功的驱动,最终运行驱动里面的代码。在驱动的 probe 函数中,首先获得驱动所对应的节点,通过 platform_device 的 of_node 成员传 递。获得驱动对应的节点之后,通过调用 of_property_read_string_index() 函数获得 “BiscuitOS-strings”属性中第二个字符串,并打印属性值,驱动编写如下:

/*
* DTS: of_property_match_string
* of_property_count_strings
* of_property_read_string_index
* of_property_read_string_array
* of_property_read_string_helper
*
* int of_property_match_string(struct device_node *np, const char *propname,
* const char *string)
*
* static inline int of_property_count_strings(struct device_node *np,
* const char *propname)
*
* static inline int of_property_read_string_index(struct device_node *np,
* const char *propname,
* int index, const char **output)
*
* static inline int of_property_read_string_array(struct device_node *np,
* const char *propname,
* const char **out_strs, size_t sz)
*
* int of_property_read_string_helper(struct device_node *np,
* const char *propname,
* const char *out_strs,
* size_t sz, int skip)
*
* (C) 2019.01.11 BuddyZhang1 <buddy.zhang@aliyun.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/ /*
* Private DTS file: DTS_demo.dtsi
*
* / {
* DTS_demo {
* compatible = "DTS_demo, BiscuitOS";
* status = "okay";
* BiscuitOS-strings = "uboot", "kernel",
* "rootfs", "BiscuitOS";
* };
* };
*
* On Core dtsi:
*
* include "DTS_demo.dtsi"
*/ #include <linux/init.h>
#include <linux/kernel.h>
#include <linux/of_platform.h> /* define name for device and driver */
#define DEV_NAME "DTS_demo" /* probe platform driver */
static int DTS_demo_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
const char *string_array[4];
const char *string;
int count, index;
int rc; printk("DTS demo probe entence.\n"); /* Verify property whether contains special string. */
rc = of_property_match_string(np, "BiscuitOS-strings", "rootfs");
if (rc < 0)
printk("BiscuitOS-strings doesn't contain \"rootfs\"\n");
else
printk("BiscuitOS-strings[%d] is \"rootfs\"\n", rc); /* Count the string on string-list property */
count = of_property_count_strings(np, "BiscuitOS-strings");
printk("String count: %#x\n", count); /* Read special string on string-list property with index */
for (index = 0; index < count; index++) {
rc = of_property_read_string_index(np, "BiscuitOS-strings",
index, &string);
if (rc < 0) {
printk("Unable to read BiscuitOS-strings[%d]\n", index);
continue;
}
printk("BiscuitOS-strings[%d]: %s\n", index, string);
} /* Read number of strings from string-list property */
rc = of_property_read_string_array(np, "BiscuitOS-strings",
string_array, count);
if (rc < 0) {
printk("Faild to invoke of_property_read_string_array()\n");
return -1;
}
for (index = 0; index < count; index++)
printk("String_array[%d]: %s\n", index, string_array[index]); /* Read a string with index on string-list property (index = 2) */
rc = of_property_read_string_helper(np, "BiscuitOS-strings",
&string, 1, 2);
if (rc < 0)
printk("Faild to invoke of_property_read_string_helper()!\n");
else
printk("BiscuitOS-strings[index=2]: %s\n", string); return 0;
} /* remove platform driver */
static int DTS_demo_remove(struct platform_device *pdev)
{
return 0;
} static const struct of_device_id DTS_demo_of_match[] = {
{ .compatible = "DTS_demo, BiscuitOS", },
{ },
};
MODULE_DEVICE_TABLE(of, DTS_demo_of_match); /* platform driver information */
static struct platform_driver DTS_demo_driver = {
.probe = DTS_demo_probe,
.remove = DTS_demo_remove,
.driver = {
.owner = THIS_MODULE,
.name = DEV_NAME, /* Same as device name */
.of_match_table = DTS_demo_of_match,
},
};
module_platform_driver(DTS_demo_driver);

编写好驱动之后,将其编译进内核。编译内核和 dts,如下命令:

make ARCH=arm BiscuitOS/output/linux-4.20.8/arm-linux-gnueabi/arm-linux-gnueabi/bin/arm-linux-gnueabi- j8
make ARCH=arm BiscuitOS/output/linux-4.20.8/arm-linux-gnueabi/arm-linux-gnueabi/bin/arm-linux-gnueabi- dtbs

启动内核,在启动阶段就会运行驱动的 probe 函数,并打印如下信息:

[    3.580217] DTS demo probe entence.
[ 3.580233] BiscuitOS-strings[2] is "rootfs"
[ 3.580247] String count: 0x4
[ 3.580258] BiscuitOS-strings[0]: uboot
[ 3.580271] BiscuitOS-strings[1]: kernel
[ 3.580284] BiscuitOS-strings[2]: rootfs
[ 3.580297] BiscuitOS-strings[3]: BiscuitOS
[ 3.580311] String_array[0]: uboot
[ 3.580322] String_array[1]: kernel
[ 3.580334] String_array[2]: rootfs
[ 3.580346] String_array[3]: BiscuitOS
[ 3.580358] BiscuitOS-strings[index=2]: rootfs

 

of_property_read_string_index(转)的更多相关文章

  1. ARM Linux 3.x的设备树(Device Tree)

    http://blog.csdn.net/21cnbao/article/details/8457546 宋宝华 Barry Song <21cnbao@gmail.com> 1.     ...

  2. ARM Linux 3.x的设备树(Device Tree)

    1. ARM Device Tree起源 Linus Torvalds在2011年3月17日的ARM Linux邮件列表宣称“this whole ARM thing is a f*cking pai ...

  3. linux内核中的GPIO系统之(2):pin control subsystem

    一.前言 在linux2.6内核上工作的嵌入式软件工程师在pin control上都会遇到这样的状况: (1)启动一个新的项目后,需要根据硬件平台的设定进行pin control相关的编码.例如:在b ...

  4. [dts]Device Tree机制

    转自:http://blog.csdn.net/machiner1/article/details/47805069 ------------------Based on linux 3.10.24 ...

  5. 【转】 ARM Linux 3.x的设备树(Device Tree)

    1.    ARM Device Tree起源 http://blog.csdn.net/21cnbao/article/details/8457546 Linus Torvalds在2011年3月1 ...

  6. 【转】ARM Linux 3.x的设备树(Device Tree)

    原文网址:http://blog.csdn.net/21cnbao/article/details/8457546 1.    ARM Device Tree起源 Linus Torvalds在201 ...

  7. 基於tiny4412的Linux內核移植 --- 实例学习中断背后的知识(1)

    作者:彭东林 邮箱:pengdonglin137@163.com QQ:405728433 平台 tiny4412 ADK Linux-4.9 概述 前面几篇博文列举了在有设备树的时候,gpio中断的 ...

  8. 高通ASOC中的machine驱动

    ASoC被分为Machine.Platform和Codec三大部分,其中的Machine驱动负责Platform和Codec之间的耦合以及部分和设备或板子特定的代码,再次引用上一节的内容:Machin ...

  9. [dts]Device Tree机制【转】

    转自:https://www.cnblogs.com/aaronLinux/p/5496559.html 转自:http://blog.csdn.net/machiner1/article/detai ...

随机推荐

  1. docke通信之Linux 网络命名空间

    一.前言 namespace(命名空间)和cgroup是软件容器化(想想Docker)趋势中的两个主要内核技术.简单来说,cgroup是一种对进程进行统一的资源监控和限制,它控制着你可以使用多少系统资 ...

  2. Mysql系列(五)—— 分页查询及问题优化

    一.用法 在Mysql中分页查询使用关键字limit.limit的语法如下: SELECT * FROM tbl LIMIT 5,10; # Retrieve rows 6-15 limit关键字带有 ...

  3. 【02】Jenkins:第一个项目

    写在前面的话 通过上一节我们成功的搭建起来 Jenkins,那么接下来就是体验如何构建我们的第一个项目了.当然在这之前我们得专门针对 Java 环境就行简单的配置. 全局工具配置 其实这次配置的主要还 ...

  4. Blend 触发器

    原文:Blend 触发器 介绍用定义触发器来控制视频 的 开始 暂停 继续 停止 触发器设置 效果

  5. WPF 精修篇 事件触发器

    原文:WPF 精修篇 事件触发器 事件触发器 一般使用的就是动画 <Grid> <TextBlock Text="事件触发器" Opacity="0.2 ...

  6. Go语言http包简易入门

    说道go语言web编程,必不可少的会使用到net/http包.go语言将web开发需要使用到的很多内容都放在了标准库中——net/http. 如何写一个简单的web程序很容易.如下: package ...

  7. 'while' statement cannot complete without throwing an exception

    You are probably using Android Studio or IntelliJ. If so, you can add this above your method contain ...

  8. MySQL 8.0.13安装修改密码的一个问题,记录一下。

    https://blog.csdn.net/qq_37350706/article/details/81707862 关于安装MySQL 8.0.13,本人就不多说了,上面这个链接讲的非常详细 请参考 ...

  9. 在VS2019创建WebForm程序,开个箱

    现在公司用的是VS2010+ASP.NET WebForm + DevExpress控件做系统开发,好老好老了,没办法,只能在这里尝一尝新鲜的味道. TMD,还以为马上创建,谁知还有一关!!! 还是那 ...

  10. 49道spring面试题整理,附带答案

    1.选择使用Spring框架的原因? 使用Spring: 第一是使用它的IOC功能,在解耦上达到了配置级别. 第二是使用它对数据库访问事务相关的封装. 第三就是各种其他组件与Spring的融合,在Sp ...