Linux总线、设备、驱动模型

内核:Linux-3.14.27

一、Linux总线设备驱动模型框架

从Linux2.6开始Linux加入了一套驱动管理和注册机制—platform平台总线驱动模型。platform平台总线是一条虚拟总线,platform_device为相应的设备,platform_driver为相应的驱动。与传统的bus/device/driver机制相比,platform由内核统一进行管理,提高了代码的可移植性和安全性。所谓的platform_device并不是与字符设备、块设备和网络设备并列的概念,而是Linux系统提供的一种附加手段。Linux总线设备驱动模型的框架如下图所示:


    从图中我们可以很清楚的看出Linux平台总线设备驱动模型的整体架构。在总线设备驱动模型中,需关心总线、设备和驱动这3个实体,总线将设备和驱动绑定。当系统向内核注册每一个驱动程序时,都要通过调用platform_driver_register函数将驱动程序注册到总线,并将其放入所属总线的drv链表中,注册驱动的时候会调用所属总线的match函数寻找该总线上与之匹配的每一个设备,如果找到与之匹配的设备则会调用相应的probe函数将相应的设备和驱动进行绑定;同样的当系统向内核注册每一个设备时,都要通过调用platform_device_register函数将设备注册到总线,并将其放入所属总线的dev链表中,注册设备的时候同样也会调用所属总线的match函数寻找该总线上与之匹配的每一个驱动程序,如果找到与之匹配的驱动程序时会调用相应的probe函数将相应的设备和驱动进行绑定;而这一匹配的过程是由总线自动完成的。
    接下来我们就以Linux-3.14.27版本的内核,分析一下总线设备驱动模型的执行机制。

二、platform驱动的相关数据结构

1. 结构体驱动对应的结构体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;
};
    可以看到platform_driver结构体中包含了probe和remove等相关操作,同时还内嵌了device_driver结构体。

2. device_driver结构体

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;
};
    其中有一个指向driver_private的指针p,一些与其他的组件相关的联系都被移到这个结构变量中。

3. driver_private结构体

struct driver_private {
	struct kobject kobj;		// 在sysfs中代表目录本身
	struct klist klist_devices;	// 驱动链表即我们上面所说的drv链表
	struct klist_node knode_bus;	// 挂载在总线上的驱动链表的节点
	struct module_kobject *mkobj;	// driver与相关的module之间的联系
	struct device_driver *driver;
};
#define to_driver(obj) container_of(obj, struct driver_private, kobj)

三、platform设备的相关数据结构

1. platform设备对应的结构体platform_device

struct platform_device {
	const char	*name;		// 设备的名字这将代替device->dev_id,用作sys/device下显示的目录名
	int		id;		// 设备id,用于给插入给该总线并且具有相同name的设备编号,如果只有一个设备的话填-1。
	bool		id_auto;
	struct device	dev;		// 内嵌device结构
	u32		num_resources;	// 资源的数目
	struct resource	*resource;	// 资源

	const struct platform_device_id	*id_entry;

	/* MFD cell pointer */
	struct mfd_cell *mfd_cell;

	/* arch specific additions */
	struct pdev_archdata	archdata;
};
    可以看出platform_device结构体中包含了名字、id、资源和内嵌device结构体。

2. resource结构体

struct resource {
	resource_size_t start;	// 资源的起始地址
	resource_size_t end;	// 资源的结束地址
	const char *name;
	unsigned long flags;	// 资源的类型
	struct resource *parent, *sibling, *child;
};

    该结构体非常重要,用于存放设备的资源信息,如IO地址、中断号等。

四、platform_driver的注册过程

platform_driver的注册过程可以简化为如下过程
platform_driver *drv;			// 定义一个平台驱动并初始化
platform_driver_register(drv)		// 注册
	->>__platform_driver_register(drv, THIS_MODULE)
		->>driver_register(&drv->driver)
			->>bus_add_driver(&drv->driver)
				->>driver_attach(&drv->driver)
					->>bus_for_each_dev((&drv->driver)->bus, NULL, &drv->driver, __driver_attach);
					 ->>__driver_attach(&drv->driver, dev)
					 	->>driver_probe_device(&drv->driver, dev)
					 		->>really_probe(dev, &drv->driver)
					 			->>dev->bus->probe(dev) 或 ->>&drv->driver->probe(dev)
