当前位置: 首页 > news >正文

Linux驱动学习笔记(八)

设备树插件

1.设备树替换了平台总线的plat_device部分,减少了内核的硬件相关代码,硬件发生变化以后,无需编译内核,只需要重新编译设备树即可。Linux4.4版本以后引入了设备树新技术Dynamic DeviceTree,这个技术可以翻译为动态设备树,或者设备树插件,Dynamic DeviceTree技术可以在系统运行期间动态的修改设备树,该技术的应用场景主要有:调试驱动、应用于无法预先在设备里面描述的设备、修改设备树引脚复用等等。

2.设备树插件语法如下图所示,需要在文件头部加上/plugin/;,一共有四种编写方式:

设备树插件仍然采用dtc来编译,编译语法与编译普通设备树文件一样。当要使用设备树插件时,首先要烧写支持设备树插件的 Linux 系统,并且将用来支持设备树插件的相关驱动加载到系统。其次要查看configfs是否挂载成功,如果使用命令cat /proc/filesystems可以在该文件中看到configfs说明configfs文件系统是被支持的(设备树插件需要configfs文件系统支持,/proc/filesystem是一个虚拟文件,它列出了当前Linux内核支持的所有文件系统类型,这个文件的内容反映了内核编译时内置的文件系统支持,以及运行时动态加载的文件系统模块,这个文件是一个虚拟文件,它由内核动态生成,而不是存储在磁盘上的普通文件,无法用vi打开),mount | grep configfs查看configfs是否被挂载,configfs是Linux内核提供的一种用户空间可配置的虚拟文件系统,主要用于动态管理内核对象。用来支持设备树插件的相关驱动加载成功后,可以在/sys/kernel/config/目录下看到/sys/kernel/config/device-tree/overlays/(这个目录需要加载用来支持设备树插件的驱动才会被创建,/device-tree/overlays/这部分目录的名字是在设备树插件的相关驱动代码中决定的,可以自定义),进入这个目录后,用mkdir “name”创建一个内核对象,并进入这个创建的目录,如果创建的是item,这个新创建的目录下会有dtbo和status两个属性文件(这两个文件名是根据设备树插件的相关驱动代码中的item属性部分决定的,可以自定义),假设想要添加的设备树插件编译后的二进制文件为test.dtbo,则以此执行cat /test.dtbo>dtbo、echo 1>status便可以加载设备树插件,加载成功后可以在/proc/device-tree/目录下看到对应的节点,要删除设备树插件时只要将“name”目录删除即可。还可以同时使用多个设备树插件,具体可参考讯为Linux驱动视频第八期P4。

3.虚拟文件系统的作用是Linux内核和用户空间进行数据交换,内核常用的虚拟文件系统有procfs、debugfs、sysfs、configfs,其中sysfs和configfs理论上都可以实现设备树插件技术,但是二者的区别是:sysfs虚拟文件系统将内核中的数据、属性以文件的方式导出到用户空间,导出到用户空间以后,读这些文件就表示读取设备的文件,写这些文件就表示控制设备;configfs英文被解释为 Userspace-driven kernel object configuration 意思就是用户空间配置内核对象,所以 configfs与 sysfs恰恰相反,sysfs导出内核对象给用户空间,它只能在用户空间对已有的内核对象做修改而不能创建或删除内核对象,configfs是从用户空间去配置内核对象,他可以在用户空间创建或删除内核对象,并且不需要重新编译内核或者修改内核代码,所以configfs更适合设备树插件这个技术。configfs源码位于/kernel/fs/configs路径下。

4.configfs虚拟文件系统相关的数据结构主要有:configfs_subsystem、config_group和config_item,他们都定义在内核源码目录下的/include/linux/configfs.h文件中,如下图所示:

当使用虚拟文件系统时,这三个数据结构分别对应不同层级的文件,例如configfs_subsystem对应的是/sys/kernel/config/目录下的文件,如上图中的/sys/kernel/config/device-tree,需要注意的是这个device-tree本身也可以看成是一个group。当使用mkdir test(make “name”)创建test这个目录时(item),会调用configfs_group_operations结构体里的make_group函数(优先级更高)或make_item函数,当使用rmdir test删除test这个目录时(item),会调用configfs_group_operations结构体里的drop_item函数(优先级更高)或者configfs_item_operations结构体里的release函数。上图中的dtbo和status是存储在struct configfs_attribute中的(代表item的attribute,一个item可以有多个attribute,每个attribute对应一个文件),该结构体中的show和store定义了对这些文件进行读写时的效果。在group下面可以创建group和item,但是在item下面不能创建group或item(具体可参考讯为Linux驱动视频第八期P6-P12)。

