上一章我们分析了bus-driver-device模型中bus接口部分,本章我们将分析driver接口,在bus-driver-device模型中,driver接口是依附于bus上,而不像device有独立统一的kset,而driver接口是依附于具体类型的bus总线。针对bus-driver-device这三类模块之间的关联与区别,我们在总线接口分析时,已经分析过,此处不再赘述,仅引用《LINUX设备驱动模型分析之一 总体概念说明》中的一张图,试图再次说明bus-driver-device之间的关联。

如下图所示,所有注册的设备均在sysfs的device(即通过devices_kset将所有device对应的kobject链接在一起),而具体bus_type->p->devices_kset->kobj则对该总线下所有注册的设备,创建链接目录,用以链接至devices_kset下汇聚的kobject。

针对driver接口,相对来说内容也不复杂,本章我们还是从数据接口、driver的注册以及注销

接口进行分析驱动接口。

相关结构体分析

针对driver子模块而言,涉及的结构体主要包括device_driver、driver_private,其中device_driver用于抽象驱动类,而具体的驱动可理解为一个驱动对象,而driver_private则主要用于链接至sysfs、bus模块、device模块。下面我们介绍这两个结构体变量。

struct device_driver 结构体分析

该结构体包含的内容可梳理为如下几个部分:

  1. 性能管理部分,主要与性能管理模块管理(非本次分析内容,暂不展开,这块我还不熟);
  2. 该驱动相关的接口指针,包括probe、remove等,其中
    1. probe为该驱动的探测接口,实现对设备的探测操作(包括设备相关的寄存器初始化、中断初始化等);
    2. remove为该驱动的移除接口,当需要移除一个驱动模块时,则调用该接口实现移除接口
    3. shutdown、suspend、resume主要为电源管理相关的接口;
    4. of_device_id类型的变量主要为设备树所用,该结构体变量中会定义该驱动所支持的of device,用compatible值表示支持的of device的名称。
  3. 该驱动所包含的属性,通过attribute_group类型的变量传递该驱动所有的默认属性;
  4. 通过driver_private类型的变量,包含了该驱动与sysfs、device、bus之间关联的关联;
    1. 通过定义kobject类型的变量,为该变量在sysfs文件系统中创建了该驱动对应的命令;
    2. 通过klist_device,链接所有该驱动支持且绑定的设备;
    3. 通过knode_bus将该驱动链接至总线的驱动链表中;
    4. 通过module_kobject类型的变量,将该驱动与module模块关联(本次不对module模块关联);
  5. 通过bus_type类型的关联,说明本驱动所依附的总线。
struct device_driver {const char     *name;/*驱动名称*/struct bus_type       *bus;/*该驱动所依附的总线*//*该驱动所属module*/struct module      *owner;/*模块的名称*/const char      *mod_name;  /* used for built-in modules */bool suppress_bind_attrs;    /* disables bind/unbind via sysfs *//*设备树使用的设备id*/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);/*shutdown 、suspend、resume主要是对应电源管理方面的接口*/void (*shutdown) (struct device *dev);int (*suspend) (struct device *dev, pm_message_t state);int (*resume) (struct device *dev);/*该驱动所相关的属性接口,主要用于与sysfs模块管理*/const struct attribute_group **groups;/*性能管理相关的内容*/const struct dev_pm_ops *pm;/*该驱动模块相关的私有变量,主要包括驱动对应的kobject、所属模块的kobject等*/struct driver_private *p;
};

struct driver_private结构体分析

该结构体变量主要是包含了与driver、device、bus、sysfs模块关联的结构体变量,其中

  1. 通过定义kobject类型的变量,为该变量在sysfs文件系统中创建了该驱动对应的命令;
  2. 通过klist_device,链接所有该驱动支持且绑定的设备;
  3. 通过knode_bus将该驱动链接至总线的驱动链表中;
  4. 通过module_kobject类型的变量,将该驱动与module模块关联(本次不对module模块关联);
struct driver_private {/*该驱动对应的kobject*/struct kobject kobj;/*用于汇聚该驱动所绑定的所有设备*/struct klist klist_devices;/*用于链接至xxx_bus_type的klist_drivers链表上*/struct klist_node knode_bus;/*该驱动所属模块的kobject*/struct module_kobject *mkobj;/*指向本driver_private类型变量所属的driver变量*/struct device_driver *driver;
};

以上便是driver模块相关的结构体变量,为了让我们更好的理解bus-driver-device,我们现将bus_type、device_driver、kobject、driver_private等结构体变量的关联关系画出来,以此说明driver模块在bus-driver-device中的位置,以及是如何与sysfs进行关联的。

