参考文档:
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
1258

被折叠的 条评论
为什么被折叠?



