1 架构目的
基于4.1.15内核,kernel中的component框架是为了subsystem能够按照一定的顺序初始化设备而提出的架构。subsystem中由较多设备模块组成,而内核加载每个模块时间不定。因此需要component框架来保证需最后初始化的设备加载前,所需设备全部加载完毕。
2 架构简介
在component中,包含两个基本概念,master和component。master是设备树中的“超级设备(superdevice)”,负责管理该超级设备下的普通设备,用于挂在全局链表masters上。component是由master管理的普通设备,所有的component都会挂在全局链表component_list链表上。看下两个结构体的定义:
struct master {
struct list_head node; // 用于添加自身到masters链表中
bool bound; // 当所有component都执行完毕以后置true
const struct component_master_ops *ops;
struct device *dev;
struct component_match *match; // 旗下必需的component列表
struct dentry *dentry;
};
struct component {
struct list_head node;
struct master *master; // 决定挂在哪个master下
bool bound;
const struct component_ops *ops;
int subcomponent;
struct device *dev;
};
Component架构大致如下:
1.3 文件路径
/driver/base/component.c文件包含了主要逻辑。
1.4 qcom driver初始化
kmd主要由三个模块组成,分别是crm,cam sync以及子模块,umd层是控制kmd运转的大致框图如下。在provider初始化的时候会open video0,遍历所有的子设备节点,将所有子设备信息都放到CSL中,为之后的数据流转做好准备:
crm是qcom driver的核心,其注册为platform_driver后,会调用相应的probe方法:
static int cam_req_mgr_probe(struct platform_device *pdev) {
int rc = 0;
struct component_match *match_list = NULL;
struct device *dev = &pdev->dev;
rc = camera_component_match_add_drivers(dev, &match_list);
if (rc) {
CAM_ERR(CAM_CRM,
"Unable to match components, probe failed rc: %d",
rc);
goto end;
}
/* Supply match_list to master for handing over control */
rc = component_master_add_with_match(dev,
&cam_req_mgr_component_master_ops, match_list);
if (rc) {
CAM_ERR(CAM_CRM,
"Unable to add master, probe failed rc: %d",
rc);
goto end;
}
end:
return rc;
}
这里会调用camera_component_match_add_drivers方法将crm需要的子设备信息都收集到一个match_list结构体中:
int camera_component_match_add_drivers(struct device *master_dev,
struct component_match **match_list) {
int i, rc = 0;
struct platform_device *pdev = NULL;
struct device *start_dev = NULL, *match_dev = NULL;
if (!master_dev || !match_list) {
CAM_ERR(CAM_UTIL, "Invalid parameters for component match add");
rc = -EINVAL;
goto end;
}
for (i = 0; i < ARRAY_SIZE(cam_component_drivers); i++) {
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 4, 0)
struct device_driver const *drv =
&cam_component_drivers[i]->driver;
const void *drv_ptr = (const void *)drv;
#else
struct device_driver *drv = &cam_component_drivers[i]->driver;
void *drv_ptr = (void *)drv;
#endif
start_dev = NULL;
while ((match_dev = bus_find_device(&platform_bus_type,
start_dev, drv_ptr, &camera_platform_compare_dev))) {
put_device(start_dev);
// 相当于是类型转换
pdev = to_platform_device(match_dev);
CAM_DBG(CAM_UTIL, "Adding matched component:%s", pdev->name);
component_match_add(master_dev, match_list,
camera_component_compare_dev, match_dev);
start_dev = match_dev;
}
put_device(start_dev);
}
end:
return rc;
}
这里会遍历拿到crm下所有的子驱动列表,并且调用bus_find_device在bus总线上找到每个driver对应的device设备,然后调用component_match_add函数将设备信息收集到match_list列表中,这里的match_list非常重要,后面就是用match_list中收集的信息来进行component和从属master的配对。
static struct platform_driver *const cam_component_drivers[] = {
/* BASE */
&cam_sync_driver,
&cam_smmu_driver,
&cam_cpas_driver,
&cam_cdm_intf_driver,
&cam_hw_cdm_driver,
#ifdef CONFIG_SPECTRA_TFE
&cam_csid_ppi100_driver,
&cam_tfe_driver,
&cam_tfe_csid_driver,
#endif
#ifdef CONFIG_SPECTRA_ISP
&cam_ife_csid_driver,
&cam_ife_csid_lite_driver,
&cam_vfe_driver,
&cam_sfe_driver,
&isp_driver,
#endif
#ifdef CONFIG_SPECTRA_SENSOR
&cam_res_mgr_driver,
&cci_driver,
&csiphy_driver,
&cam_actuator_platform_driver,
&cam_sensor_platform_driver,
&cam_eeprom_platform_driver,
&cam_ois_platform_driver,
&cam_tpg_driver,
#if IS_REACHABLE(CONFIG_LEDS_QPNP_FLASH_V2) || \
IS_REACHABLE(CONFIG_LEDS_QTI_FLASH)
&cam_flash_platform_driver,
#endif
#endif
#ifdef CONFIG_SPECTRA_ICP
&cam_a5_driver,
&cam_lx7_driver,
&cam_ipe_driver,
&cam_bps_driver,
&cam_icp_driver,
#endif
#ifdef CONFIG_SPECTRA_OPE
&cam_ope_driver,
&cam_ope_subdev_driver,
#endif
#ifdef CONFIG_SPECTRA_JPEG
&cam_jpeg_enc_driver,
&cam_jpeg_dma_driver,
&jpeg_driver,
#endif
#ifdef CONFIG_SPECTRA_CRE
&cam_cre_driver,
&cam_cre_subdev_driver,
#endif
#ifdef CONFIG_SPECTRA_FD
&cam_fd_hw_driver,
&cam_fd_driver,
#endif
#ifdef CONFIG_SPECTRA_LRME
&cam_lrme_hw_driver,
&cam_lrme_driver,
#endif
};
看下component_match_add具体实现:
void component_match_add(struct device dev, struct component_match **matchptr, int (compare)(struct device *, void *), void *compare_data) {
struct component_match *match = *matchptr;
if (IS_ERR(match))
return;
if (!match || match->num == match->alloc) {
size_t new_size = match ? match->alloc + 16 : 15;
match = component_match_realloc(dev, match, new_size);
*matchptr = match;
if (IS_ERR(match))
return;
}
// match.compare是一个链状数组,可以使用[]一样访问里面的成员
// 特别注意这里的compare_data,后面执行匹配的时候就是通过比较该变量来确定的
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++; // 每添加一个成员到match中,相应的num+1
}
// 顺便看下match-list是啥样的
struct component_match {
size_t alloc;
size_t num;
// 也就是每个component包含的信息,下面称之为entry
struct component_match_array *compare;
};
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;
};
(这里习惯将单个component_match.compare称为entry)
可以看出,上述camera_component_match_add_drivers方法就是将crm子设备对应的entry都放进match_list列表中,函数结束后,crm需要的match-list就被填充好(主要存放匹配信息)。
特别注意,这里的compare_data对应于match_dev,后面将component-list中的component和match-list的entry中的component配对时,就是通过比较该变量来确定的。
回头继续看下component_master_add_with_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的match-list,这里面有component的包装信息
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);
// 封装master,然后将master添加到component架构中的masters链表中
list_add(&master->node, &masters);
// 尝试初始化该master
ret = try_to_bring_up_master(master, NULL);
if (ret < 0)
free_master(master);
mutex_unlock(&component_mutex);
return ret < 0 ? ret : 0;
}
这里主要做以下几个动作:
1、调用component_match_realloc,裁剪match内存为实际占用的内存(分配的时候数组大小为16,实际可能用不到那么多,因此裁剪一下);
2、封装master结构体,并且添加到全局链表master上,也就是crm将自己作为master注册进Component框架的masters链表中;
3、调用try_to_bring_up_master尝试初始化该master,因为crm中的子设备还没有集齐,所以这里不会初始化成功。
注意:目前尚未对match-list中的entry的component指针赋值,只赋值了匹配信息(用于找component)。
现在,component架构中的master已经创建好了,接下来自然要创建相应的component。crm中有很多的子设备,以sensor为例子,看子设备是如何添加到component架构中的。
static int32_t cam_sensor_driver_platform_probe(
struct platform_device *pdev) {
int rc = 0;
CAM_DBG(CAM_SENSOR, "Adding Sensor component");
// cam_sensor_component_ops里装的就是该子设备初始化后执行的函数
rc = component_add(&pdev->dev, &cam_sensor_component_ops);
if (rc)
CAM_ERR(CAM_SENSOR, "failed to add component rc: %d", rc);
return rc;
}
static int __component_add(struct device *dev, const struct component_ops *ops,
int subcomponent) {
struct component *component;
int ret;
component = kzalloc(sizeof(*component), GFP_KERNEL);
if (!component)
return -ENOMEM;
// 这里暂时未确定master
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);
// 这里竟然朝着总链masters动手了
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;
}
这里sensor将自己作为component注册进Component框架的component_list链表中,然后调用try_to_bring_up_masters试图将该component对应的master进行初始化(也就是查看masters中是否也有该component对应的master)。注意,每个子设备在注册为component时,并没有确定components->master,那是如何找到相应的master呢,继续往下看:
static int try_to_bring_up_masters(struct component *component) {
struct master *m;
int ret = 0;
list_for_each_entry(m, &masters, node) {
if (!m->bound) {
ret = try_to_bring_up_master(m, component);
if (ret != 0)
break;
}
}
return ret;
}
上述会去遍历链表,其中m就是链表中的一个master成员,如果该master没有绑定过(即没有收齐所有的component,相应的master-bound=false),则接下来通过执行try_to_bring_up_master函数来查看该master是否和conponent匹配,注意传入的参数:
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;
}
// 说明函数find_components会填充component->master
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;
// 如果所有的component都收集好了,就会执行master对应的bind方法
ret = master->ops->bind(master->dev);
if (ret < 0) {
devres_release_group(master->dev, NULL);
if (ret != -EPROBE_DEFER)
dev_info(master->dev, "master bind failed: %d\n", ret);
return ret;
}
// 设置标记
master->bound = true;
return 1;
}
try_to_bring_up_master函数中传入的形参component只做判断使用,没有其他用途。find_components中会确定components->master。这里先通过find_components来查看该master下所有的component是否集齐:
static int find_components(struct master *master) {
struct component_match *match = master->match;
size_t i;
int ret = 0;
for (i = 0; i < match->num; i++) {
// 遍历match-list中的entry
struct component_match_array *mc = &match->compare[i];
struct component *c;
dev_dbg(master->dev, "Looking for component %zu\n", i);
// 不为空就跳过执行下一次循环,这里的目的是为空的entry找到相应的component
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;
// 上面创建的component在此确定master属性
c->master = master;
}
return ret;
}
static struct component *find_component(struct master *master,
struct component_match_array *mc) {
struct component *c;
list_for_each_entry(c, &component_list, node) {
// 遍历component-list,查看是否有和当前传入的master匹配的component
if (c->master && c->master != master)
continue;
// 如果master匹配,且相应的比较函数也匹配,就说明找到了component
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;
}
find_component函数的作用是查看component-list链表中是的component成员与match-list的entry中包含的component是否相匹配,也就是查看前面赋值的dev是否一致,若匹配则将component-list中的component返回;
find_components函数的作用是遍历某master中的match-list,查找entry中的component是否和component-list上的一个具体的component匹配,如果匹配,则将component-list中的component放到match-list相应entry中保存(也就是保存在match_list.compare[i]中)。
比如crm在收集子设备的时候,已经将sensor放进match-list中。接着sensor在probe的时候将自己添加进了component-list列表,然后尝试在masters中试图找到和自身匹配的component成员。
上述函数的大致过程如下:
如果某master的match_list中的每个entry都有相应的component_list中的component成员与之匹配(也就是find_components函数返回值为0),就表示该master已经收集完旗下所有的component,此时就要调用该master对应的bind函数。这里看下crm相应的bind函数:
static int cam_req_mgr_component_master_bind(struct device *dev) {
int rc = 0;
// first: create v4l2-device node
rc = cam_v4l2_device_setup(dev);
if (rc)
return rc;
// second: create media node
rc = cam_media_device_setup(dev);
if (rc)
goto media_setup_fail;
// third: create video0 node
rc = cam_video_device_setup();
if (rc)
goto video_setup_fail;
g_dev.open_cnt = 0;
g_dev.shutdown_state = false;
mutex_init(&g_dev.cam_lock);
spin_lock_init(&g_dev.cam_eventq_lock);
mutex_init(&g_dev.dev_lock);
rc = cam_req_mgr_util_init();
if (rc) {
CAM_ERR(CAM_CRM, "cam req mgr util init is failed");
goto req_mgr_util_fail;
}
rc = cam_req_mgr_core_device_init();
if (rc) {
CAM_ERR(CAM_CRM, "core device setup failed");
goto req_mgr_core_fail;
}
INIT_LIST_HEAD(&cam_req_mgr_ordered_sd_list);
// 激活所有子设备的bind方法
rc = component_bind_all(dev, NULL);
if (rc) {
CAM_ERR(CAM_CRM,
"Error in binding all components rc: %d, Camera initialization failed!", rc);
goto req_mgr_device_deinit;
}
这里会注册v4l2-device设备、video0节点、media节点等,然后调用component_bind_all激活所有子设备的bind方法。
component_bind_all函数实现如下:
int component_bind_all(struct device *master_dev, void *data) {
struct master *master;
struct component *c;
size_t i;
int ret = 0;
WARN_ON(!mutex_is_locked(&component_mutex));
master = __master_find(master_dev, NULL);
if (!master)
return -EINVAL;
/* Bind components in match order */
for (i = 0; i < master->match->num; i++)
if (!master->match->compare[i].duplicate) {
c = master->match->compare[i].component;
// 执行每个component对应的bind方法
ret = component_bind(c, master, data);
if (ret)
break;
}
}
return ret;
}
static int component_bind(struct component *component,
struct master * master,void *data){
int ret;
if (!devres_open_group(master->dev, NULL, GFP_KERNEL))
return -ENOMEM;
if (!devres_open_group(component->dev, component, GFP_KERNEL)) {
devres_release_group(master->dev, NULL);
return -ENOMEM;
}
dev_dbg(master->dev, "binding %s (ops %ps)\n",
dev_name(component->dev), component->ops);
// 执行该component的相应bind方法,crm在前面注册为master时会赋值该ops方法
ret = component->ops->bind(component->dev, master->dev, data);
return ret;
}
1.5 总结
1.控制中枢(如crm)在probe函数里先创建一个master->match_list链表,将其下所有子设备信息记录在此链表中,然后将自己注册成master放到masters链表中;
2.所有的子驱动在初始化的时候,都会通过component_add方法把自己加入到component_list链表中,然后调用try_to_bring_up_masters尝试初始化masters中某个未绑定的master,实际上是查找masters链表中是否有master处于bound状态,如果有的话,则尝试初始化该master(执行完bind方法的master,需要做上标记master->bound == true);
3.当master中所有的component都收集完毕以后,调用相应的bind函数,在该bind方法中做一些初始化动作,如解析设备树、创建节点等,并激活该master下所有component对应的bind方法。
注:上面是高通8550上的代码实现,8650上稍有改变,但是大体逻辑没变。