将此过程展开如下

1. 分配一个platform_driver结构并调用platform_driver_register函数进行注册

#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;	// 设置driver的bus的类型为platform_bus_type
	if (drv->probe)				// 如果drv含有probe(device_driver类型)则driver上的probe指向总线的probe函数
		drv->driver.probe = platform_drv_probe;
	if (drv->remove)			// 如果drv含有remove(device_driver类型)则driver上的remove指向总线的remove函数
		drv->driver.remove = platform_drv_remove;
	if (drv->shutdown)			// 如果drv含有shutdown(device_driver类型)则driver上的shutdown指向总线的shutdown函数
		drv->driver.shutdown = platform_drv_shutdown;

	return driver_register(&drv->driver);	// 注册平台驱动
}

2. 调用driver_register函数将驱动添加到总线的drv链表(其中大部分工作通过调用bus_add_driver函数来完成)

int driver_register(struct device_driver *drv)
{
	int ret;
	struct device_driver *other;

	BUG_ON(!drv->bus->p);

	if ((drv->bus->probe && drv->probe) ||
	    (drv->bus->remove && drv->remove) ||
	    (drv->bus->shutdown && drv->shutdown))
		printk(KERN_WARNING "Driver '%s' needs updating - please use "
			"bus_type methods\n", drv->name);

	other = driver_find(drv->name, drv->bus);
	if (other) {
		printk(KERN_ERR "Error: Driver '%s' is already registered, "
			"aborting...\n", drv->name);
		return -EBUSY;
	}

	ret = bus_add_driver(drv);	// 添加驱动到总线驱动链表即我们上面所说的drv链表
	if (ret)
		return ret;
	ret = driver_add_groups(drv, drv->groups);
	if (ret) {
		bus_remove_driver(drv);
		return ret;
	}
	kobject_uevent(&drv->p->kobj, KOBJ_ADD);

	return ret;
}

3. 调用bus_add_driver函数添加驱动到总线

int bus_add_driver(struct device_driver *drv)
{
	struct bus_type *bus;
	struct driver_private *priv;
	int error = 0;

	bus = bus_get(drv->bus);				// 获取总线类型
	if (!bus)
		return -EINVAL;

	pr_debug("bus: '%s': add driver %s\n", bus->name, drv->name);

	priv = kzalloc(sizeof(*priv), GFP_KERNEL);		// 分配一个driver_private结构并初始化(也就是drv->p)
	if (!priv) {
		error = -ENOMEM;
		goto out_put_bus;
	}
	klist_init(&priv->klist_devices, NULL, NULL);
	priv->driver = drv;
	drv->p = priv;
	priv->kobj.kset = bus->p->drivers_kset;
	error = kobject_init_and_add(&priv->kobj, &driver_ktype, NULL,
				     "%s", drv->name);		//将drv加入sysfs
	if (error)
		goto out_unregister;

	klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers);	//将drv挂入到总线的链表中
	if (drv->bus->p->drivers_autoprobe) {
		error = driver_attach(drv);				//如果总线可以自动的probe,就会调用匹配函数
		if (error)
			goto out_unregister;
	}
	module_add_driver(drv->owner, drv);			//创建driver相关的模块

	error = driver_create_file(drv, &driver_attr_uevent);
	if (error) {
		printk(KERN_ERR "%s: uevent attr (%s) failed\n",
			__func__, drv->name);
	}
	error = driver_add_groups(drv, bus->drv_groups);
	if (error) {
		/* How the hell do we get out of this pickle? Give up */
		printk(KERN_ERR "%s: driver_create_groups(%s) failed\n",
			__func__, drv->name);
	}

	if (!drv->suppress_bind_attrs) {
		error = add_bind_files(drv);
		if (error) {
			/* Ditto */
			printk(KERN_ERR "%s: add_bind_files(%s) failed\n",
				__func__, drv->name);
		}
	}

	return 0;

