设备 和 驱动 如何自动匹配,并调用我们驱动开发者自己实现的probe函数?

linux中 驱动框架由三部分实现:总线,驱动,设备。
驱动和 设备是两个分离的链表,分别挂载总线上。

那么驱动和设备是如何匹配后,并调用我们自己书写的驱动文件中的probe函数,从而开启驱动的其妙旅行??

当我们向内核中注册一个驱动时,会直接或间接的调用driver_resgister()来注册驱动。
设备和驱动的匹配过程 和 调用probe函数就在这里进行。

大致流程如下:

driver_register(drv)
	bus_add_driver(drv)
		driver_attach(drv)
			__driver_attach(dev,data)
				driver_match_device(drv, dev)	//调用bus->match函数匹配设备与驱动
				driver_probe_device(drv, dev)	//匹配成功,调用probe()
					really_probe(dev, drv){		//drivers/base/dd.c
							...
							if (dev->bus->probe) {
								ret = dev->bus->probe(dev);		//优先调用bus->probe
								if (ret)
									goto probe_failed;
							} else if (drv->probe) {			//其次调用drv->probe
								ret = drv->probe(dev);
								if (ret)
									goto probe_failed;
							}
							...
							}

当我们直接或间接调用 device_add()向内核添加设备时,也会触发 设备与驱动的匹配,并调用probe()函数。
大致流程如下:

device_add(dev)
	bus_probe_device(dev)
		device_initial_probe(dev)
			__device_attach(dev, true)
				__device_attach_driver(drv,data)
					driver_match_device(drv, dev)	//调用bus->match函数匹配设备与驱动
					driver_probe_device(drv, dev)	//匹配成功,调用probe()
						really_probe(dev, drv){		//drivers/base/dd.c
							...
							if (dev->bus->probe) {
								ret = dev->bus->probe(dev);		//优先调用bus->probe
								if (ret)
									goto probe_failed;
							} else if (drv->probe) {			//其次调用drv->probe
								ret = drv->probe(dev);
								if (ret)
									goto probe_failed;
							}
							...
							}

当我们调用driver_resgister()时,它的整个过程代码如下:

1. driver_register(drv)

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);					//向总线中添加新的驱动,这里进行了设备和驱动的匹配,并调用了probe.		
	if (ret)
		return ret;
	ret = driver_add_groups(drv, drv->groups);	//在/sys/class系统下添加属性文件,指定特殊功能。
	if (ret) {
		bus_remove_driver(drv);
		return ret;
	}
	kobject_uevent(&drv->p->kobj, KOBJ_ADD);	//kobject 是sys文件系统中,一个文件的表示

	return ret;
}
EXPORT_SYMBOL_GPL(driver_register);

2. bus_add_driver(drv)

/**
 * bus_add_driver - Add a driver to the bus.
 * @drv: 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);
	if (!priv) {
		error = -ENOMEM;
		goto out_put_bus;
	}
	klist_init(&priv->klist_devices, NULL, NULL);		//klist一个比list更安全的内核级的双向链表。
	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);
	if (error)
		goto out_unregister;

	klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers);		//将驱动对应的klist节点添加到klist链表的末尾。
	if (drv->bus->p->drivers_autoprobe) {				//在我们注册总线bus_register()中,将值置为1.
		if (driver_allows_async_probing(drv)) {			//主要是判断drv->probe_type,当然我们并没有给他赋值。
			pr_debug("bus: '%s': probing driver %s asynchronously\n",
				drv->bus->name, drv->name);
			async_schedule(driver_attach_async, drv);
		} else {										//走这里
			error = driver_attach(drv);					//这里进行设备和驱动的匹配,并调用probe().
			if (error)
				goto out_unregister;
		}
	}
	module_add_driver(drv->owner, drv);					//module模块的添加。

	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;


}

3. driver_attach(drv)

/**
 * driver_attach - try to bind driver to devices.  尝试绑定 driver到总线的设备链表中。
 * @drv: driver.
 *
 * Walk the list of devices that the bus has on it and try to
 * match the driver with each one.  If driver_probe_device()
 * returns 0 and the @dev->driver is set, we've found a
 * compatible pair.
 */
int driver_attach(struct device_driver *drv)
{
	return bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);		//__driver_attach
}
EXPORT_SYMBOL_GPL(driver_attach);

