平台总线-probe函数 的了解和使用
驱动-平台总线-platform设备注册platform驱动注册篇 的文章中,我们理解了platform 总线,了解了platform driver和platform device 的注册,配对 知识。
匹配成功之后会进入在注册 platform 驱动程序中编写的 probe 函数,在上个章节只是为了验证是否匹配成功,所以只是在 probe 中加入了一句相关打印,而驱动是要控制硬件的,但是平台总线模型对硬件的描述写在了 platform_device.c 中,platform 设备和 platform 驱动匹配成功之后,那我们如何在驱动platform_driver.c 的 probe 函数中,得到 platform_device.c 中编写的硬件资源呢?
也就是 平台总线体系中,device 负责描述设备相关,但是驱动需要把设备用起来,那就需要再驱动里面初始化设备、控制设备、获取设备相关信息的。 这里就是probe 方法里面要做的。
驱动-平台总线-platform设备注册platform驱动注册篇
平台总线-probe函数编写
手把手教Linux驱动-platform总线详解
platform总线设备驱动模型
驱动-平台总线-platform设备注册platform驱动注册篇 里面的程序我们直接拿来用,编码如下:
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/ioport.h>
#define MEM_START_ADDR 0xFDD60000
#define MEM_END_ADDR 0xFDD60004
#define IRQ_NUMBER 101
static struct resource my_resources[] = {
{
.start = MEM_START_ADDR, // 内存资源起始地址
.end = MEM_END_ADDR, // 内存资源结束地址
.flags = IORESOURCE_MEM, // 标记为内存资源
},
{
.start = IRQ_NUMBER, // 中断资源号
.end = IRQ_NUMBER, // 中断资源号
.flags = IORESOURCE_IRQ, // 标记为中断资源
},
};
static void my_platform_device_release(struct device *dev)
{
// 释放资源的回调函数
}
static struct platform_device my_platform_device = {
.name = "my_platform_device", // 设备名称
.id = -1, // 设备ID 可以用于区分同一种设备的不同实例。这个参数是可选的,如果不需要使用 ID 进行区分,可以将其设置为-1,
.num_resources = ARRAY_SIZE(my_resources), // 资源数量
.resource = my_resources, // 资源数组
.dev.release = my_platform_device_release, // 释放资源的回调函数
};
static int __init my_platform_device_init(void)
{
int ret;
ret = platform_device_register(&my_platform_device); // 注册平台设备
if (ret) {
printk(KERN_ERR "Failed to register platform device\n");
return ret;
}
printk(KERN_INFO "Platform device registered\n");
return 0;
}
static void __exit my_platform_device_exit(void)
{
platform_device_unregister(&my_platform_device); // 注销平台设备
printk(KERN_INFO "Platform device unregistered\n");
}
module_init(my_platform_device_init);
module_exit(my_platform_device_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("fangchen");
源码解读:这里前面的基本知识,
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/ioport.h>
static int my_platform_driver_probe(struct platform_device *pdev)
{
struct resource *res_mem, *res_irq;
// 方法1:直接访问 platform_device 结构体的资源数组
if (pdev->num_resources >= 2) {
struct resource *res_mem = &pdev->resource[0];
struct resource *res_irq = &pdev->resource[1];
// 使用获取到的硬件资源进行处理
printk("Method 1: Memory Resource: start = 0x%llx, end = 0x%llx\n",
res_mem->start, res_mem->end);
printk("Method 1: IRQ Resource: number = %lld\n", res_irq->start);
}
// 方法2:使用 platform_get_resource() 获取硬件资源
res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res_mem) {
dev_err(&pdev->dev, "Failed to get memory resource\n");
return -ENODEV;
}
res_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (!res_irq) {
dev_err(&pdev->dev, "Failed to get IRQ resource\n");
return -ENODEV;
}
// 使用获取到的硬件资源进行处理
printk("Method 2: Memory Resource: start = 0x%llx, end = 0x%llx\n",
res_mem->start, res_mem->end);
printk("Method 2: IRQ Resource: number = %lld\n", res_irq->start);
return 0;
}
static int my_platform_driver_remove(struct platform_device *pdev)
{
// 设备移除操作
return 0;
}
static struct platform_driver my_platform_driver = {
.driver = {
.name = "my_platform_device", // 与 platform_device.c 中的设备名称匹配
.owner = THIS_MODULE,
},
.probe = my_platform_driver_probe,
.remove = my_platform_driver_remove,
};
static int __init my_platform_driver_init(void)
{
int ret;
ret = platform_driver_register(&my_platform_driver); // 注册平台驱动
if (ret) {
printk("Failed to register platform driver\n");
return ret;
}
printk("Platform driver registered\n");
return 0;
}
static void __exit my_platform_driver_exit(void)
{
platform_driver_unregister(&my_platform_driver); // 注销平台驱动
printk("Platform driver unregistered\n");
}
module_init(my_platform_driver_init);
module_exit(my_platform_driver_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("fangchen");
我们分别加载 device 和 driver 驱动,如下:
我们直接看看结果:
这里看看结果,
struct resource *platform_get_resource(struct platform_device *dev,
unsigned int type, unsigned int num);
参数说明:
dev:指向 platform_device 结构的指针
type:资源类型,常用值:IORESOURCE_MEM:内存区域资源;IORESOURCE_IO:I/O端口资源;IORESOURCE_IRQ:中断资源
num:资源的索引号(从0开始)
成功:返回指向 resource 结构的指针
struct resource *mem_res;
mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!mem_res) {
dev_err(&pdev->dev, "Failed to get memory resource\n");
return -ENXIO;
}
// 通常接着进行内存映射
void __iomem *base = devm_ioremap_resource(&pdev->dev, mem_res);
if (IS_ERR(base)) {
return PTR_ERR(base);
}
struct resource *irq_res;
irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (!irq_res) {
dev_err(&pdev->dev, "Failed to get IRQ resource\n");
return -ENXIO;
}
int irq_num = irq_res->start; // 获取实际中断号
虽然 platform_get_resource 仍然可用,但内核推荐使用更高级的接口:
void __iomem *base;
base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(base)) {
return PTR_ERR(base);
}
这个函数一次性完成了资源获取和内存映射,并自动管理资源释放。
int irq;
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
return irq; // irq contains error code
}
static struct resource my_device_resources[] = {
[0] = {
.start = 0xFE000000,
.end = 0xFE000FFF,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = 42,
.end = 42,
.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE,
}
};
my_device: my-device@fe000000 {
compatible = "vendor,my-device";
reg = <0xFE000000 0x1000>;
interrupts = <0 42 IRQ_TYPE_EDGE_RISING>;
};