linux建立设备模型的目的:这事2.6内核版本引入的一种设备管理机制,同时出现的还有sysfs文件系统(他完全表现向用户呈现了内核中设备的层次结构,也有人说之为设备模型的副产物),具体的为什么要引入设备模型呢?为内核建立一个统一的设备模型,从而有一个对系统结构的一般性抽象描述。好吧,这句话并不是很好懂。这样说吧,跟以前比,引入他有什么好处呢?
1 电源管理,根据设备的层次关系,当系统进入睡眠的时候,不需要一个一个设备的关,只需要关一个总线设备,接在总线下的设备就都会关掉。
2 sysfs 虚拟文件系统的实现与设备模型的紧密相关, 并向外界展示它所表述的结构。向用户空间提供系统信息、改变操作参数的接口正越来越多地通过 sysfs , 也就是设备模型来完成。
3 关于热插拔,这跟扫描有关系,比如说,你把一个设备直接接在USB上,系统就会去扫描设备,并且在USB总线上寻找匹配的设备驱动,最后初始化设备,等待用户使用。
4 设备模型的实现需要创建一系列机制来处理对象的生命周期、对象间的关系和对象在用户空间的表示。Linux 设备模型是一个复杂的数据结构。但对模型的大部分来说, Linux 设备模型代码会处理好这些关系, 而不是把他们强加于驱动作者。模型隐藏于交互的背后,与设备模型的直接交互通常由总线级的逻辑和其他的内核子系统处理。所以许多驱动作者可完全忽略设备模 型, 并相信设备模型能处理好他所负责的事。
怎么说呢,自从有了设备模型,我们需要写的驱动代码也少了,大多数面向用户的接口都不需要实现了,只需要写一些跟硬件相关的代码。比如说input设备,上面的事件处理都是系统自带的代码,我们需要写的只是从外设获取输入信息,然后提交给input core。在设备模型中,input就是class中的一个子目录,其他的输入设备(注册在input中的)都只是他下面的文件。这些在sysfs文件系统中都可以看到。那就先来说说sysfs吧。
sysfs文件系统:用于将系统中的设备组织成层次结构,并向用户模式程序提供详细的内核数据结构信息。
这是sysfs下面的子目录,设备模型可分为:驱动程序,设备,总线三部分。这些都会在这些目录下体现,这些目录只是从不同的视角去看设备模型,比如说,block中只有块设备,bus下既有驱动也有设备。class下也有设备信息,dev下是节点,devices下是所有的设备等,都是交叉的。但他们都属于设备模型三部分。
sysfs的信息来源是kobject层次结构,读一个sysfs文件,就是动态的从kobject结构提取信息,生成文件。这也解释了设备模型与sysfs的关系。(kobject与kset就是构成设备模型的关键结构体)设备模型说到底还是一堆有序的结构体构成的。热插拔的时候都会在对应的地方产生新的结构体(把一个结构体插入到对应的链表中去),或者删除一个结构体。
kobject 结构为一些大的数据结构和子系统提供了基本的对象管理,避免了类似机能的重复实现。这些机能包括
- 对象引用计数.
- 维护对象链表(集合).
- 对象上锁.
- 在用户空间的表示.
每一个设备就是对应一个kobject结构体。在sysfs中对应一个目录。
Kobject结构定义为: struct kobject { char * k name; 指向设备名称的指针 char name[KOBJ NAME LEN]; 设备名称 struct kref kref; 对象引用计数
//当引用计数为0时,所有该对象使用的资源释放 struct list head entry; 挂接到所在kset中去的单元 struct kobject * parent; 指向父对象的指针 struct kset * kset; 所属kset的指针 struct kobj type * ktype; 指向其对象类型描述符的指针 他下面的kobject都共享这个类型 struct dentry * dentry; sysfs文件系统中与该对象对应的文件节点路径指针 };
http://blog.csdn.net/fudan_abc/article/details/1768296 这儿的解释还是很不错的。
相关函数
void kobject_init(struct kobject * kobj);kobject初始化函数。
int kobject_set_name(struct kobject *kobj, const char *format, ...);设置指定kobject的名称。
struct kobject *kobject_get(struct kobject *kobj);将kobj 对象的引用计数加1,同时返回该对象的指针。
void kobject_put(struct kobject * kobj); 将kobj对象的引用计数减1,如果引用计数降为0,则调用kobject release()释放该kobject对象。
int
kobject_add(struct kobject *
kobj);将kobj对象加入Linux设备层次。挂接该kobject对象到kset的list链中,增加父目录各级kobject的引用计数,在其
parent指向的目录下创建文件节点,并启动该类型内核对象的hotplug函数。
int kobject_register(struct kobject * kobj);kobject注册函数。通过调用kobject init()初始化kobj,再调用kobject_add()完成该内核对象的注册。
void kobject_del(struct kobject * kobj);从Linux设备层次(hierarchy)中删除kobj对象。
void
kobject_unregister(struct kobject * kobj);kobject注销函数。与kobject
register()相反,它首先调用kobject del从设备层次中删除该对象,再调用kobject
put()减少该对象的引用计数,如果引用计数降为0,则释放kobject对象。
struct kset { struct subsystem * subsys; 所在的subsystem的指针 管理kset用的 struct kobj type * ktype; 指向该kset对象类型描述符的指针 struct list head list; 用于连接该kset中所有kobject的链表头 struct kobject kobj; 嵌入的kobject 所有属于这个kset 的kobject对象的parent域均指向这个内嵌的对象 struct kset hotplug ops * hotplug ops; 指向热插拔操作表的指针 };
这个图就表明了kset与kobject之中一部分指针之间的关系。这个图大家都在用。
相关函数 系统在添加和删除设备的时候都会用到这些函数来管理整个设备系统。
与kobject
相似,kset_init()完成指定kset的初始化,kset_get()和kset_put()分别增加和减少kset对象的引用计数。
Kset_add()和kset_del()函数分别实现将指定keset对象加入设备层次和从其中删除;kset_register()函数完成
kset的注册而kset_unregister()函数则完成kset的注销。
kset中的subsystem:
如果說kset 是管理kobject 的集合,同理,subsystem 就是管理kset 的集合。它描述系统中某一类设备子系统,如block subsys表示所有的块设备,对应于sysfs文件系统中的block目录。类似的,devices subsys对应于sysfs中的devices目录,描述系统中所有的设备。Subsystem由struct subsystem数据结构描述,
struct subsystem { struct kset kset; 内嵌的kset对象 struct rw semaphore rwsem; 互斥访问信号量 };
可以看出,subsystem与kset的区别就是多了一个信号量,所以在后来的代码中,subsystem已经完全被kset取缔了。现在看到的应该就是kset中有kset的情况。
想一想一个设备 一个驱动 一个总线,他们在系统中怎么描述呢?是结构体。他们之间的关系怎么描述呢?是结构体。怎么管理他们呢?啊 不是结构体是函数啊。