Linux Kernel内核component子系统架构

参考文档:
https://docs.kernel.org/driver-api/component.html

component框架用来处理内核模块加载/卸载顺序,保证最后加载的模块在需要先加载的模块都加载后加载。

总结:

总结:master主设备链表里关联的match匹配条件data与component从设备链表里的device进行匹配的过程。
回调master的bind()->component_bind_all()->回调component的bind()

主从链表法+匹配条件数组:
(masters链表+匹配条件数组) + component_list链表:
匹配条件数组:匹配条件组成的数组
匹配条件:匹配条件结构体struct包含,匹配函数如(*compare)(...)和component指针(指向满足匹配条件的component组件)。
1,先构造匹配条件数组,填充匹配函数如(*compare)(...),这时匹配条件里的component指针为NULL。
2,master主设备注册到masters链表,并关联上匹配条件数组,master主设备遍历一遍component_list链表和匹配条件数组,来找到满足匹配条件的从设备component,把其填充到匹配条件里的component指针上。
3,当component从设备注册到component_list链表,遍历一遍masters链表,每个master主设备遍历一遍component_list链表和匹配条件数组,来找到满足匹配条件的从设备component,把其填充到匹配条件里的component指针上。
4,当匹配条件数组里每个匹配条件的component指针都填充好后,回调master的bind()
回调函数,在该回调函数里面在调用componend_bind_all(),component_bind_all()按照匹配条件数组顺序调用component指针指向的从设备的bind()回调函数。
这样就实现了按照匹配条件数组顺序加载从设备了。

设备链表和设备的驱动链表是相互遍历找到设备对应的驱动的。

linux内核component子系统架构分析资源连接:
https://download.youkuaiyun.com/download/luoqingyan/92170361?spm=1001.2014.3001.5503
https://download.youkuaiyun.com/download/luoqingyan/92170365?spm=1001.2014.3001.5503
lqy-linux-kernel-component-subsystem.odg 可用LibreOffice打开编辑

举例分析高通audio的wcd938x codec:
在这里插入图片描述
在这里插入图片描述


设备树:
// 使用component框架来实现:多个component先后加载顺序
	wcd938x_codec: wcd938x-codec {  //  主设备
		compatible = "qcom,wcd938x-codec";
              ...
		qcom,rx-slave = <&wcd938x_rx_slave>;   // 从设备
		qcom,tx-slave = <&wcd938x_tx_slave>;   //  从设备
       }

			wcd938x_rx_slave: wcd938x-rx-slave {
				compatible = "qcom,wcd938x-slave";
				reg = <0x0D 0x01170224>;
			};

			wcd938x_tx_slave: wcd938x-tx-slave {
				compatible = "qcom,wcd938x-slave";
				reg = <0x0D 0x01170223>;
			};

1,linux内核component子系统的master主设备驱动框架:


linux内核component子系统的master主设备驱动框架:

static int wcd938x_add_slave_components(struct device *dev,
				struct component_match **matchptr)
{
	struct device_node *np, *rx_node, *tx_node;

	np = dev->of_node;

	rx_node = of_parse_phandle(np, "qcom,rx-slave", 0);

	of_node_get(rx_node);
	component_match_add_release(dev, matchptr,
			wcd938x_release_of,
			wcd938x_compare_of,
			rx_node);

	tx_node = of_parse_phandle(np, "qcom,tx-slave", 0);

	of_node_get(tx_node);
	component_match_add_release(dev, matchptr,
			wcd938x_release_of,
			wcd938x_compare_of,
			tx_node);
	return 0;
}

static int wcd938x_probe(struct platform_device *pdev)
{
	struct component_match *match = NULL;

	ret = wcd938x_add_slave_components(dev, &match);

	return component_master_add_with_match(dev,
					&wcd938x_comp_ops, match);
       ...
}

static int wcd938x_bind(struct device *dev)
{
	ret = component_bind_all(dev, wcd938x);
}
static void wcd938x_unbind(struct device *dev)
{
	component_unbind_all(dev, wcd938x);
}

static const struct component_master_ops wcd938x_comp_ops = {
	.bind   = wcd938x_bind,
	.unbind = wcd938x_unbind,
};

static const struct of_device_id wcd938x_dt_match[] = {
	{ .compatible = "qcom,wcd938x-codec", .data = "wcd938x"},
	{}
};

static const struct component_master_ops wcd938x_comp_ops = {
	.bind   = wcd938x_bind,
	.unbind = wcd938x_unbind,
};

static int wcd938x_compare_of(struct device *dev, void *data)
{
	return dev->of_node == data;
}

static void wcd938x_release_of(struct device *dev, void *data)
{
	of_node_put(data);
}

static struct platform_driver wcd938x_codec_driver = {
	.probe = wcd938x_probe,
	.remove = wcd938x_remove,
	.driver = {
		.name = "wcd938x_codec",
		.owner = THIS_MODULE,
		.of_match_table = of_match_ptr(wcd938x_dt_match),
#ifdef CONFIG_PM_SLEEP
		.pm = &wcd938x_dev_pm_ops,
#endif
		.suppress_bind_attrs = true,
	},
};

module_platform_driver(wcd938x_codec_driver);
MODULE_DESCRIPTION("WCD938X Codec driver");
MODULE_LICENSE("GPL v2");

2,linux内核component子系统的slave从设备驱动框架:


linux内核component子系统的slave从设备驱动框架:

static int wcd938x_slave_bind(struct device *dev,
				struct device *master, void *data)
{
}

static const struct of_device_id wcd938x_swr_dt_match[] = {
	{
		.compatible = "qcom,wcd938x-slave",
	},
	{}
};

static const struct component_ops wcd938x_slave_comp_ops = {
	.bind   = wcd938x_slave_bind,
	.unbind = wcd938x_slave_unbind,
};

static int wcd938x_swr_probe(struct swr_device *pdev)
{
	return component_add(&pdev->dev, &wcd938x_slave_comp_ops);
}

static int wcd938x_swr_remove(struct swr_device *pdev)
{
	component_del(&pdev->dev, &wcd938x_slave_comp_ops);
}

static struct swr_driver wcd938x_slave_driver = {
	.driver = {
		.name = "wcd938x-slave",
		.owner = THIS_MODULE,
		.of_match_table = wcd938x_swr_dt_match,
	},
	.probe = wcd938x_swr_probe,
	.remove = wcd938x_swr_remove,
	.id_table = wcd938x_swr_id,
};
调试:
mount -t debugfs debugfs /sys/kernel/debug
cat /sys/kernel/debug/device_component/wcd938x-codec

kalama:/d/device_component # cd wcd938x-codec                                                                                 
/system/bin/sh: cd: /d/device_component/wcd938x-codec: Not a directory
2|kalama:/d/device_component # cat wcd938x-codec                                                                              
master name                                            status
-------------------------------------------------------------
wcd938x-codec                                           bound

device name                                            status
-------------------------------------------------------------
wcd938x-slave.d01170224                                 bound
wcd938x-slave.d01170223                                 bound
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值