驱动-设备树插件-注册group

设备树插件里面:注册group 实验


前言

参考资料

前面设备树插件相关的基本知识点可供参考
Linux驱动-设备树插件语法
设备树插件基础必备
驱动-设备树插件注册子系统

设备树插件-注册group容器实验

一、注册 group 容器

基础代码

#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/configfs.h>

// 定义一个名为"mygroup"的config_group结构体
static struct config_group mygroup;
// 定义一个名为"mygroup_config_item_type"的config_item_type结构体,用于描述配置项类型。
static const struct config_item_type mygroup_config_item_type = {
    .ct_owner = THIS_MODULE,
    .ct_item_ops = NULL,
    .ct_group_ops = NULL,
    .ct_attrs = NULL,
};

// 定义名为"myconfig_item_type"的配置项类型结构体
static const struct config_item_type myconfig_item_type = {
    .ct_owner = THIS_MODULE,
    .ct_group_ops = NULL,
};

// 定义一个configfs_subsystem结构体实例"myconfigfs_subsystem"
static struct configfs_subsystem myconfigfs_subsystem = {
    .su_group = {
        .cg_item = {
            .ci_namebuf = "myconfigfs",
            .ci_type = &myconfig_item_type,
        },
    },
};

// 模块的初始化函数
static int myconfig_group_init(void)
{
  // 初始化配置组
  config_group_init(&myconfigfs_subsystem.su_group);
  // 注册子系统
  configfs_register_subsystem(&myconfigfs_subsystem);

  // 初始化配置组"mygroup"
  config_group_init_type_name(&mygroup, "mygroup", &mygroup_config_item_type);
  // 在子系统中注册配置组"mygroup"
  configfs_register_group(&myconfigfs_subsystem.su_group, &mygroup);
  return 0;
}

// 模块退出函数
static void myconfig_group_exit(void)
{
  // 注销子系统
  configfs_unregister_subsystem(&myconfigfs_subsystem);
}

module_init(myconfig_group_init); // 指定模块的初始化函数
module_exit(myconfig_group_exit); // 指定模块的退出函数

MODULE_LICENSE("GPL");   // 模块使用的许可证
MODULE_AUTHOR("fangchen"); // 模块的作者

代码分析

这份代码和前面 驱动-设备树插件注册子系统 代码基础上多了一些代码如下:

  //第一步
// 定义一个名为"mygroup"的config_group结构体
static struct config_group mygroup;
// 定义一个名为"mygroup_config_item_type"的config_item_type结构体,用于描述配置项类型。
static const struct config_item_type mygroup_config_item_type = {
    .ct_owner = THIS_MODULE,
    .ct_item_ops = NULL,
    .ct_group_ops = NULL,
    .ct_attrs = NULL,
};

  // 第二步
  // 初始化配置组"mygroup"
  config_group_init_type_name(&mygroup, "mygroup", &mygroup_config_item_type);
  
   //第三步
  // 在子系统中注册配置组"mygroup"
  configfs_register_group(&myconfigfs_subsystem.su_group, &mygroup);






其实在之前驱动-设备树插件注册子系统 多了三部分内容:

  • 定义组:config_group 和 后面这个组关联的 config_item_type

  • 初始化一个 config_group 结构体,设置其名称和类型。

  • config_group 注册到父组中,在 configfs 文件系统中创建对应的目录和属性

实验结果

直接看实际测试结果,如下:路径/sys/kernel/config/myconfigfs/mygroup,生成了:myconfigfs、mygroup 两个组。

在这里插入图片描述

API函数详解

函数config_group_init_type_name

功能
初始化一个 config_group 结构体,设置其名称和类型。
函数原型

void config_group_init_type_name(
    struct config_group *group, 
    const char *name,
    struct config_item_type *type);

参数详解

  • group: 要初始化的 config_group 结构体指针
  • name: 该组的名称(将显示在 configfs 文件系统中)
  • type: 指向 config_item_type 结构的指针,定义该组的行为和属性

内部实现

  • 调用 config_item_init 初始化基础的 config_item
  • 设置组的名称
  • 初始化组的默认组(default_groups)
  • 设置组的 item_type

使用示例

static struct config_group my_group;
static struct config_item_type my_group_type = {
    .ct_owner = THIS_MODULE,
    // 其他回调函数
};

