瑞芯微RK3568芯片是一款定位中高端的通用型SOC,采用22nm制程工艺,搭载一颗四核Cortex-A55处理器和Mali G52 2EE 图形处理器。RK3568 支持4K 解码和 1080P 编码,支持SATA/PCIE/USB3.0 外围接口。RK3568内置独立NPU,可用于轻量级人工智能应用。RK3568 支持安卓 11 和 linux 系统,主要面向物联网网关、NVR 存储、工控平板、工业检测、工控盒、卡拉 OK、云终端、车载中控等行业。
【公众号】迅为电子
【粉丝群】824412014(加群获取驱动文档+例程)
【视频观看】嵌入式学习之Linux驱动(第八期_设备树插件_全新升级)_基于RK3568
【购买链接】迅为RK3568开发板瑞芯微Linux安卓鸿蒙ARM核心板人工智能AI主板
第75章ConfigFS的核心数据结构
在前面的章节中,我们对于ConfigFS 有了一个感性的认识,本章节将进一步深入,探讨ConfigFS的核心数据结构,这将为我们理解ConfigFS的内部工作原理提供基础。让我们一起深入学习ConfigFS的核心数据结构吧!
75.1 关键数据结构
接下来我们将要学习如何创建内核对象,然后生成对应的文件和目录。
在创建之前,我们先要了解下和ConfigFs文件系统相关的几个核心数据结构。
ConfigFS的核心数据结构主要包括以下几个部分:
- :是一个顶层的数据结构,用于表示整个ConfigFS子系统。它包含了根配置项组的指针,以及ConfigFS的其他属性和状态信息。
- :是一种特殊类型的配置项,表示一个配置项组。它可以包含一组相关的配置项,形成一个层次结构。config_group结构包含了父配置项的指针,以及指向子配置项的链表。
- :这是ConfigFS中最基本的数据结构,用于表示一个配置项。每个配置项都是一个内核对象,可以是设备、驱动程序、子系统等。结构包含了配置项的类型、名称、属性、状态等信息,以及指向父配置项和子配置项的指针。
这些数据结构之间的关系可以形成一个树形结构,其中configfs_subsystem是根节点,config_group表示配置项组,config_item表示单个配置项。子配置项通过链表连接在一起,形成父子关系。如下表(图 75-1)所示:
75.2 子系统、容器和config_item
本小节我们来了解下子系统,容器,config_item的结构体。
configfs_subsystem结构体,如下所示:
struct configfs_subsystem {
struct config_group su_group;
struct mutex su_mutex;
};
configfs_subsystem结构体中包含config_group结构体,config_group结构体如下所示:
struct config_group {
struct config_item cg_item;
struct list_head cg_children;
struct configfs_subsystem *cg_subsys;
struct list_head default_groups;
struct list_head group_entry;
};
config_group结构体中包含config_item结构体,config_item结构体如下所示:
struct config_item {
char *ci_name;
char ci_namebuf[CONFIGFS_ITEM_NAME_LEN]; //目录的名字
struct kref ci_kref;
struct list_head ci_entry;
struct config_item *ci_parent;
struct config_group *ci_group;
const struct config_item_type *ci_type; //目录下属性文件和属性操作
struct dentry *ci_dentry;
};
接下来我们来分析设备树插件驱动代码,如下(图 75-2)所示:
图 75-2
这段代码定义了一个名为dtbocfg_root_subsys的configfs_subsystem结构体实例,表示ConfigFS中的一个子系统。
首先,dtbocfg_root_subsys.su_group是一个config_group结构体,它表示子系统的根配置项组。在这里,该结构体的.cg_item字段表示根配置项组的基本配置项。
- = "device-tree":配置项的名称设置为"device-tree",表示该配置项的名称为"device-tree"。
- = &dtbocfg_root_type:配置项的类型设置为dtbocfg_root_type,这是一个自定义的配置项类型。
接下来,.su_mutex字段是一个互斥锁,用于保护子系统的操作。在这里,使用了__MUTEX_INITIALIZER宏来初始化互斥锁。
通过这段代码,创建了一个名为"device-tree"的子系统,它的根配置项组为空。可以在该子系统下添加更多的配置项和配置项组,用于动态配置和管理设备树相关的内核对象。Linux系统下创建了device-tree这个子系统,如下图(图 75-3)所示:
图 75-3
接下来继续分析设备树插件驱动代码中注册配置项组的部分,如下图(图 75-4)所示:
图 75-4
这段代码是一个初始化函数dtbocfg_module_init(),用于初始化和注册ConfigFS子系统和配置项组。首先,通过config_group_init()函数初始化了dtbocfg_root_subsys.su_group,即子系统的根配置项组。接下来,使用config_group_init_type_name()函数初始化了dtbocfg_overlay_group,表示名为"overlays"的配置项组,并指定了配置项组的类型为dtbocfg_overlays_type,这是一个自定义的配置项类型。然后,调用configfs_register_subsystem()函数注册了dtbocfg_root_subsys子系统。如果注册失败,将打印错误信息,并跳转到register_subsystem_failed标签处进行错误处理。接着,调用configfs_register_group()函数注册了dtbocfg_overlay_group配置项组,并将其添加到dtbocfg_root_subsys.su_group下。如果注册失败,同样会打印错误信息,并跳转到register_group_failed标签处进行错误处理。最后,如果所有的注册过程都成功,将打印"OK"消息,并返回0,表示初始化成功。如果在注册配置项组失败时,会先调用configfs_unregister_subsystem()函数注销之前注册的子系统,然后返回注册失败的错误码retval。
这段代码的作用是初始化和注册一个名为"device-tree"的ConfigFS子系统,并在其下创建一个名为"overlays"的配置项组。Linux系统下,在device-tree子系统下创建了overlays容器,如下图(图 75-5)所示:
图 75-5
75.3 属性和方法
我们要在容器下放目录或属性文件,所以我们看一下config_item结构体,如下所示:
struct config_item {
char *ci_name;
char ci_namebuf[CONFIGFS_ITEM_NAME_LEN]; //目录的名字
struct kref ci_kref;
struct list_head ci_entry;
struct config_item *ci_parent;
struct config_group *ci_group;
const struct config_item_type *ci_type; //目录下属性文件和属性操作
struct dentry *ci_dentry;
};
config_item结构体中包含了 config_item_type结构体,config_item_type结构体如下所示:
struct config_item_type {
struct module *ct_owner;
struct configfs_item_operations *ct_item_ops; //item(目录)的操作方法
struct configfs_group_operations *ct_group_ops; //group(容器)的操作方法
struct configfs_attribute **ct_attrs; //属性文件的操作方法
struct configfs_bin_attribute **ct_bin_attrs; //bin属性文件的操作方法
};
- 结构体中包含了struct configfs_item_operations结构体,如下所示:
struct configfs_item_operations {
//删除item方法,在group下面使用rmdir命令会调用这个方法
void (*release)(struct config_item *);
int (*allow_link)(struct config_item *src, struct config_item *target);
void (*drop_link)(struct config_item *src, struct config_item *target);
};
- 结构体中包含了struct configfs_group_operations结构体,如下所示:
struct configfs_group_operations {
//创建item的方法,在group下面使用mkdir命令会调用这个方法
struct config_item *(*make_item)(struct config_group *group, const char *name);
//创建group的方法
struct config_group *(*make_group)(struct config_group *group, const char *name);
int (*commit_item)(struct config_item *item);
void (*disconnect_notify)(struct config_group *group, struct config_item *item);
void (*drop_item)(struct config_group *group, struct config_item *item);
};
- 结构体中包含了struct configfs_attribute结构体 ,如下所示:
struct configfs_attribute {
const char *ca_name; 属性文件的名字
struct module *ca_owner; 属性文件文件的所属模块
umode_t ca_mode; 属性文件访问权限
读写方法的函数指针,具体功能需要自行实现。
ssize_t (*show)(struct config_item *, char *);
ssize_t (*store)(struct config_item *, const char *, size_t); };
75.4 总结
在上面几个小节中,对ConfigFS的核心数据结构做出了详细的解释,本小节我们来总结一下。这些核心数据结构相互关联,通过在ConfigFS层级结构进行组织和管理,使得设备的配置和管理更加灵活和可定制。如下图(图 75-6)所示:
图 75-6
理解ConfigFS的核心数据结构对于深入使用和定制ConfigFS非常重要,可以帮助开发者更好地进行设备的配置和管理,提高系统的灵活性和可扩展性。如果大家还有不理解的地方,建议反复观看视频学习。