linux component组件架构分析

Linux component 组件系统架构分析

原创文章,转载请标明出处。

背景介绍

任何架构的提出都是有其现实应用背景的,都是为了解决一些现实问题。而component系统架构的提出就是出于这样一种现实需求:构建功能系统!

系统就是各种功能单元(组件)的有序结合。一个系统,只有集齐了它的所有组件才能正常工作。
可以打个比方:一辆车就是一个系统,它由各种组件–发动机,变速箱,中控台,车轮等构成。

一辆车,只装上发动机,或变速箱。是不能工作的,必须安装了所有的组件,才能开始发动。

而发动的过程,也是有顺序要求的,如先采离合,再挂当(变速箱初始化),再踩油门(发动机初始化),车轮再开始转动。(有序)

所以component架构构建功能系统就包括两方面的作用:

  1. 保证系统安装了所有的组件
  2. 规定了系统各组件初始化的顺序

component架构在linux内核中现在主要的应用是用来构建display-subsystem,一个显示子系统,由LCD控制器(vop),接口控制器(mipi,lvds,hdmi),液晶背光,电源等多个独立的功能单元构成。而把这些功能单元构成一个系统,就需要这些功能单元间有一定的协同配合。

如在扫描设备树时,每一个设备节点依次被注册到系统中(一般用platform_device_register)。而只有当所有显示子系统相关的设备节点都注册到系统中时,整个显示系统才能正常工作。

如果没有component架构的参与,在用platform_device_register函数注册每个设备节点时,在其驱动的probe函数中。就已经执行了一系列的初始化工作,而此时系统相关的其他设备节点可能还没有注册到内核中,这样可能就会导致一些问题出现。

在component架构的参下,可以保证在显示子系统的所有功能单元都注册后,才按照一定顺序执行初始化操作。

架构分析

component架构的实现位于drivers/base/componet.c
对系统组件架构有了概念上的理解后,分析架构就比较简单了。

数据结构

component系统组件架构涉及到如下几个数据结构:
struct component用来表示系统组件。
struct master表示需要构建的系统。
struct component_match用来匹配系统需要的组件。并规定了组件的初始化顺序。
component 架构上述结构可以用拼乐高积木的过程来理解:
一个一个形态各异的积木就用struct component来表示,而struct master就是
要拼接成的东西(系统)(例如想拼成一辆车,一只恐龙,或一个房子)。而struct component_match就是你手里的图纸。根据图纸,你就可以在一个个积木(component)中,找出需要的积木,然后拼成一个想要的作品(master)。
根据上面的理解我们在详细的看一下这些结构体中的内容就比较好理解了.

  1. component
struct component {
	struct list_head node;        
	struct list_head master_node;
	struct master *master;
	bool bound;
	const struct component_ops *ops;
	struct device *dev;
};

node:用于加入到component_list链表,该链表保存了注册到组件系统架构中的所有component
master_node:该组件如果最终被某个master选中,则通过此成员用于加入到该master的components链表中,便于后续该master来遍历其组件。
master: 组件所属的master
bound: 表示组件是否已经执行了bind操作
ops: 组件可执行的初始化操作。

  1. master
struct master {
	struct list_head node;
	struct list_head components;
	bool bound;
	const struct component_master_ops *ops;
	struct device *dev;
	struct component_match *match;
};

node:同compnent中node作用一样,用于向组件系统架构中注册master。
components:用于保存该系统(master)下的组件。
ops:master可执行的初始化和退出操作。
match:该master用到的compnent_match,master 应用该match在组件系统架构component_list链表中找到适配于自己的component组件。

3.component_match

我们之前说过组件系统的两方面作用,即保证系统安装了所有组件和保证组件的初始化顺序。compnent_match是实现这两个作用的核心数据结构! component_match中用compare结构体数组表示一个系统(master)中需要的所有组件。每个数组条目代表了一个需要安装的组件。而一个系统中所需的组件数量是不定的,所以采用了零长数组的方式,用于动态扩展组件数量。 而master又是如何通过compnent_match匹配到component的呢?答案就是通过每个compare[]数组元素中的fn函数,int (*fn)(struct device *, void *)函数指针指定了匹配的规则(方法)*data 中保存了fn用到的匹配数据。