config_group_init_type_name(&my_group, "my_group", &my_group_type);

函数configfs_register_group

功能
将一个已初始化的 config_group 注册到父组中,在 configfs 文件系统中创建对应的目录和属性。

函数原型

int configfs_register_group(
    struct config_group *parent_group,
    struct config_group *group);

参数详解

  • parent_group: 父组,新组将作为其子组
  • group: 要注册的组(必须已通过 config_group_init_type_name 初始化)

内部操作

  • 在父组的目录下创建新目录(使用 group 的名称)
  • 创建该组的所有属性文件
  • 如果定义了默认子组,也会创建它们

使用示例

int ret;
struct config_group *parent = ...; // 获取父组

ret = configfs_register_group(parent, &my_group);
if (ret < 0) {
    pr_err("Failed to register group: %d\n", ret);
    return ret;
}

典型使用场景

如上,两个API 结合起来用,如下:

// 1. 定义组类型
static struct config_item_type my_group_type = {
    .ct_owner = THIS_MODULE,
    .ct_item_ops = &my_item_ops,
    .ct_attrs = my_group_attrs,
};

// 2. 初始化组
struct config_group my_group;
config_group_init_type_name(&my_group, "my_config", &my_group_type);

// 3. 注册组
int ret = configfs_register_group(parent_group, &my_group);

二、知识扩展一-子系统和组的区别和联系-在子系统中添加组操作

在设备树插件(Device Tree Overlay)中,子系统(Subsystem)和组(Group)是用于模块化管理和动态加载的重要概念。它们的核心区别在于:

  • 子系统是逻辑分类(按功能划分,如 i2c、gpio)。

  • 组是物理加载单位(一个 .dtbo 文件包含多个节点)。

而在子系统中添加组操作,通常是指通过设备树插件的机制,将一组节点(组)动态绑定到某个子系统中。以下是具体分析和实现方法:

子系统和组的核心区别

维度子系统(Subsystem)组(Group)
定义功能逻辑单元(如 i2c、spi 总线下的设备)物理加载单元(一个 .dtbo 文件)
作用范围跨多个设备树插件存在仅限当前插件文件内
标识方式通过 compatible 属性或节点标签标识通过文件名(如 my_group.dtbo)标识
操作对象内核驱动通过子系统匹配设备用户或脚本通过 dtc 或内核接口加载/卸载

在子系统中添加组的操作

第一种方案:如上,写一个驱动,动态实现。

第二种方案:前面讲过的知识点,在设备树插件中.dts 文件中描述,生成dtbo,然后命令实现。

  • 定义设备树插件(组)
    在插件文件中,将节点挂载到目标子系统(如 i2c1)下:
// 文件:sensors.dtbo.dts
/dts-v1/;
/plugin/;

&i2c1 {  // 目标子系统:i2c1
    #address-cells = <1>;
    #size-cells = <0>;

    /* 在i2c子系统中添加一组设备 */
    temp_sensor: temp@48 {
        compatible = "ti,tmp75";
        reg = <0x48>;
    };

    humidity_sensor: humidity@49 {
        compatible = "sensirion,sht3x";
        reg = <0x49>;
    };
};
  • 编译并加载组
    将插件编译为 .dtbo 文件,并动态加载到内核:
dtc -@ -I dts -O dtb -o sensors.dtbo sensors.dtbo.dts
echo sensors.dtbo > /sys/kernel/config/device-tree/overlays/load
  • 验证子系统中的组
    加载后,新的设备节点会出现在 i2c1 子系统中:
ls /sys/bus/i2c/devices/  # 查看i2c1下的设备
cat /proc/device-tree/i2c@40000000/temp@48/compatible  # 验证节点

三、 知识扩展二-数据结构_关联关系_在此注册group

对于设备树插件,每次写代码头疼,也不知道怎么写,看似就是一个简单的树结构,看看其它人的文章知识点和视频 也会绕晕。 基础还是补一补,加深印象,日积月累吧!

核心数据结构及关联关系

(1) config_item

  • 作用:基础配置单元(如参数、设备等)。

  • 关键成员:

struct config_item {
    char ci_namebuf[CONFIGFS_ITEM_NAME_LEN]; // 名称缓冲区(默认20字节)
    struct config_group *ci_group;           // 所属父group
    struct config_item_type *ci_type;        // 关联的操作和属性
};
  • ci_namebuf:存储该item在configfs中的显示名称(如echo “name” > /config/path/item时会写入此缓冲区)。

