一,component概述
1.1 背景
linux内核中的驱动,需要有一定的加载顺序,用来解决驱动之间的依赖问题。虽然说linux内核有定传统的驱动优先级,用来定义驱动的先后顺序,但是不足以更加细分的加载。
有的驱动可以独立加载而不依赖于其他驱动,但是在一个比较庞大的驱动面前,细分驱动的加载就比较重要了,因为这些庞大的驱动,环环相扣,一环出了问题就影响整个驱动的顺利走完。
所以component架构构建功能系统就包括两方面的作用:
-
保证系统安装了所有的组件;
-
规定了系统各组件初始化的顺序;
1.2 介绍
component架构在linux内核中现在主要的应用是用来构建display-subsystem,一个显示子系统由显示控制器(vop)、接口控制器(mipi,lvds,hdmi等)、液晶背光,电源等多个独立的功能单元构成。而把这些功能单元构成一个系统,就需要这些功能单元间有一定的协同配合。
如在扫描设备树时,每一个设备节点依次被注册到系统中(一般将设备节点转换为platform_device,然后使用platform_device_register注册),而只有当所有显示子系统相关的设备节点都注册到系统中时,整个显示系统才能正常工作。
如果没有component架构的参与,在用platform_device_register函数注册每个设备节点时,其platform_driver驱动的probe函数中会执行了一系列的初始化工作,而此时系统相关的其它设备节点可能还没有注册到内核中,这样可能就会导致一些问题出现。
在component架构的参下,可以保证在显示子系统的所有功能单元都注册后,才按照一定顺序执行初始化操作。
二,component核心数据结构
component架构的实现位于drivers/base/component.c,其主要涉及到的数据结构有struct component、struct aggregate_device、struct component_match。
2.1 关系图
component架构上述结构可以用拼乐高积木的过程来理解:
-
一个一个形态各异的积木就用struct component来表示;
-
struct aggregate_device就是要拼接成的东西(系统)(例如想拼成一辆车或一个房子);
-
struct component_match就是你手里的图纸;
根据图纸,就可以在一个个积木(component)中,找出需要的积木,然后拼成一个想要的作品(aggregate_device)。
如果对应到display-subsystem中的话,:
-
struct component对应的就是显示子系统的各个功能单元,每个component都会和一个platform_device关联起来;
-
struct aggregate_device对应的就是显示子系统;
为了更加形象的表示struct component、struct aggregate_device、struct component_match 之间的关系,我们绘制了如下关系框图:
刚开始component会将自己注册进入系统,并尝试唤醒aggregate_device来统筹(component也不了解自己是不是最后一个注册的,所有有义务唤醒aggregate_device).
最后aggregate_device把自己注册进入系统,根据aggregate_device自己定义的匹配方法找到所有的component,调用component的bind调函数.
2.2 struct component
struct component用来表示系统组件,定义在drivers/base/component.c;
struct component {
struct list_head node;
struct aggregate_device *adev;
bool bound;
const struct component_ops *ops;
int subcomponent;
struct device *dev;
};
其中:
-
node: 链表节点,用于将当前节点添加到全局链表component_list,链表component_list保存了注册到系统中的所有component;
-
adev:用于保存与该组件匹配的aggregate_device;
-
bound:表示组件已经执行了bind操作,当操作集ops中的bind函数被执行,该标志位设置为true;
-
ops:组件可执行的初始化操作;
-
dev:组件所属的device;
2.2.1 全局链表component_list
全局链表component_list定义如下:
static LIST_HEAD(component_list);
2.2.2 struct component_ops
struct component_ops定义在include/linux/component.h,用于表示component可执行的初始化操作;
/**
* struct component_ops - callbacks for component drivers
*
* Components are registered with component_add() and unregistered with
* component_del().
*/
struct component_ops {
/**
* @bind:
*
* Called through component_bind_all() when the aggregate driver is
* ready to bind the overall driver.
*/
int (*bind)(struct device *comp, struct device *master,
void *master_data);
/**
* @unbind:
*
* Called through component_unbind_all() when the aggregate driver is
* ready to bind the overall driver, or when component_bind_all() fails
* part-ways through and needs to unbind some already bound components.
*/
void (*unbind)(struct device *comp, struct device *master,
void *master_data);
};
该结构体中包含两个回调函数:
-
bind:执行组件的绑定操作;当调用component_bind_all函数时,回调该函数;
-
unbind:执行组件的解绑操作;当调用component_unbind_all函数时,回调该函数;
2.3 struct aggregate_device
struct aggregate_device表示需要构建的系统,定义在drivers/base/component.c;
struct aggregate_device {
struct list_head node;
bool bound;
const struct component_master_ops *ops;
struct device *parent;
struct component_match *match;
};
其中:
-
node:链表节点,用于将当前节点添加到全局链表aggregate_devices,链表aggregate_devices保存了注册到系统中的所有aggregate_device;
-
bound:表示系统已经执行了bind操作,当操作集ops中的bind函数被执行,该标志位设置为true;
-
ops:aggregate_device可执行的初始化操作;
-
parent:aggregate_device所属的device;
-
match:该aggregate_device用到的component_match,aggregate_device应用该match在component_list链表中找到适配于自己的component组件,并将所有匹配的component保存到该结构体的中;
2.3.1 全局链表aggregate_devices
全局链表aggregate_devices定义如下:
static LIST_HEAD(aggregate_devices);
2.3.2 struct component_master_ops
struct component_master_ops定义在include/linux/component.h,用于表示aggregate_device可执行的初始化操作;
/**
* struct component_master_ops - callback for the aggregate driver
*
* Aggregate drivers are registered with component_master_add_wi