out_unregister:
	kobject_put(&priv->kobj);
	kfree(drv->p);
	drv->p = NULL;
out_put_bus:
	bus_put(bus);
	return error;
}

4. 调用driver_attach函数,对总线drv链表中的驱动与总线dev链表中的设备进行匹配

int driver_attach(struct device_driver *drv)
{
	return bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);
}

(1)bus_for_each_dev函数源码:

int bus_for_each_dev(struct bus_type *bus, struct device *start,
		     void *data, int (*fn)(struct device *, void *))
{
	struct klist_iter i;
	struct device *dev;
	int error = 0;

	if (!bus || !bus->p)
		return -EINVAL;

	klist_iter_init_node(&bus->p->klist_devices, &i,
			     (start ? &start->p->knode_bus : NULL));
	while ((dev = next_device(&i)) && !error)		// 遍历总线dev链表中的所有设备
		error = fn(dev, data);				// 判断驱动与设备是否匹配,若匹配则将二者绑定
	klist_iter_exit(&i);
	return error;
}

(2)__driver_attach函数源码:

static int __driver_attach(struct device *dev, void *data)
{
	struct device_driver *drv = data;

	/*
	 * Lock device and try to bind to it. We drop the error
	 * here and always return 0, because we need to keep trying
	 * to bind to devices and some drivers will return an error
	 * simply if it didn't support the device.
	 *
	 * driver_probe_device() will spit a warning if there
	 * is an error.
	 */

	if (!driver_match_device(drv, dev))	// 调用bus的match函数对设备和驱动进行匹配,若不匹配driver_match_device函数的返回值为1,则程序立即返回,若匹配则继续向下执行
		return 0;

	if (dev->parent)	/* Needed for USB */
		device_lock(dev->parent);
	device_lock(dev);
	if (!dev->driver)
		driver_probe_device(drv, dev);	// 若设备和驱动匹配且设备的驱动程序为空,则将该驱动程序绑定到该设备(调用驱动程序的probe函数)
	device_unlock(dev);
	if (dev->parent)
		device_unlock(dev->parent);

	return 0;
}

5. 调用driver_probe_device函数,将设备与驱动程序进行绑定(调用probe函数)