/* 
 * bus_for_each_dev - device iterator.  设备迭代器
 * @bus: bus type.
 * @start: device to start iterating from.
 * @data: data for the callback.
 * @fn: function to be called for each device.
 * 遍历 总线上的 设备链表,并将每一个设备作为参数,执行fn().
 * 总线中的设备链表 是klist 双向链表。
 */
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,	//klist链表和list链表还有不一样的地方。比如循环遍历
			     (start ? &start->p->knode_bus : NULL));
	while ((dev = next_device(&i)) && !error)			//循环取出总线上的设备链表
		error = fn(dev, data);							//循环执行fn(),也就是__driver_attach().
	klist_iter_exit(&i);								//这个和上面的遍历是一组
	return error;
}
EXPORT_SYMBOL_GPL(bus_for_each_dev);

4. __driver_attach(dev,data)

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()进行设备和驱动的匹配。
		return 0;							//匹配失败,直接返回,不在调用probe()函数。

	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;
}
/* 调用bus-match()进行设备和驱动的匹配。 */
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(drv, dev)

/**
 * driver_probe_device - attempt to bind device & driver together
 * @drv: driver to bind a device to
 * @dev: device to try to bind to the driver
 *
 * This function returns -ENODEV if the device is not registered,
 * 1 if the device is bound successfully and 0 otherwise.
 *
 * This function must be called with @dev lock held.  When called for a
 * USB interface, @dev->parent lock must be held as well.
 *
 * If the device has a parent, runtime-resume the parent before driver probing.
 */
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);

	if (dev->parent)
		pm_runtime_get_sync(dev->parent);	//电源管理

	pm_runtime_barrier(dev);
	ret = really_probe(dev, drv);			//这里调用了bus->probe/drv->probe. 也就是驱动开发者提供的probe().
	pm_request_idle(dev);

	if (dev->parent)
		pm_runtime_put(dev->parent);

	return ret;
}

