神奇的platform_get_resource函数

本文解析了Linux平台驱动中如何通过platform_get_resource直接获取I/O内存资源,并介绍了如何确保驱动与platform_device匹配。文章详细解释了通过声明platform_device资源数组并利用machine_desc结构体中的init_machine接口进行注册的过程。
阅读platformdriver的代码时,发现在probe函数直接调用platform_get_resource从pdev中获取io内存,但却没有判断传给probe的pdev是否属于这个驱动 !

后来发现原来在arch目录下的对应目录里面有个devs.c文件(这个文件可能因不同的架构而不一样),这个文件里面声明了一个platform设备的资源数组foo_devices,原型如下:

static struct platform_device* foo_devices[] __initdata;

这个数组里面包含了所有platform设备的资源信息。例如:一个设备的资源声明如下:

static struct resource foo_resource[] =
{
[0] =
{
.start = (FOO_BASE_PA),
.end = (FOO_BASE_PA) + (0x0008000),
.flags = IORESOURCE_MEM,
},
[1] =
{
.start = (IRQ_FOO),
.end = (IRQ_FOO),
.flags = IORESOURCE_IRQ,
},
};

static struct platform_device device_foo =
{
.name = "device_foo",
.id = 0,
.resource = foo_resource,
.num_resources = ARRAY_SIZE(foo_resource),
.dev =
{
//根据源代码,这两个成员置成0表示不起作用
.dma_mask = 0x0,
.coherent_dma_mask = 0x0,
},
};

那么将这个device_foo加入foo_devices数组,就能直接在probe函数中用platform_get_resource获取资源了,但是要注意驱动的name成员必须和platform_device结构中的name成员完全相同。

那为什么加入foo_devices数组后就能直接访问了呢?
在 相关体系的machine_desc结构体中(对于每个特定平台都有一个MACHINE_START宏用来定义machine_desc结构体),有一个 接口init_machine,这个接口中会调用platform_add_devices添加foo_devices。例如:

platform_add_devices(foo_devices);

### 三、platform_get_resource 函数的作用与使用方法 `platform_get_resource` 是 Linux 内核中用于从 `platform_device` 中提取资源信息的一个关键函数,常用于设备驱动初始化阶段获取内存地址、中断号等硬件相关参数[^4]。该函数通过指定资源类型和索引,遍历设备的资源数组,找到匹配的资源结构体并返回其指针。 #### 资源类型与用途 资源类型包括但不限于: - `IORESOURCE_MEM`:表示内存映射 I/O 地址范围; - `IORESOURCE_IRQ`:表示中断请求线; - `IORESOURCE_REG`:通常用于寄存器块; - `IORESOURCE_DMA`:表示 DMA 通道。 通过这些资源类型,驱动程序可以准确地访问特定的硬件寄存器区域、中断号或DMA通道,实现对平台设备的控制和通信[^2]。 #### 使用示例 以下是一个典型的使用场景:在设备驱动的 `probe` 函数中获取设备的内存基地址,并进行映射。 ```c struct resource *res; void __iomem *regs; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { dev_err(&pdev->dev, "cannot find IO resource\n"); return -ENOENT; } regs = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(regs)) return PTR_ERR(regs); ``` 在此示例中,`platform_get_resource` 获取了第一个类型为 `IORESOURCE_MEM` 的资源,随后通过 `devm_ioremap_resource` 将物理地址映射到内核虚拟地址空间,以便后续访问硬件寄存器[^3]。 #### 中断资源的获取 类似地,也可以获取设备的中断资源: ```c int irq; irq = platform_get_irq(pdev, 0); if (irq < 0) return irq; ret = devm_request_irq(&pdev->dev, irq, my_interrupt_handler, 0, "my_device", pdev); if (ret) return ret; ``` 上述代码中,`platform_get_irq` 实际上调用了 `platform_get_resource` 并提取了 `IORESOURCE_IRQ` 类型的第一个资源,进而获取中断号并注册中断处理函数[^1]。 #### 注意事项 为了确保资源获取成功,必须保证设备驱动中的名称与 `platform_device` 中的名称一致,否则将导致匹配失败,无法获取资源[^5]。此外,在多资源情况下,应根据实际需求选择正确的索引编号(num)以避免错误。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值