component框架

Linux驱动component框架使用

目录

  • 1. component框架介绍
    • 1.1 component框架产生的原因
    • 1.2 component框架可以解决的问题
  • 2. component框架使用方法
    • 2.1 master component驱动
    • 2.2 slave component驱动
  • 3. 示例代码
    • 3.1 设备树配置
    • 3.2 master component驱动
    • 3.3 slave component驱动

1. component框架介绍

我认为要了解一个技术框架,最好的切入点是了解这个框架是为了解决什么问题而产生的。

1.1 component框架产生的原因

传统驱动加载方式中,依赖关系难以正确管理,因为不同的硬件模块之间可能存在复杂的依赖关系,导致驱动的加载顺序不确定。这可能导致一些驱动在其依赖的硬件还没有初始化的情况下被加载,从而引发系统错误。这里举一个两个驱动之间存在依赖关系并需要按顺序加载的例子:有一个设备,外接了很多I2C控制的smart PA,smart PA的具体配置都在codec驱动里执行。这样就需要smart PA驱动先probe上并初始化后,codec驱动才能进行PA的配置。若这个加载顺序出现了问题,可能会引发系统错误,导致crash并死机。

1.2 component框架可以解决的问题

简单的说component框架可以解决驱动之间的依赖关系和加载问题。component框架引入了component标识符和component关系的概念,使得内核可以更清晰地了解component之间的依赖关系。通过该机制,内核可以按需地加载和卸载component,确保正确的加载和卸载顺序;而不是强制性地依赖预定义的加载顺序。这有助于解决传统加载方式中可能出现的顺序依赖问题。

2. component框架使用方法

component框架的使用可以简单的理解为:开车出行(master),需要先点火(slave a),挂挡(slave b),踩油门(所有slave都完成后才有效)然后就能跑了。

核心思想为:先等所有的slave component都probe上后,master component再通过component_bind_all(…)函数回调所有slave component的bind方法。

  • 流程图:
    component框架_第1张图片

2.1 master component驱动

  • probe阶段
  1. 用component_match_add_release(…)函数添加slave component设备
  2. 用component_master_add_with_match(…)注册component
  • bind阶段
  1. 用component_bind_all(…)函数绑定master component的所有slave component
  2. component_bind_all(…)函数执行完后就可以调用任意会用到salve驱动的函数

2.2 slave component驱动

  • probe阶段
  1. component_add(…)函数注册一个slave component
  • bind阶段
  1. slave驱动初始化

3. 示例代码

假设master为平台驱动,slave为i2c驱动; component框架相关的api在#include 头文件

tips: 示例代码省去了错误检查,实际中需要加入错误检查。示例代码参照Linux5.15内核提供的api编写

3.1 设备树配置

master {
    ...
    slave_a = <&slave_component_a>;
    slave_b = <&slave_component_b>;
};

&i2c {
    slave_component_a:a@67 {
        ...
    };
    slave_component_b:b@01 {
        ...
    };
};

3.2 master component驱动

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

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

static void master_unbind(struct device *dev)
{
    component_unbind_all(dev, <需要传递给slave component的数据>);
}

static int master_bind(struct device *dev)
{
    /*3. 绑定master component的所有slave component*/
    component_bind_all(dev, <需要传递给slave component的数据>);
    /*4. master驱动一些需要用到slave驱动的操作都可以在这之后调用*/
}

static const struct component_master_ops master_comp_ops = {
	.bind   = master_bind,
	.unbind = master_unbind,
};

static int master_component_probe(struct platform_device *pdev)
{
    struct device_node *a_node, *b_node;
    struct component_match *match = NULL;
    ...
    /*1. 添加slave component设备*/
    a_node = of_parse_phandle(pdev->dev.np, "slave_a", 0);
    of_node_get(a_node);
    component_match_add_release(&pdev->dev, &match,
            master_release_of,
            master_compare_of,
            a_node
    );
    b_node = of_parse_phandle(pdev->dev.np, "slave_b", 0);
    of_node_get(b_node);
    component_match_add_release(&pdev->dev, &match,
            master_release_of,
            master_compare_of,
            b_node
    );
    ...
    /*2. 注册component*/
    return component_master_add_with_match(&pdev->dev,
					&master_comp_ops, match);
}

tips: 步骤2里的添加slave component还有别的方法,可以根据具体实现细节修改

3.3 slave component驱动

static void slave_unbind(struct device *comp, 
               struct device *master, void *master_data)
{
    ;
}

static int slave_bind(struct device *comp, 
               struct device *master, void *master_data)
{
    /*2. slave驱动初始化*/
    //comp为slave_component_probe()里component_add()第一个形参传入的struct device *
    //master为component_bind_all()里第一个形参传入的struct device *
    //master_data为component_bind_all()里第二个形参传入的void *,即master component传递给slave component的数据
}
static const struct component_ops slave_comp_ops = {
    .bind = slave_bind,
    .unbind = slave_unbind,
};
static int slave_component_probe(struct i2c_client *client)
{
    ...
    /*1. 注册一个slave component*/
    return component_add(&client->dev, &slave_comp_ops);
}

你可能感兴趣的:(Linux驱动笔记,linux,驱动开发)