struct component_match {
	size_t alloc;
	size_t num;
	struct {
		void *data;
		int (*fn)(struct device *, void *);
	} compare[0];
};

alloc:用于记录分配的compare数组大小。
num:用于记录系统实际需要的组件(compnents)数量。当num等于alloc时,会引发compare数组的空间扩展分配。

我们再回到最初的问题:

如何保证系统安装了所有组件?

答案即是通过component_match的compare数组。master只有在匹配到了compare数组中指定的所有组件后才会执行初始化函数component_master_ops->bind

而又是如何指定各个组件的执行顺序呢?

同样也是通过compare数组,compare数组元素的顺序即指定了加入master 的component链表的顺序,进而决定了component组件初始化的顺序。

4.component_master_ops master执行的操作。

struct component_master_ops {
	int (*add_components)(struct device *, struct master *);
	int (*bind)(struct device *);
	void (*unbind)(struct device *);
};

5.component_ops 组件可以执行的操作。

struct component_ops {
	int (*bind)(struct device *, struct device *, void *);
	void (*unbind)(struct device *, struct device *, void *);
};

组件系统工作流程

组件系统大致包括如下操作:

  1. 向组件系统注册component
    注册的component被保存到static LIST_HEAD(component_list);静态链表中。此操作通过int component_add(struct device *dev, const struct component_ops *ops)函数实现。每次向系统注册一个组件时,都会遍历系统的master链表,尝试把该组件绑定到合适的master中去。这个过程是通过master扫描其component_mach,并遍历系统component_list,找出符合mach匹配函数的组件进行绑定。
    当一个master找到了其所有的组件后会执行其初始化函数。
    ret = master->ops->bind(master->dev);

  2. 构建component_match
    component_match作为master查找component的地图,需要在master注册到系统前来构建。系统通过component_match_add函数逐一添加compare条目,用于匹配每一个comonent,这个过程也确定了后续每个component的初始化过程。

  3. 向组件系统注册master。
    注册的master被保存到组件系统架构的static LIST_HEAD(masters)静态链表中。一般通过component_master_add_with_match函数实现。此函数同时会遍历系统component_list链表,找出符合match的组件进行绑定。
    当一个master找到了其所有的组件后会执行其初始化函数。
    ret = master->ops->bind(master->dev);

  4. bind执行
    系统和系统组件初始化函数执行的时机是什么呢?
    无论是通过component_add函数向组件系统中注册component,还是通过component_master_add_with_match函数向系统中注册master时,当mastr安装了其所有的componet后都会执行master->ops->bind(master->dev);操作,在此操作中一般会执行component_bind_all函数,开始执行各组件的初始化:component->ops->bind

代码分析

/*
 * Add a component to be matched.
 *
 * The match array is first created or extended if necessary.
 */
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;

	/*当第一次分配match或mactch中compare数组已经满了时,进行match的空间分配*/
	if (!match || match->num == match->alloc) {
		size_t new_size = match ? match->alloc + 16 : 15;//如果是第一次分配compare数组size 为15,如果不是第一次分配,会用原来大小alloc+16

		match = component_match_realloc(dev, match, new_size);//new_size表示的是分配的compare数组的大小。

		*matchptr = match;

		if (IS_ERR(match))
			return;
	}

	/*下面初始化了一个compare数组元素,表示增加了一个组件的匹配项*/
	match->compare[match->num].fn = compare;
	match->compare[match->num].data = compare_data;
	match->num++;//可以看到num记录了match中增加的组件数。最终作为master需要的组件数。
}

static struct component_match *component_match_realloc(struct device *dev,
	struct component_match *match, size_t num)
{
	struct component_match *new;

	if (match && match->alloc == num)
		return match;
	
	/*分配component_match空间,num指定了compare结构体数组的大小*/
	new = devm_kmalloc(dev, component_match_size(num), GFP_KERNEL);
	if (!new)
		return ERR_PTR(-ENOMEM);
	
	if (match) {
		memcpy(new, match, component_match_size(min(match->num, num)));
		devm_kfree(dev, match);//扩展match时执行的是重新分配。释放了原来的空间。
	} else {
		new->num = 0;
	}
	
	new->alloc = num;//记录了分配的compare数组size
	
	return new;
}