5.编写自己的支持设备树插件的驱动时设计的函数即代码主要有:首先需要在模块初始化函数中(module_init函数中注册的模块初始化函数)初始化configfs_subsystem结构体中的group,并向系统注册该configfs子系统,然后将需要挂载在此configfs_subsystem下面的group进行初始化及注册。这部分涉及的函数有(所有函数定义在/kernel/fs/configs目录下的.c文件中):

  • void config_group_init(struct config_group *group);:该函数用于初始化一个config_group结构体,设置其默认值和初始化内部链表。
  • int configfs_register_subsystem(struct configfs_subsystem *subsys);:该函数向内核注册一个configfs子系统,使其在用户空间的/sys/kernel /config/目录下可见。
  • void config_group_init_type_name(struct config_group *group, const char *name, struct config_item_type *type);:该函数用于初始化一个config_group并设置其名称和关联的config_item_type(操作函数和属性)。其中group指向要初始化的config_group结构体的指针;name为该group的名字,(在用户空间/sys/kernel /config/目录中显示的目录名);type指向config_item_type结构体的指针,定义该group的操作函数(如属性、释放方法等)。
  • int configfs_register_group(struct config_group *parent_group, struct config_group *group);:该函数用于将一个子组(group)注册到父组(parent_group)下,形成层次结构。其中parent_group指向父组的config_group结构体(如子系统的根组);group指向要注册的子组的config_group结构体。

如下图所示:

然后根据实际需要构造层级结构。在命令行使用mkdir命令创建内核对象时,如果当前对应的group(pwd命令显示的路径)关联的config_item_type中的结构体configfs_group_operations中定义了操作函数make_group则会调用该函数创建一个子group,如果定义了操作函数make_item则会调用该函数创建一个item,如果这俩操作函数都没定义则创建失败。在命令行使用rmdir命令删除内核对象时,如果当前对应的group(pwd命令显示的路径)关联的config_item_type中的结构体configfs_group_operations中定义了操作函数drop_item则调用该函数进行删除,如果该函数没定义则会调用删除的目标item中的结构体configfs_item_operations中定义的操作函数release,另外还可以在上述的操作函数drop_item中调用config_item_put函数来间接执行release函数。涉及的函数及宏定义如下:

  • void config_item_init_type_name(struct config_item *item, const char *name, struct config_item_type *type);:该函数用于初始化一个config_item并设置其名称和关联的config_item_type(操作函数和属性)。其中item指向要初始化的config_ item结构体的指针;name为该item的名字,(在用户空间/sys/kernel /config/”group”/目录中显示的目录名);type指向config_item_type结构体的指针,定义该item的操作函数(如属性、释放方法等)。
  • void config_item_put(struct config_item *item);:这个函数会调用参数item的config_item_type中的结构体configfs_item_operations中定义的操作函数release。
  • CONFIGFS_ATTR_RO (_prefix, _name):定义一个名为_prefix##attr_##_name的具有只读属性的configfs_attribute结构体,代表configfs文件系统的attribute(属性)文件,在该结构体中绑定的操作函数show定了读该文件时的具体操作。
  • CONFIGFS_ATTR_WO (_prefix, _name):定义一个名为_prefix##attr_##_name的具有只写属性的configfs_attribute结构体,代表configfs文件系统的attribute(属性)文件,在该结构体中绑定的操作函数store定了写该文件时的具体操作。

6.想要配置linux支持设备树插件,首先需要在make menuconfig界面打开以下选项:File systems->Pseudo filesystems->Userspace-driven configuration filesystem、Device Drivers->Device Tree and Open Firmware support->Device Tree overlays以及File systems->下的下图中的所有选项:

然后去github下载支持设备树插件的驱动源码编译成.ko文件,并将该.ko文件编译进内核或者以内核模块的方式加载即可(可参考讯为Linux驱动视频第八期P13)。在支持设备树插件的驱动源码中,也是将设备树文件转换为device_nade再转换为platform_device,但引入了改变集的概念,方便设备树插件动态的加载和删除(可参考讯为Linux驱动视频第八期P14)。

相关文章:

  • 数据结构——二叉树
  • 设计模式(结构型)-享元模式
  • 【C++】哈希unordered_map和set的使用以及哈希表,哈希桶的概念以及底层实现
  • MATLAB遇到内部问题,需要关闭,Crash Decoding : Disabled - No sandbox or build area path
  • MySQL NDB Cluster详解
  • 用 Vue.js 构建基础购物车:从 0 到 1 的实战解析
  • git 提交标签
  • React与Vue:选择哪个框架入门?
  • 【图灵Python爬虫逆向】题七:千山鸟飞绝
  • 从 SYN Flood 到 XSS:常见网络攻击类型、区别及防御要点
  • 25年河南事业单位报名详细流程图解
  • 计算机视觉与深度学习 | 视觉SLAM学习思路总结与视觉SLAM发展历程(1986年至2025年)
  • 独立开发者之网站的robots.txt文件如何生成和添加
  • 趣味编程之go与rust的爱恨情仇
  • 基于SSM+Layui毕业设计选题系统源码
  • 【持续更新】WT-YOLO数据集配置与目录划分
  • [特殊字符] 终端效率提升指南:zsh + tmux
  • MQ(RabbitMQ.1)
  • CSS 字体学习笔记
  • C#里使用MaterialDesign时在VS2022里出错
  • 2024年境内酒店住宿行业指标同比下滑:酒店行业传统增长模式面临挑战
  • 深交所修订创业板指数编制方案,引入ESG负面剔除机制
  • “80后”蒋美华任辽宁阜新市副市长
  • 招行一季度净利372.86亿降2.08%,营收降逾3%
  • 比熬夜更伤肝的事,你可能每天都在做
  • 五一假期如何躺赚利息?来看国债逆回购操作攻略