Linux平台总线

目录

一、定义

二、功能

三、主要结构体

1、struct platform_device

2、struct platform_driver

3、struct bus_type


一、定义

平台总线是Linux内核中虚拟出来的一条总线,并非真实的物理导线。它主要用于连接和管理设备驱动与设备之间的通信,为它们提供一个匹配的平台。平台总线的设计目的是为了管理上的方便和统一。

二、功能

  1. 平台总线模型把原来的驱动C文件分为了两个C文件,分别是device.c和driver.c。
  2. 其中,device.c 用来存放设备硬件数据,通常是变化的。而 driver.c 用来存放设备驱动的逻辑,通常是通用的。
  3. 平台总线为驱动和设备提供了一个匹配的平台,使得一个驱动可以匹配多个设备,实现“一夫多妻制”。
  4. 在编写驱动时,使用平台总线可以减少编写重复的代码,因为驱动中相似操作与硬件差异化数据被分离。
  5. 平台总线有利于平台或设备的升级。例如,当板子上的芯片不变,但外设从一个串口更换为另一个串口时,只需要更改一些硬件资源,而不需要重写整个驱动。

三、主要结构体

平台总线的工作体系主要涉及三个结构体:struct platform_device , struct platform_driver 和 struct bus_type。

1、struct platform_device

struct platform_device {
	const char	*name;
	int		id;
	bool		id_auto;
	struct device	dev;
	u64		platform_dma_mask;
	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;
};
  • name:平台总线下设备的名字。
  • id:设备的ID。
  • dev:所有设备通用的属性部分(父类)。
  • num_resources:设备使用到的资源(如IO或中断号等)的个数。
  • resource:设备使用到的资源数组的首地址。
  • id_entry:设备ID表,用于多个类似的同系列产品使用同一个驱动。
  • driver_override:用于强制匹配一个 driver
  • archdata:自留地,用于提供扩展性,表示设备的一些属性。

注册和注销方式

int platform_device_register(struct platform_device *pdev);
int platform_device_unregister(struct platform_device *pdev);

2、struct platform_driver

struct platform_driver {
	int (*probe)(struct platform_device *);
	int (*remove)(struct platform_device *);
	void (*shutdown)(struct platform_device *);
	int (*suspend)(struct platform_device *, pm_message_t state);
	int (*resume)(struct platform_device *);
	struct device_driver driver;
	const struct platform_device_id *id_table;
	bool prevent_deferred_probe;
};
  • probe:在与 device 匹配成功时调用
  • remove:device 卸载 或 driver 卸载时调用
  • shutdown:当系统即将关闭时,此函数会被调用。它通常用于执行一些清理操作,以确保设备在系统关闭前处于安全的状态。
  • suspend:当系统进入低功耗模式(如挂起或休眠)时,此函数会被调用。它通常用于保存设备的状态,以便在系统恢复时能够恢复到之前的状态。
  • resume:当系统从低功耗模式恢复时,此函数会被调用。它通常用于恢复设备在suspend函数中保存的状态,并重新初始化设备。
  • driver:包含通用的驱动程序信息(父类)
  • id_table:用于匹配此驱动程序可以支持的多个设备。这通常用于支持同一驱动程序下的多个不同设备。
  • prevent_deferred_probe:这是一个布尔值,用于控制是否延迟设备的探测。在某些情况下,驱动程序可能希望立即探测设备而不是延迟到稍后进行。将此值设置为true可以防止设备探测被延迟

注册和注销方式

#define platform_driver_register(drv) \
	__platform_driver_register(drv, THIS_MODULE)

void platform_driver_unregister(struct platform_driver *drv)
{
	driver_unregister(&drv->driver);
}

3、struct bus_type

struct bus_type 在内核中已经定义好了,以实现 device 和 driver 的自动匹配

struct bus_type platform_bus_type = {
	.name		= "platform",
	.dev_groups	= platform_dev_groups,
	.match		= platform_match,
	.uevent		= platform_uevent,
	.dma_configure	= platform_dma_configure,
	.pm		= &platform_dev_pm_ops,
};

 当 device 和 driver 匹配成功时,会调用 platform_match 回调函数

 四、匹配优先级

platform_match 回调函数定义如下

static int platform_match(struct device *dev, struct device_driver *drv)
{
	struct platform_device *pdev = to_platform_device(dev);
	struct platform_driver *pdrv = to_platform_driver(drv);

	/* When driver_override is set, only bind to the matching driver */
	if (pdev->driver_override)
		return !strcmp(pdev->driver_override, drv->name);

	/* Attempt an OF style match first */
	if (of_driver_match_device(dev, drv))
		return 1;

	/* Then try ACPI style match */
	if (acpi_driver_match_device(dev, drv))
		return 1;

	/* Then try to match against the id table */
	if (pdrv->id_table)
		return platform_match_id(pdrv->id_table, pdev) != NULL;

	/* fall-back to driver name match */
	return (strcmp(pdev->name, drv->name) == 0);
}

由此可知,平台总线匹配的优先级为:

  1. 如果 pdev->driver_override 存在,那么会强制将 pdev->driver_override 和 drv->name进行匹配,如果不相同则匹配失败
  2. 利用设备树的 name/type/compatible和 of_match_table 进行匹配
  3. ACPI style 的 dev 和 drv 匹配
  4. 如果 pdrv->id_table 存在,那么会强制和 pdev->name 匹配
  5. 以上都不满足,最后用 pdev->name 和 drv->name 匹配

五、驱动获取设备信息

1、资源获取

在struct platform_device 结构体中,资源记录在 struct resource *resource 表示的数组中。

常用的资源:地址资源,中断资源

 struct resource 结构体定义如下

struct resource {
	resource_size_t start;
	resource_size_t end;
	const char *name;
	unsigned long flags;
	unsigned long desc;
	struct resource *parent, *sibling, *child;
};
  • start:如果是地址资源,表示起始地址;如果是中断资源,表示中断号
  • end:如果是地址资源,表示内存结束地址,如果是中断资源,start表示中断号
  • name:资源标识符
  • flags:资源种类:地址资源 IORESOURCE_MEM,中断资源 IORESOURCE_IRQ

定义方式举例

#define GPIOZ  0x54004000
struct resource led_resource[] = {
    [0] = {
        .start = GPIOZ,
        .end = GPIOZ + 0x400,
        .name = "led_reg",
        .flags = IORESOURCE_MEM,
    },
    [1] = {
        .start = 13,
        .end = 13,
        .name = "led_irq",
        .flags = IORESOURCE_IRQ,
    },
    [2] = {
        .start = 14,
        .end = 14,
        .name = "led_irq",
        .flags = IORESOURCE_IRQ,
    },
};

 在 pdrv 中可以以如下方式获取

res = platform_get_resource(pdev, IORESOURCE_MEM, 0);//同类型资源编号从0开始
printk("reg addr is [%#x]\n", res->start);

res = platform_get_resource(pdev, IORESOURCE_IRQ, 1);//同类型资源编号从0开始
printk("irq num is [%d]\n", res->start);

irq_num = platform_get_irq(pdev, 0);//获取第一个中断资源
printk("irq num is [%d]\n", irq_num);

结果如下

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

暗里い着迷

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

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

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

打赏作者

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

抵扣说明:

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

余额充值