/*向comonent架构系统中注册一个组件*/
int component_add(struct device *dev, const struct component_ops *ops)
{
	struct component *component;
	int ret;

	component = kzalloc(sizeof(*component), GFP_KERNEL);//分配component
	
	if (!component)
		return -ENOMEM;
	
	component->ops = ops;//对compnent进行初始化,指定了组件的操作函数
	component->dev = dev;
	
	dev_dbg(dev, "adding component (ops %ps)\n", ops);
	
	mutex_lock(&component_mutex);
	list_add_tail(&component->node, &component_list);//把组件加入链表component_list
	
	ret = try_to_bring_up_masters(component);//遍历注册的每个master,并尝试把compnent绑定之。
	if (ret < 0) {
		list_del(&component->node);
	
		kfree(component);
	}
	mutex_unlock(&component_mutex);
	
	return ret < 0 ? ret : 0;
}

int component_master_add_with_match(struct device *dev,
	const struct component_master_ops *ops,
	struct component_match *match)
{
	struct master *master;
	int ret;

	if (ops->add_components && match)
		return -EINVAL;
	
	if (match) {//根据compare数组的大小重新分配match空间
		/* Reallocate the match array for its true size */
		match = component_match_realloc(dev, match, match->num);
		if (IS_ERR(match))
			return PTR_ERR(match);
	}
	
	/*master初始化并注册*/
	master = kzalloc(sizeof(*master), GFP_KERNEL);
	if (!master)
		return -ENOMEM;
	
	master->dev = dev;
	master->ops = ops;
	master->match = match;
	INIT_LIST_HEAD(&master->components);
	
	/* 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) {
		/* Delete off the list if we weren't successful */
		list_del(&master->node);
		kfree(master);
	}
	mutex_unlock(&component_mutex);
	
	return ret < 0 ? ret : 0;
}

static int try_to_bring_up_masters(struct component *component)
{
	struct master *m;
	int ret = 0;

	list_for_each_entry(m, &masters, node) {
		ret = try_to_bring_up_master(m, component);
		if (ret != 0)
			break;
	}
	
	return ret;
}

/*
 * Try to bring up a master.  If component is NULL, we're interested in
 * this master, otherwise it's a component which must be present to try
 * and bring up the master.
 *
 * Returns 1 for successful bringup, 0 if not ready, or -ve errno.
 */
static int try_to_bring_up_master(struct master *master,
	struct component *component)
{
	int ret;

	if (master->bound)
		return 0;

	/*
	 * Search the list of components, looking for components that
	 * belong to this master, and attach them to the master.
	 */
	if (find_components(master)) {
		/* Failed to find all components */
		ret = 0;
		goto out;
	}

	if (component && component->master != master) {//如果component !=NULL,component必须属于master。才会执行后面的系统初始化。
		ret = 0;
		goto out;
	}

	if (!devres_open_group(master->dev, NULL, GFP_KERNEL)) {//设备模型中的设备资源管理相关操作,用于管理设备的资源组。这里不具体介绍。
		ret = -ENOMEM;
		goto out;
	}

	/* Found all components */
	ret = master->ops->bind(master->dev);//如果绑定了所有的组件,开始执行系统初始化。一般在此函数中会继续调用component_bind_all函数执行组件的初始化。
	if (ret < 0) {
		devres_release_group(master->dev, NULL);
		dev_info(master->dev, "master bind failed: %d\n", ret);
		goto out;
	}

	master->bound = true;//表示系统已经绑定了所有组件,并执行了初始化。
	return 1;

out:
	master_remove_components(master);

	return ret;
}

static int find_components(struct master *master)
{
	struct component_match *match = master->match;
	size_t i;
	int ret = 0;

	if (!match) {
		/*
		 * Search the list of components, looking for components that
		 * belong to this master, and attach them to the master.
		 */
		return master->ops->add_components(master->dev, master);
	}
	
	/*
	 * Scan the array of match functions and attach
	 * any components which are found to this master.
	 */
	for (i = 0; i < match->num; i++) {//遍历了component_match中的compare数组。对比每一个数组项,绑定component到master
		ret = component_master_add_child(master,
						 match->compare[i].fn,
						 match->compare[i].data);
		if (ret)
			break;
	}
	return ret;
}
  • 8
    点赞
  • 39
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值