linux设备模型七(device_driver细节)

阅读这篇之前,建议先阅读我的下面这篇博客了解device_driver的数据结构和大概作用。

https://blog.csdn.net/qq_16777851/article/details/81429257

了解我的下面这篇博客可以对device部分了解清晰。同时,下面用到了device中相同的接口分析,也会略过。

https://blog.csdn.net/qq_16777851/article/details/81437352

1.driver的注册过程


/**
 * driver_register - register driver with bus
 * @drv: driver to register
 *
 * We pass off most of the work to the bus_add_driver() call,
 * since most of the things we have to do deal with the bus
 * structures.
 */
int driver_register(struct device_driver *drv)
{
	int ret;
	struct device_driver *other;

	BUG_ON(!drv->bus->p);    /* driver的总线必须要有自己的subsys,因为这个才是整个bus连接device和driver的核心 */

    /* driver和bus两种都实现了下面函数,而实际最只能执行一个,所以告警说重复 */
	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) {
		put_driver(other);
		printk(KERN_ERR "Error: Driver '%s' is already registered, "
			"aborting...\n", drv->name);
		return -EBUSY;
	}
    
    /* 把驱动加入总线的驱动链表 */
	ret = bus_add_driver(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;
}

1.1 查找总线bus下的driver链表有没有名为name的driver


/**
 * driver_find - locate driver on a bus by its name.
 * @name: name of the driver.
 * @bus: bus to scan for the driver.
 *
 * Call kset_find_obj() to iterate over list of drivers on
 * a bus to find driver by name. Return driver if found.
 *
 * This routine provides no locking to prevent the driver it returns
 * from being unregistered or unloaded while the caller is using it.
 * The caller is responsible for preventing this.
 */
struct device_driver *driver_find(const char *name, struct bus_type *bus)
{
	struct kobject *k = kset_find_obj(bus->p->drivers_kset, name);    /* 在bus所管理的driver链表中,查找有没有name这个driver */
	struct driver_private *priv;

	if (k) {
		/* Drop reference added by kset_find_obj() */
		kobject_put(k);             /* 把该driver的kobject引用计数减1,kset_find_obj函数对其+1了 */
		priv = to_driver(k);        /* 通过driver里面的kobject返回driver */
		return priv->driver;
	}
	return NULL;
}

1.1.1  遍历kset的kobject链表中有没有名为name的kobject


/**
 * kset_find_obj - search for object in kset.
 * @kset: kset we're looking in.
 * @name: object's name.
 *
 * Lock kset via @kset->subsys, and iterate over @kset->list,
 * looking for a matching kobject. If matching object is found
 * take a reference and return the object.
 */
struct kobject *kset_find_obj(struct kset *kset, const char *name)
{
	struct kobject *k;
	struct kobject *ret = NULL;

	spin_lock(&kset->list_lock);
    /* 查找方法很简单,依次遍历bus的driver链表每个driver的kobject的name,如果有相同的返回对应的kobject */
	list_for_each_entry(k, &kset->list, entry) {    
		if (kobject_name(k) && !strcmp(kobject_name(k), name)) {
			ret = kobject_get(k);    /* 记住,找到的话,这里对其引用计数+1了 */
			break;
		}
	}
	spin_unlock(&kset->list_lock);
	return ret;
}

上面步骤很简单,我在网上找到了一个图,可以更形象的描述上面的过程

1.2 把driver放入bus的driver链表中去


/**
 * 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);        /* 得到bus */
	if (!bus)
		return -EINVAL;

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

        /* bus有自己的private,device有自己的private,driver也必须有自己的啊,他们的功能就是负责连接对方 */
	priv = kzalloc(sizeof(*priv), GFP_KERNEL);    
	if (!priv) {
		error = -ENOMEM;
		goto out_put_bus;
	}
    /* 初始化klist,以及填充dricer的private里面的内容 */
	klist_init(&priv->klist_devices, NULL, NULL);
	priv->driver = drv;
	drv->p = priv;
	priv->kobj.kset = bus->p->drivers_kset;        /* driver绑定bus(通过各自里面的privte) */
	error = kobject_init_and_add(&priv->kobj, &driver_ktype, NULL,
				     "%s", drv->name);
	if (error)
		goto out_unregister;
    
    /* 把driver在bus的节点,加入到bus的driver链表的最后一个 */
	klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers);

    /* 前面算是已经把driver注册到对应的bus里面了 */
    
    /* 默认所有的bus都是开启autoprobe的,除非应用层给写0,关闭了 */
	if (drv->bus->p->drivers_autoprobe) {  
		if (driver_allows_async_probing(drv)) {    /* 查看driver的probe_type支不支持异步匹配 */
			pr_debug("bus: '%s': probing driver %s asynchronously\n",
				drv->bus->name, drv->name);
			async_schedule(driver_attach_async, drv);    /* 支持异步匹配,则重开一个线程,执行driver_attach_async函数,在那个线程中执行匹配 */
		} else {
			error = driver_attach(drv);        /* 不支持异步匹配,则直接在这个函数中匹配 */
			if (error)
				goto out_unregister;
		}
	}
	module_add_driver(drv->owner, drv);

	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);
	/* drv->p is freed in driver_release()  */
	drv->p = NULL;