如下图为 bus_type、device-driver、kobject相关结构体之间的关联,该图说明了bus_type、device-driver、kobject之间的关联。我们分几个方面进行说明:

  1. 系统下所有已注册bus_type类型的关联
  2. device_driver与bus_type、kobject之间的关联
    1. 已注册的device_driver类型的变量通过其driver_private类型的成员变量中的knode_bus成员,链接至其依附的总线变量的klist_drivers链表上,并且设置device_driver的成员变量bus指向为其所依附的总线变量;
    2. 已注册的device_driver类型的变量通过其driver_private类型的成员变量中的kobject变量,将该kobject链接至总线变量的driver_kset中,而总线变量通过其driver_kset变量,实现将所有已注册的设备驱动对应的kobject变量汇聚至一起,这是driver_kset-kobject的关联。
  3. device_driver类型变量与xxx_device_driver类型变量之间的关联,我们介绍的device_driver变量,在实际使用时,一般会嵌入至具体类型的驱动结构体中,如i2c_driver、platform_driver,以便针对具体类型的驱动,增加该驱动相关的一些特定属性以及接口等。

上面针对driver-kobject-sysfs之间的关联,没有详细说明,下图则详细说明了这三者之间的关联。

  1. driver与kobject的关联,当注册一个driver时,即会创建一个kobject,用以与sysfs关联
  2. kobject通过sysfs_drient、sysfs_open_dirent、sysfs_buffer、kobj_type、sysfs_ops,实现了在sysfs目录下创建目录,并为该驱动对应的属性创建sysfs类型的文件。

driver-kobj_type相关说明

在上面的图中,说明了driver-kobj_type,此处稍作说明。针对driver-kobject,其kobj_type为driver_ktype,该结构体定义了所有device-driver的通用sysfs_ops以及driver-koject的释放接口,其定义如下

static struct kobj_type driver_ktype = {.sysfs_ops        = &driver_sysfs_ops,.release        = driver_release,};

其中driver_release的定义如下,主要是将driver_private类型的内存变量释放。

static void driver_release(struct kobject *kobj){struct driver_private *drv_priv = to_driver(kobj);pr_debug("driver: '%s': %s\n", kobject_name(kobj), __func__);kfree(drv_priv);}

而driver_sysfs_ops主要是driver属性的通用读写接口(show/store),这两个接口通

driver_attribute类型变量(该结构体变量在上一篇文章中已经介绍,此处不再赘述),实现调用具体驱动属性的读写接口(show/store)

static ssize_t drv_attr_show(struct kobject *kobj, struct attribute *attr,char *buf){struct driver_attribute *drv_attr = to_drv_attr(attr);struct driver_private *drv_priv = to_driver(kobj);ssize_t ret = -EIO;if (drv_attr->show)ret = drv_attr->show(drv_priv->driver, buf);return ret;}static ssize_t drv_attr_store(struct kobject *kobj, struct attribute *attr,const char *buf, size_t count){struct driver_attribute *drv_attr = to_drv_attr(attr);struct driver_private *drv_priv = to_driver(kobj);ssize_t ret = -EIO;if (drv_attr->store)ret = drv_attr->store(drv_priv->driver, buf, count);return ret;}

驱动注册与注销接口分析说明

上一小节说明了device-driver相关的结构体,以及这些结构体与kobject、bus、device之间

的关联。通过上面的关联图,我们大概也是可以知道驱动注册涉及哪些部分,简单的说明就是建立device-driver相关的结构体与kobject、sysfs、bus、device之间的关联,以及驱动与设备的绑定,并实现对设备的初始化等操作。下面我们就介绍驱动注册与注销接口。

驱动注册接口driver_register

驱动注册接口为driver_register,该接口实现的功能如下:

  1. 为该驱动创建私有变量(driver_private类型),并对其进行初始化,同时实现device-driver与driver_private类型变量的绑定操作
  2. 为该驱动创建kobject类型的变量,设置kobject的kobj_type为driver_ktype,将该kobject变量链接至所依附总线变量的driver_kset成员上(bus_type->p->drivers_kset);
  3. 将该驱动链接至其所依附总线变量的已注册驱动链表上(klist_drivers);
  4. 为该驱动创建通用的默认属性文件(即其所依附总线变量定义的默认驱动属性,这在上一篇文章中已经说明,需要了解的请查看上一篇文章《》)
  5. 为该驱动与模块建立联系(此处不细说,后续会单独分析module部分)
  6. 若该驱动依附的总线支持自动探测功能,则遍历该总线上已注册的所有设备,实现设备-驱动的绑定操作。
  7. 为该驱动私有的默认属性,创建对应的sysfs文件。
  8. 向应用层发送driver-kobj已添加的uevent,应用层的udev/mdev,会根据制定的策略,执行相应的动作。

