platfor设备驱动(1)-什么是platform设备驱动?platform设备驱动基础总结

platform 设备驱动:平台设备驱动,是一条虚拟的总线,而不是像IIC、SPI这种的物理总线,是驱动分离和分层思想的产物,适用于那些无法使用IIC、SPI、USB等总线的外设。

1.驱动的分离与分层

1.1 前因

嵌入式系统中有许多的总线,例如IIC、SPI等,而如果按照之前写驱动的方法,假设有ABC三个平台,都有一个IIC接口的传感器,那么在编写驱动时,最终的驱动框架将会是下图所示,会产生大量的重复代码。
于是便有了驱动分离和分层的思想,在这里引入了IIC总线、SPI总线、USB总线等概念,而有些外设是不属于这些总线,但他也要使用这个设备模型,于是加入了platform这个虚拟总线,给这些设备使用。
image.png

1.2 驱动分离与分层概念

1)驱动分离:
主机驱动(主机上的IIC等)和设备驱动(采用IIC通信的设备)分隔开,总线作为它们建立联系的桥梁,形成总线(bus)驱动(driver)设备(device) 模型,关系如下图。

当注册驱动时,总线会在右侧的设备中寻找与之匹配的设备,反之注册设备,总线会在左边查找匹配的驱动,寻找到后将他们建立联系。
image.png

这里借鉴网上找到的一张图,详细介绍了平台设备驱动分离与函数调用堆栈,留着慢慢参考研究

2)驱动分层:
为了在不同层处理不同的内容,例如Input子系统负责管理所有与输入相关的驱动,input 核心层会处理各种 IO 模型,各个层级各司其职。

2.platform驱动模型简介

2.1 platform bus

Linux系统内核使用bus_type 结构体表示总线,该结构体定义在文include/linux/device.h

struct bus_type {
	const char		*name;
	const char		*dev_name;
	struct device		*dev_root;
	struct device_attribute	*dev_attrs;	/* use dev_groups instead */
	const struct attribute_group **bus_groups;
	const struct attribute_group **dev_groups;
	const struct attribute_group **drv_groups;

	int (*match)(struct device *dev, struct device_driver *drv);	
	int (*uevent)(struct device *dev, struct kobj_uevent_env *env);
	int (*probe)(struct device *dev);
	int (*remove)(struct device *dev);
	void (*shutdown)(struct device *dev);

	int (*online)(struct device *dev);
	int (*offline)(struct device *dev);

	int (*suspend)(struct device *dev, pm_message_t state);
	int (*resume)(struct device *dev);

	const struct dev_pm_ops *pm;

	const struct iommu_ops *iommu_ops;

	struct subsys_private *p;
	struct lock_class_key lock_key;
};

其中的match函数用于总线完成设备和驱动之间匹配 dev为设备,drv为驱动,所以每一条总线都必须实现这个函数。

platform总线是bus_type的一个示例,在 drivers/base/platform.c 文件,内容如下:

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

其中使用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);
}

of_driver_match_device:设备树的匹配方式,通过compatible属性在OF表匹配,匹配后执行probe函数
acpi_driver_match_device:ACPI匹配方式
platform_match_id:id_table方式
(strcmp(pdev->name, drv->name):直接比较驱动和设备的name字段进行匹配

依次执行上面的四种方式,完成驱动和设备的匹配

2.2 platform驱动

Linux系统内核使用 platform_driver 结构体表示platform驱动,该结构体定义在文include/linux/ platform_device.h

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;
};

struct device_driver {
	const char		*name;
	struct bus_type		*bus;

	struct module		*owner;
	const char		*mod_name;	/* used for built-in modules */

	bool suppress_bind_attrs;	/* disables bind/unbind via sysfs */

	const struct of_device_id	*of_match_table;
	const struct acpi_device_id	*acpi_match_table;

	int (*probe) (struct device *dev);
	int (*remove) (struct device *dev);
	void (*shutdown) (struct device *dev);
	int (*suspend) (struct device *dev, pm_message_t state);
	int (*resume) (struct device *dev);
	const struct attribute_group **groups;

	const struct dev_pm_ops *pm;

	struct driver_private *p;
};


struct platform_device_id {
	char name[PLATFORM_NAME_SIZE];
	kernel_ulong_t driver_data;
};

probe函数:驱动和设备匹配成功执行
driver:提供最基本的驱动框架
id_tabel:id_table方式匹配时,便是匹配这个
of_match_table: OF匹配表,设备树的匹配方式,通过compatible属性在OF表匹配,匹配后执行probe函数

2.3 platform设备

Linux系统内核使用 platform_device 结构体表示platform设备,该结构体定义在**include/linux/ ** include/linux/platform_device.h
如果
内核不支持设备树
,则使用 platform_device描述设备。

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;
};

struct resource {
	resource_size_t start;
	resource_size_t end;
	const char *name;
	unsigned long flags;
	struct resource *parent, *sibling, *child;
};

name:设备名字,与platform_driver的name字段相同
num_resources:资源数量
resource:设备信息资源

start:资源起始信息
end:资源终止信息
name:资源名字
flags:资源类型
资源信息例如下面的宏定义

#define IORESOURCE_BITS		0x000000ff	/* Bus-specific bits */

#define IORESOURCE_TYPE_BITS	0x00001f00	/* Resource type */
#define IORESOURCE_IO		0x00000100	/* PCI/ISA I/O ports */
#define IORESOURCE_MEM		0x00000200
#define IORESOURCE_REG		0x00000300	/* Register offsets */
#define IORESOURCE_IRQ		0x00000400
#define IORESOURCE_DMA		0x00000800
#define IORESOURCE_BUS		0x00001000

其实就是一系列的偏移地址

3.platform驱动API

如果是内核支持设备树的情况下,则不需要使用platform device描述设备,不使用platform_device的注册及注销函数。

void platform_device_unregister(struct platform_device *pdev) //注销platform设备
int platform_device_register(struct platform_device *pdev)  //注册platform设备

int platform_driver_register (struct platform_driver *driver) //注册platform驱动
void platform_driver_unregister(struct platform_driver *drv) //注销platform驱动
  • 22
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值