linux设备模型七(device_driver细节)

本文详细解析了Linux内核中驱动程序的注册流程,包括driver_register函数的内部实现、driver与device之间的匹配机制以及异步匹配的过程。通过具体的代码示例和步骤说明,帮助读者深入理解驱动注册的工作原理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

阅读这篇之前,建议先阅读我的下面这篇博客了解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;
};

 

This is, on the surface, a book about writing device drivers for the Linux system. That is a worthy goal, of course; the flow of new hardware products is not likely to slow down anytime soon, and somebody is going to have to make all those new gadgets work with Linux. But this book is also about how the Linux kernel works and how to adapt its workings to your needs or interests. Linux is an open system; with this book, we hope, it is more open and accessible to a larger community of developers. This is the third edition of Linux Device Drivers. The kernel has changed greatly since this book was first published, and we have tried to evolve the text to match. This edition covers the 2.6.10 kernel as completely as we are able. We have, this time around, elected to omit the discussion of backward compatibility with previous kernel versions. The changes from 2.4 are simply too large, and the 2.4 interface remains well documented in the (freely available) second edition. This edition contains quite a bit of new material relevant to the 2.6 kernel. The discussion of locking and concurrency has been expanded and moved into its own chapter. The Linux device model, which is new in 2.6, is covered in detail. There are new chapters on the USB bus and the serial driver subsystem; the chapter on PCI has also been enhanced. While the organization of the rest of the book resembles that of the earlier editions, every chapter has been thoroughly updated. We hope you enjoy reading this book as much as we have enjoyed writing it.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

奔跑的小刺猬

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值