常用的与平台设备注册相关的函数及其作用:
1. platform_device_register()
功能:用于注册平台设备到内核设备模型中。注册后,设备与相应的驱动程序绑定,驱动的 probe
函数被调用以进行初始化。
函数原型:
int platform_device_register(struct platform_device *pdev);
参数:
pdev
:指向platform_device
结构体的指针,描述了要注册的设备。
返回值:
- 成功时返回 0,失败时返回负数的错误代码。
示例:
struct platform_device my_device = {
.name = "my_device",
.id = -1,
};
platform_device_register(&my_device);
2. platform_device_unregister()
功能:用于注销已注册的平台设备,释放相关的资源。
函数原型:
void platform_device_unregister(struct platform_device *pdev);
参数:
pdev
:指向platform_device
结构体的指针,描述要注销的设备。
示例:
platform_device_unregister(&my_device);
3. platform_device_alloc()
功能:动态分配一个平台设备结构体,并初始化其 name
和 id
字段。它为设备结构体的内存分配提供便利。
函数原型:
struct platform_device *platform_device_alloc(const char *name, int id);
参数:
name
:设备的名称。id
:设备的唯一 ID。如果不需要指定 ID,可以使用-1
。
返回值:
- 成功时返回指向
platform_device
结构体的指针,失败时返回NULL
。
示例:
struct platform_device *pdev;
pdev = platform_device_alloc("my_device", -1);
if (!pdev)
return -ENOMEM;
4. platform_device_add()
功能:将已经通过 platform_device_alloc()
分配的设备添加到内核设备模型中。
函数原型:
int platform_device_add(struct platform_device *pdev);
参数:
pdev
:指向platform_device
结构体的指针,描述要添加的设备。
返回值:
- 成功时返回 0,失败时返回负数的错误代码。
示例:
struct platform_device *pdev;
pdev = platform_device_alloc("my_device", -1);
if (pdev) {
platform_device_add(pdev);
}
5. platform_device_put()
功能:减少设备的引用计数,并在设备的引用计数为 0 时释放设备的内存。这通常与 platform_device_alloc()
和 platform_device_add()
一起使用。
函数原型:
void platform_device_put(struct platform_device *pdev);
参数:
pdev
:指向platform_device
结构体的指针,描述要释放的设备。
示例:
platform_device_put(pdev);
6. platform_device_add_resources()
功能:为平台设备添加资源(如内存地址、I/O 地址、中断号等)。这些资源在设备注册时传递给驱动程序的 probe
函数。
函数原型:
int platform_device_add_resources(struct platform_device *pdev, const struct resource *res, unsigned int num);
参数:
pdev
:指向platform_device
结构体的指针。res
:指向resource
结构体数组的指针,定义了设备的资源。num
:资源的数量。
返回值:
- 成功时返回 0,失败时返回负数的错误代码。
示例:
struct resource my_resources[] = {
[0] = {
.start = 0x10000000,
.end = 0x100000ff,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = 5,
.end = 5,
.flags = IORESOURCE_IRQ,
},
};
platform_device_add_resources(pdev, my_resources, ARRAY_SIZE(my_resources));
7. platform_device_add_data()
功能:为平台设备添加私有数据。这些数据在 probe
函数中通过 platform_get_drvdata()
函数获取,方便驱动程序使用。
函数原型:
int platform_device_add_data(struct platform_device *pdev, const void *data, size_t size);
参数:
pdev
:指向platform_device
结构体的指针。data
:指向要添加的数据。size
:数据的大小。
返回值:
- 成功时返回 0,失败时返回负数的错误代码。
示例:
struct my_data {
int value;
} my_device_data = {
.value = 42,
};
platform_device_add_data(pdev, &my_device_data, sizeof(my_device_data));
小结
- 设备的注册与注销:
platform_device_register()
和platform_device_unregister()
是用于设备注册和移除的主要函数。 - 资源管理:使用
platform_device_add_resources()
来为设备添加硬件资源,比如内存或中断。 - 动态分配:
platform_device_alloc()
和platform_device_add()
提供了灵活的动态分配方式,而platform_device_put()
则用于释放资源。 - 数据传递:
platform_device_add_data()
可以将私有数据与设备一起传递给驱动程序,以便在probe
函数中使用。
Linux platform 设备注册详解
在 Linux 驱动开发中,平台设备(Platform Device)通常用于描述嵌入式系统中那些没有标准总线(如 PCI、USB 等)连接的硬件设备。平台设备的注册是驱动开发的重要步骤,通过注册设备,内核可以识别并与之进行交互。平台设备的注册通常有两种方式:静态注册 和 动态注册。下面详细介绍这两种方式,以及如何在设备树(Device Tree)中进行注册。
1. 静态注册
静态注册主要在代码中显式定义平台设备,并通过相关的 API 函数将其注册到内核中。这种方式比较适合简单的硬件或者不依赖设备树的设备。
静态注册步骤
Step 1:定义 platform_device
结构体
#include <linux/platform_device.h>
static struct platform_device my_platform_device = {
.name = "my_platform_device", // 设备名称,驱动会通过该名称匹配
.id = -1, // 如果系统中只存在一个此类设备,使用 -1
// 如果有资源,使用 resource 结构体进行描述
};
Step 2:注册平台设备
通过调用 platform_device_register()
函数将设备注册到内核。
static int __init my_device_init(void) {
return platform_device_register(&my_platform_device);
}
module_init(my_device_init);
Step 3:卸载平台设备
在卸载模块时,调用 platform_device_unregister()
函数注销设备。
static void __exit my_device_exit(void) {
platform_device_unregister(&my_platform_device);
}
module_exit(my_device_exit);
完整示例:
#include <linux/module.h>
#include <linux/platform_device.h>
static struct platform_device my_platform_device = {
.name = "my_platform_device",
.id = -1,
};
static int __init my_device_init(void) {
return platform_device_register(&my_platform_device);
}
static void __exit my_device_exit(void) {
platform_device_unregister(&my_platform_device);
}
module_init(my_device_init);
module_exit(my_device_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Author");
MODULE_DESCRIPTION("A simple Platform Device example");
2. 动态注册
动态注册方式通常用于需要灵活地在运行时添加或删除设备。使用 platform_device_alloc()
和 platform_device_add()
函数动态分配和添加设备。
动态注册步骤
Step 1:动态分配 platform_device
结构体
struct platform_device *pdev;
pdev = platform_device_alloc("my_platform_device", -1);
if (!pdev)
return -ENOMEM;
Step 2:注册平台设备
int ret = platform_device_add(pdev);
if (ret) {
platform_device_put(pdev); // 注册失败时,释放资源
return ret;
}
Step 3:注销和释放设备
在模块卸载时,调用 platform_device_unregister()
注销设备,并使用 platform_device_put()
释放资源。
platform_device_unregister(pdev);
platform_device_put(pdev);
3. 设备树(Device Tree)中的平台设备注册
在嵌入式系统中,使用设备树来定义平台设备是一种标准做法。设备树用于描述硬件资源,并由内核解析以匹配对应的驱动程序。设备树方式相比于静态注册更加灵活,因为它将硬件信息与代码分离。
设备树注册步骤
Step 1:在设备树中定义设备
设备树中的 compatible
字段用于描述设备类型,驱动程序通过 compatible
与设备匹配。
设备树(.dts 文件)片段:
my_device@10000000 {
compatible = "my_vendor,my_device"; // 匹配驱动程序中的 compatible
reg = <0x10000000 0x1000>; // 设备的寄存器地址范围
interrupt-parent = <&intc>; // 中断控制器
interrupts = <5>; // 中断号
};
Step 2:在驱动中匹配设备
在驱动中,使用 of_match_table
来匹配设备树中的 compatible
字段。
static const struct of_device_id my_of_match[] = {
{ .compatible = "my_vendor,my_device", },
{},
};
MODULE_DEVICE_TABLE(of, my_of_match);
Step 3:驱动与设备树匹配
驱动的 platform_driver
结构体中包含了 of_match_table
,用于将设备树中的设备与驱动匹配。
static struct platform_driver my_driver = {
.probe = my_probe,
.remove = my_remove,
.driver = {
.name = "my_platform_device",
.of_match_table = my_of_match,
.owner = THIS_MODULE,
},
};
module_platform_driver(my_driver);
4. 资源管理
Platform 设备可能需要管理的资源包括内存映射寄存器、I/O 端口和中断号等。资源可以通过设备树或者 resource
结构体在设备注册时传递给驱动程序。
资源定义和注册
Step 1:定义资源
如果不使用设备树,可以手动定义 resource
结构体来描述设备的资源。
static struct resource my_resources[] = {
[0] = {
.start = 0x10000000,
.end = 0x100000ff,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = 5,
.end = 5,
.flags = IORESOURCE_IRQ,
},
};
Step 2:在设备注册时添加资源
pdev = platform_device_alloc("my_platform_device", -1);
if (!pdev)
return -ENOMEM;
ret = platform_device_add_resources(pdev, my_resources, ARRAY_SIZE(my_resources));
if (ret) {
platform_device_put(pdev);
return ret;
}
5. 加载和卸载驱动
在注册设备之后,需要加载驱动程序以匹配并初始化设备。驱动程序编译为内核模块后,可以通过 insmod
或 modprobe
命令加载:
- 加载驱动:
sudo insmod my_platform_driver.ko
- 卸载驱动:
sudo rmmod my_platform_driver
总结
- 静态注册:适合简单的设备,直接在代码中定义并注册
platform_device
结构体。 - 动态注册:更加灵活,适用于需要在运行时动态添加或删除设备的场景。
- 设备树注册:常用于嵌入式系统,通过设备树描述硬件资源,驱动通过
compatible
字段与设备匹配。 - 资源管理:无论是通过代码或设备树注册平台设备,都需要正确管理设备的硬件资源。
通过合理选择注册方式,可以更有效地开发和管理 Linux 平台设备驱动。
标签:platform,详解,注册,Linux,device,pdev,my,设备 From: https://blog.csdn.net/weixin_44251074/article/details/142875074