后期补充说明:
2025-03-20 19:55:13 :关于 Platform总线不错的视频总结回顾讲解,请百度网盘搜索“1-3_03_SPI总线设备驱动”,然后从头开始看。
结构体platform_device的概述
platform_device 是 Linux 内核中用于描述 Platform 设备(片上资源)的关键结构体。它的作用是定义硬件资源的基本属性,并通过注册到 Platform 总线上与对应的驱动匹配。
结构体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;
};
结构体platform_device的字段详解
1 const char *name
- 功能:定义设备的名称,用于与驱动的名称进行匹配。
- 匹配机制:设备和驱动通过名称进行匹配(
platform_driver.driver.name == platform_device.name)。【完整准确的匹配机制请参考 https://blog.youkuaiyun.com/wenhao_ir/article/details/145023181】 - 示例:
struct platform_device my_device = { .name = "my_platform_device", };
2 int id
- 功能:定义设备的唯一 ID,用于区分同类设备。
- 特殊值:
-1:表示没有具体 ID,即单一设备无需区分。- 非负整数:用于区分多个同类设备。
- 示例:
struct platform_device my_device = { .name = "my_platform_device", .id = 0, // 第一个设备 };
3 bool id_auto
- 功能:指示是否自动分配设备 ID。
- 用途:
- 如果设置为
true,内核会为设备自动分配唯一的 ID。 - 如果设置为
false,则使用id字段中提供的值。 - 通常结构体
platform_device的实例都作为全局变量,所以其默认值为false。详情见 https://blog.youkuaiyun.com/wenhao_ir/article/details/144612305
- 如果设置为
- 示例:
struct platform_device my_device = { .name = "my_platform_device", .id_auto = true, };
4 struct device dev
- 功能:嵌套的通用设备结构体,用于设备的通用管理。
- 作用:
- 提供设备的基础功能(如设备注册、供电管理等)。
- 与设备模型(sysfs)集成。
- 关键字段:
dev.parent:指定设备的父设备。dev.of_node:与设备树节点关联。
- 示例:
my_device.dev.parent = &some_device; // 设置父设备
注意:这个dev结构体的成员release一般情况下需要被赋值才行,因为platform_device_unregister函数执行时会调用它,相关示例代码如下:
//led_dev_release函数即使为空也必须要有,因为platform_device_unregister函数执行时会调用它
static void led_dev_release(struct device *dev)
{
}
.....
static struct platform_device board_A_led_dev = {
.name = "gpio_led_suwenhao",
.num_resources = ARRAY_SIZE(resources),
.resource = resources,
.dev = {
.release = led_dev_release,
},
};
.....
static void __exit led_dev_exit(void)
{
platform_device_unregister(&board_A_led_dev);
}
.....
module_exit(led_dev_exit);
附结构体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;
};
5 u32 num_resources
- 功能:定义设备使用的资源数量。
- 说明:
- 通常与
resource字段配合使用,用于描述设备的硬件资源(如内存、I/O 端口、IRQ)。
- 通常与
- 示例:
struct resource my_resources[] = { { .start = 0x12340000, .end = 0x123400FF, .flags = IORESOURCE_MEM, }, }; struct platform_device my_device = { .name = "my_platform_device", .resource = my_resources, .num_resources = ARRAY_SIZE(my_resources), };
6 struct resource *resource
- 功能:指向设备的硬件资源数组。
resource 结构体定义如下:
位置:include\linux\ioport.h
struct resource {
resource_size_t start;
resource_size_t end;
const char *name;
unsigned long flags;
unsigned long desc;
struct resource *parent, *sibling, *child;
};
- 成员flags表示资源类型:
- IORESOURCE_MEM:内存资源。
- IORESOURCE_IRQ:中断资源。
- IORESOURCE_IO:I/O 端口资源。
- 说明:
- 资源描述通过
struct resource定义。 num_resources表示资源数组的大小。
- 资源描述通过
- 特别注意:
- 资源类型
IORESOURCE_MEM和IORESOURCE_IO不能随便选,要根据实际情况选,否则函数platform_get_resource()在解析资源时会报错failed to claim resource 0。这是因为函数platform_get_resource()在解析资源时,会去检查resource的start、end成员的数值是否在应该的范围内,比如内存资源的物理地址应该在哪个范围,I/O 端口资源的物理地址又在哪个范围内,不过IORESOURCE_IRQ没啥限制,因为如果选它,start或end表示的是中断编号,中断编号就随便一个数值就行了,所以一般在不涉及具体的硬件的操作中选demo。这里要注意,GPIO口实际上属于ORESOURCE_MEM,而不是想像中的IORESOURCE_IO。实际使用函数platform_get_resource()的例子见博文 https://blog.youkuaiyun.com/wenhao_ir/article/details/145013236
- 资源类型
7 const struct platform_device_id *id_entry
- 功能:用于描述设备的匹配表。
- 作用:
- 提供一个备用的匹配机制,尤其在没有设备树的情况下使用。
- 驱动中的
platform_driver也可能包含类似的匹配表,用于与设备进行匹配。
-注意:通过对内核函数platform_match的分析,发现这个字段在内核的标准匹配机制中并没有使用,详情见 https://blog.youkuaiyun.com/wenhao_ir/article/details/145023181
8 char *driver_override
- 功能:指定强制匹配的驱动程序名称。详情见 https://blog.youkuaiyun.com/wenhao_ir/article/details/145023181
- 说明:
- 通过覆盖机制,强制将设备匹配到指定的驱动程序。
- 用途:
- 调试或特定需求时使用。
- 示例:
my_device.driver_override = "specific_driver_name";
9 struct mfd_cell *mfd_cell
- 功能:多功能设备 (MFD) 的扩展字段。
- 说明:
- 当设备属于一个 MFD 时,这个字段可以指向对应的子设备结构体。
10 struct pdev_archdata archdata
- 功能:存储与平台架构相关的特定数据。
- 说明:
- 在不同的硬件平台上,这个字段可能包含特定于架构的信息。
** 关键函数**
1 注册设备
-
动态注册:
使用platform_device_register()注册设备。struct platform_device my_device = { .name = "my_platform_device", .id = -1, }; platform_device_register(&my_device); -
静态注册:
通过设备树(Device Tree)描述设备,内核自动解析并注册。
2 卸载设备
- 使用
platform_device_unregister()卸载设备。platform_device_unregister(&my_device);
3. 示例代码
以下代码展示了如何定义和注册一个 platform_device:
#include <linux/module.h>
#include <linux/platform_device.h>
// 硬件资源描述
static struct resource led_resources[] = {
{
.start = 0x12340000,
.end = 0x123400FF,
.flags = IORESOURCE_MEM, // 内存资源
},
{
.start = 5,
.end = 5,
.flags = IORESOURCE_IRQ, // 中断资源
},
};
// 定义设备
static struct platform_device led_device = {
.name = "led", // 设备名称
.id = -1, // 无具体 ID
.resource = led_resources, // 资源指针
.num_resources = ARRAY_SIZE(led_resources),
};
// 初始化
static int __init led_device_init(void) {
return platform_device_register(&led_device);
}
// 卸载
static void __exit led_device_exit(void) {
platform_device_unregister(&led_device);
}
module_init(led_device_init);
module_exit(led_device_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Example Author");
MODULE_DESCRIPTION("Platform Device Example");
总结
platform_device的核心作用是描述设备的基本属性和硬件资源,并注册到系统中供驱动匹配。- 它通过简单的名称匹配机制实现了设备和驱动的解耦,为嵌入式系统中片上资源的管理提供了极大的便利。
如何查看系统中存在的platform_device结构体的记录文件
这部分内容请访问博文 https://blog.youkuaiyun.com/wenhao_ir/article/details/145056170 【搜索“查看设备树节点生成”】查看相应的内容。

321

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



