1 Linux为什么要引入Component框架?
为了让subsystem按照一定顺序初始化设备才提出来的。
subsystem中由很多设备模块,内核加载这些模块的时间不确定。子系统内有些模块是需要依赖其它模块先初始化才能进行自己初始化工作(例如v4l2 subdev和v4l2 video device),这时就要用到component框架。
例如v4l2 subdev和v4l2 video device中,谁依赖谁先创建?
v4l2 video device依赖V4l2 subdev,它要等subdev创建后再创建,同时将subdev绑定到v4l2 video device上。
1.1 高通camera kmd中component的使用
入口:camera_init是入口。
submodule_table[i].component[j].init()
对submodule table中定义的每个component做init。
相关定义:
static const struct camera_submodule_component camera_base[] = {
{&cam_req_mgr_init, &cam_req_mgr_exit},
{&cam_sync_init, &cam_sync_exit},
{&cam_smmu_init_module, &cam_smmu_exit_module},
{&cam_cpas_dev_init_module, &cam_cpas_dev_exit_module},
{&cam_cdm_intf_init_module, &cam_cdm_intf_exit_module},
{&cam_hw_cdm_init_module, &cam_hw_cdm_exit_module},
};
static const struct camera_submodule_component camera_isp[] = {
{&cam_ife_csid_init_module, &cam_ife_csid_exit_module},
{&cam_ife_csid_lite_init_module, &cam_ife_csid_lite_exit_module},
{&cam_vfe_init_module, &cam_vfe_exit_module},
{&cam_sfe_init_module, &cam_sfe_exit_module},
{&cam_isp_dev_init_module, &cam_isp_dev_exit_module},
};
...
static const struct camera_submodule submodule_table[] = {
{
.name = "Camera BASE",
.num_component = ARRAY_SIZE(camera_base),
.component = camera_base,
},
{
.name = "Camera TFE",
.num_component = ARRAY_SIZE(camera_tfe),
.component = camera_tfe,
},
{
.name = "Camera ISP",
.num_component = ARRAY_SIZE(camera_isp),
.component = camera_isp,
},
{
.name = "Camera SENSOR",
.num_component = ARRAY_SIZE(camera_sensor),
.component = camera_sensor
},
...
};
1.2 重要数据结构
-
master
表示要构建的系统struct master {
struct list_head node; //用于链接到全局masters中
bool bound; //标记当前master是否bind了
const struct component_master_ops *ops; //master设备的回调接口
struct device *dev;
struct component_match *match; //安装顺序保存了当前master的所有component匹配条件
}; -
Component
表示系统组件struct component {
struct list_head node;//用于链接到全局的component_list中
struct master *master;//保存本组件属于哪个master device
bool bound;//本component是否bind过
const struct component_ops *ops;//本component的回调接口
struct device *dev; //本组件属于哪个设备
}; -
component_match
用来匹配系统需要的组件,并规定了组件的初始化顺序struct component_match_array {
void *data;//比较数据
int (*compare)(struct device *, void *);//比较接口
void (*release)(struct device *, void *);
struct component *component;//当前比较匹配规则属于哪个component
bool duplicate;//标记是否做移除
};struct component_match {
size_t alloc;//分配了多少个比较条件对象component_match_array
size_t num;//保存了多少个component匹配条件
struct component_match_array *compare;//匹配条件数组地址
}; -
全局变量masters和component_list
保存整个linux系统中所有主设备的数据结构。
保存整个linux系统中所有添加到component框架里的component数据结构。static LIST_HEAD(component_list);
static LIST_HEAD(masters);
1.3 CRM和其他component如何联系起来?
在高通KMD框架中,CRM属于主设备(master设备),其他cam_sync、cam_smmu、cam_cap、cam_tfe、cam_sensor等属于组件component。
他们是通过配置cam_component_platform_drivers时联系起来。
static struct platform_driver *const cam_component_platform_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
...
}
1.4 camera kmd中component如何bind
camera_submodule_component 的camera base数组中,会依次执行cam_req_mgr_init和cam_sync_init以及其他component的init函数实现。
1.4.1 crm init
cam_req_mgr_init就是crm的init,也是master设备的init。
它主要做了什么?
- 向linux系统注册crm的platform_driver驱动
- cam_req_mgr_probe
crm的platform_driver驱动中定义了probe函数,当驱动名称和设备名称匹配时,调用驱动的probe函数。
这里cam_req_mgr_probe主要做了两件事:
1)遍历cam_component_platform_drivers按顺序添加到match_list
2)添加match_list到master设备,并遍历是否所有的component都添加完成。
如果所有的component都添加完成,尝试初始化master_device。
尝试初始化master_device通过调用try_to_bring_up_aggregate_device(adev,NULL),它主要做两件事,一是查看是不是所有component_match列表里的component都已经添加到全局链表component_list中,二是如果所有component_match列表里的component都ready,就调用master设备的bind接口进行初始化。master的bind会顺序执行各component的bind()。
(通过调用component_bind_all())
1.4.2 cam_sync init
它主要做了什么?
- 向linux系统注册cam_sync的platform_driver驱动
- cam_sync_probe
cam_sync_probe做了什么?
为cam_sync创建一个component,并添加到component框架。
它会调用component_add()进行添加,进一步调用try_to_bring_up_masters(component),
try_to_bring_up_masters会遍历全局链表master_devices中所有的master设备,尝试bringup每一个遍历出来的aggregate device。