linux驱动(八)驱动设备模型
http://blog.csdn.net/xiahouzuoxin/article/details/8943863
http://blog.chinaunix.net/uid-25627207-id-3343854.html
http://blog.csdn.net/phunxm/article/details/8994311
http://blog.csdn.net/new_abc/article/details/7558845
http://www.cnblogs.com/andtt/articles/2178905.html
http://blog.csdn.net/heli200482128/article/details/51828745
2.6内核增加了一个引人注目的新特性——统一设备模型(device model)。设备模型提供了一个独立的机制专门来表示设备,并描述其在系统中的拓扑结构,从而使得系统具有以下优点:
(1)代码重复最小化。
(2)提供诸如引用计数这样的统一机制。
(3)可以列举系统中所有的设备,观察它们的状态,并且查看它们连接的总线。
(4)可以将系统中的全部设备结构以树的形式完整、有效的展现出来——包括所有的总线和内部连接。
(5)可以将设备和其对应的驱动联系起来,反之亦然。
(6)可以将设备按照类型加以归类,比如分类为输入设备,而无需理解物理设备的拓扑结构。
(7)可以沿设备树的叶子向其根的方向依次遍历,以保证能以正确顺序关闭各设备的电源。
最后一点是实现设备模型的最初动机,若想在内核中实现智能的电源管理,就需要来建立表示系统中设备拓扑关系的树结构。当在树上端的设备关闭电源时,内核必须首先关闭该设备节点以下的(处于叶子上的)设备电源。比如内核需要先关闭一个USB鼠标,然后才可关闭USB控制器;同样内核也必须在关闭PCI总线前先关闭USB控制器。简而言之,若要准确而又高效的完成上述电源管理目标,内核无疑需要一颗设备树。
(注:设备模型与电源管理相关联,貌似匪夷所思,可实际上,一个新观点或模型出现,在其背后都是需求的刺激。最近以来,节电一直是Intel、IBM等大公司孜孜追求的目标,虚拟化技术的本质其实就是节能。或者说,在能源日趋紧张的今日,节能是人类共同追求的目标)。
为什么驱动模型有助于电源管理,再说两句:
系统中所有硬件设备由内核全权负责电源管理。例如,在以电池供电的计算机进入“待机”状态时,内核应立刻强制每个硬件设备(硬盘,显卡,声卡,网卡,总线控制器等等)处于低功率状态。因此,每个能够响应“待机”状态的设备驱动程序必须包含一个回调函数,它能够使得硬件设备处于低功率状态。而且,硬件设备 必须按准确的顺序进入“待机”状态,否则一些设备可能会处于错误的电源状态。例如,内核必须首先将硬盘置于“待机”状态,然后才是它们的磁盘控制器,因为若按照相反的顺序执行,磁盘控制器就不能向硬盘发送命令。
虽然设备模型的初衷是为了方便电源管理而提供出的一种设备拓扑结构,但是,为了方便调试,设备模型的开发者决定将设备结构树导出为一个文件系统,这就是sysfs文件系统,它可以帮助用户以一个简单文件系统的方式来观察系统中各种设备的拓扑结构。这个举措很快被证明是非常明智的,首先sysfs代替了先前处于/proc下的设备相关文件;另外它为系统对象提供了一个很有效的视图。实际上,sysfs起初被称为driverfs。最终sysfs使得我们认识到一个全新的对象模型非常有利于系统。今天所有2.6内核的系统都拥有sysfs文件系统,而且几乎都毫无例外的将其挂载。
图一是挂载于/sys目录下的sysfs文件系统的局部视图。
> mount -t sysfs sysfs /sys
/sys
|—block/
| |–fd0
| |–had
| |–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。
(1)block目录下的每个子目录都对应着系统中的一个块设备。反过来,每个目录下又都包含了该块设备的所有分区。
(2)bus目录提供了一个系统总线视图。
(3)class目录包含了以高层功能逻辑组织起来的系统设备视图。
(4)devices目录是系统中设备拓扑结构视图,它直接映射出了内核中设备结构体的组织层次。
(5)firmware目录包含了一些诸如ACPI,EDD,EFI等低层子系统的特殊树。
(6)power目录包含了系统范围的电源管理数据。
(7)module目录包含了内核模块。模块是一种向Linux内核添加设备驱动程序、文件系统及其他组件的有效方法。
其中最重要的目录是devices,该目录将设备模型导出到用户空间。目录结构就是系统中实际的设备拓扑。其它目录中的很多数据都是将devices目录下的数据加以转换加工而得。比如,/sys/class/net/目录是以注册网络接口这一高层概念来组织设备关系的,在这个目中可能会有目录eth0,它里面包含的devices文件其实就是一个指回到devices下实际设备目录的符号连接。
随便看看任何你可访问到的Linux系统,这种系统设备视图相当准确和漂亮,而且可以看到class中的高层概念与devices中的低层物理设备,以及bus中的实际驱动程序之间互相联络是非常广泛的。
软件设计的根本是把现实世界的事物用计算机世界的模型表示出来,Linux设备模型的设计采用了面向对象(Object Oriented)的思想。
在前一讲中,提到sysfs文件系统,sysfs文件系统的目标就是要展现设备驱动模型组件之间的层次关系。在Linux中,sysfs文件系统被安装于/sys目录下,见上图一。那么,在这样的目录树中,哪些目录是驱动模型要关注的对象?
bus-系统中用于连接设备的总线,在内核中对应的结构体为structbus_type { … };
device-内核所识别的所有设备,依照连接它们的总线对其进行组织,对应的结构体为struct device {… };
class-系统中设备的类型(声卡,网卡,显卡,输入设备等),同一类中包含的设备可能连接到不同的总线,对应的结构体为struct class{… };
为什么不对Power进行单独描述?实际上,Power与device有关,它只是device中的一个字段。
除此之外,立马闪现在我们脑子里的对象还有:driver-在内核中注册的设备驱动程序,对应的结构体为struct device_driver{… };
以上bus,device,class,driver是可以感受到的对象,在内核中都用相应的结构体来描述。而实际上,按照面向对象的思想,我们需要抽象出一个最基本的对象,这就是设备模型的核心对象kobject。
kobject是Linux 2.6引入的新的设备管理机制,在内核中就是一个struct kobject结构体。有了这个数据结构,内核中所有设备在底层都具有统一的接口,kobject提供基本的对象管理,是构成Linux2.6设备模型的核心结构,它与sysfs文件系统紧密关联,每个在内核中注册的kobject对象都对应于sysfs文件系统中的一个目录。kobject是组成设备模型的基本结构。类似于C++中的基类,好比MFC中的CObject、Java中的Object和COM中的IUnKnown。kobject嵌入于更大的对象中,即所谓的容器,如上面提到的bus,class,devices,drivers都是典型的容器,它们是描述设备模型的组件。
---------------------------------------------------------------------------------------------------------------------------------------------------
kobj:
在Linux内核里,kobject是组成Linux设备模型的基础,一个kobject对应sysfs里的一个目录。从面向对象的角度来说,kobject可以看作是所有设备对象的基类,因为C语言并没有面向对象的语法,所以一般是把kobject内嵌到其他结构体里来实现类似的作用,这里的其他结构体可以看作是kobject的派生类。Kobject为Linux设备模型提供了很多有用的功能,比如引用计数,接口抽象,父子关系等等,所以,在内核中,没有用kobject直接定义的变量,kobject只是作为一个抽象的基类而存在。一般都是将kobject嵌入到另一个结构,这个结构就可以看做是kobject的一个子类。而kobject的子类会比较关心kobject的属性和方法。
内核里的设备之间是以树状形式组织的,在这种组织架构里比较靠上层的节点可以看作是下层节点的父节点,反映到sysfs里就是上级目录和下级目录之间的关系,在内核里,正是kobject帮助我们实现这种父子关系。在kobject的定义里,name表示的是kobject在sysfs中的名字;指针parent用来指向kobject的父对象;Kref大家应该比较熟悉了,kobject通过它来实现引用计数;Kset指针用来指向这个kobject所属的kset;对于ktype,如果只是望文生义的话,应该是用来描述kobject的类型信息。
-----------------------------------------------------------------------------------------------------------------------------------------------------------
kset:
有时候,某个设备的可能具有多个kobject的子类对象,或者某些设备具有相同的特性,为了便于管理,应该把这些对象统一放入一个容器中。这里要用到的容器就是kset。kset只是kobject的一个集合。对应到Linux文件系统中,一个kset就是/sys下的一个文件夹。
Kset本身也是一个kobject,所以它在sysfs里同样表现为一个目录,但它和kobject的不同之处在于kset可以看作是一个容器,如果你把它类比为C++里的容器类如list也无不可。Kset之所以能作为容器来使用,其内部正是内嵌了一个双向链表结构struct list_head
kset 象 kobj_type 结构的扩展; 一个 kset 是嵌入到相同类型结构的 kobject 的集合。但 struct kobj_type 关注的是对象的类型,而struct kset 关心的是对象的聚合和集合,其主要功能是包容,可认为是kobjects 的顶层容器类。每个 kset 在内部包含自己的 kobject, 并可以用多种处理kobject 的方法处理kset。 ksets 总是在 sysfs 中出现; 一旦设置了 kset 并把它添加到系统中, 将在 sysfs 中创建一个目录;kobjects 不必在 sysfs 中表示, 但kset中的每一个 kobject 成员都在sysfs中得到表述。
kobject建立的目录下只能添加文件,
kset建立的目录下添加目录,
kset是具有相同类型的kobject的集合。
-----------------------------------------------------------------------------------------------------------------------------------------------------------
kobj与kset的关系
我们看一下sys目录下的文件:
每个文件夹都对应一个kobject,/sys/目录下的文件夹是kset中包含的kobject,
sys目录下的所有文件夹都是一个层次的,每个文件夹都是一个kset,每个kset->object 都指向sys的kset以及kset->kobject;
在追踪到子目录中:
如class目录:
这里的每一个文件夹也都是一个kset,这个文件夹是在一个层次上的;
每个kset->object 都指向class的kset以及kset->kobject;
追到最底层的文件夹对应一个kobject,kobject中的文件就是kstyle中的attribute;
设备模型就是这么一层层建立起来的;
-----------------------------------------------------------------------------------------------------------------------------------------------------------