大家好,今天小编来为大家解答以下的问题,关于LINUX设备驱动模型分析第三部分:驱动模块相关(DRIVER)接口分析,这个很多人还不知道,现在让我们一起来看看吧!
《LINUX设备驱动模型分析之一 总体概念说明》
《LINUX设备驱动模型分析之二 总线(BUS)接口分析》
在上一章中,我们分析了总线-驱动程序-设备模型的总线接口部分。在本章中,我们将分析驱动程序接口。在总线-驱动程序-设备模型中,驱动程序接口依附于总线,与设备不同,设备具有独立且统一的kset。并且驱动程序接口附加到特定类型的总线。关于总线-驱动-设备三类模块之间的关联和区别,我们在总线接口分析时已经分析过了。这里我们不再赘述,仅引用。
《LINUX设备驱动模型分析之一 总体概念说明》中的一张图试图再次说明总线-驱动-设备之间的关系。
如下图所示,所有注册的设备都在sysfs的device中(即所有设备对应的kobject通过devices_kset链接在一起),具体bus_type-p-devices_kset-kobj下为所有注册的设备创建链接公交车。目录,用于链接到在devices_kset 下聚合的kobject。
关于驱动界面,内容相对不复杂。本章我们将从数据接口、驱动注册和注销接口来分析驱动接口。
相关结构体分析
对于驱动子模块,涉及的结构体主要有device_driver和driver_private。 device_driver用于抽象驱动类,具体的驱动可以理解为驱动对象,而driver_private主要用于链接sysfs和bus。模块,设备模块。下面我们介绍一下这两个结构体变量。
struct device_driver 结构体分析
该结构体包含的内容可以分为以下几个部分:
绩效管理部分主要涉及绩效管理模块的管理(本次分析不包含在内,暂时不展开,因为我还不熟悉);与驱动相关的接口指针,包括probe、remove等,其中probe是驱动的检测接口,实现设备的检测操作(包括设备相关寄存器初始化、中断初始化等); remove是驱动程序的删除接口。当需要移除某个驱动模块时,调用该接口来实现移除接口shutdown、suspend、resume,主要是与电源管理相关的接口; of_device_id类型变量主要供设备树使用。该结构体变量将定义驱动程序支持的设备名称,并使用兼容值来表示支持的设备名称。驱动包含的属性通过attribute_group类型的变量传递驱动的所有默认属性; driver_private类型的变量包括driver与sysfs、device、bus的关联;通过定义kobject类型的变量,该变量在sysfs文件系统中创建驱动对应的命令;通过klist_device,链接驱动程序支持绑定的所有设备;通过knote_bus,将驱动程序链接到总线的驱动程序列表;通过module_kobject 类型的变量,将driver 驱动与module 模块关联起来(此时不会与module 模块关联);通过bus_type类型关联,解释了驱动程序所附加的总线。
struct driver_private结构体分析
该结构体变量主要包含与driver、device、bus、sysfs模块相关的结构体变量,其中
通过定义kobject类型的变量,为该变量在sysfs文件系统中创建驱动对应的命令;通过klist_device链接所有驱动支持并绑定的设备;通过knote_bus,将驱动程序链接到总线的驱动程序列表;通过module_kobject类型的变量,将驱动与module模块关联起来(此时module模块不会关联);以上是驱动模块相关的结构体变量。为了让我们更好的理解bus-driver-device,我们现在将使用bus_type、device_driver、kobject、driver_private等结构体变量进行绘制来说明驱动模块在bus-driver-device中的位置以及它是如何关联的sysfs。
下图展示了bus_type、device-driver、kobject相关结构体之间的关系。该图说明
总线类型、设备驱动程序和kobject 之间的关联。我们从几个方面来解释:
系统下所有注册的bus_type类型的关联(这些在之前的文章《LINUX设备驱动模型分析之二 总线(BUS)接口分析》中已经介绍过,不再详述)
device_driver、bus_type 和kobject 之间的关联。注册的device_driver类型变量通过其driver_private类型成员变量的knode_bus成员链接到其所附着的bus变量的klist_drivers链表上,并设置device_driver的成员变量bus指向它。附加总线变量;注册的device_driver类型变量通过其driver_private类型成员变量中的kobject变量将kobject链接到bus变量的driver_kset上,bus变量实现了所有注册的设备驱动对应的kobject变量聚集在一起。这是driver_kset-kobject 关联。 device_driver类型变量和xxx_device_driver类型变量之间的关系。我们引入的device_driver变量在实际使用时一般嵌入到特定类型的驱动结构体中,如i2c_driver和platform_driver,这样就可以针对特定类型的驱动添加驱动。一些相关的具体属性和接口等。driver-kobject-sysfs之间的关系上面没有详细解释,但下图详细说明了三者之间的关系。
driver和kobject之间的关联。当注册一个驱动程序时,将会创建一个kobject来与sysfs关联。 Kobject使用sysfs_drient、sysfs_open_dirent、sysfs_buffer、kobj_type和sysfs_ops在sysfs目录下创建一个与驱动对应的目录。属性创建sysfs 类型的文件。 drivers-kobject 和sysfs 模块相关结构之间的关联
driver-kobj_type相关说明
上图中,说明了driver-kobj_type,这里将对其进行简要说明。对于driver-kobject,其kobj_type是driver_ktype。该结构体定义了所有device-drivers通用的sysfs_ops以及driver-koject的release接口。定义如下
静态结构kobj_type driver_ktype={
.sysfs_ops=driver_sysfs_ops,
.release=driver_release,
};
driver_release的定义如下,主要释放driver_private类型的内存变量。
静态无效driver_release(struct kobject *kobj)
{
结构driver_private *drv_priv=to_driver(kobj);
pr_debug('driver: '%s': %s\n', kobject_name(kobj), __func__);
kfree(drv_priv);
}
driver_sysfs_ops主要是驱动属性的通用读写接口(show/store)。这两个接口使用driver_attribute类型变量(该结构体变量在上一篇文章中已经介绍过,这里不再赘述)来调用具体的驱动程序。属性读写接口(show/store)
驱动程序通用显示/存储界面
驱动注册与注销接口分析说明
上一节解释了设备驱动相关的结构体以及这些结构体与kobject、bus、device的关系。通过上面的关联图,我们大概可以知道驱动注册涉及到哪些部分。简单的解释就是建立设备驱动相关结构体与kobject、sysfs、bus、device之间的关联,以及驱动与设备之间的绑定。并实现设备的初始化等操作。接下来介绍驱动程序注册和取消接口。
驱动注册接口driver_register
驱动程序注册接口为driver_register。该接口实现的功能如下:
为驱动程序创建一个私有变量(driver_private类型)并初始化它。同时实现device-driver与driver_private类型变量的绑定操作。创建驱动程序的kobject类型变量,将kobject的kobj_type设置为driver_ktype,并将kobject变量Link设置为附加总线变量的driver_kset成员(bus_type -p-drivers_kset);将驱动程序链接到附加总线变量(klist_drivers)的注册驱动程序列表;为驱动程序创建一个通用的默认属性文件(即其附加的总线变量定义的默认驱动程序属性,在上一篇文章中已经解释过,如果需要了解更多,请参见上一篇文章《LINUX设备驱动模型分析之二 总线(BUS)接口分析》)建立连接驱动程序和模块之间(这里不详细说明,后面会单独讨论分析模块部分)如果驱动程序所挂接的总线支持自动检测功能,则会遍历总线上注册的所有设备来实现该设备-驱动程序绑定操作。为驱动程序的私有默认属性创建相应的sysfs文件。将driver-kobj添加的uevent发送到应用层。应用层的udev/mdev会根据制定的策略执行相应的动作。以上就是驱动注册接口的大致功能,就是实现device、driver、bus、kobject、sysfs等模块相关结构体的关联操作。
在总线中注册驱动程序的主要接口是bus_add_driver。我们来解释一下这个接口的实现。
bus_add_driver接口分析
该接口实现了上述大部分功能。该接口的实现流程图如下。主要功能有:
为驱动程序创建一个私有变量(driver_private类型)并初始化它。同时实现device-driver与driver_private类型变量的绑定操作。创建驱动程序的kobject类型变量,将kobject的kobj_type设置为driver_ktype,并将kobject变量Link设置为附加总线变量的driver_kset成员(bus_type -p-drivers_kset);将驱动程序链接到附加总线变量(klist_drivers)的注册驱动程序列表;为驱动程序创建一个通用的默认属性文件(即其附加的总线变量定义的默认驱动程序属性,这在上一篇文章中已经解释过,如果需要了解更多,请参考上一篇文章)建立连接驱动程序和模块之间(这里不详述,模块部分稍后会单独分析))如果驱动程序所挂接的总线支持自动检测功能,则会遍历总线上注册的所有设备来实现设备-驱动绑定操作。
driver_attach接口分析
在上面的接口中,注册的设备和驱动是通过调用driver_attach来绑定的,所以我们有必要引入这个接口。该接口的实现过程如下。对于每个已注册的设备,执行以下步骤主要操作:
调用driver-bus-match接口判断设备与驱动是否匹配。如果不匹配则直接返回(一般匹配接口主要判断设备和驱动的名称,如果驱动和设备名称相同则认为匹配);如果驱动和设备匹配,且设备尚未绑定到驱动:调用bus-probe/driver-probe初始化设备(一般总线的probe接口也称为驱动的probe接口初始化设备);调用driver_bond 将设备绑定到驱动程序。 (包括将设备链接到驱动程序变量的klist_devices变量,同时设备驱动程序指针执行驱动程序变量。同时向系统发送设备驱动程序绑定通知)。上述驱动注册相关接口的实现过程与上述流程图类似。基本上根据上面的流程图就可以明白相应的代码实现了。这里不再列出对应的代码实现,对每一行代码进行解释(上图),流程分析是在熟悉sysfs文件系统的基础上进行的。如果对sysfs文件系统的实现不熟悉,建议阅读我之前写的分析文档(《LINUX SYSFS文件系统分析之四 文件处理及相关系统调用分析》等)。
驱动注销接口driver_unregister
该接口主要用于从总线上注销驱动程序,相应的操作与驱动程序注册相反。主要涉及的函数有driver_unregister、driver_remove_groups、bus_remove_driver。相对来说还是比较简单的。主要实现的功能如下:
通过调用driver_remove_groups接口(sysfs_remove_group)删除驱动私有默认属性对应的sysfs文件;删除驱动通用属性对应的sysfs文件(通过调用driver_remove_attrs接口实现,最后通过调用sysfs_remove_file删除sysfs文件);删除driver_remove_attrs接口对应的sysfs文件。从bus-klist_drivers链表中删除该驱动程序;调用driver_detach接口实现驱动与设备的解除绑定操作;调用module_remove_driver实现模块与驱动的解绑操作;调用kobject_put 将driver-kobj 的引用计数减一。如果减一,如果为0,就会调用kobject_release来释放kobject,同时会调用kobj_type-release,即driver_release接口来释放driver_private类型变量。调用bus_put将bus-kset-kobject的引用计数减1。如果减一后为0,则调用kobject_release进行bus-kset-kobject释放内存等操作。这个接口的实现还是比较清晰的。这里不给出详细的流程图,留给读者自己实现。
以上就完成了驱动模块的分析操作。下一篇文章将分析设备模块。
用户评论
这篇文章分析得真细啊,特别是关于驱动模块相关的接口,我之前一直不太明白,现在总算明白了!学习linux驱动总是要慢慢来,一步一个脚印地理解很重要
有6位网友表示赞同!
讲道理,我是刚开始接触LINUX驱动,这篇博文帮了我不少忙,接口的介绍很清晰易懂,感觉自己能更快上手了。希望作者能够继续分享更多深入的内容。
有19位网友表示赞同!
终于有人详细讲解驱动模块相关的接口啦!我一直想弄明白为什么这些接口设计得这么复杂,看了这篇文章后,感觉驱动开发确实需要扎实的内核知识和系统设计能力。
有18位网友表示赞同!
作为一名嵌入式开发工程师,我对这个驱动模块的分析非常感兴趣!接口的设计确实体现了Linux的强大和灵活,也让我对驱动开发有了更深入的了解。希望以后能看到更多针对不同类型的驱动的解析。
有16位网友表示赞同!
说实话,这篇文章写的有点深奥,我还在努力消化内核代码中的这些知识点。希望作者能够加入一些通俗易懂的解释,让新手更容易理解
有8位网友表示赞同!
驱动模块的接口设计确实非常重要,它直接影响着硬件和软件的交互方式。这篇博文对主要的接口进行了清晰的阐述,有助于开发者深入了解Linux驱动的核心机制。很棒!
有11位网友表示赞同!
作者分析得都很仔细,不过有些概念还是需要多方学习才能真正理解。像一些高级接口的使用场景,希望能提供更多的实例讲解,这样更便于我们实际应用。
有5位网友表示赞同!
我个人感觉这篇博文略显枯燥,缺少了一些实例代码和生动化的描述。如果能增加一些案例解析,并结合实际开发场景进行讲解,可以让文章更易读也更具参考价值。
有9位网友表示赞同!
最近在学习Linux驱动,刚好看到这篇文章,介绍的非常全面,尤其是这些接口的细节分析真的很有帮助!感谢作者的分享。
有10位网友表示赞同!
对于初学者来说,阅读这类技术深度文章确实有些难度。希望作者能关注一些基础知识点的讲解,比如驱动模块的基本结构、作用等等,能让新手更快速入门Linux驱动开发。
有13位网友表示赞同!
这篇文章让我对驱动模块相关的接口有了更深入的理解,特别是关于其设计理念和功能实现机制的解释非常透彻!感谢作者为我们提供如此宝贵的学习资源。
有12位网友表示赞同!
我一直很好奇Linux驱动是如何实现硬件与软件的交互的,这篇博文解析了驱动模块的相关接口,让我看到了内核代码运行的逻辑,受益匪浅!期待继续关注作者的文章,学习更多关于驱动开发的内容。
有6位网友表示赞同!
作为一名嵌入式系统爱好者,我对 Linux 驱动的开发一直充满兴趣。本文对驱动模块相关的接口分析非常详细,让我更加了解内核是如何协调硬件设备和软件应用程序互动的。感谢作者的分享!
有18位网友表示赞同!
我觉得这篇博文写得比较专业,对一些接口的解释还是需要结合更具体的代码示例才能更好地理解。希望作者能提供一些案例讲解,让读者更容易掌握这些概念。
有5位网友表示赞同!
这篇文章非常有启发意义,让我们明白设计驱动模块接口是何等重要!希望能更多地学习类似深度分析的文章,提升自己在Linux驱动的理解和开发能力
有19位网友表示赞同!
我一直在探索如何高效地学习Linux驱动,阅读这样的文章非常有助于加深我对内核结构的理解。希望作者可以继续分享更多关于驱动开发的经验和技巧,比如调试技巧、安全方面的考虑等等。
有7位网友表示赞同!
说实话,这篇博文读起来比较费劲,缺少一些针对初学者的引导。如果能够用通俗易懂的语言进行讲解,并结合一些实例分析,相信会更加吸引读者。
有7位网友表示赞同!
在学习Linux驱动过程中,接口的理解确实非常关键。这篇博文对不同类型的接口进行了分类和解释,帮助我理清了思路。希望作者可以补充一些关于驱动测试和调试方面的知识,可以更有针对性的帮助我们解决实际问题。
有18位网友表示赞同!