Linux 内核 component 框架背景
Linux 内核中驱动,某些驱动之间加载是要按照一定的顺序的;kernel 中的 component 框架是为了 subsystem 能够按照一定的初始化顺序初始化设备而提出的架构
subsystem 有较多的设备模块驱动组成,内核在加载这些驱动时间是不确定的,所以需要component 框架来保证加载顺序
component 架构一般用于DRM 显示驱动架构和ALSA音频驱动架构
struct component 框架 关键结构
struct master {
struct list_head node;
bool bound;
const struct component_master_ops *ops;
struct device *dev;
struct component_match *match;
struct dentry *dentry;
};
struct component {
struct list_head node;
struct master *master;
bool bound;
const struct component_ops *ops;
int subcomponent;
struct device *dev;
};
struct component_ops {
// component_bind_all
int (*bind)(struct device *comp, struct device *master,
void *master_data);
//component_unbind_all
void (*unbind)(struct device *comp, struct device *master,
void *master_data);
};
component 中的 master 被看成是一个统筹的角色,component 表示在这个复杂驱动中不可或缺的组件,每个component 都会和一个 platform_device 结构关联起来
刚开始component 会将自己注册进入系统,并尝试唤醒master 来统筹(component 也不了解自己是不是最后一个注册的,所有有义务唤醒master)
最后master 把自己注册进入系统,根据master 自己定义的对比方法找到所有的 component,调用component 的回调函数
component的注册
驱动都是以probe 的形式加载的,但是probe 函数没有特别明确加载顺序,做为 subsystem 的设备驱动,需要在probe 函数中将自己抽象为 component 设备注册进系统,等待master 来统筹各个component 的加载顺序
使用 component_add 和 component_del 函数注册和注销
注册和注销,是内核组织形式的一种,component 是以链表的形式去组织的,在系统启后就已经注册了两个链表头,用来组织master 和 component
static LIST_HEAD(component_list); //component list head
static LIST_HEAD(masters);//master list head
static int __component_add(struct device *dev, const struct component_ops *ops,
int subcomponent)
{
struct component *component;
int ret;
// alloc memory for component
component = kzalloc(sizeof(*component), GFP_KERNEL);
if (!component)
return -ENOMEM;
// 初始化 component, 并且为 component 绑定一个操作合集, 包含 bind 和 unbind 函数
component->ops = ops;
component->dev = dev;
component->subcomponent = subcomponent;
dev_dbg(dev, "adding component (ops %ps)\n", ops);
mutex_lock(&component_mutex);
// 将 component 加入 component_list 链表
list_add_tail(&component->node, &component_list);
//尝试唤醒master 来回调各个 component 的 bind
ret = try_to_bring_up_masters(component);
if (ret < 0) {
if (component->master)
remove_component(component->master, component);
list_del(&component->node);
kfree(component);
}
mutex_unlock(&component_mutex);
return ret < 0 ? ret : 0;
}
主要步骤:
- 为component 对象申请内存
- 初始化 component,并且为component 添加一个ops 操作合集,包含 bind 和 unbind 函数
- 将component 加入 component_list 链表
- 尝试唤醒master 去回调各个component 的 bind
struct component match 的创建
struct component_match_array {
void *data;
int (*compare)(struct device *, void *);
int (*compare_typed)(struct device *, int, void *);
void (*release)(struct device *, void *);
struct component *component;
bool duplicate;
};
struct component_match {
size_t alloc;
size_t num;
struct component_match_array *compare;
};
component_match 是一个用于匹配的对象,substem 的所有platform_device,注册成 component 组件,相关的component 都硬件保存在component_match 对象中,最后受到 master 对象的统筹
一个master 对应一个 component_match ,一个component_match 对应一组 component_match_array
使用 component_match_add_release 添加一个带release 函数的 component_match
void component_match_add_release(struct device *master,struct component_match **matchptr,
void (*release)(struct device *, void *), int (*compare)(struct device *, void *), void *compare_data)
static void __component_match_add(struct device *master,
struct component_match **matchptr,
void (*release)(struct device *, void *),
int (*compare)(struct device *, void *),
int (*compare_typed)(struct device *, int, void *),
void *compare_data)
{
struct component_match *match = *matchptr;
if (IS_ERR(match))
return;
// alloc memory for component match
if (!match) {
match = devres_alloc(devm_component_match_release,
sizeof(*match), GFP_KERNEL);
if (!match) {
*matchptr = ERR_PTR(-ENOMEM);
return;
}
devres_add(master, match);
*matchptr = match;
}
// alloc memory for component match
if (match->num == match->alloc) {
size_t new_size = match->alloc + 16;
int ret;
ret = component_match_realloc(master, match, new_size);
if (ret) {
*matchptr = ERR_PTR(ret);
return;
}
}
// 填充一个 component_match array, 包含 compare 函数 和 compare 数据
match->compare[match->num].compare = compare;
match->compare[match->num].compare_typed = compare_typed;
match->compare[match->num].release = release;
match->compare[match->num].data = compare_data;
match->compare[match->num].component = NULL;
match->num++;
}
- 如果传进来的component_match对象是NULL,创建一个新的 component_match 对象
- 如果一组component_match对象已经满了,或者空的,新增16个空位
- 填充一个component_match_array,里面包含了很重要的compare函数和compare 数据
注意此时的 component 指针设置为NULL,component_match_array 中的元素并没有绑定component
component_match_array 对应一个component,component_match 对象是关联的 component 对象的集合,等待master 对象统一触发
component_match_array 里的 component 对象还没有指定,但是指定了每个 component 的compare 函数,在master 注册的时候,遍历全局的 component 链表,调用 compare 函数,将符合的要求的component 对象加入component_match_array
master 对象的注册
master 作为一个统筹的角色,在所有的 component 被注册进入系统后,就可以将master 对象注册进入系统
通过 component_master_add_with_match 将master 注册进入系统
int component_master_add_with_match(struct device *dev, const struct component_master_ops *ops, struct component_match *match)
master 对象的定义:
struct master {
struct list_head node;
bool bound;
const struct component_master_ops *ops;
struct device *dev;
struct component_match *match;
struct dentry *dentry;
};
master 对应也对应于一个 platform_device,component_master_add_with_match 传入的参数是 master 对应的驱动设备,master 的 操作函数集合和 对应的component_match 对象
·int component_master_add_with_match(struct device *dev,
const struct component_master_ops *ops,
struct component_match *match)
{
struct master *master;
int ret;
/* Reallocate the match array for its true size */
ret = component_match_realloc(dev, match, match->num);
if (ret)
return ret;
master = kzalloc(sizeof(*master), GFP_KERNEL);
if (!master)
return -ENOMEM;
master->dev = dev;
master->ops = ops;
master->match = match;
component_master_debugfs_add(master);
/* Add to the list of available masters. */
mutex_lock(&component_mutex);
list_add(&master->node, &masters);
ret = try_to_bring_up_master(master, NULL);
if (ret < 0)
free_master(master);
mutex_unlock(&component_mutex);
return ret < 0 ? ret : 0;
}
- 将master 加入系统之前重新规划了component_match指向的数组,修改成为真实存在的数量
- 为master 对象申请空间,绑定master 操作,绑定 component_match
- 将master 对象加入全局的链表,最后尝试唤醒 master 对象
master 对象的唤醒
- master 注册的时候唤醒:
static int try_to_bring_up_master(struct master *master,
struct component *component)
{
int ret;
dev_dbg(master->dev, "trying to bring up master\n");
if (find_components(master)) {
dev_dbg(master->dev, "master has incomplete components\n");
return 0;
}
if (component && component->master != master) {
dev_dbg(master->dev, "master is not for this component (%s)\n",
dev_name(component->dev));
return 0;
}
if (!devres_open_group(master->dev, NULL, GFP_KERNEL))
return -ENOMEM;
/* Found all components */
ret = master->ops->bind(master->dev);
if (ret < 0) {
devres_release_group(master->dev, NULL);
dev_info(master->dev, "master bind failed: %d\n", ret);
return ret;
}
master->bound = true;
return 1;
}
其中关键的函数是find_components,find_components会遍历全局 component链表,如果已经和 master 绑定就跳过,如果发现一个孤立的component,就会调用component_match_array 中的 compare 函数来对比此component 是否满足要求,如果满足要求,就将当前的 component 和 component_match_array 的component 指针关联
static int find_components(struct master *master)
{
struct component_match *match = master->match;
size_t i;
int ret = 0;
/*
* Scan the array of match functions and attach
* any components which are found to this master.
*/
for (i = 0; i < match->num; i++) {
struct component_match_array *mc = &match->compare[i];
struct component *c;
dev_dbg(master->dev, "Looking for component %zu\n", i);
if (match->compare[i].component)
continue;
c = find_component(master, mc);
if (!c) {
ret = -ENXIO;
break;
}
dev_dbg(master->dev, "found component %s, duplicate %u\n", dev_name(c->dev), !!c->master);
/* Attach this component to the master */
match->compare[i].duplicate = !!c->master;
match->compare[i].component = c;
c->master = master;
}
return ret;
}
确保find_components 函数执行完成后,执行 master 对象中的 bind 函数,注意此时 component 对象只是经过compare函数加入了 component macth array,component 对象本身的 bind 函数并没有执行到
一般要在master 对象的bind 函数中,执行 component_bind_all 函数,执行component macth array 所有component 的 bind 函数
component 的 compare 函数
component 的compare 函数是 能否加入component macth array的关键,一般使用 component_match_add_release函数,注意其中最后一个参数 compare_data
void component_match_add_release(struct device *master,
struct component_match **matchptr,
void (*release)(struct device *, void *),
int (*compare)(struct device *, void *), void *compare_data)
{
__component_match_add(master, matchptr, release, compare, NULL,
compare_data);
}
最后 find_component 执行时将 component的 device 参数 和 compare_data作为参数,调用compare 函数
static struct component *find_component(struct master *master,
struct component_match_array *mc)
{
struct component *c;
list_for_each_entry(c, &component_list, node) {
if (c->master && c->master != master)
continue;
if (mc->compare && mc->compare(c->dev, mc->data))
return c;
if (mc->compare_typed &&
mc->compare_typed(c->dev, c->subcomponent, mc->data))
return c;
}
return NULL;
}
参考博客
https://blog.csdn.net/weixin_44551105/article/details/127315884