首页 > 学院 > 开发设计 > 正文

Linux总线、设备、驱动模型

2019-11-06 07:28:06
字体:
来源:转载
供稿:网友
内核: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系统提供的一种附加手段。


发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表