一、设备树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
: 指向平台设备标识表的指针,用于驱动程序的设备匹配。
platform
驱动总线使用设备树中的设备节点来与驱动程序进行匹配。介绍 platform
驱动总线的三种常见的匹配方式。
- 基于
driver.name
属性的匹配方式:通过driver.name
和device.name
来进行对比匹配
- 基于
compatible
属性的匹配方式: 设备树中的设备节点通常会包含一个compatible
属性,用于描述设备的兼容性标识。platform
驱动总线通过比较设备节点的compatible
属性与驱动程序中定义的of_device_id
结构体数组中的兼容性标识,来进行匹配。具体示例可以参考前面提到的of_match_device()
函数的用法。 - 基于
platform_device_id
的匹配方式: 驱动程序可以定义一个platform_device_id
结构体数组,并通过MODULE_DEVICE_TABLE(platform, ...)
宏将其注册为可供内核使用的设备表。设备节点在与驱动程序匹配时,会通过比较设备节点的name
属性与驱动程序中定义的platform_device_id
结构体数组中的设备名称,来进行匹配。具体示例可以参考前面提到的platform_device_id
的用法。
platform
驱动总线的匹配方式是基于设备树的,因此要求设备树中正确地描述了设备的配置信息,包括设备节点的兼容性标识和其他属性。
具体的驱动可参考:
驱动——platform驱动总线三种匹配方式_platform匹配过程_犩未的博客-CSDN博客
三、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_table
是 platform_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);函数接受两个参数:
matches
:一个指向of_device_id
结构体数组的指针,包含了设备驱动程序所支持的设备兼容性标识。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
头文件中声明的。
标签:struct,driver,platform,device,驱动,id,设备
From: https://www.cnblogs.com/lethe1203/p/18095679