以上即是驱动注册接口的大致功能,即是实现device、driver、bus、kobject、sysfs等模块

相关结构体的关联操作。

以上实现向bus中注册driver的主要接口为bus_add_driver,我们对该接口的实现再进行一下说明

bus_add_driver接口分析

该接口即实现了上述说明的大部分功能,该接口的实现流程图如下,主要实现功能为

  1. 为该驱动创建私有变量(driver_private类型),并对其进行初始化,同时实现device-driver与driver_private类型变量的绑定操作
  2. 为该驱动创建kobject类型的变量,设置kobject的kobj_type为driver_ktype,将该kobject变量链接至所依附总线变量的driver_kset成员上(bus_type->p->drivers_kset);
  3. 将该驱动链接至其所依附总线变量的已注册驱动链表上(klist_drivers);
  4. 为该驱动创建通用的默认属性文件(即其所依附总线变量定义的默认驱动属性,这在上一篇文章中已经说明,需要了解的请查看上一篇文章《》)
  5. 为该驱动与模块建立联系(此处不细说,后续会单独分析module部分)
  6. 若该驱动依附的总线支持自动探测功能,则遍历该总线上已注册的所有设备,实现设备-驱动的绑定操作。

driver_attach接口分析

在上面接口中,通过调用driver_attach实现已注册的device与driver的绑定,因此我们有必要介绍下这个接口,这个接口的实现流程如下,针对每一个已注册的设备,执行如下几个主要的操作:

  1. 调用driver->bus->match接口,判断设备与驱动是否匹配,不匹配则直接返回(一般匹配接口主要是对设备与驱动名称进行判断,若驱动与设备名称相同则认为匹配);
  2. 若驱动与设备匹配,且设备尚未绑定驱动:
    1. 调用bus->probe/driver-probe对设备进行初始化(一般bus的probe接口,也是调用driver的probe接口,实现对设备的初始化操作);
    2. 调用driver_bond实现设备与驱动绑定(包括将设备链接至驱动变量的klist_devices变量中,同时device->driver指针执行该驱动变量。同时向系统中发送device-driver绑定的通知)。

以上driver注册相关的接口,其实现流程与上面流程图类似,基本上根据上述流程图即可理解相应的代码实现,此处不再列出对应的代码实现,对代码的每一行进行解释(以上流程分析建立在对sysfs文件系统熟悉的情况下,若对sysfs文件系统的实现不熟悉,建议阅读我之前写的分析文档《LINUX SYSFS文件系统分析之二 sysfs文件系统相关的结构体说明》、《LINUX SYSFS文件系统分析之四 文件处理及相关系统调用分析》等)。

驱动注销接口driver_unregister

该接口主要是将驱动从总线上注销,相应的操作刚好与驱动注册相反。主要涉及的函数包括driver_unregister、driver_remove_groups、bus_remove_driver。相对来说也比较简单,主要实现的功能如下:

  1. 删除该驱动的私有默认属性对应sysfs文件,通过调用driver_remove_groups接口实现(sysfs_remove_group);
  2. 删除该驱动的通用属性对应的sysfs文件(通过调用driver_remove_attrs接口实现,最终通过调用sysfs_remove_file实现sysfs文件的删除);
  3. 将该驱动从bus->klist_drivers链表删除;
  4. 调用driver_detach接口,实现驱动与设备的解绑操作;
  5. 调用module_remove_driver,实现module与driver的解绑操作;
  6. 调用kobject_put,使driver-kobj的引用计数减一,若减一后为0,则会调用kobject_release对kobject进行释放,同时调用kobj_type->release,即driver_release接口,实现对driver_private类型变量的释放操作。
  7. 调用bus_put,使bus-kset-kobject的引用计数减一,若减一后为0,则对bus-kset-kobject调用kobject_release进行内存的释放等操作。

该接口的实现相对来说也比较明晰,此处不再给出详细的流程图,由读者自己去实现。

以上完成了driver模块的分析操作,下一篇进行device模块的分析。

