痛苦之旅一:linux总线设备驱动模型概述

一.什么是总线设备驱动模型

简而言之,linux驱动非常重视软件的可重用和跨平台的能力,最好一行不改就能在任何一个平台上跑起来,基于这样的事实,驱动中如果集成所有平台的设备信息显然太过臃肿,驱动也会显得很奇怪,所以把设备信息分离出去,设备就负责表示设备的硬件信息和资源,驱动就负责用标准化的手法得到设备的资源,总线就负责匹配设备和驱动

痛苦之旅一:linux总线设备驱动模型概述_第1张图片

二.platform设备驱动

1.基本概念

痛苦之旅一:linux总线设备驱动模型概述_第2张图片

2.相关结构体

用结构体struct 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;
};

/*
 * Resources are tree-like, allowing
 * nesting etc..
 */
struct resource {
	resource_size_t start;
	resource_size_t end;
	const char *name;
	unsigned long flags;
	unsigned long desc;
	struct resource *parent, *sibling, *child;
};

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

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

/* struct device_driver - The basic device driver structure */
struct device_driver {
	const char		*name;/* Name of the device driver */
	struct bus_type *bus;/* The bus which the device of this driver belongs to */
	struct module	*owner;
	const char		*mod_name;/* used for built-in modules */
	bool suppress_bind_attrs;/* disables bind/unbind via sysfs */
	enum probe_type probe_type;
	const struct of_device_id	*of_match_table;/* The open firmware table */
	const struct acpi_device_id	*acpi_match_table;/* The 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 used for matching a device
 */
struct of_device_id {
	char	name[32];
	char	type[32];
	char	compatible[128];
	const void *data;
};

 系统为platform bus定义了一个实例叫做platform_bus_type

/* @match:	Called, perhaps multiple times, whenever a new device or driver
 *		    is added for this bus. It should return a positive value if the
 *		    given device can be handled by the given driver and zero
 *		    otherwise. It may also return error code if determining that
 *		    the driver supports the device is not possible. In case of
 *		    -EPROBE_DEFER it will queue the device for deferred probing.
 */
struct bus_type platform_bus_type = {
	.name		= "platform", /* The name of the bus */
	.dev_groups	= platform_dev_groups,
	.match		= platform_match, 
	.uevent		= platform_uevent,
	.pm		= &platform_dev_pm_ops,
};

 3.驱动和设备的匹配函数platform_match

/**
 * platform_match - bind platform device to platform driver.
 * @dev: device.
 * @drv: driver.
 *
 * Platform device IDs are assumed to be encoded like this:
 * "", where  is a short description of the type of
 * device, like "pci" or "floppy", and  is the enumerated
 * instance of the device, like '0' or '42'.  Driver IDs are simply
 * "".  So, extract the  from the platform_device structure,
 * and compare it against the name of the driver. Return whether they match
 * or not.
 */
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);
}

 

注:书籍参考<深入Linux设备驱动程序内核机制> 

注:代码来源:linux-4.14.99

你可能感兴趣的:(Linux基础)