out_put_bus:
	bus_put(bus);
	return error;
}

1.2.1 可以看一下下面的,异步匹配和同步匹配是完全一样的代码,只不过异步匹配是多开一个线程(多核cpu有效),在里面指行匹配(这样可以不影响本cpu的效率,因为一般同一个bus上的device还是很多的,一个一个匹配要很久的。)

static void driver_attach_async(void *_drv, async_cookie_t cookie)
{
	struct device_driver *drv = _drv;
	int ret;

	ret = driver_attach(drv);

	pr_debug("bus: '%s': driver %s async attach completed: %d\n",
		 drv->bus->name, drv->name, ret);
}

1.2.2 通过driver匹配同一bus上的device

/**
 * driver_attach - try to bind driver to devices.
 * @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);
}

1.2.2.1 给出匹配函数,driver匹配同一总线下的device。注意对比上篇的bus_for_each_drv,比较异同。


/**
 * 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.
 *
 * Iterate over @bus's list of devices, and call @fn for each,
 * passing it @data. If @start is not NULL, we use that device to
 * begin iterating from.
 *
 * We check the return of @fn each time. If it returns anything
 * other than 0, we break out and return that value.
 *
 * NOTE: The device that returns a non-zero value is not retained
 * in any way, nor is its refcount incremented. If the caller needs
 * to retain this data, it should do so, and increment the reference
 * count in the supplied callback.
 */
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;

     /* 把总线上的device链表的头节点给i(注意头节点是不带有效信息的) */
	klist_iter_init_node(&bus->p->klist_devices, &i,
			     (start ? &start->p->knode_bus : NULL));
	while ((dev = next_device(&i)) && !error)    /* 从第一个device开始,调用fn函数,匹配driver和device */
		error = fn(dev, data);
	klist_iter_exit(&i);        /* 结束使用klist */
	return error;
}

注意:一个驱动可能匹配到多个device,所以上面的匹配除非发生错误,否则就要匹配整个链表的device.

1.2.2.2 drivace匹配device函数,对比上篇的__device_attach_driver函数,结构个功能都是一样的。

static inline int driver_match_device(struct device_driver *drv,
				      struct device *dev)
{
    /* 调用bus的match函数匹配,bus的match函数不存在,则返回1 */
	return drv->bus->match ? drv->bus->match(dev, drv) : 1;
}

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

	/*
	 * 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.
	 */

	ret = driver_match_device(drv, dev);    /* 在本函数上面,使用bus的match函数匹配 */
	if (ret == 0) {                                             /* 为0,没匹配到 */
		/* no match */
		return 0;
	} else if (ret == -EPROBE_DEFER) {
		dev_dbg(dev, "Device match requests probe deferral\n");
		driver_deferred_probe_add(dev);                         /* 重新匹配 */
	} else if (ret < 0) {
		dev_dbg(dev, "Bus failed to match device: %d", ret);    /* 总线错误 */
		return ret;    
	} /* ret > 0 means positive match */                        /* 大于0,标明正在匹配(配上了,但还有一些操作要执行) */


    /* 到这里以及匹配到了,接下来就是要真正连接device和driver,以及执行probe函数了 */


	if (dev->parent)	/* Needed for USB */
		device_lock(dev->parent);        /* 设备的parent锁定,不能执行睡眠,卸载之类的操作,否则下面driver_probe_device函数如果匹配上指行probe函数,就没parent了 */
	device_lock(dev);   /* 要用device了,device肯定不能出乱子啊,否则删除了,这里的device接下来的操作就成野指针了 */
	if (!dev->driver)   /* 该device没driver,执行下句函数-----device有driver,还能匹配再到一个driver也是神了 */
		driver_probe_device(drv, dev);    /* 绑定device和driver,调用probe函数, */
	device_unlock(dev);   /* 注册好后,device就可以随意了 */
	if (dev->parent)
		device_unlock(dev->parent);    /*  */

	return 0;
}