6. really_probe(dev, drv)

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);		//如果驱动或设备中还指定了某些pins引脚,而且指定了当前的工作状态,则将它设置为需要的工作状态。
	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->pm_domain && dev->pm_domain->activate) {	//如果指定了电源电压域,并提供了这些激活函数。
		ret = dev->pm_domain->activate(dev);	//相应电源电压域激活
		if (ret)
			goto probe_failed;
	}

	if (dev->bus->probe) {				//优先判断使用bus->probe()函数。
		ret = dev->bus->probe(dev);		//bus->probe()的内部其实最总也是调转到驱动开发者提供的probe()函数中。如果是我们自己实现的总线,记得实现这个跳转。
		if (ret)
			goto probe_failed;
	} else if (drv->probe) {			//其次判断使用drv->probe()函数。
		ret = drv->probe(dev);			//drv->probe()函数的一个重要任务就是跳转到驱动开发者提供的probe()函数中。
		if (ret)
			goto probe_failed;
	}

	/*
	当前工作就是执行probe().当执行完毕,就需要将pins状态,再设置为默认的“default”工作状态
	这里和 pinctrl_bind_pins(dev) 正好相反。 
	pins的工作状态 就像资源,比较紧缺,不用时,需要返回原来的状态。
	这里的工作状态,在设备树中指定,例如:
	pinctrl-names = "default", "gpio"; 
	pinctrl-0 = <&i2c4_xfer>; 
	pinctrl-1 = <&i2c4_gpio>;   
	*/
	pinctrl_init_done(dev);				

	if (dev->pm_domain && dev->pm_domain->sync)
		dev->pm_domain->sync(dev);		//同步更新电源电压域。

	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 (dev->pm_domain && dev->pm_domain->dismiss)
		dev->pm_domain->dismiss(dev);

	switch (ret) {
	case -EPROBE_DEFER:
		/* Driver requested deferred probing */
		dev_dbg(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();
		break;
	case -ENODEV:
	case -ENXIO:
		pr_debug("%s: probe of %s rejects match %d\n",
			 drv->name, dev_name(dev), ret);
		break;
	default:
		/* driver matched but the probe failed */
		printk(KERN_WARNING
		       "%s: probe of %s failed with error %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().
举例:

(以spidev.c 为例)
(1)spi驱动核心spi.c中,如下指定和设置spi总线:
	struct bus_type spi_bus_type = {
		.name		= "spi",
		.dev_groups	= spi_dev_groups,
		.match		= spi_match_device,		//spi总线指定的设备和驱动的匹配方法。
		.uevent		= spi_uevent,
	};
	/* spi总线指定的设备和驱动的匹配方法。
		匹配优先级:设备树匹配, acpi匹配,设备ID表匹配。
	 */
	static int spi_match_device(struct device *dev, struct device_driver *drv)
	{
		const struct spi_device	*spi = to_spi_device(dev);
		const struct spi_driver	*sdrv = to_spi_driver(drv);
	
		/* Attempt an OF style match */
		if (of_driver_match_device(dev, drv))   //设备树的匹配方法。
			return 1;
	
		/* Then try ACPI */
		if (acpi_driver_match_device(dev, drv))	//apci的匹配方法。
			return 1;
	
		if (sdrv->id_table)
			return !!spi_match_id(sdrv->id_table, spi);	//设备ID表的匹配方法。
	
		return strcmp(spi->modalias, drv->name) == 0;
	}2)spi驱动框架核心spi.c提供的驱动注册:
	int __spi_register_driver(struct module *owner, struct spi_driver *sdrv)
	{
		sdrv->driver.owner = owner;
		sdrv->driver.bus = &spi_bus_type;			//spi总线,这里指定了驱动和设备的匹配方式。
		if (sdrv->probe)
			sdrv->driver.probe = spi_drv_probe;		//这里函数中指定调用spi_driver提供的probe函数。也就是驱动开发者提供的probe().
		if (sdrv->remove)
			sdrv->driver.remove = spi_drv_remove;	//指定调用,spi_driver提供的remove函数。
		if (sdrv->shutdown)
			sdrv->driver.shutdown = spi_drv_shutdown;	//指定嗲用 spi_driver提供的shutdown函数。
		return driver_register(&sdrv->driver);		//这里会进行驱动和设备的匹配,并调用sdrv->driver.probe,最总调用到驱动开发者提供的probe: spi_driver->probe().
	}
	EXPORT_SYMBOL_GPL(__spi_register_driver);

	这里以sdrv->driver.probe = spi_drv_probe举例:
	static int spi_drv_probe(struct device *dev)
	{
		const struct spi_driver		*sdrv = to_spi_driver(dev->driver);
		struct spi_device		*spi = to_spi_device(dev);
		int ret;
	
		ret = of_clk_set_defaults(dev->of_node, false);			//不设置时钟。
		if (ret)
			return ret;
	
		if (dev->of_node) {
			spi->irq = of_irq_get(dev->of_node, 0);				//获取中断号。
			if (spi->irq == -EPROBE_DEFER)
				return -EPROBE_DEFER;
			if (spi->irq < 0)
				spi->irq = 0;
		}
	
		/* 电源管理操作 */
		ret = dev_pm_domain_attach(dev, true);
		if (ret != -EPROBE_DEFER) {
			ret = sdrv->probe(spi);								//执行外围提供的probe函数。及spi_driver->probe(),也就是驱动开发者提供的probe().
			if (ret)
				dev_pm_domain_detach(dev, true);
		}
	
		return ret;
	}3)spidev.c 从设备驱动的驱动文件:
	static int __init spidev_init(void)
	{
		int status;
	
		/* Claim our 256 reserved device numbers.  Then register a class
		 * that will key udev/mdev to add/remove /dev nodes.  Last, register
		 * the driver which manages those device numbers.
		 */
		BUILD_BUG_ON(N_SPI_MINORS > 256);
		status = register_chrdev(SPIDEV_MAJOR, "spi", &spidev_fops);		//使用老的字符设备接口注册字符设备。
		if (status < 0)
			return status;
	
		spidev_class = class_create(THIS_MODULE, "spidev");				//创建设备类,并在/sys/class下多出spidev目录。
		if (IS_ERR(spidev_class)) {
			unregister_chrdev(SPIDEV_MAJOR, spidev_spi_driver.driver.name);
			return PTR_ERR(spidev_class);
		}
	
		/*
			以上并没有触发udev/mdev在/dev目录下,创建设备节点。
			还需要调用device_add() 才可以在/dev目录下创建设备节点。
			spidev_spi_driver->probe()函数中调用device_add().
			spi_register_driver()调用driver_register()从而触发设备和驱动的匹配,
			并最终调用到了spidev_spi_driver->probe()函数。
		*/
	
		status = spi_register_driver(&spidev_spi_driver);		//从设备需要注册驱动。
		if (status < 0) {
			class_destroy(spidev_class);
			unregister_chrdev(SPIDEV_MAJOR, spidev_spi_driver.driver.name);
		}
		return status;
	}
	module_init(spidev_init);		//内核在启动中会自动执行内核中的0~7s端中的驱动出初始化,其中就包含module_init()指定的驱动初始化

整个spi中执行probe的顺序如下:


module_init(spidev_init);
	spidev_init(void)
		spi_register_driver(&spidev_spi_driver)
			driver_register(&sdrv->driver){
				driver_register()内部如何进行设备和驱动的匹配,并调用probe()在此省略,
				详细请看上面的介绍。
			}
				。。。
				really_probe(){
					。。。
					if (dev->bus->probe) {				//spi驱动框架中没有提供这个。
						ret = dev->bus->probe(dev);		
						if (ret)
							goto probe_failed;
					} else if (drv->probe) {			//spi驱动框架中提供了这个:sdrv->driver.probe = spi_drv_probe;	
						ret = drv->probe(dev);
						if (ret)
							goto probe_failed;
					}
					。。。
					}
						spi_drv_probe()
							sdrv->probe(spi)
								spi_driver->probe()  //这个就是spidev.c中驱动开发者提供的probe()函数。

当我们调用device_add(dev)时,它的整个过程的代码如下:

1. device_add(dev)

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

	dev = get_device(dev);		//引用计数加1.
	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);	    //该设备的父设备对应的kobject的相关操作。
	if (IS_ERR(kobj)) {
		error = PTR_ERR(kobj);
		goto parent_error;
	}
	if (kobj)
		dev->kobj.parent = kobj;

	/* use parent numa_node */
	if (parent && (dev_to_node(dev) == NUMA_NO_NODE))
		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);	//sys文件系统中kobject的添加,将当前设备对应的kobject和父设备对应的kobject进行连接。 kobject在sys文件系统中表示一个文件。
	if (error) {
		glue_dir = get_glue_dir(dev);
		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;

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

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

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

		devtmpfs_create_node(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);		//这里进行设备和总线的驱动链表中的驱动进行匹配,并最总调用对应驱动的probe函数。
	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);
	}
	。。。
	
}
EXPORT_SYMBOL_GPL(device_add);

