component示例程式碼及實現原理跟蹤(一)
阿新 • • 發佈:2021-02-11
概述
kernel中的component框架是為了subsystem能夠按照一定的順序初始化裝置而提出的架構。
在component中,包含兩個基本概念,master和component。master是裝置樹中的“超級裝置(superdevice)”,負責管理該超級裝置下的普通裝置。component是由master管理的普通裝置,要先初始化。
示例
平臺:rk3399
kernel版本:4.4
我們自己來編寫幾個驅動程式,來測試component機制。
dts
sub1: sub-test1 { compatible = "rk3399,sub1"; status = "okay"; }; sub2: sub-test2 { compatible = "rk3399,sub2"; status = "okay"; }; component-test { compatible = "rk3399,componenttest"; status = "okay"; ports = <&sub1>, <&sub2>; };
component_test1.c
#include <linux/kernel.h> #include <linux/module.h> #include <linux/platform_device.h> #include <linux/of.h> #include <linux/of_device.h> #include <linux/pm_runtime.h> #include <linux/component.h> static int sub1_bind(struct device *dev, struct device *master, void *data) { pr_info("zxh: 0910: sub1_bind @@@\n"); return 0; } static void sub1_unbind(struct device *dev, struct device *master, void *data) { pr_info("zxh: 0910: sub1_unbind @@@---\n"); } const struct component_ops sub1_component_ops = { .bind = sub1_bind, .unbind = sub1_unbind, }; static int testsub1_platform_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; pr_info("zxh: 0910: testsub 1 probe ...\n"); if (!dev->of_node) { dev_err(dev, "can't find vop devices\n"); return -ENODEV; } return component_add(dev, &sub1_component_ops); } static const struct of_device_id testsub1_dt_ids[] = { { .compatible = "rk3399,sub1", }, { /* sentinel */ }, }; MODULE_DEVICE_TABLE(of, testsub1_dt_ids); static struct platform_driver testsub1_platform_driver = { .probe = testsub1_platform_probe, .driver = { .name = "testsub1-drm", .of_match_table = testsub1_dt_ids, }, }; module_platform_driver(testsub1_platform_driver); MODULE_DESCRIPTION("ROCKCHIP component test1 Driver"); MODULE_LICENSE("GPL v2");
component_test2.c
#include <linux/kernel.h> #include <linux/module.h> #include <linux/platform_device.h> #include <linux/of.h> #include <linux/of_device.h> #include <linux/pm_runtime.h> #include <linux/component.h> static int sub2_bind(struct device *dev, struct device *master, void *data) { pr_info("zxh: 0910: sub2_bind @@@\n"); return 0; } static void sub2_unbind(struct device *dev, struct device *master, void *data) { pr_info("zxh: 0910: sub2_unbind @@@---\n"); } const struct component_ops sub2_component_ops = { .bind = sub2_bind, .unbind = sub2_unbind, }; static int testsub2_platform_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; pr_info("zxh: 0910: testsub 2 probe ...\n"); if (!dev->of_node) { dev_err(dev, "can't find vop devices\n"); return -ENODEV; } return component_add(dev, &sub2_component_ops); } static const struct of_device_id testsub2_dt_ids[] = { { .compatible = "rk3399,sub2", }, { /* sentinel */ }, }; MODULE_DEVICE_TABLE(of, testsub2_dt_ids); static struct platform_driver testsub2_platform_driver = { .probe = testsub2_platform_probe, .driver = { .name = "testsub2-drm", .of_match_table = testsub2_dt_ids, }, }; module_platform_driver(testsub2_platform_driver); MODULE_DESCRIPTION("ROCKCHIP component test2 Driver"); MODULE_LICENSE("GPL v2");
master_test.c
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/pm_runtime.h>
#include <linux/component.h>
#include <drm/drm.h>
#include <drm/drmP.h>
#include <drm/drm_atomic.h>
#include <drm/drm_crtc.h>
#include <drm/drm_crtc_helper.h>
#include <drm/drm_flip_work.h>
#include <drm/drm_plane_helper.h>
static int compare_of(struct device *dev, void *data)
{
struct device_node *np = data;
return dev->of_node == np;
}
static int rockchip_test_drm_bind(struct device *dev)
{
int ret;
pr_info("zxh: 0910: rockchip_drm_bind ---\n");
ret = component_bind_all(dev, "hello");
if (ret)
pr_info("component_bind_all error\n");
pr_info("zxh: 0910: rockchip_drm_bind ---end---\n");
return 0;
}
static void rockchip_test_drm_unbind(struct device *dev)
{
pr_info("zxh: 0910: rockchip_drm_unbind ~~~\n");
}
static const struct component_master_ops rockchip_test_drm_ops = {
.bind = rockchip_test_drm_bind,
.unbind = rockchip_test_drm_unbind,
};
static int testdrm_platform_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct component_match *match = NULL;
struct device_node *np = dev->of_node;
struct device_node *port;
int i;
pr_info("zxh: 0910: testdrm_platform_probe ...\n");
for (i = 0;; i++) {
port = of_parse_phandle(np, "ports", i);
if (!port)
break;
if (!of_device_is_available(port)) {
continue;
}
component_match_add(dev, &match, compare_of, port);
}
if (i == 0) {
dev_err(dev, "missing 'ports' property\n");
return -ENODEV;
}
if (!match) {
dev_err(dev, "No available vop found for component-subsystem.\n");
return -ENODEV;
}
return component_master_add_with_match(dev, &rockchip_test_drm_ops, match);
}
static const struct of_device_id testdrm_dt_ids[] = {
{ .compatible = "rk3399,componenttest", },
{ /* sentinel */ },
};
MODULE_DEVICE_TABLE(of, rockchip_drm_dt_ids);
static struct platform_driver testdrm_platform_driver = {
.probe = testdrm_platform_probe,
.driver = {
.name = "test-drm",
.of_match_table = testdrm_dt_ids,
},
};
module_platform_driver(testdrm_platform_driver);
MODULE_DESCRIPTION("ROCKCHIP master test Driver");
MODULE_LICENSE("GPL v2");
執行結果
由此可看出,需要先執行完component_test1.c和component_test2.c中的bind(),然後才會繼續執行master_test.c中的bind(),這樣就可以保證執行順序的。
下一篇
下篇文章介紹component的實現原理