int driver_probe_device(struct device_driver *drv, struct device *dev)
{
	int ret = 0;

	if (!device_is_registered(dev))
		return -ENODEV;

	pr_debug("bus: '%s': %s: matched device %s with driver %s\n",
		 drv->bus->name, __func__, dev_name(dev), drv->name);

	pm_runtime_barrier(dev);
	ret = really_probe(dev, drv);			// 调用probe
	pm_request_idle(dev);

	return ret;
}
static int really_probe(struct device *dev, struct device_driver *drv)
{
	int ret = 0;
	int local_trigger_count = atomic_read(&deferred_trigger_count);

	atomic_inc(&probe_count);
	pr_debug("bus: '%s': %s: probing driver %s with device %s\n",
		 drv->bus->name, __func__, drv->name, dev_name(dev));
	WARN_ON(!list_empty(&dev->devres_head));

	dev->driver = drv;

	/* If using pinctrl, bind pins now before probing */
	ret = pinctrl_bind_pins(dev);
	if (ret)
		goto probe_failed;

	if (driver_sysfs_add(dev)) {
		printk(KERN_ERR "%s: driver_sysfs_add(%s) failed\n",
			__func__, dev_name(dev));
		goto probe_failed;
	}

	if (dev->bus->probe) {					// 如果设备本身含有probe函数,那么久调用设备的probe函数
		ret = dev->bus->probe(dev);
		if (ret)
			goto probe_failed;
	} else if (drv->probe) {				// 如果设备不含有probe函数,那么就调用驱动程序的probe函数
		ret = drv->probe(dev);
		if (ret)
			goto probe_failed;
	}

	driver_bound(dev);
	ret = 1;
	pr_debug("bus: '%s': %s: bound device %s to driver %s\n",
		 drv->bus->name, __func__, dev_name(dev), drv->name);
	goto done;

probe_failed:
	devres_release_all(dev);
	driver_sysfs_remove(dev);
	dev->driver = NULL;
	dev_set_drvdata(dev, NULL);

	if (ret == -EPROBE_DEFER) {
		/* Driver requested deferred probing */
		dev_info(dev, "Driver %s requests probe deferral\n", drv->name);
		driver_deferred_probe_add(dev);
		/* Did a trigger occur while probing? Need to re-trigger if yes */
		if (local_trigger_count != atomic_read(&deferred_trigger_count))
			driver_deferred_probe_trigger();
	} else if (ret != -ENODEV && ret != -ENXIO) {
		/* driver matched but the probe failed */
		printk(KERN_WARNING
		       "%s: probe of %s failed with error %d\n",
		       drv->name, dev_name(dev), ret);
	} else {
		pr_debug("%s: probe of %s rejects match %d\n",
		       drv->name, dev_name(dev), ret);
	}
	/*
	 * Ignore errors returned by ->probe so that the next driver can try
	 * its luck.
	 */
	ret = 0;
done:
	atomic_dec(&probe_count);
	wake_up(&probe_waitqueue);
	return ret;
}
注:若调用probe函数时为drv->probe(dev),则实际调用的函数为platform_drv_probe其源码为
static int platform_drv_probe(struct device *_dev)
{
	struct platform_driver *drv = to_platform_driver(_dev->driver);
	struct platform_device *dev = to_platform_device(_dev);
	int ret;

	if (ACPI_HANDLE(_dev))
		acpi_dev_pm_attach(_dev, true);

	ret = drv->probe(dev);		 	// 此处间接地调用了platform_driver提供的probe函数
	if (ret && ACPI_HANDLE(_dev))
		acpi_dev_pm_detach(_dev, true);

	if (drv->prevent_deferred_probe && ret == -EPROBE_DEFER) {
		dev_warn(_dev, "probe deferral not supported\n");
		ret = -ENXIO;
	}

	return ret;
}
注:platform_driver提供的probe函数即为注册平台驱动时程序员自己编写的probe函数

五、platform_device的注册过程

platform_device的注册过程可以简化为以下过程:
struct platform_device *pdev;		// 定义一个平台设备并初始化
platform_device_register(pdev)		// 注册
	->>platform_device_add(pdev)
		->>device_add(&pdev->dev)
			->>bus_probe_device(&pdev->dev)
				->>device_attach(&pdev->dev)
					->>bus_for_each_drv(&(pdev->dev)->bus, NULL, &pdev->dev, __device_attach)
						->>__device_attach(drv, &pdev->dev)
							->>driver_probe_device(drv, &pdev->dev)
								->>really_probe(&pdev->dev, drv)
									->>&pdev->dev->bus->probe(dev) 或 drv->probe(dev)
将此过程展开如下:

1. 分配一个platform_device结构并调用platform_device_register函数进行注册

int platform_device_register(struct platform_device *pdev)
{
	device_initialize(&pdev->dev);		// 初始化platform_device的device成员
	arch_setup_pdev_archdata(pdev);
	return platform_device_add(pdev);		// 向内核添加一个平台设备
}

2. 调用platform_device_add函数向内核添加一个平台设备

int platform_device_add(struct platform_device *pdev)
{
	int i, ret;

	if (!pdev)
		return -EINVAL;

	if (!pdev->dev.parent)				//如果pdev->dev.parent为空则将pdev->dev.parent设置为platform_bus
		pdev->dev.parent = &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);		// 向内核添加一个device
	if (ret == 0)
		return ret;

 failed:
	if (pdev->id_auto) {
		ida_simple_remove(&platform_devid_ida, pdev->id);
		pdev->id = PLATFORM_DEVID_AUTO;
	}

	while (--i >= 0) {
		struct resource *r = &pdev->resource[i];
		unsigned long type = resource_type(r);

		if (type == IORESOURCE_MEM || type == IORESOURCE_IO)
			release_resource(r);
	}

 err_out:
	return ret;
}