2. bus_probe_device(dev)

/**
 * bus_probe_device - probe drivers for a new device
 * @dev: device to probe
 *
 * - Automatically probe for a driver if the bus allows it.
 */
void bus_probe_device(struct device *dev)
{
	struct bus_type *bus = dev->bus;
	struct subsys_interface *sif;

	if (!bus)
		return;

	if (bus->p->drivers_autoprobe)	//在调用bus_register()时,被置为1. (注册总线时)
		device_initial_probe(dev);	//这里进行了驱动和设备的匹配,并调用匹配驱动的probe()函数。

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

3. device_initial_probe(dev)

void device_initial_probe(struct device *dev)
{
	__device_attach(dev, true);	
}

4. __device_attach(dev, true)

static int __device_attach(struct device *dev, bool allow_async)
{
	int ret = 0;

	device_lock(dev);
	/*
	一般我们在添加设备时,不会指定它对应的驱动。所以这里一般是false.
	当然有的设备会指定,那么一旦指定,则直接进行设备和驱动的绑定就可以
	device_bind_driver()其内部也会调用到probe函数。
	*/
	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 {			//通常我们都会走这里,因为我们一般不给设备制定驱动,这样更灵活。
		struct device_attach_data data = {
			.dev = dev,
			.check_async = allow_async,
			.want_async = false,
		};

		if (dev->parent)
			pm_runtime_get_sync(dev->parent);
		/* 
 			遍历总线上的 驱动链表,并将每个驱动作为参数 传递给__device_attach_driver()函数。
 			__device_attach_driver()函数中进行设备和驱动的匹配,并最终调用驱动的probe函数。
 		 */
		ret = bus_for_each_drv(dev->bus, NULL, &data,
					__device_attach_driver);
		if (!ret && allow_async && data.have_async) {
			/*
			 * If we could not find appropriate driver
			 * synchronously and we are allowed to do
			 * async probes and there are drivers that
			 * want to probe asynchronously, we'll
			 * try them.
			 */
			dev_dbg(dev, "scheduling asynchronous probe\n");
			get_device(dev);
			async_schedule(__device_attach_async_helper, dev);
		} else {
			pm_request_idle(dev);
		}

		if (dev->parent)
			pm_runtime_put(dev->parent);
	}
out_unlock:
	device_unlock(dev);
	return ret;
}

/* 
	遍历总线上的 驱动链表,并将每个驱动作为参数 传递给__device_attach_driver()函数。
	__device_attach_driver()函数中进行设备和驱动的匹配,并最终调用驱动的probe函数。
 */
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双向链表和list链操作有所不同,比如:遍历:
	klist遍历,需要三个函数/宏配合:
		1.klist_iter_init_node
		2.next_driver
		3.klist_iter_exit
	*/
	klist_iter_init_node(&bus->p->klist_drivers, &i,
			     start ? &start->p->knode_bus : NULL);
	while ((drv = next_driver(&i)) && !error)
		error = fn(drv, data);			//每一个获取的驱动,都执行fn()函数。
	klist_iter_exit(&i);
	return error;
}
EXPORT_SYMBOL_GPL(bus_for_each_drv);

