Platform总线设备驱动中非常重要的结构体`platform_device`的详细介绍【以及如何查看系统中存在的`platform_device`结构体的记录文件】

后期补充说明:

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。
  • 用途
  • 示例
    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_MEMIORESOURCE_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


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 【搜索“查看设备树节点生成”】查看相应的内容。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

昊虹AI笔记

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值