3. 调用device_add函数向内核添加一个device

int device_add(struct device *dev)
{
	struct device *parent = NULL;
	struct kobject *kobj;
	struct class_interface *class_intf;
	int error = -EINVAL;

	dev = get_device(dev);
	if (!dev)
		goto done;

	if (!dev->p) {
		error = device_private_init(dev);
		if (error)
			goto done;
	}

	/*
	 * for statically allocated devices, which should all be converted
	 * some day, we need to initialize the name. We prevent reading back
	 * the name, and force the use of dev_name()
	 */
	if (dev->init_name) {
		dev_set_name(dev, "%s", dev->init_name);
		dev->init_name = NULL;
	}

	/* subsystems can specify simple device enumeration */
	if (!dev_name(dev) && dev->bus && dev->bus->dev_name)
		dev_set_name(dev, "%s%u", dev->bus->dev_name, dev->id);

	if (!dev_name(dev)) {
		error = -EINVAL;
		goto name_error;
	}

	pr_debug("device: '%s': %s\n", dev_name(dev), __func__);

	parent = get_device(dev->parent);
	kobj = get_device_parent(dev, parent);
	if (kobj)
		dev->kobj.parent = kobj;

	/* use parent numa_node */
	if (parent)
		set_dev_node(dev, dev_to_node(parent));

	/* first, register with generic layer. */
	/* we require the name to be set before, and pass NULL */
	error = kobject_add(&dev->kobj, dev->kobj.parent, NULL);
	if (error)
		goto Error;

	/* notify platform of device entry */
	if (platform_notify)
		platform_notify(dev);

	error = device_create_file(dev, &dev_attr_uevent);
	if (error)
		goto attrError;

	if (MAJOR(dev->devt)) {
		error = device_create_file(dev, &dev_attr_dev);
		if (error)
			goto ueventattrError;

		error = device_create_sys_dev_entry(dev);
		if (error)
			goto devtattrError;

		devtmpfs_create_node(dev);
	}

	error = device_add_class_symlinks(dev);
	if (error)
		goto SymlinkError;
	error = device_add_attrs(dev);
	if (error)
		goto AttrsError;
	error = bus_add_device(dev);
	if (error)
		goto BusError;
	error = dpm_sysfs_add(dev);
	if (error)
		goto DPMError;
	device_pm_add(dev);

	/* Notify clients of device addition.  This call must come
	 * after dpm_sysfs_add() and before kobject_uevent().
	 */
	if (dev->bus)
		blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
					     BUS_NOTIFY_ADD_DEVICE, dev);

	kobject_uevent(&dev->kobj, KOBJ_ADD);
	bus_probe_device(dev);				// 为总线上的设备寻找驱动
	if (parent)
		klist_add_tail(&dev->p->knode_parent,
			       &parent->p->klist_children);

	if (dev->class) {
		mutex_lock(&dev->class->p->mutex);
		/* tie the class to the device */
		klist_add_tail(&dev->knode_class,
			       &dev->class->p->klist_devices);

		/* notify any interfaces that the device is here */
		list_for_each_entry(class_intf,
				    &dev->class->p->interfaces, node)
			if (class_intf->add_dev)
				class_intf->add_dev(dev, class_intf);
		mutex_unlock(&dev->class->p->mutex);
	}
