component示例代码及实现原理跟踪(一)

概述

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的实现原理

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值