5. __device_attach_driver(drv,data)

static int __device_attach_driver(struct device_driver *drv, void *_data)
{
	struct device_attach_data *data = _data;
	struct device *dev = data->dev;
	bool async_allowed;

	/*
	 * Check if device has already been claimed. This may
	 * happen with driver loading, device discovery/registration,
	 * and deferred probe processing happens all at once with
	 * multiple threads.
	 */
	if (dev->driver)
		return -EBUSY;

	if (!driver_match_device(drv, dev))			//查看设备与驱动是否匹配,调用 总线的match函数。
		return 0;

	async_allowed = driver_allows_async_probing(drv);

	if (async_allowed)
		data->have_async = true;

	if (data->check_async && async_allowed != data->want_async)
		return 0;

	return driver_probe_device(drv, dev);		//这里调用驱动开发者的probe函数。
}

6. driver_probe_device(drv, dev)

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

	if (dev->parent)
		pm_runtime_get_sync(dev->parent);

	pm_runtime_barrier(dev);
	ret = really_probe(dev, drv);		//这里调用了驱动开发者提供的probe().
	pm_request_idle(dev);

	if (dev->parent)
		pm_runtime_put(dev->parent);

	return ret;
}

7. really_probe(dev, drv)

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);		//如果驱动或设备中还指定了某些pins引脚,而且指定了当前的工作状态,则将它设置为需要的工作状态。
	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->pm_domain && dev->pm_domain->activate) {	//如果指定了电源电压域,并提供了这些激活函数。
		ret = dev->pm_domain->activate(dev);	//相应电源电压域激活
		if (ret)
			goto probe_failed;
	}

	if (dev->bus->probe) {				//优先判断使用bus->probe()函数。
		ret = dev->bus->probe(dev);		//bus->probe()的内部其实最总也是调转到驱动开发者提供的probe()函数中。如果是我们自己实现的总线,记得实现这个跳转。
		if (ret)
			goto probe_failed;
	} else if (drv->probe) {			//其次判断使用drv->probe()函数。
		ret = drv->probe(dev);			//drv->probe()函数的一个重要任务就是跳转到驱动开发者提供的probe()函数中。
		if (ret)
			goto probe_failed;
	}

	/*
	当前工作就是执行probe().当执行完毕,就需要将pins状态,再设置为默认的“default”工作状态
	这里和 pinctrl_bind_pins(dev) 正好相反。 
	pins的工作状态 就像资源,比较紧缺,不用时,需要返回原来的状态。
	这里的工作状态,在设备树中指定,例如:
	pinctrl-names = "default", "gpio"; 
	pinctrl-0 = <&i2c4_xfer>; 
	pinctrl-1 = <&i2c4_gpio>;   
	*/
	pinctrl_init_done(dev);				

	if (dev->pm_domain && dev->pm_domain->sync)
		dev->pm_domain->sync(dev);		//同步更新电源电压域。

	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 (dev->pm_domain && dev->pm_domain->dismiss)
		dev->pm_domain->dismiss(dev);

	switch (ret) {
	case -EPROBE_DEFER:
		/* Driver requested deferred probing */
		dev_dbg(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();
		break;
	case -ENODEV:
	case -ENXIO:
		pr_debug("%s: probe of %s rejects match %d\n",
			 drv->name, dev_name(dev), ret);
		break;
	default:
		/* driver matched but the probe failed */
		printk(KERN_WARNING
		       "%s: probe of %s failed with error %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().

我们一般通过如下函数来调用device_add():

device_create()
	device_create_vargs()
		device_create_groups_vargs()
			device_initialize(dev)
			device_add(dev)

有的,则直接使用device_initialize(dev)device_add(dev)来进行设备注册。
  • 4
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring4GWT GWT Spring 使得在 Spring 框架下构造 GWT 应用变得很简单,提供一个易于理解的依赖注入和RPC机制。 Java扫雷游戏 JVMine JVMine用Applets开发的扫雷游戏,可在线玩。 public class JVMine extends java.applet.Applet 简单实现!~ 网页表格组件 GWT Advanced Table GWT Advanced Table 是一个基于 GWT 框架的网页表格组件,可实现分页数据显示、数据排序和过滤等功能! Google Tag Library 该标记库和 Google 有关。使用该标记库,利用 Google 为你的网站提供网站查询,并且可以直接在你的网页里面显示搜查的结果。 github-java-api github-java-api 是 Github 网站 API 的 Java 语言版本。 java缓存工具 SimpleCache SimpleCache 是一个简单易用的java缓存工具,用来简化缓存代码的编写,让你摆脱单调乏味的重复工作!1. 完全透明的缓存支持,对业务代码零侵入 2. 支持使用Redis和Memcached作为后端缓存。3. 支持缓存数据分区规则的定义 4. 使用redis作缓存时,支持list类型的高级数据结构,更适合论坛帖子列表这种类型的数据 5. 支持混合使用redis缓存和memcached缓存。可以将列表数据缓存到redis中,其他kv结构数据继续缓存到memcached 6. 支持redis的主从集群,可以做读写分离。缓存读取自redis的slave节点,写入到redis的master节点。 Java对象的SQL接口 JoSQL JoSQL(SQLforJavaObjects)为Java开发者提供运用SQL语句来操作Java对象集的能力.利用JoSQL可以像操作数据库中的数据一样对任何Java对象集进行查询,排序,分组。 搜索自动提示 Autotips AutoTips是为解决应用系统对于【自动提示】的需要(如:Google搜索), 而开发的架构无关的公共控件, 以满足该类需求可以通过快速配置来开发。AutoTips基于搜索引擎Apache Lucene实现。AutoTips提供统一UI。 WAP浏览器 j2wap j2wap 是一个基于Java的WAP浏览器,目前处于BETA测试阶段。它支持WAP 1.2规范,除了WTLS 和WBMP。 Java注册表操作类 jared jared是一个用来操作Windows注册表的 Java 类库,你可以用来对注册表信息进行读写。 GIF动画制作工具 GiftedMotion GiftedMotion是一个很小的,免费而且易于使用图像互换格式动画是能够设计一个有趣的动画了一系列的数字图像。使用简便和直截了当,用户只需要加载的图片和调整帧您想要的,如位置,时间显示和处理方法前帧。 Java的PList类库 Blister Blister是一个用于操作苹果二进制PList文件格式的Java开源类库(可用于发送数据给iOS应用程序)。 重复文件检查工具 FindDup.tar FindDup 是一个简单易用的工具,用来检查计算机上重复的文件。 OpenID的Java客户端 JOpenID JOpenID是一个轻量级的OpenID 2.0 Java客户端,仅50KB+(含源代码),允许任何Web网站通过OpenID支持用户直接登录而无需注册,例如Google Account或Yahoo Account。 JActor的文件持久化组件 JFile JFile 是 JActor 的文件持久化组件,以及一个高吞吐量的可靠事务日志组件。 Google地图JSP标签库 利用Google:maps JSP标签库就能够在你的Web站点上实现GoogleMaps的所有功能而且不需要javascript或AJAX编程。它还能够与JSTL相结合生成数据库驱动的动态Maps。 OAuth 实现框架 Agorava Agorava 是一个实现了 OAuth 1.0a 和 OAuth 2.0 的框架,提供了简单的方式通过社交媒体进行身份认证的功能。 Eclipse的JavaScript插件 JSEditor JSEditor 是 Eclipse 下编辑 JavaScript 源码的插件,提供语法高亮以及一些通用的面向对象方法。 Java数据库连接池 BoneCP BoneCP 是一个高性能的开源java数据库连接池实现库。它的设计初衷就是为了提高数据库连接池的性能,根据某些测试数据发现,BoneCP是最快的连接池。BoneCP很小,只有四十几K

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值