done:
	put_device(dev);
	return error;
 DPMError:
	bus_remove_device(dev);
 BusError:
	device_remove_attrs(dev);
 AttrsError:
	device_remove_class_symlinks(dev);
 SymlinkError:
	if (MAJOR(dev->devt))
		devtmpfs_delete_node(dev);
	if (MAJOR(dev->devt))
		device_remove_sys_dev_entry(dev);
 devtattrError:
	if (MAJOR(dev->devt))
		device_remove_file(dev, &dev_attr_dev);
 ueventattrError:
	device_remove_file(dev, &dev_attr_uevent);
 attrError:
	kobject_uevent(&dev->kobj, KOBJ_REMOVE);
	kobject_del(&dev->kobj);
 Error:
	cleanup_device_parent(dev);
	if (parent)
		put_device(parent);
name_error:
	kfree(dev->p);
	dev->p = NULL;
	goto done;
}

4. 调用bus_probe_device函数为总线上的设备寻找驱动

void bus_probe_device(struct device *dev)
{
	struct bus_type *bus = dev->bus;
	struct subsys_interface *sif;
	int ret;

	if (!bus)
		return;

	if (bus->p->drivers_autoprobe) {
		ret = device_attach(dev);		// 调用device_attach()进行实际的寻找
		WARN_ON(ret < 0);
	}

	mutex_lock(&bus->p->mutex);
	list_for_each_entry(sif, &bus->p->interfaces, node)
		if (sif->add_dev)
			sif->add_dev(dev, sif);
	mutex_unlock(&bus->p->mutex);
}
int device_attach(struct device *dev)
{
	int ret = 0;

	device_lock(dev);
	if (dev->driver) {
		if (klist_node_attached(&dev->p->knode_driver)) {
			ret = 1;
			goto out_unlock;
		}
		ret = device_bind_driver(dev);
		if (ret == 0)
			ret = 1;
		else {
			dev->driver = NULL;
			ret = 0;
		}
	} else {
		ret = bus_for_each_drv(dev->bus, NULL, dev, __device_attach);	// 遍历bus的drv链表为设备寻找驱动
		pm_request_idle(dev);
	}
out_unlock:
	device_unlock(dev);
	return ret;
}

(1) bus_for_each_drv函数源码:

int bus_for_each_drv(struct bus_type *bus, struct device_driver *start,
		     void *data, int (*fn)(struct device_driver *, void *))
{
	struct klist_iter i;
	struct device_driver *drv;
	int error = 0;

	if (!bus)
		return -EINVAL;

	klist_iter_init_node(&bus->p->klist_drivers, &i,
			     start ? &start->p->knode_bus : NULL);
	while ((drv = next_driver(&i)) && !error)	// 遍历整个drv链表
		error = fn(drv, data);			// 寻找该设备匹配的驱动程序,若匹配则将二者绑定
	klist_iter_exit(&i);
	return error;
}

(2)__device_attach函数源码

static int __device_attach(struct device_driver *drv, void *data)
{
	struct device *dev = data;

	if (!driver_match_device(drv, dev))		// 调用bus的match函数对设备和驱动进行匹配,若不匹配driver_match_device函数的返回值为1,则程序立即返回,若匹配则继续向下执行
		return 0;	

	return driver_probe_device(drv, dev);		// 若设备和驱动匹配,则将该驱动程序绑定到该设备
}
static inline int driver_match_device(struct device_driver *drv,
				      struct device *dev)
{
	return drv->bus->match ? drv->bus->match(dev, drv) : 1;
}

5. 调用driver_probe_device将设备与驱动程序进行绑定(调用probe函数)

