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

linux设备模型七(device_driver细节)相关推荐

  1. 《linux设备驱动程序》——Linux设备模型

    一.概论 1.2.6版内核对系统结构的一般性抽象描述.现在内核使用了该抽象支持了多种不同的任务,其中包括: 1).电源管理和系统关机. 2).与用户控件通信. 3).热插拔设备. 4).设备类型. 5 ...

  2. Linux设备模型(总结)

    转:http://www.360doc.com/content/11/1219/16/1299815_173418267.shtml 看了一段时间的驱动编程,从LDD3的hello wrod到后来的字 ...

  3. Linux 文件系统与设备文件系统 (二)—— sysfs 文件系统与Linux设备模型

    提到 sysfs 文件系统 ,必须先需要了解的是Linux设备模型,什么是Linux设备模型呢? 一.Linux 设备模型 1.设备模型概述 从2.6版本开始,Linux开发团队便为内核建立起一个统一 ...

  4. Linux设备驱动程序学习-Linux设备模型(总线、设备、驱动程序和类)

    文章的例子和实验使用<LDD3>所配的lddbus模块(稍作修改). 总线 总线是处理器和一个或多个设备之间的通道,在设备模型中, 所有的设备都通过总线相连, 甚至是内部的虚拟" ...

  5. linux过去硬件设备状态,Linux 设备模型基本概念 (一)

    1.设备模型引入 Linux 2.6内核最初为了应付电源管理的需要,提出了一个设备模型来管理所有的设备.在物理上,外设之间是有一种层次关系的,比如把一个U盘插到笔记本上,实际上这个U盘是接在一个USB ...

  6. Linux设备模型-1-主要概念

    0 linux设备模型出现的背景 随着计算机的周边外设越来越丰富,设备管理已经成为现代操作系统的一项重要任务,这对于Linux来说也是同样的情况.每次Linux内核新版本的发布,都会伴随着一批设备驱动 ...

  7. linux设备模型详解

    Linux 2.6内核的一个重要特色是提供了统一的内核设备模型.随着技术的不断进步,系统的拓扑结构越来越复杂,对智能电源管理.热插拔以及plug and play的支持要求也越来越高,2.4内核已经难 ...

  8. Linux 设备模型基本概念 (一)

    1.设备模型引入 Linux 2.6内核最初为了应付电源管理的需要,提出了一个设备模型来管理所有的设备.在物理上,外设之间是有一种层次关系的,比如把一个U盘插到笔记本上,实际上这个U盘是接在一个USB ...

  9. linux设备模型 —— sysfs

    1 sysfs初探 "sysfs is a ram-based filesystem initially based on ramfs. It provides a means to exp ...

  10. linux设备模型--sysfs

    1 sysfs初探 "sysfs is a ram-based filesystem initially based on ramfs. It provides a means to exp ...

最新文章

  1. web.xml 配置 加载顺序
  2. android 多个占位符,Android多语言支持:由于占位符计数不同导致的字符串格式问题...
  3. MYSQL常用命令(转载)
  4. php7-sapnwrfc
  5. java轩辕剑天之痕游戏攻略_轩辕剑之天之痕游戏攻略大全
  6. 浅谈Linux磁盘存储管理续【逻辑卷管理(LVM)】
  7. 后端技术:Nginx从安装到高可用,看完本篇就够了!
  8. PowerBI 报表服务器刷新失败自动重刷并邮件通知
  9. mysql sqlserver firstrow=2_将CSV文件导入SQLServer
  10. JDK8利用Stream为集合对象分组并编号
  11. 不是所有的程序员都来自匿名区!
  12. SSM框架之Spring MVC(四)异常处理和拦截器实现
  13. 音译 —— 本身的含义
  14. Django Mysql数据库-聚合查询与分组查询
  15. Android 关于内存泄漏的一些总结
  16. MIUI9修改手机机型 修改王者荣耀版本
  17. 用C++写一个简单的表白小程序
  18. 机电一体化综合实训考核设备
  19. MySQL--找出每个部门薪水最高的员工 方法总结
  20. ubuntu 20.04 安装ibus-rime输入法

热门文章

  1. Abbyy FineReader PDF转word不乱码
  2. 什么是智能合约安全审计
  3. 智能合约安全审计指南
  4. 基于 CSS3 的下一代 Web 应用开发,第 1 部分: 发展历史及新特性
  5. 如何申请阿里云的免费域名HTTPS证书
  6. 硬件加速原理分析探索
  7. 【ZZULIOJ】1116: 删除元素
  8. 2021年化工自动化控制仪表考试内容及化工自动化控制仪表作业考试题库
  9. ★另人无比怀念的90年代动画片★ ‖最终整理篇‖
  10. 计算机超链接文档顶端,电脑在Word文档里插入目录超链接的方法