《Linux驱动开发(一)—环境搭建与hello world》
《Linux驱动开发(二)—驱动与设备的分离设计》
继续宣传一下韦老师的视频
70天30节Linux驱动开发快速入门系列课程【实战教学、技术讨论、直播答疑】
前面的设备分离模式,将模块分为了驱动部分和设备部分,设备部分目前也是c语言编写的,但是这样就为内核引入了大量的代码,有点惹怒了linus,然后就引入了设备树这个东西。大佬就是大佬,可靠。
简单来说,就是通过配置文件的方法,代替device部分的c代码,来描述了设备的信息,参数等。
那么简单一下介绍一下设备树的格式,设备树使用的语言叫DTS语法,可以参考博客《一文搞定 Linux 设备树》
DTS( device tree source)文件通过DTC工具编译为DTB(device tree blob)文件,系统启动时候,会通过解析dtb文件,自动来创建节点和设备。
这些基本知识点还是要掌握,至少要能看得懂一个dts文件的内容大概是什么意思。
多说无益,还是介绍怎么用DTS配置文件,替换掉device模块。
首先在DTS根节点下增加一个DTS节点,并且要保证其能够生成一个device,而且最重要的是要匹配上对应的driver。
一个例子
这个comoatible就是我们所要查找的驱动的标记字符串,内容随意,一般都是“厂商,驱动名字”。
这个DTS编译之后,系统启动的时候进行解析,就能够创建对应的节点,然后创建对应的device。是不是很智能,并且还提供了一个pin的参数,其实可以任意提供数据,只要定义好,例如:
myled_ok: myled_for_test_ok {
compatible = "100ask,led";
pin = "gpio5_3";
para_A = "hello";
para_B = "world";
};
那么,和之前的文章一样,关键点来了,驱动如何和这个device匹配上,那么就需要驱动引入另一个参数of_device_id 。
static const struct of_device_id dts_device_ids[] = {
{ .compatible = "100ask,led", },
{/* sentinel */}
};
/* A. 实现platform_driver */
static struct platform_driver led_driver = {
.probe = led_probe,
.remove = led_remove,
.driver = {
.name = "100ask_led",
.of_match_table = dts_device_ids,
},
.id_table = led_id_table,
};
这个driver结构中的of_match_table ,里面就提供了,匹配的参数,里面可以定义多个,匹配的就是节点中的compatible 参数。
这样一来。设备和驱动就又匹配上了,自然就可以快乐的执行到driver中的probe函数了。
那么新的问题又来了,之前参数通过device中的resource传递,这下没了resource,多了一个pin参数,那怎么处理呢,方法来了
在probe函数中,入参为platform_device pdev,这个pdev内部有标记,表明是普通的模块device还是设备树创建的device。
前者可以通过platform_get_resource得到参数数据
后者可以通过设备树接口来访问节点,然后得到参数。
例如
if (!pdev->dev.of_node) /* 普通的platform_device */
{
res = platform_get_resource(pdev, IORESOURCE_IRQ, i++);
if (!res)
return -EINVAL;
minor = g_ledcnt;
leds_desc[minor].pin = res->start;
}
else
{
of_property_read_string(pdev->dev.of_node, "pin", &tmp_str);
printk("pin = %s\n", tmp_str);
minor = g_ledcnt;
leds_desc[minor].pin = tmp_str[6] - '0';
}
of_property_read_string就可以读出节点数据中的pin参数。
真是上有政策,下有对策,灵活选择。
获取参数还可以通过如下几种接口
功能 | 函数 |
---|---|
查找节点 | of_find_node_by_path 函数,通过指定全路径来查找指定节点。 |
提取属性值 | of_find_property 函数 ,获取到的值保存到了 property 结构体中。 |
读整数u32 | of_property_read_u32 |
读整数u64 | of_property_read_u64 |
读某个整数u32 | of_property_read_u32_index |
读某个整数u64 | of_property_read_u64_index |
读取属性中数组数据 | of_property_read_variable_u8_array |
of_property_read_variable_u16_array | |
of_property_read_variable_u32_array | |
of_property_read_variable_u64_array | |
读取属性中字符串值 | of_property_read_string 函数。 |
直接内存映射 | of_iomap 函数,获取内存地址所对应的虚拟地址 |
内核中已经有了很多驱动,这些驱动需要的参数,叫什么,其实都已经定义好了,所以我们再增加DTS的时候,需要了解驱动需要定义那些参数,对应提供好即可。
补充知识点可以参考阅读下面博客
《ARM 设备树》
昨天行程码带星的取消了,大家都开始高兴,说明国家的大趋势已经开始要精准防疫了,不会再一个小区高风险,整个城市受限制了。
希望这个夏天能够去一下海边……
公司里的技术专家辞职了,可能是受不了各种奇葩的规矩吧,一个从华为出来的人,怕是怎么也理解不了老板的脑回路,对比起华为,我们这里更社会。
其实这就是人生啊,哪有一帆风顺,都是跌跌撞撞。