1. 程式人生 > 其它 >component示例程式碼及實現原理跟蹤(一)

component示例程式碼及實現原理跟蹤(一)

技術標籤:componentlinux

概述

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的實現原理