LINUX设备驱动模型分析之三 驱动(DRIVER)接口分析相关推荐

  1. linux下camera驱动分析_LINUX设备驱动模型分析之三 驱动模块相关(DRIVER)接口分析...

    本系列前几篇文章链接如下: <LINUX设备驱动模型分析之一 总体概念说明> <LINUX设备驱动模型分析之二 总线(BUS)接口分析> 上一章我们分析了bus-driver- ...

  2. linux i2c adapter 增加设备_LINUX设备驱动模型分析之四 设备模块相关(DEVICE)接口分析...

    本系列前几篇文章链接如下: <LINUX设备驱动模型分析之一 总体概念说明> <LINUX设备驱动模型分析之二 总线(BUS)接口分析> <LINUX设备驱动模型分析之三 ...

  3. linux RTC 驱动模型分析

    linux RTC 驱动模型分析 RTC(real time clock)实时时钟,主要作用是给Linux系统提供时间.RTC因为是电池供电的,所以掉电后时间不丢失.Linux内核把RTC用作&quo ...

  4. linux MISC 驱动模型分析

    linux MISC 驱动模型分析 阅读led驱动程序的代码的时候,没有发现ldd3中提到的各种字符设备注册函数,而是发现了一个misc_register函数,这说明led设备是作为杂项设备出现在内核 ...

  5. char添加一个字符_LINUX字符设备驱动模型分析(起始篇)

    在前面几个模块的介绍中,我们主要以vfs为起始,完成了sysfs.设备-总线-驱动模型.platform设备驱动模型.i2c设备驱动模型.spi设备驱动模型的分析.在对这些模块进行分析的时候,我们或多 ...

  6. 通过虚拟驱动vivi分析摄像头驱动

    Linux摄像头驱动学习之:(二)通过虚拟驱动vivi分析摄像头驱动 一.通过指令 "strace -o xawtv.log xawtv" 得到以下调用信息: // 1~7都是在v ...

  7. 步进电机28BYJ-48的驱动(arduino,STM32平台),最全的驱动详细原理,驱动电路分析,驱动代码解释

    步进电机28BYJ-48的驱动(arduino平台,STM32),最全的驱动详细原理,驱动电路分析,驱动代码解释 目录 步进电机28BYJ-48的驱动(arduino平台,STM32),最全的驱动详细 ...

  8. LINUX I2C设备驱动模型分析之二 总线部分分析

    上一章我们对I2C模块做了总体框架的分析,本章我们主要分析下I2C模块的总线部分,主要涉 及总线初始化.总线相关属性.总线相关接口函数处理等几部分 I2c bus的定义 I2c bus的定义如下,主要 ...

  9. LINUX SPI设备驱动模型分析之二 SPI总线模块分析

    上一篇文章我们简要介绍了SPI驱动模块,本章我们详细说明一下spi总线.设备.驱动模块的注册.注销以及这几个模块之间的关联. SPI总线的注册 spi模块也是基于LINUX设备-总线-驱动模型进行开发 ...

最新文章

  1. 在Ubuntu中打开pycharm步骤:
  2. 微信小程序开发系列一:微信小程序的申请和开发环境的搭建
  3. 汉中职业技术学院计算机专业,2020年陕西省青年职业技能大赛计算机网络管理员决赛开幕式在汉中职院举行...
  4. 适用于System Center 2016所需前期准备工作
  5. 【Python】青少年蓝桥杯_每日一题_2.27_杨辉三角
  6. Java连接SQL Server 2012【查看自己电脑上的SQL Server端口号;附:jar包】
  7. 中文整合包_MIMOSA2: 基于微生物组和代谢组数据的整合分析
  8. 路由包含#号导致的nginx_分布式实战:Nginx缓存之OpenResty部署
  9. java内存管理(适合初学者)
  10. C#下载文件和将文件转换为数据流下载的示例
  11. python文字竖排的2种实现方法
  12. CXF WebService整合SpringMVC的maven项目
  13. 《Windows Mobile平台应用与开发》写作工作顺利进行中
  14. [Vue warn]: Duplicate keys detected: '0'. This may cause an update error. found in解决办法
  15. 课堂练习--最大子数组和
  16. rgb转yuv422 matlab,MATLAB读取一张RGB图片转成YUV420格式、YUV422格式、YUV444格式
  17. 阿里巴巴早期发展简史
  18. ifonts提取下载ttf文件
  19. 智能门禁(1)---几种人脸识别门禁系统设计的方案介绍
  20. 初学Mean Shift 聚类算法

热门文章

  1. android 彩信附件添加删除
  2. 如何在操作系统中快速查询机器的序列号
  3. 前端三大主流框架React、Vue.js、Angular的优缺点分析
  4. 3dsmax2009-2019哪个版本更好?
  5. hql删除mysql语句_如何使用delete语句删除数据
  6. 完整恢复玩客云官方固件,恢复迅雷下载和备份
  7. 第 3-3 课:狼、羊、菜和农夫过河问题
  8. JDBC:标准接口API ,即同一套Java代码操作不同的关系型数据库
  9. Velocity中文
  10. 字符串截取的两种方式(substring、split)的区别和使用方式。