• Linux驱动开发(三)---设备树


    前文回顾

    《Linux驱动开发(一)—环境搭建与hello world》

    《Linux驱动开发(二)—驱动与设备的分离设计》

    继续宣传一下韦老师的视频

    70天30节Linux驱动开发快速入门系列课程【实战教学、技术讨论、直播答疑】

    在这里插入图片描述

    设备树

    前面的设备分离模式,将模块分为了驱动部分和设备部分,设备部分目前也是c语言编写的,但是这样就为内核引入了大量的代码,有点惹怒了linus,然后就引入了设备树这个东西。大佬就是大佬,可靠。

    在这里插入图片描述

    简单来说,就是通过配置文件的方法,代替device部分的c代码,来描述了设备的信息,参数等。
    那么简单一下介绍一下设备树的格式,设备树使用的语言叫DTS语法,可以参考博客《一文搞定 Linux 设备树》

    DTS( device tree source)文件通过DTC工具编译为DTB(device tree blob)文件,系统启动时候,会通过解析dtb文件,自动来创建节点和设备。

    这些基本知识点还是要掌握,至少要能看得懂一个dts文件的内容大概是什么意思。
    在这里插入图片描述

    代替device模块

    多说无益,还是介绍怎么用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";
    	};
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    在这里插入图片描述

    那么,和之前的文章一样,关键点来了,驱动如何和这个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,
    };
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    这个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';
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    of_property_read_string就可以读出节点数据中的pin参数。
    真是上有政策,下有对策,灵活选择。
    在这里插入图片描述
    获取参数还可以通过如下几种接口

    功能函数
    查找节点of_find_node_by_path 函数,通过指定全路径来查找指定节点。
    提取属性值of_find_property 函数 ,获取到的值保存到了 property 结构体中。
    读整数u32of_property_read_u32
    读整数u64of_property_read_u64
    读某个整数u32of_property_read_u32_index
    读某个整数u64of_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 设备树》

    结束语

    昨天行程码带星的取消了,大家都开始高兴,说明国家的大趋势已经开始要精准防疫了,不会再一个小区高风险,整个城市受限制了。
    希望这个夏天能够去一下海边……
    在这里插入图片描述
    公司里的技术专家辞职了,可能是受不了各种奇葩的规矩吧,一个从华为出来的人,怕是怎么也理解不了老板的脑回路,对比起华为,我们这里更社会。
    在这里插入图片描述
    其实这就是人生啊,哪有一帆风顺,都是跌跌撞撞。
    在这里插入图片描述

  • 相关阅读:
    Android 音频可视化
    【计算机网络】 RTT和RTO
    C++面向对象程序设计 - 构造函数
    arm 汇编基础指令
    成员变量、静态成员变量、局部变量、常量的内存区域
    含氯甲基大孔径苯乙烯-二乙烯基苯微球/交联聚苯乙烯微球固载双齿席夫碱型氧钒(Ⅳ)
    接手了一个外包开发的项目,我感觉我的头快要裂开了~
    【星海出品】SDN neutron (四) 流分析
    局部异常因子(Local Outlier Factor, LOF)算法详解及实验
    如何优雅的设计权限系统才算yyds?(荣耀典藏版)
  • 原文地址:https://blog.csdn.net/baidu_19348579/article/details/125520060