后期补充说明:
2025-03-20 19:55:13 :关于 Platform总线不错的视频总结回顾讲解,请百度网盘搜索“1-3_03_SPI总线设备驱动”,然后从头开始看。
Platform总线设备驱动的匹配规则
首先在 include\linux\device.h中定义了下面这个与Platform总线 (Platform Bus)相关的结构体:
struct bus_type {
const char *name;
const char *dev_name;
struct device *dev_root;
struct device_attribute *dev_attrs; /* use dev_groups instead */
const struct attribute_group **bus_groups;
const struct attribute_group **dev_groups;
const struct attribute_group **drv_groups;
int (*match)(struct device *dev, struct device_driver *drv);
int (*uevent)(struct device *dev, struct kobj_uevent_env *env);
int (*probe)(struct device *dev);
int (*remove)(struct device *dev);
void (*shutdown)(struct device *dev);
int (*online)(struct device *dev);
int (*offline)(struct device *dev);
int (*suspend)(struct device *dev, pm_message_t state);
int (*resume)(struct device *dev);
const struct dev_pm_ops *pm;
const struct iommu_ops *iommu_ops;
struct subsys_private *p;
struct lock_class_key lock_key;
};
其中的成员struct subsys_private *p;里存储着通过platform_device_register()注册进Platform总线的设备列表和通过 platform_driver_register() 注册进Platform总线的驱动列表。
在drivers\base\base.h中定义了结构体subsys_privat,如下:
struct subsys_private {
struct kset subsys;
struct kset *devices_kset;
struct list_head interfaces;
struct mutex mutex;
struct kset *drivers_kset;
struct klist klist_devices;
struct klist klist_drivers;
struct blocking_notifier_head bus_notifier;
unsigned int drivers_autoprobe:1;
struct bus_type *bus;
struct kset glue_dirs;
struct class *class;
};
其成员struct kset *devices_kset;里便存储着所有注册进Platform总线的设备资源描述结构体(platform_device),成员struct kset *drivers_kset;里便存储着所有注册进Platform总线的驱动结构体(platform_driver)。
struct bus_type中的成员match就是对设备资源描述结构体(platform_device)和驱动结构体(platform_driver)进行区配的函数,当有设备资源描述结构体(platform_device)注册进Platform总线或者有驱动结构体(platform_driver)注册进总线时,Platform总线设备驱动便会调用match函数去匹配设备资源描述结构体(platform_device)和驱动结构体(platform_driver)。
具体来说Platform总线设备驱动的区配规则如下:
当一个设备资源描述结构体 (platform_device) 被注册到 Platform 总线时,Platform 总线会将该设备与已经注册到总线的驱动结构体 (platform_driver) 列表进行匹配,尝试找到合适的驱动以绑定该设备。匹配的具体规则是由 platform_driver 的 driver 字段中定义的 of_match_table 或者 name 来决定的。如果匹配成功,会调用驱动的 probe 函数以初始化设备。
反过来,当一个驱动结构体 (platform_driver) 被注册到 Platform 总线时,Platform 总线会将该驱动与已经注册到总线的设备资源描述结构体 (platform_device) 列表进行匹配,尝试找到合适的设备以绑定该驱动。匹配的具体规则同样由驱动的 of_match_table 或者 name 决定。如果匹配成功,会调用驱动的 probe 函数。
匹配规则的核心逻辑由总线的 match 函数实现,match 函数是总线实现设备与驱动匹配的核心。对于 Platform 总线来说,它定义了如何根据设备和驱动的信息判断两者是否匹配。
所以下面我们来仔细看看 match 函数。
在 drivers\base\platform.c中初始化了struct bus_type的一个实例:
struct bus_type platform_bus_type = {
.name = "platform",
.dev_groups = platform_dev_groups,
.match = platform_match,
.uevent = platform_uevent,
.pm = &platform_dev_pm_ops,
};
成员函数platform_match()就是具体的匹配函数,我们可以通过分析它来看它是如何实现匹配的。
通过分析函数platform_match()得出具体的匹配规则
相关代码
函数platform_match()的定义
函数platform_match()的位置在:drivers\base\platform.c,其代码如下:
static int platform_match(struct device *dev, struct device_driver *drv)
{
struct platform_device *pdev = to_platform_device(dev);
struct platform_driver *pdrv = to_platform_driver(drv);
/* When driver_override is set, only bind to the matching driver */
if (pdev->driver_override)
return !strcmp(pdev->driver_override, drv->name);
/* Attempt an OF style match first */
if (of_driver_match_device(dev, drv))
return 1;
/* Then try ACPI style match */
if (acpi_driver_match_device(dev, drv))
return 1;
/* Then try to match against the id table */
if (pdrv->id_table)
return platform_match_id(pdrv->id_table, pdev) != NULL;
/* fall-back to driver name match */
return (strcmp(pdev->name, drv->name) == 0);
}
参数中的结构体struct device *dev的定义
函数platform_match()中的参数中涉及到的结构体struct device的定义【位置:include\linux\device.h】
struct device {
struct device *parent;
struct device_private *p;
struct kobject kobj;
const char *init_name; /* initial name of the device */
const struct device_type *type;
struct mutex mutex; /* mutex to synchronize calls to
* its driver.
*/
struct bus_type *bus; /* type of bus device is on */
struct device_driver *driver; /* which driver has allocated this
device */
void *platform_data; /* Platform specific data, device
core doesn't touch it */
void *driver_data; /* Driver data, set and get with
dev_set/get_drvdata */
struct dev_links_info links;
struct dev_pm_info power;
struct dev_pm_domain *pm_domain;
#ifdef CONFIG_GENERIC_MSI_IRQ_DOMAIN
struct irq_domain *msi_domain;
#endif
#ifdef CONFIG_PINCTRL
struct dev_pin_info *pins;
#endif
#ifdef CONFIG_GENERIC_MSI_IRQ
struct list_head msi_list;
#endif
#ifdef CONFIG_NUMA
int numa_node; /* NUMA node this device is close to */
#endif
u64 *dma_mask; /* dma mask (if dma'able device) */
u64 coherent_dma_mask;/* Like dma_mask, but for
alloc_coherent mappings as
not all hardware supports
64 bit addresses for consistent
allocations such descriptors. */
unsigned long dma_pfn_offset;
struct device_dma_parameters *dma_parms;
struct list_head dma_pools; /* dma pools (if dma'ble) */
struct dma_coherent_mem *dma_mem; /* internal for coherent mem
override */
#ifdef CONFIG_DMA_CMA
struct cma *cma_area; /* contiguous memory area for dma
allocations */
#endif
/* arch specific additions */
struct dev_archdata archdata;
struct device_node *of_node; /* associated device tree node */
struct fwnode_handle *fwnode; /* firmware device node */
dev_t devt; /* dev_t, creates the sysfs "dev" */
u32 id; /* device instance */
spinlock_t devres_lock;
struct list_head devres_head;
struct klist_node knode_class;
struct class *class;
const struct attribute_group **groups; /* optional groups */
void (*release)(struct device *dev);
struct iommu_group *iommu_group;
struct iommu_fwspec *iommu_fwspec;
bool offline_disabled:1;
bool offline:1;
};
函数体中结构体struct platform_device *pdev的定义
函数platform_match()的函数体中结构体struct platform_device的定义如下【位置:include\linux\platform_device.h】:
struct platform_device {
const char *name;
int id;
bool id_auto;
struct device dev;
u32 num_resources;
struct resource *resource;
const struct platform_device_id *id_entry;
char *driver_override; /* Driver name to force a match */
/* MFD cell pointer */
struct mfd_cell *mfd_cell;
/* arch specific additions */
struct pdev_archdata archdata;
};
对这个结构体的详细介绍见博文 https://blog.youkuaiyun.com/wenhao_ir/article/details/145018442
参数中的结构体struct device_driver *drv的定义
函数platform_match()中的参数中涉及到的结构体device_driver的定义【位置:include\linux\device.h】
struct device_driver {
const char *name;
struct bus_type *bus;
struct module *owner;
const char *mod_name; /* used for built-in modules */
bool suppress_bind_attrs; /* disables bind/unbind via sysfs */
enum probe_type probe_type;
const struct of_device_id *of_match_table;
const struct acpi_device_id *acpi_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 platform_driver *pdrv的定义
函数platform_match()的函数体中结构体struct platform_driver的定义如下【位置:include\linux\platform_device.h】:
struct platform_driver {
int (*probe)(struct platform_device *);
int (*remove)(struct platform_device *);
void (*shutdown)(struct platform_device *);
int (*suspend)(struct platform_device *, pm_message_t state);
int (*resume)(struct platform_device *);
struct device_driver driver;
const struct platform_device_id *id_table;
bool prevent_deferred_probe;
};
dev和pdev和关系?drv和pdrv的关系?
从上面的结构体定义中我们可以看出:
dev其实是pdev所指向的主结构体的一个成员,可利用带参数宏定义to_platform_device()得到其所在的主结构体的指针pdev;
drv其实是pdrv所指向的主结构体的一个成员,可利用带参数宏定义to_platform_driver得到其所在的主结构体的指针pdrv;
相关代码如下:
struct platform_device *pdev = to_platform_device(dev);
struct platform_driver *pdrv = to_platform_driver(drv);
代码并不复杂,仔细分析下上面的代码,得出具体的匹配规则如下:
Linux 的 Platform 总线设备驱动采用了一种分层机制,按照优先级逐步尝试设备资源描述结构体(platform_device)与驱动结构体(platform_driver)的匹配,直到找到合适的驱动结构体(platform_driver)为止。以下是具体的匹配步骤和逻辑:
1. 匹配步骤
1.1 Driver Override
- 条件:设备资源描述结构体(platform_device)的
pdev->driver_override成员不为空。 - 逻辑:直接将
pdev->driver_override指定的驱动名称与驱动结构体(platform_driver)的drv->name进行比较。 - 说明:
- 这是最高优先级的匹配方式。
- 主要用于手动指定特定驱动与设备绑定,忽略其他匹配方式。
- 从匹配代码中我们可以看到,只要定义了
pdev->driver_override,那么不管匹配成功没有,都会产生返回值并离开这个函数,这一点要注意。
1.2 OF (Open Firmware) 匹配
- 条件:设备树(Device Tree, DT)中存在设备与驱动结构体(platform_driver)的绑定信息。
- 逻辑:调用
of_driver_match_device(dev, drv),通过设备树中的信息匹配设备和驱动结构体(platform_driver)。 - 说明:
- 如果驱动结构体(platform_driver)提供了 of_match_table,则优先通过设备树的 compatible 属性进行匹配。
1.3 ACPI (Advanced Configuration and Power Interface) 匹配
- 条件:设备的 ACPI 信息存在。
- 逻辑:调用
acpi_driver_match_device(dev, drv),通过设备的 ACPI 信息匹配驱动结构体(platform_driver)。 - 说明:
- 在 ACPI 规范支持的硬件平台上(如 x86),设备和驱动结构体(platform_driver)可以通过 ACPI 描述匹配。
1.4 ID Table 匹配
- 条件:驱动提供了 ID 表(
pdrv->id_table)。 - 逻辑:调用
platform_match_id(),通过设备的pdev->name在 ID 表中查找匹配项。 - 说明:
- 这是比较灵活的匹配方式,驱动可以列出一组支持的设备名。其代码如下:
static const struct platform_device_id *platform_match_id(
const struct platform_device_id *id,
struct platform_device *pdev)
{
while (id->name[0]) {
if (strcmp(pdev->name, id->name) == 0) {
pdev->id_entry = id;
return id;
}
id++;
}
return NULL;
}
1.5 Driver Name 匹配
- 条件:前面所有匹配方式都未成功。
- 逻辑:直接比较设备资源描述结构体(platform_device)的
pdev->name和驱动结构体(platform_driver)的drv->name。 - 说明:
- 这是最基础的匹配方式,也是最简单的方式,依赖于设备和驱动名称完全一致。
2. 匹配逻辑顺序的意义
2.1 灵活性与优先级
driver_override提供了最高优先级的匹配,允许用户动态控制设备和驱动的绑定。- OF 和 ACPI 匹配适合平台设备通过设备树或 ACPI 描述的硬件,能准确绑定特定设备。
- ID 表和名称匹配是通用方式,适用于没有设备树或 ACPI 的设备。
2.2 回退机制
- 匹配按照优先级逐层下降,确保设备尽可能找到匹配的驱动,即使缺少更具体的信息(如 OF 或 ACPI)。
3. 示例解析
假设我们有以下设备资源描述结构体(platform_device)和驱动结构体(platform_driver):
设备
struct platform_device my_device = {
.name = "my_platform_device",
.driver_override = "my_override_driver",
};
驱动
static const struct platform_device_id my_id_table[] = {
{ "my_platform_device", 0 },
{ },
};
struct platform_driver my_driver = {
.driver = {
.name = "my_platform_device",
},
.id_table = my_id_table,
};
匹配过程
-
Driver Override:
- 设备资源描述结构体(platform_device)的
driver_override被设置为"my_override_driver"。 - 如果驱动结构体(platform_driver)的
drv->name的值为my_override_driver,将直接匹配,不考虑其他逻辑。 - 如果没有此驱动,则继续下一步。
- 设备资源描述结构体(platform_device)的
-
OF 匹配:
- 如果设备树中存在设备的
compatible属性且与驱动结构体(platform_driver)匹配,则直接绑定。
- 如果设备树中存在设备的
-
ACPI 匹配:
- 如果设备的 ACPI 描述中匹配当前驱动结构体(platform_driver),则绑定。
-
ID Table 匹配:
- 检查驱动结构体(platform_driver)的
id_table中是否包含设备资源描述结构体(platform_device)的name。 - 在本例中,
"my_platform_device"在my_id_table中,因此匹配成功。
- 检查驱动结构体(platform_driver)的
-
Driver Name 匹配:
- 如果以上所有方式均失败,则检查设备资源描述结构体(platform_device)
name是否等于驱动结构体(platform_driver)的drv->name。 - 在本例中,两者均为
"my_platform_device",所以也会匹配成功。
- 如果以上所有方式均失败,则检查设备资源描述结构体(platform_device)
4. 总结
Platform 总线设备驱动的匹配机制是多层次的,包括:
- Driver Override:最高优先级,允许用户手动绑定。
- 设备树 (OF) 匹配:适合嵌入式设备和 ARM 平台。
- ACPI 匹配:适合 x86 平台。
- ID 表匹配:灵活支持多个设备。
- 名称匹配:最基础的方式,作为最后的兜底。
这种机制保证了设备和驱动的灵活性和兼容性,能够适应不同的平台和硬件环境。
一个具体的由设备树节点生成的结构体platform_device和驱动结构体platform_driver匹配的例子
详情见我的另一篇博文:
https://blog.youkuaiyun.com/wenhao_ir/article/details/145056170

1667

被折叠的 条评论
为什么被折叠?



