您好,欢迎访问三七文档
当前位置:首页 > 商业/管理/HR > 管理学资料 > Linux设备驱动编程模型之上层容器篇
Linux设备驱动编程模型之上层容器篇分类:Linux2012-10-0617:18245人阅读评论(0)收藏举报linux编程struct数据结构listnull2.6内核增加了一个引人注目的新特性——统一设备模型(devicemodel)。设备模型提供了一个独立的机制专门来表示设备,并描述其在系统中的拓扑结构,从而使得系统具有以下优点:代码重复最小化。提供诸如引用计数这样的统一机制。可以列举系统中所有的设备,观察它们的状态,并且查看它们连接的总线。可以将系统中的全部设备结构以树的形式完整、有效的展现出来——包括所有的总线和内部连接。可以将设备和其对应的驱动联系起来,反之亦然。可以将设备按照类型加以归类,比如分类为输入设备,而无需理解物理设备的拓扑结构。可以沿设备树的叶子向其根的方向依次遍历,以保证能以正确顺序关闭各设备的电源。最后一点是实现设备模型的最初动机。若想在内核中实现智能的电源管理,就需要来建立表示系统中设备拓扑关系的树结构。当在树上端的设备关闭电源时,内核必须首先关闭该设备节点以下的(处于叶子上的)设备电源。比如内核需要先关闭一个USB鼠标,然后才可关闭USB控制器;同样内核也必须在关闭PCI总线前先关闭USB控制器。简而言之,若要准确而又高效的完成上述电源管理目标,内核无疑需要一颗设备树。一、原理虽然设备模型的初衷是为了方便电源管理而提供出的一种设备拓扑结构,但是,为了方便调试,设备模型的开发者决定将设备结构树导出为一个文件系统,这就是sysfs文件系统,它可以帮助用户能以一个简单文件系统的方式来观察系统中各种设备的拓扑结构。这个举措很快被证明是非常明智的,首先sysfs代替了先前处于/proc下的设备相关文件;另外它为系统对象提供了一个很有效的视图。实际上,sysfs起初被称为driverfs。最终sysfs使得我们认识到一个全新的对象模型非常有利于系统。今天所有2.6内核的系统都拥有sysfs文件系统,而且几乎都毫无例外的将其挂载。图一是挂载于/sys目录下的sysfs文件系统的局部视图。/sys|—block/||–fd0||–hda||–dev||–device-../../devices/pci0000:00/0000:00:1f.1/ide0/0.0|…|–bus/|–class/|–devices/|–firmware/|–power/|–module/Sysfs的根目录下包含了七个目录:block,bus,class,devices,firmware,,module和power。block目录下的每个子目录都对应着系统中的一个块设备。反过来,每个目录下又都包含了该块设备的所有分区。bus目录提供了一个系统总线视图。class目录包含了以高层功能逻辑组织起来的系统设备视图。devices目录是系统中设备拓扑结构视图,它直接映射出了内核中设备结构体的组织层次。firmware目录包含了一些诸如ACPI,EDD,EFI等低层子系统的特殊树。power目录包含了系统范围的电源管理数据。其中最重要的目录是devices,该目录将设备模型导出到用户空间。目录结构就是系统中实际的设备拓扑。其它目录中的很多数据都是将devices目录下的数据加以转换加工而得。比如,/sys/class/net/目录是以注册网络接口这一高层概念来组织设备关系的,在这个目中可能会有目录eth0,它里面包含的devices文件其实就是一个指回到devices下实际设备目录的符号连接。随便看看任何你可访问到的Linux系统,这种系统设备视图相当准确和漂亮,而且可以看到class中的高层概念与devices中的低层物理设备,以及bus中的实际驱动程序之间互相联络是非常广泛的。Sysfs文件系统的目标就是要展现设备驱动模型组件之间的层次关系。在Linux中,sysfs文件系统被安装于/sys目录下:mount-tsysfssysfs/sys/sys|—block/||–fd0||–hda||–dev||–device-../../devices/pci0000:00/0000:00:1f.1/ide0/0.0|…|–bus/|–class/|–devices/|–firmware/|–power/|–module/那么,在这样的目录树中,哪些目录是驱动模型要关注的对象?bus-系统中用于连接设备的总线,在内核中对应的结构体为structbus_type{…};device-内核所识别的所有设备,依照连接它们的总线对其进行组织,对应的结构体为structdevice{…};class-系统中设备的类型(声卡,网卡,显卡,输入设备等),同一类中包含的设备可能连接到不同的总线,对应的结构体为structclass{…};为什么不对Power进行单独描述?实际上,Power与device有关,它只是device中的一个字段。除此之外,立马闪现在我们脑子里的对象还有:driver-在内核中注册的设备驱动程序,对应的结构体为structdevice_driver{…};以上bus,device,class,driver,是可以感受到的对象,在内核中都用相应的结构体来描述。而实际上,按照面向对象的思想,我们需要抽象出一个最基本的对象,这就是设备模型的核心对象kobject.Kobject是Linux2.6引入的新的设备管理机制,在内核中就是一个structkobject结构体。有了这个数据结构,内核中所有设备在底层都具有统一的接口,kobject提供基本的对象管理,是构成Linux2.6设备模型的核心结构,它与sysfs文件系统紧密关联,每个在内核中注册的kobject对象都对应于sysfs文件系统中的一个目录。Kobject是组成设备模型的基本结构。类似于C++中的基类,它嵌入于更大的对象中,即所谓的容器,如上面提到的bus,class,devices,drivers都是典型的容器,它们是描述设备模型的组件。二、主要对象介绍1,核心对象kobject话说kobject是驱动模型的核心对象,但在sysfs文件系统中似乎并没有对应的项,而这种看似“无”,实际上蕴藏着“有”。这“有”从何说起。回想文件系统中的核心对象“索引节点(indoe)”和目录项“dentry”:Inode—与文件系统中的一个文件相对应(而实际上,只有文件被访问时,才在内存创建索引节点)。Dentry-每个路径中的一个分量,例如路径/bin/ls,其中/、bin和ls三个都是目录项,只是前两个是目录,而最后一个是普通文件。也就是说,目录项目录项或者是一子目录,或者是一个文件。从上面的定义可以看出,indoe和dentry谁的包容性更大?当然是dentry!那么,kobject与dentry有何关系?由此我们可以推想,把dentry作为kobject中的一个字段,恍然间,kobject变得强大起来了。何谓“强大“,因为这样以来,就可以方便地将kobject映射到一个dentry上,也就是说,kobject与/sys下的任何一个目录或文件相对应了,进一步说,把kobject导出形成文件系统就变得如同在内存中构建目录项一样简单。由此可知,kobject其实已经形成一棵树了。这就是以隐藏在背后的对象模型为桥梁,将驱动模型和sysfs文件系统全然联系起来。由于kobject被映射到目录项,同时对象模型层次结构也已经在内存形成一个树,因此sysfs的形成就水到渠成了。既然,kobject要形成一颗树,那么其中的字段就要有parent,以表示树的层次关系;另外,kobject不能是无名氏,得有name字段,按说,目录或文件名并不会很长,但是,sysfs文件系统为了表示对象之间复杂的关系,需要通过软链接达到,而软链接常常有较长的名字。[cpp]viewplaincopyprint?1./*设备驱动程序模型的核心数据结构,每个kobject2.数据结构对应于sysfs文件系统中的一个目录*/3.structkobject{4.constchar*name;/*指向含有容器名称的字符*/5.structlist_headentry;/*用于kobject所插入的链表的指针*/6.structkobject*parent;/*指向父kobject*/7.structkset*kset;/*指向包含的kset*/8.structkobj_type*ktype;/*指向kobject的类型的描述符*/9.structsysfs_dirent*sd;/*用同一种structsysfs_dirent来统一设备模型中的kset/kobject/attr/attr_group.*/10.structkrefkref;/*容器的引用计数器*/11.unsignedintstate_initialized:1;/*指明kobject是否被初始化*/12.unsignedintstate_in_sysfs:1;/*指明是否使用了sysfs*/13.unsignedintstate_add_uevent_sent:1;/*热插拔加载事件*/14.unsignedintstate_remove_uevent_sent:1;/*热插拔卸载事件*/15.unsignedintuevent_suppress:1;/*如果设置了uevent_suppress字段,说明不希望产生事件,忽略事件正确返回*/16.};[cpp]viewplaincopyprint?1./*设备驱动程序模型的核心数据结构,每个kobject2.数据结构对应于sysfs文件系统中的一个目录*/3.structkobject{4.constchar*name;/*指向含有容器名称的字符*/5.structlist_headentry;/*用于kobject所插入的链表的指针*/6.structkobject*parent;/*指向父kobject*/7.structkset*kset;/*指向包含的kset*/8.structkobj_type*ktype;/*指向kobject的类型的描述符*/9.structsysfs_dirent*sd;/*用同一种structsysfs_dirent来统一设备模型中的kset/kobject/attr/attr_group.*/10.structkrefkref;/*容器的引用计数器*/11.unsignedintstate_initialized:1;/*指明kobject是否被初始化*/12.unsignedintstate_in_sysfs:1;/*指明是否使用了sysfs*/13.unsignedintstate_add_uevent_sent:1;/*热插拔加载事件*/14.unsignedintstate_remove_uevent_sent:1;/*热插拔卸载事件*/15.unsignedintuevent_suppress:1;/*如果设置了uevent_suppress字段,说明不希望产生事件,忽略事件正确返回*/16.};2.引用计数krefkobject的主要功能之一就是为我们提供了一个统一的引用计数系统,为什么说它具有“统一”的能力?那是因为kobject是“基”对象,就像大厦的基地,其他对象(如devic,bus,class,device_driver等容器)都将其包含,以后,其他对象的引用技术继承或封装kobject的引用技术就可以了。初始化时,kobject的引用计数设置为1。只要引用计数不为零,那么该对象就会继续保留在内存中,也可以说是被“钉住”了。任何包含对象引用的代码首先要增加该对象的引用计数,当代码结束后则减少它的引用计数。增加引用计数称为获得(getting)对象的引用,减少引用计数称为释放(putting)对象的引用。当引用计数跌到零时
本文标题:Linux设备驱动编程模型之上层容器篇
链接地址:https://www.777doc.com/doc-1307027 .html