platform_driver驱动及设备驱动匹配标识符

一、设备树platform_driver示例

设备树中需要定义一个设备节点,包含设备的相关信息和属性。例如,假设有一个名为 "my_device" 的设备,其设备树节点可能如下所示:
/dts-v1/;
/ {
    compatible = "example,my_device";
    my_device {
        compatible = "example,my_device";
        reg = <0x12345678 0x1000>;
        interrupt-parent = <&gpio0>;
        interrupts = <10 IRQ_TYPE_LEVEL_HIGH>;
    };
};
在上述示例中,该设备节点具有 compatible 属性来标识设备的兼容性,reg 属性用于指定设备的地址范围,interrupt-parent 属性指定中断控制器的父节点,interrupts 属性指定设备的中断号和触发类型。
在驱动程序中定义 platform_driver 结构体,并使用 of_match_ptr() 宏将设备的兼容性标识与驱动程序关联起来。例如:
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/of_device.h>

static int my_driver_probe(struct platform_device *pdev)
{
    // 在这里执行设备的初始化和操作
    return 0;
}

static int my_driver_remove(struct platform_device *pdev)
{
    // 在这里执行设备的清理和操作
    return 0;
}

static const struct of_device_id my_driver_of_match[] = {
    { .compatible = "example,my_device" },
    {},
};
MODULE_DEVICE_TABLE(of, my_driver_of_match);

static struct platform_driver my_driver = {
    .driver = {
        .name = "my_device",
        .of_match_table = of_match_ptr(my_driver_of_match),
    },
    .probe = my_driver_probe,
    .remove = my_driver_remove,
};

module_platform_driver(my_driver);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("lethe1203");
 

二、platform驱动总线的匹配方式

首先看下platform_driver、device_driver和device_driver结构体的定义:
 
struct platform_driver 是Linux内核中用于表示平台驱动程序的结构体。它包含了与平台设备驱动相关的属性和操作,用于管理和控制平台设备。
下面是 struct platform_driver 结构体的定义:
struct platform_driver {
    int (*probe)(struct platform_device *pdev);
    int (*remove)(struct platform_device *pdev);
    void (*shutdown)(struct platform_device *pdev);
    int (*suspend)(struct platform_device *pdev, pm_message_t state);
    int (*resume)(struct platform_device *pdev);
    struct device_driver driver;                  // device_driver结构体**
    const struct platform_device_id *id_table;    // 匹配规则三
    bool prevent_deferred_probe;
};
struct platform_driver 结构体的主要字段如下:
  • probe: 当匹配到某个平台设备时,调用该函数进行设备的初始化。
  • remove: 在设备被移除时,调用该函数进行设备的清理和释放资源操作。
  • shutdown: 可选字段,在系统关机时调用该函数进行设备的关机处理。
  • suspend: 可选字段,在设备进入挂起状态时调用该函数进行设备的挂起操作。
  • resume: 可选字段,在设备从挂起状态恢复时调用该函数进行设备的恢复操作。
  • driver: 包含了和设备驱动相关的属性,如名称、owner等。
  • id_table: 可选字段,用于指定平台设备的标识表,用于驱动程序的设备匹配。
  • prevent_deferred_probe: 可选字段,用于控制是否延迟设备的探测。
 
struct device_driver 是 Linux 内核中用于表示设备驱动程序的结构体。它包含了与设备驱动相关的属性和操作,用于管理和控制特定类型的设备。
下面是 struct device_driver 结构体的定义:
struct device_driver {
    const char *name;        // 匹配规则一
    struct bus_type *bus;
    struct module *owner;
    const char *mod_name;
    bool suppress_bind_attrs;
    const struct of_device_id *of_match_table;    // 匹配规则二
    int (*probe)(struct device *dev);
    int (*remove)(struct device *dev);
    void (*shutdown)(struct device *dev);
    int (*suspend)(struct device *dev, pm_message_t state);
    int (*resume)(struct device *dev);
    const struct attribute_group **groups;
    const struct dev_pm_ops *pm;
    struct driver_private *p;
};
struct device_driver 结构体的主要字段如下:
  • name: 设备驱动程序的名称。
  • bus: 指向设备所属的总线类型的指针。
  • owner: 指向拥有该设备驱动程序的模块的指针。
  • mod_name: 拥有该设备驱动程序的模块的名称。
  • suppress_bind_attrs: 一个布尔值,用于控制是否在 sysfs 中暴露 bind/unbind 相关的属性。
  • of_match_table: 指向设备树匹配表的指针,用于匹配设备树节点。
  • probe: 当匹配到设备时,调用该函数来初始化设备。
  • remove: 在设备被移除时,调用该函数来清理和释放资源。
  • shutdown: 可选字段,在系统关机时调用该函数进行设备的关机处理。
  • suspend: 可选字段,在设备进入挂起状态时调用该函数进行设备的挂起操作。
  • resume: 可选字段,在设备从挂起状态恢复时调用该函数进行设备的恢复操作。
  • groups: 指向设备驱动程序所属的属性组数组的指针。
  • pm: 指向设备的电源管理操作的指针。
 
struct platform_device 是 Linux 内核中用于表示平台设备的结构体。它用于描述与特定平台相关的设备,例如 SoC 上的外设或其他与硬件集成的设备。
下面是 struct platform_device 结构体的定义:
struct platform_device {
    const char *name;        // 匹配方式一
    int id;
    struct device dev;
    u32 num_resources;
    struct resource *resource;
    const struct platform_device_id *id_entry;
};
struct platform_device 结构体的主要字段如下:
  • name: 设备的名称。该名称通常与设备驱动程序关联。
  • id: 设备的 ID。用于标识同一类型的多个设备。
  • dev: 表示该平台设备的通用设备结构体。它可以被设备模型用于管理设备对象。
  • num_resources: 设备资源的数量。
  • resource: 指向设备资源描述符的指针数组。每个资源描述符包含了设备在系统中所需的 I/O 地址、中断等信息。
  • id_entry: 指向平台设备标识表的指针,用于驱动程序的设备匹配。
 