int driver_probe_device(struct device_driver *drv, struct device *dev)
{
	int ret = 0;

	if (!device_is_registered(dev))
		return -ENODEV;

	pr_debug("bus: '%s': %s: matched device %s with driver %s\n",
		 drv->bus->name, __func__, dev_name(dev), drv->name);

	pm_runtime_barrier(dev);
	ret = really_probe(dev, drv);			// 调用probe
	pm_request_idle(dev);

	return ret;
}
static int really_probe(struct device *dev, struct device_driver *drv)
{
	int ret = 0;
	int local_trigger_count = atomic_read(&deferred_trigger_count);

	atomic_inc(&probe_count);
	pr_debug("bus: '%s': %s: probing driver %s with device %s\n",
		 drv->bus->name, __func__, drv->name, dev_name(dev));
	WARN_ON(!list_empty(&dev->devres_head));

	dev->driver = drv;

	/* If using pinctrl, bind pins now before probing */
	ret = pinctrl_bind_pins(dev);
	if (ret)
		goto probe_failed;

	if (driver_sysfs_add(dev)) {
		printk(KERN_ERR "%s: driver_sysfs_add(%s) failed\n",
			__func__, dev_name(dev));
		goto probe_failed;
	}

	if (dev->bus->probe) {					// 如果设备本身含有probe函数,那么久调用设备的probe函数
		ret = dev->bus->probe(dev);
		if (ret)
			goto probe_failed;
	} else if (drv->probe) {					// 如果设备不含有probe函数,那么就调用驱动程序的probe函数
		ret = drv->probe(dev);
		if (ret)
			goto probe_failed;
	}

	driver_bound(dev);
	ret = 1;
	pr_debug("bus: '%s': %s: bound device %s to driver %s\n",
		 drv->bus->name, __func__, dev_name(dev), drv->name);
	goto done;

probe_failed:
	devres_release_all(dev);
	driver_sysfs_remove(dev);
	dev->driver = NULL;
	dev_set_drvdata(dev, NULL);

	if (ret == -EPROBE_DEFER) {
		/* Driver requested deferred probing */
		dev_info(dev, "Driver %s requests probe deferral\n", drv->name);
		driver_deferred_probe_add(dev);
		/* Did a trigger occur while probing? Need to re-trigger if yes */
		if (local_trigger_count != atomic_read(&deferred_trigger_count))
			driver_deferred_probe_trigger();
	} else if (ret != -ENODEV && ret != -ENXIO) {
		/* driver matched but the probe failed */
		printk(KERN_WARNING
		       "%s: probe of %s failed with error %d\n",
		       drv->name, dev_name(dev), ret);
	} else {
		pr_debug("%s: probe of %s rejects match %d\n",
		       drv->name, dev_name(dev), ret);
	}
	/*
	 * Ignore errors returned by ->probe so that the next driver can try
	 * its luck.
	 */
	ret = 0;
done:
	atomic_dec(&probe_count);
	wake_up(&probe_waitqueue);
	return ret;
}
    到此Linux内核的总线设备驱动模型分析完毕。从上面的分析过程可以看出,所谓的platform_device并不是与字符设备、块设备和网络设备并列的概念,而是Linux系统提供的一种附加手段。


































  • 7
    点赞
  • 52
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
Linux总线设备模型是一种用于管理和操作硬件设备的框架。它提供了一种统一的方式来访问和控制连接到计算机系统上的各种设备,包括串口、USB、PCI、I2C等。 在Linux系统中,每个设备都被视为一个文件,并通过文件路径来访问。总线设备模型定义了设备之间的层次关系和通信机制,使得设备可以被识别、配置和操作。 Linux总线设备模型由以下几个重要组件组成: 1. 设备树(Device Tree):在启动过程中,设备树用于描述连接到系统的各种硬件设备和其相互关系。它是一个以文本方式描述的树状结构,包含了设备的类型、地址、中断等信息。 2. 设备驱动程序(Device Driver):驱动程序是用来控制和管理特定硬件设备的软件模块。每个设备都有相应的驱动程序,它们与设备进行通信,并提供对设备的访问接口。 3. 总线(Bus):总线是连接多个设备的物理或逻辑通道。例如,PCI总线、USB总线等。总线提供了设备之间通信的基础。 4. 设备类(Device Class):设备类是一组具有相似功能的设备的集合。例如,USB设备类包括存储设备、键盘、鼠标等。设备类可以帮助系统区分和管理不同类型的设备。 通过使用总线设备模型Linux系统可以自动检测和配置连接到系统的设备,使其能够正常工作。同时,开发者也可以编写自定义的驱动程序来支持新的硬件设备总线设备模型的设计使得设备的添加、删除和管理变得更加灵活和可扩展。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值