linux内核总线驱动模型-platform篇

linux从2.6开始就加入了一套新的驱动管理和注册机制平台总线,是一条虚拟的总线,设备用platform_device表示,驱动用platform_driver进行注册。于传统的总线/设备/驱动程序机制相比,平台由内核进行统一管理,在驱动中使用资源,提高了代码的安全性和可移植性。

下面来看看内核时怎么注册platform总线的过程:

struct device platform_bus = {
    
    
	.init_name	= "platform",
};

struct bus_type platform_bus_type = {
    
    
	.name		= "platform",
	.dev_groups	= platform_dev_groups,
	.match		= platform_match,
	.uevent		= platform_uevent,
	.pm		= &platform_dev_pm_ops,
};
int __init platform_bus_init(void)
{
    
    
	int error;

	early_platform_cleanup();

	error = device_register(&platform_bus);
	if (error)
		return error;
	error =  bus_register(&platform_bus_type);
	if (error)
		device_unregister(&platform_bus);
	of_platform_register_reconfig_notifier();
	return error;
}

由传统的机制,也不难总结出平台的开发流程为,其过程和总线的注册过程差不多,驱动和设备匹配后,调用平台的匹配函数。

  1. 定义一个platform_device,并注册
  2. 定义一个platform_driver,并注册

平台设备定义如下:

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

注册过程如下:

int platform_device_register(struct platform_device *pdev)
{
    
    
	device_initialize(&pdev->dev);//dev初始化
	arch_setup_pdev_archdata(pdev);
	return platform_device_add(pdev);//dev加入到链表中
}
int platform_device_add(struct platform_device *pdev)
{
    
    
	int i, ret;

	if (!pdev)
		return -EINVAL;

	if (!pdev->dev.parent)
		pdev->dev.parent = &platform_bus; //设置父设备为platform_bus

	pdev->dev.bus = &platform_bus_type;   //设置总线为platform_bus_type

	switch (pdev->id) {
    
    
	default:
		dev_set_name(&pdev->dev, "%s.%d", pdev->name,  pdev->id);
		break;
	case PLATFORM_DEVID_NONE:
		dev_set_name(&pdev->dev, "%s", pdev->name);
		break;
	case PLATFORM_DEVID_AUTO:
		/*
		 * Automatically allocated device ID. We mark it as such so
		 * that we remember it must be freed, and we append a suffix
		 * to avoid namespace collision with explicit IDs.
		 */
		ret = ida_simple_get(&platform_devid_ida, 0, 0, GFP_KERNEL);
		if (ret < 0)
			goto err_out;
		pdev->id = ret;
		pdev->id_auto = true;
		dev_set_name(&pdev->dev, "%s.%d.auto", pdev->name, pdev->id);
		break;
	}
     
	/*完成资源的初始化*/
	for (i = 0; i < pdev->num_resources; i++) {
    
    
		struct resource *p, *r = &pdev->resource[i];

		if (r->name == NULL)
			r->name = dev_name(&pdev->dev);

		p = r->parent;
		if (!p) {
    
    
			if (resource_type(r) == IORESOURCE_MEM)
				p = &iomem_resource;
			else if (resource_type(r) == IORESOURCE_IO)
				p = &ioport_resource;
		}

		if (p && insert_resource(p, r)) {
    
    
			dev_err(&pdev->dev, "failed to claim resource %d\n", i);
			ret = -EBUSY;
			goto failed;
		}
	}

	pr_debug("Registering platform device '%s'. Parent at %s\n",
		 dev_name(&pdev->dev), dev_name(pdev->dev.parent));

	ret = device_add(&pdev->dev);
	if (ret == 0)
		return ret;
}

其上最后也是调用device_add的,其主要是将设备加入到总线总线中,并由device_attach完成设备与驱动之间的匹配,这个过程在设备中已经有详细的分析过程中,再看看驱动的注册过程。

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

可见,它包含了设备操作的功能函数,同时包含了device_driver结构。内核提供的platform_driver结构注册函数为:

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

int __platform_driver_register(struct platform_driver *drv,
				struct module *owner)
{
    
    
	drv->driver.owner = owner;
	drv->driver.bus = &platform_bus_type;//驱动的总线设置为platform总线
	if (drv->probe)
		drv->driver.probe = platform_drv_probe;
	if (drv->remove)
		drv->driver.remove = platform_drv_remove;
	if (drv->shutdown)
		drv->driver.shutdown = platform_drv_shutdown;

	return driver_register(&drv->driver);
}

其注册功能中比较重要的还是调用了driver_register,添加到平台总线链表,完成设备与驱动之间的匹配过程,其主要的过程在总线设备驱动模型的驱动文章已经有过分析。

下面看看驱动和设备的匹配过程,主要是调用bus的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);
}

由以上的分析可以看出,platform是一条虚拟的总线,本身还是基于的总线设备驱动模型的。

猜你喜欢

转载自blog.csdn.net/wll1228/article/details/108392321
今日推荐