在 Linux 内核中,platform 驱动总线使用设备树中的设备节点来与驱动程序进行匹配。介绍 platform 驱动总线的三种常见的匹配方式
  1. 基于driver.name属性的匹配方式:通过driver.namedevice.name来进行对比匹配
  1. 基于 compatible 属性的匹配方式: 设备树中的设备节点通常会包含一个 compatible 属性,用于描述设备的兼容性标识。platform 驱动总线通过比较设备节点的 compatible 属性与驱动程序中定义的 of_device_id 结构体数组中的兼容性标识,来进行匹配。具体示例可以参考前面提到的 of_match_device() 函数的用法。
  2. 基于 platform_device_id 的匹配方式: 驱动程序可以定义一个 platform_device_id 结构体数组,并通过 MODULE_DEVICE_TABLE(platform, ...) 宏将其注册为可供内核使用的设备表。设备节点在与驱动程序匹配时,会通过比较设备节点的 name 属性与驱动程序中定义的 platform_device_id 结构体数组中的设备名称,来进行匹配。具体示例可以参考前面提到的 platform_device_id 的用法。
需要注意的是,platform 驱动总线的匹配方式是基于设备树的,因此要求设备树中正确地描述了设备的配置信息,包括设备节点的兼容性标识和其他属性。
具体的驱动可参考:
 

三、of_match_ptr、of_match_device、platform_get_device_id

of_match_ptr

of_match_ptr() 是一个用于将 of_device_id 结构体数组传递给 of_match_table 字段的宏。它将 of_device_id 结构体数组的指针转换为 const struct of_device_id * 类型,以便在注册 platform_driver 时使用。
of_match_tableplatform_driver 结构体中的一个字段,用于指定设备树匹配表。通过传递 of_match_ptr() 宏转换后的指针,可以将设备树匹配表与驱动程序关联起来,实现设备树节点和驱动程序的匹配。
示例代码中的这行代码:
.driver = {
    .name = "my_device",
    .of_match_table = of_match_ptr(my_driver_of_match),
},
使用了 of_match_ptr() 宏将 my_driver_of_match 数组的指针传递给了 of_match_table 字段。这样,当 platform_driver 注册到内核时,内核就能根据设备树节点的兼容性标识进行匹配,并调用相应的回调函数。
 

of_match_device

of_match_device() 函数用于在设备树中查找与给定设备匹配的设备兼容性标识(compatible)。
以下是 of_match_device() 函数的原型:
const struct of_device_id *of_match_device(const struct of_device_id *matches, const struct device *dev);
函数接受两个参数:
  1. matches:一个指向 of_device_id 结构体数组的指针,包含了设备驱动程序所支持的设备兼容性标识。
  2. dev:一个指向 struct device 的指针,表示当前需要匹配的设备。
函数返回一个指向匹配的 of_device_id 结构体的指针。如果找不到匹配项,则返回 NULL
以下是一个示例用法:
static const struct of_device_id my_driver_dt_ids[] = {
    { .compatible = "device1" },
    { .compatible = "device2" },
    // 其他设备兼容性标识
};

static int my_driver_probe(struct platform_device *pdev)
{
    const struct of_device_id *id;

    id = of_match_device(my_driver_dt_ids, &pdev->dev);
    if (!id)
        return -ENODEV;

    if (strcmp(id->compatible, "device1") == 0) {
        // 匹配到 device1 的处理逻辑
    } else if (strcmp(id->compatible, "device2") == 0) {
        // 匹配到 device2 的处理逻辑
    }

    return 0;
}
在上述示例中,my_driver_dt_ids 是一个包含设备兼容性标识的数组。在驱动程序的 probe 函数中,使用 of_match_device() 函数来获取与平台设备匹配的设备兼容性标识,并通过相应的操作来处理匹配到的设备。
 

platform_get_device_id

platform_get_device_id() 是一个函数,用于获取与给定平台设备匹配的平台设备标识。
函数原型如下:
const struct platform_device_id *platform_get_device_id(const struct platform_device *pdev);
参数 pdev 是一个指向 struct platform_device 的指针,表示要查询的平台设备。
函数返回值是一个指向 struct platform_device_id 的指针,表示与给定平台设备匹配的平台设备标识。如果找不到匹配的标识,则返回 NULL
struct platform_device_id 结构体定义如下:
struct platform_device_id {
    char name[PLATFORM_NAME_SIZE]; // 设备名称
    kernel_ulong_t driver_data;     // 驱动程序数据
};
platform_get_device_id() 函数通过遍历平台设备驱动程序注册的平台设备标识表(struct platform_device_id 数组),与给定的平台设备的名称进行匹配。如果找到匹配的标识,则返回该标识的指针;否则返回 NULL
通常,在编写平台设备驱动程序时,会在驱动程序中定义一个平台设备标识表,并将其注册到内核中。当平台设备被创建时,驱动程序会根据设备的名称和其他属性,匹配对应的标识,并执行相应的初始化操作。
注意:platform_get_device_id() 函数是在 include/linux/platform_device.h 头文件中声明的。
 
 
 
 
 
 
 
posted @ 2024-03-25 23:37  lethe1203  阅读(141)  评论(0编辑  收藏  举报