(2) config_group

  • 作用:既是config_item(继承),又是其他item/group的容器。

  • 关键成员:

struct config_group {
    struct config_item cg_item;              // 内嵌的config_item
    struct list_head cg_children;            // 子item/group链表
};
  • 关联关系:
通过cg_item.ci_group指向父group。
子项通过cg_children链表管理。

(3) config_item_type

  • 作用:定义item/group的类型行为(操作和属性)。

  • 结构体:

struct config_item_type {
    const struct configfs_item_operations *ct_item_ops; // item操作(如show/store)
    const struct configfs_group_operations *ct_group_ops; // group操作(如make_group)
    struct configfs_attribute **ct_attrs;    // 属性数组
};
  • 关键操作:
ct_item_ops:处理item的读写(如show_attribute、store_attribute)。
ct_group_ops:处理group的动态创建(如make_group)。

(4) configfs_attribute

  • 作用:定义item/group的属性文件(在configfs中表现为文件)。

  • 结构体:

struct configfs_attribute {
    char *ca_name;                          // 属性文件名(如"value")
    umode_t ca_mode;                        // 文件权限(如0644)
};
  • 关联关系:通过config_item_type.ct_attrs数组关联到item/group。

(5) configfs_subsystem

  • 作用:子系统的顶级描述符。

  • 结构体:

struct configfs_subsystem {
    struct config_group su_group;            // 根group
    struct mutex su_mutex;                  // 互斥锁
};

首次注册子系统

static struct configfs_attribute root_attr = {
    .ca_name = "version",
    .ca_mode = S_IRUGO,
};

static struct configfs_attribute *root_attrs[] = {
    &root_attr,
    NULL,
};

static struct config_item_type root_group_type = {
    .ct_attrs = root_attrs,
    .ct_owner = THIS_MODULE,
};

static struct configfs_subsystem my_subsys = {
    .su_group = {
        .cg_item = {
            .ci_namebuf = "my_subsystem",     // 根group名称
            .ci_type = &root_group_type,     // 关联类型
        },
    },
};

static int __init my_init(void) {
    config_group_init(&my_subsys.su_group);
    configfs_register_subsystem(&my_subsys);
    return 0;
}

结果:在/config下创建目录my_subsystem,并包含属性文件version。 这个基础代码之前就了解过,基本操作没有什么特别要讲的

二次注册Group(子Group)

这里有部分内容是需要后面讲解的,先了解下吧
在已注册的子系统下添加子group,需以下步骤:

  • (1) 定义子Group及其Item
// 子group的属性
static ssize_t child_attr_show(struct config_item *item, char *buf) {
    return sprintf(buf, "Hello from child!\n");
}

static struct configfs_attribute child_attr = {
    .ca_name = "message",
    .ca_mode = S_IRUGO,
};

static struct configfs_attribute *child_attrs[] = {
    &child_attr,
    NULL,
};

// 子group的item操作
static struct configfs_item_operations child_item_ops = {
    .show_attribute = child_attr_show,
};

// 子group的类型
static struct config_item_type child_group_type = {
    .ct_item_ops = &child_item_ops,
    .ct_attrs = child_attrs,
    .ct_owner = THIS_MODULE,
};

ci_namebuf = “my_dto_plugin”:
子系统的名称,会在 /config/ 下生成对应的目录(如 /config/my_dto_plugin)。

  • (2) 实现父Group的make_group回调
static struct config_group *create_child(struct config_group *parent, const char *name) {
    struct config_group *child = kzalloc(sizeof(*child), GFP_KERNEL);
    if (!child) return ERR_PTR(-ENOMEM);

    config_group_init_type_name(child, name, &child_group_type);
    return child;
}

static struct configfs_group_operations parent_group_ops = {
    .make_group = create_child, // 动态创建子group
};

static struct config_item_type parent_group_type = {
    .ct_group_ops = &parent_group_ops,
    .ct_owner = THIS_MODULE,
};

// 在初始化时设置父group类型
my_subsys.su_group.cg_item.ci_type = &parent_group_type;
  • 用户态触发子Group创建
# 创建子group
mkdir /config/my_subsystem/child_group

# 查看属性
cat /config/my_subsystem/child_group/message
# 输出: Hello from child!