1.2.2.3 device和driver绑定,并指向probe函数

我的上一篇博客的后面有分析到,这里就不重复了。

https://blog.csdn.net/qq_16777851/article/details/81437352

总结:

1.为什么device匹配一次driver,又driver匹配一次divice?

比如:先注册的device,device在初始化的时候也绑定了bus,之后就可以主动联系自己所属bus,进一步可以通过自己所属的bus的private找到bus的driver链表,,逐个匹配同一bus上的driver。(这里我们举例是先注册的drvice,所以肯定匹配不到)

接下来注册driver,如driver,初始化的时候也绑定了bus,之后就主动联系自己所属bus,进一步可以通过自己所属的bus的private找到bus的device链表,逐个匹配同一bus上的driver。(上面device已经先于driver注册,这次肯定可以匹配到)

相反:先注册driver(driver匹配不到device),后注册device(也能匹配到driver)。

这就是为什么要即在device注册的时候匹配driver,又要在driver注册的时候匹配device的原因,因为不能确定到底驱动工程师是先注册driver还是先注册device。

2. bus有自己的subsys_private ,device有自己的device_private ,driver也有自己的driver_private,他们的功能就是负责连接对方。(下面我放出来了他们的数据结构,可以看一下,他们之间是通过klist_node 强化版的链表,互相连接起来的)

struct driver_private {
	struct kobject kobj;
	struct klist klist_devices;        /* 一个driver可以支持多个device,所以这里用链表连接它所支持的device */
	struct klist_node knode_bus;       /* bus下所有driver组成一个链表,表头是bus的klist_drivers */
	struct module_kobject *mkobj;
	struct device_driver *driver;
};

/**
 * struct device_private - structure to hold the private to the driver core portions of the device structure.
 *
 * @klist_children - klist containing all children of this device
 * @knode_parent - node in sibling list
 * @knode_driver - node in driver list
 * @knode_bus - node in bus list
 * @deferred_probe - entry in deferred_probe_list which is used to retry the
 *	binding of drivers which were unable to get all the resources needed by
 *	the device; typically because it depends on another driver getting
 *	probed first.
 * @device - pointer back to the struct device that this structure is
 * associated with.
 *
 * Nothing outside of the driver core should ever touch these fields.
 */
struct device_private {
	struct klist klist_children;
	struct klist_node knode_parent;
	struct klist_node knode_driver;    /*  一个driver可以支持多个device,该device就是靠这个节点加入到匹配到的driver的链表的 */
	struct klist_node knode_bus;       /* bus下所有device组成一个链表,表头是bus的klist_devices */
	struct list_head deferred_probe;
	struct device *device;
};



/**
 * struct subsys_private - structure to hold the private to the driver core portions of the bus_type/class structure.
 *
 * @subsys - the struct kset that defines this subsystem
 * @devices_kset - the subsystem's 'devices' directory
 * @interfaces - list of subsystem interfaces associated
 * @mutex - protect the devices, and interfaces lists.
 *
 * @drivers_kset - the list of drivers associated
 * @klist_devices - the klist to iterate over the @devices_kset
 * @klist_drivers - the klist to iterate over the @drivers_kset
 * @bus_notifier - the bus notifier list for anything that cares about things
 *                 on this bus.
 * @bus - pointer back to the struct bus_type that this structure is associated
 *        with.
 *
 * @glue_dirs - "glue" directory to put in-between the parent device to
 *              avoid namespace conflicts
 * @class - pointer back to the struct class that this structure is associated
 *          with.
 *
 * This structure is the one that is the actual kobject allowing struct
 * bus_type/class to be statically allocated safely.  Nothing outside of the
 * driver core should ever touch these fields.
 */
struct subsys_private {
	struct kset subsys;
	struct kset *devices_kset;        /* 负责连接它下面的所有device的目录 */
	struct list_head interfaces;
	struct mutex mutex;

	struct kset *drivers_kset;        /* 负责连接它下面的所有driver的目录 */
	struct klist klist_devices;       /* 负责连接它下面的所有device的链表 */
	struct klist klist_drivers;       /* 负责连接它下面的所有driver的链表 */
	struct blocking_notifier_head bus_notifier;
	unsigned int drivers_autoprobe:1;
	struct bus_type *bus;

	struct kset glue_dirs;
	struct class *class;
};

猜你喜欢

转载自blog.csdn.net/qq_16777851/article/details/81459931