内核添加dts后,device和device_driver的match匹配的变动:通过compatible属性进行匹配

转载地址:

内核添加dts后,device和device_driver的match匹配的变动:

先看platform总线:

/driver/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);

/* Attempt an OF style match first */
if (of_driver_match_device(dev, drv))//通过这个OpenFirmware的匹配方式(of就是OpenFirmware的缩写)
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);

}


of_driver_match_device这个函数最终调用到__of_match_node()函数,在这个函数里,通过把device_driver的of_match_table(of_device_id结构体的数组)和device里的of_node(device_node结构体)进行匹配,匹配方式是分别比较两者的name、type、和compatible字符串,三者要同时相同(一般name、和type为空,只比较compatible字符串,比较compatible时,是比较整个字符串,不管字符串里的逗号的,直接compare整个字符串。所以,可以看出,对dts的OpenFirmware device的支持是从最根本的driver-model上支持的,在device和device_driver两者上都加了of_device的成员,也在bus_type的match函数里添加了of_device的匹配语句。所以driver-model的device、device_driver、bus_type都加了支持。

现在内核解析dtb文件,然后创建platform设备时,大部分platform设备是没有名字的,我还纠结那它们怎么和驱动match,原来bus_type的match函数添加了of_driver_match_device()这个匹配方式。他们大部分是通过compatible这个属性匹配成功的(这个compatible也对应dts里的compatible字符串)


再来看下其他总线的match函数,比如i2c的,也有of_device的匹配方式:

static int i2c_device_match(struct device *dev, struct device_driver *drv)
{
struct i2c_client*client = i2c_verify_client(dev);
struct i2c_driver*driver;

if (!client)
return 0;

/* Attempt an OF style match */
if (of_driver_match_device(dev, drv))
return 1;


/* Then ACPI style match */
if (acpi_driver_match_device(dev, drv))
return 1;

driver = to_i2c_driver(drv);
/* match on an id table if there is one */
if (driver->id_table)
return i2c_match_id(driver->id_table, client) != NULL;

return 0;
}

### 如何在平台架构下添加设备 在 Linux 平台架构中,`platform_device` 是一种用于表示无总线依赖硬件资源的通用方法。为了在平台上添加一个 `platform_device`,可以采用两种主要方式:静态注册动态注册。 #### 静态注册 当设备树(Device Tree, DTS)被引入到内核之后,推荐的方式是通过设备树来描述硬件资源并自动完成 `platform_device` 的注册。这种方式不需要手动调用 `platform_device_register()` 函数[^2]。 以下是实现此功能的关键步骤: 1. **定义设备节点**:在 `.dts` 文件中为特定硬件创建对应的设备节点。 ```c my_custom_device@0 { compatible = "my_company,custom-device"; reg = <0>; interrupts = <1 2>; /* 假设中断号 */ clocks = <&clk_ref>; /* 如果有时钟源 */ }; ``` 2. **编写驱动程序匹配规则**:确保驱动中的 `compatible` 字符串与设备树中的字符串一致。 ```c static const struct of_device_id custom_of_match[] = { { .compatible = "my_company,custom-device", }, { /* end of list */ } }; MODULE_DEVICE_TABLE(of, custom_of_match); static struct platform_driver custom_platform_driver = { .probe = custom_probe, .remove = custom_remove, .driver = { .name = "custom-platform-driver", .of_match_table = custom_of_match, }, }; module_platform_driver(custom_platform_driver); ``` #### 动态注册 如果无法使用设备树或者需要兼容旧版内核,则可以通过编程接口显式地向系统注册一个新的 `platform_device` 实例。尽管这种方法已不再推荐,但在某些特殊场景下仍然适用。 下面是一个简单的例子展示如何动态创建并注册 `platform_device`: ```c #include <linux/platform_device.h> static struct resource custom_resources[] = { [0] = DEFINE_RES_MEM(0x80000000, 0x100), // 资源地址范围 }; struct platform_device custom_pdev = { .name = "custom-platform-device", .id = -1, .num_resources = ARRAY_SIZE(custom_resources), .resource = custom_resources, .dev = { .platform_data = NULL, // 可选数据传递给驱动 }, }; // 注册函数 int __init register_my_device(void) { return platform_device_register(&custom_pdev); // 返回状态码检查省略 } module_init(register_my_device); void __exit unregister_my_device(void) { platform_device_unregister(&custom_pdev); } module_exit(unregister_my_device); ``` 需要注意的是,在现代开发实践中应优先考虑基于设备树的方法,因为这不仅简化了代码逻辑还增强了可移植性模块化设计能力。 对于那些希望扩展控制命令集的情况,由于 `platform_device` 自身并不支持文件操作结构体指针赋值,因此通常会借助字符型设备或杂项设备作为中介层来提供诸如 `ioctl()` 接口等功能[^1]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值