关键关联关系图示

configfs_subsystem
│
├── su_group (config_group)
│   ├── cg_item (config_item)
│   │   ├── ci_namebuf = "my_subsystem"
│   │   ├── ci_type = &parent_group_type
│   │   └── ci_group = NULL (根group)
│   │
│   ├── ct_group_ops.make_group = create_child
│   └── cg_children (链表)
│       └── child_group (config_group)
│           ├── cg_item.ci_namebuf = "child_group"
│           ├── cg_item.ci_type = &child_group_type
│           ├── ct_attrs = [&child_attr]
│           └── ct_item_ops.show_attribute = child_attr_show
│
└── su_mutex (保护并发)

总结

  • 进一步理解了子系统和组的概念、联系、如何注册的
  • 学习了两个api 初始化组:config_group_init_type_name ,组注册到子系统configfs_register_group
  • 通过这个简单的新增子group案例,再次分析细节基础知识
基于径向基函数神经网络RBFNN的自适应滑模控制学习(Matlab代码实现)内容概要:本文介绍了基于径向基函数神经网络(RBFNN)的自适应滑模控制方法,并提供了相应的Matlab代码实现。该方法结合了RBF神经网络的非线性逼近能力和滑模控制的强鲁棒性,用于解决复杂系统的控制问题,尤其适用于存在不确定性和外部干扰的动态系统。文中详细阐述了控制算法的设计思路、RBFNN的结构与权重更新机制、滑模面的构建以及自适应律的推导过程,并通过Matlab仿真验证了所提方法的有效性和稳定性。此外,文档还列举了大量相关的科研方向和技术应用,涵盖智能优化算法、机器学习、电力系统、路径规划等多个领域,展示了该技术的广泛应用前景。; 适合人群:具备一定自动控制理论基础和Matlab编程能力的研究生、科研人员及工程技术人员,特别是从事智能控制、非线性系统控制及相关领域的研究人员; 使用场景及目标:①学习和掌握RBF神经网络与滑模控制相结合的自适应控制策略设计方法;②应用于电机控制、机器人轨迹跟踪、电力电子系统等存在模型不确定性或外界扰动的实际控制系统中,提升控制精度与鲁棒性; 阅读建议:建议读者结合提供的Matlab代码进行仿真实践,深入理解算法实现细节,同时可参考文中提及的相关技术方向拓展研究思路,注重理论分析与仿真验证相结合。
先展示下效果 https://pan.quark.cn/s/a4b39357ea24 本项目是本人参加BAT等其他公司电话、现场面试之后总结出来的针对Java面试的知识点或真题,每个点或题目都是在面试中被问过的。 除开知识点,一定要准备好以下套路: 个人介绍,需要准备一个1分钟的介绍,包括学习经历、工作经历、项目经历、个人优势、一句话总结。 一定要自己背得滚瓜烂熟,张口就来 抽象概念,当面试官问你是如何理解多线程的时候,你要知道从定义、来源、实现、问题、优化、应用方面系统性地回答 项目强化,至少与知识点的比例是五五开,所以必须针对简历中的两个以上的项目,形成包括【架构和实现细节】,【正常流程和异常流程的处理】,【难点+坑+复盘优化】三位一体的组合拳 压力练习,面试的时候难免紧张,可能会严重影响发挥,通过平时多找机会参与交流分享,或找人做压力面试来改善 表达练习,表达能力非常影响在面试中的表现,能否简练地将答案告诉面试官,可以通过给自己讲解的方式刻意练习 重点针对,面试官会针对简历提问,所以请针对简历上写的所有技术点进行重点准备 Java基础 JVM原理 集合 多线程 IO 问题排查 Web框架、数据库 Spring MySQL Redis 通用基础 操作系统 网络通信协议 排序算法 常用设计模式 从URL到看到网页的过程 分布式 CAP理论 锁 事务 消息队列 协调器 ID生成方式 一致性hash 限流 微服务 微服务介绍 服务发现 API网关 服务容错保护 服务配置中心 算法 数组-快速排序-第k大个数 数组-对撞指针-最大蓄水 数组-滑动窗口-最小连续子数组 数组-归并排序-合并有序数组 数组-顺时针打印矩形 数组-24点游戏 链表-链表反转-链表相加 链表-...
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

野火少年

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值