您的位置:首页 > 运维架构 > Linux

Linux设备驱动程序系列(二) 字符设备驱动程序(2)

2011-03-28 21:29 447 查看
前几天回家转了转,跟爸妈聊到深夜,嗬嗬,最后爸妈推荐了一部电视剧《青春期撞上更年期》,所以回来以后,电视剧就开看啦,不过我觉得这不算是浪费时间吧,好的电视剧能给人不少感悟、感动和成长。

下面开始继续我的笔记···



上次写到structcdev,这次接着从structkobject开始记录:

Linux2.6引入新的设备管理机制kobject,通过这个数据结构使所有的设备在底层都具有统一的接口,kobject提供基本的对象管理,是构成Linux2.6设备模型的核心结构,它与sysfs文件系统紧密关联,每个在内核中注册的kobject对象都对应与sysfs文件系统的一个目录。多花一些时间来研究kobject是十分有意义的工作。下面我仔细研究了一下:

Kobject通常通过kset组织成层次化的结构,kset是具有相同类型的kobject的集合。在Linux2.6.30内核

linux/include/linux/kobject.h中查看structkobject结构体的实现如下:

1:structkobject{

2:constchar*name;//名称

3:structlist_headentry;

4:structkobject*parent;//父指针

5:structkset*kset;//kobject对象的集合体

6:structkobj_type*ktype;//kobject对象被关联到的一种特殊的类型

7:structsysfs_dirent*sd;

8:structkrefkref;//引用计数通过此结构体实现的

9:unsignedintstate_initialized:1;

10:unsignedintstate_in_sysfs:1;

11:unsignedintstate_add_uevent_sent:1;

12:unsignedintstate_remove_uevent_sent:1;

13:unsignedintuevent_suppress:1;

14:};

Kobject是基础的结构,它保持设备模型在一起.初始地它被作为一个简单的引用计数,但是它的责任已随时间增长,并且因此有了它自己的战场.structkobject所处理的任务和它的支持代码现在包括:



对象的引用计数


常常,当一个内核对象被创建,没有方法知道它会存在多长时间.一种跟踪这种对象生命周期的方法是通过引用计数.当没有内核代码持有对给定对象的引用,那个对象已经完成了它的有用寿命并且可以被删除.



sysfs表示


在sysfs中出现的每个对象在它的下面都有一个kobject,它和内核交互来创建它的可见表示.



数据结构粘和


设备模型是,整体来看,一个极端复杂的由多级组成的数据结构,各级之间有许多连接.kobject实现这个结构并且保持它在一起.



热插拔事件处理


kobject子系统处理事件的产生,事件通知用户空间关于系统中硬件的来去.

你可能从前面的列表总结出kobject是一个复杂的结构.这可能是对的.通过一次看一部分,但是,是有可能理解这个结构和它如何工作的.摘自——《Linux设备驱动程序(第三版)》361页

在我们进入细节前,值得花些时间理解如何使用kobjects.而且过程中会发现很多有意思的东西。如果你看被kobjects处理的函数列表,你会看到它们都是代表其他对象进行的服务.一个kobject,换句话说,对其自己很少感兴趣;它存在仅仅为了结合一个高级对象到设备模型。

因此,对于内核代码它很少(甚至不知道)创建一个孤立的kobject;相反,kobject被用来控制存取更大的,特定域的对象.。

为此,kobject被嵌入到其他结构中.如果你习惯以面向对象的术语考虑事情,kobject可被看作一个顶级的,抽象类,其他的类自它而来.一个kobject实现一系列功能,这些功能对自己不是特别有用而对其他对象是好的.C语言不允许直接表达继承,因此其他的技术--例如将一个结构嵌入另一个。(看到这大家可能有点糊涂,怀疑C语言真的有这么厉害么?其实C语言真的很厉害,以前我看过一本《C算法》(第一卷)的书,很棒,里面有很多实例都是用C语言实现面向对象编程。)

在上一篇记录中有一个十分关键的结构体:

1:structcdev{

2:structkobjectkobj;

3:structmodule*owner;//所属模块

4:conststructfile_operations*ops;

5://文件操作结构,在写驱动时,其结构体内的大部分函数要被实现

6:structlist_headlist;

7:dev_tdev;//设备号,int类型,高12位为主设备号,低20位为次设备号

8:unsignedintcount;

9:};




从中可以看到,里面嵌入了kobject结构体,如果需要使用该结构体,只需要访问kobject成员就能获得嵌入的kobject对象。但是我们在使用kobject代码时经常遇到相反的问题:对于给定的一个kobject指针,如何获取包含它的结构体指针呢?必然要抛弃一些比较简单的想法(比如你假设kobject处于包含其结构体的开始位置),此时怎么办呢?Linux黑客们帮我们写了一个十分给力的宏,也许学C语言的时候,你还没发现宏的好处,这里我们研究一下这个有意思的宏:container_of宏。

在linux内核中经常用到container_of,它被定义在:

linux/include/linux/kernel.h中,原型为:

1./**

2.*container_of-castamemberofastructureouttothecontainingstructure

3.*@ptr:thepointertothemember.

4.*@type:thetypeofthecontainerstructthisisembeddedin.

5.*@member:thenameofthememberwithinthestruct.

6.*

7.*/

8.#definecontainer_of(ptr,type,member)({/

9.consttypeof(((type*)0)->member)*__mptr=(ptr);/

10.(type*)((char*)__mptr-offsetof(type,member));})



指针ptr指向结构体type中的成员member;通过指针ptr,返回结构体type的起始地址。
这个宏一看就很厉害吧,下***体说说实现的原理。

type

|-----------------|

||

||

|-----------------|

ptr-->|member---------|

|-----------------|

||

||

其中offsetof宏定义在[include/linux/stddef.h]中定义为:

1:1.#defineoffsetof(TYPE,MEMBER)((size_t)&((TYPE*)0)->MEMBER)


这里,要说明的是,((size_t)&((TYPE*)0)->MEMBER)把0地址转化为TYPE结构的指针,然后获取该结构中MEMBER成员的指针,并将其强制转换为size_t类型。于是,由于结构从0地址开始定义,因此,这样求出的MEMBER成员地址,实际上就是它在结构中的偏移量。

分析可知__mptr指向的是一个type结构里typeof(((type*)0)->member)类型member成员的指针,offsetof(type,member)是这个成员在结构中的偏移,单位是字节,所以为了计算type结构的起始地址,__mptr减去它自己的偏移。

至此应该明白这个宏的意思了,它十分关键,以后将常常使用。以后要讲的open函数中就将使用这个宏。

下面看下structktype结构体:

1:structkobj_type{

2:void(*release)(structkobject*kobj);//kobject引用计数减至0时要调用的析构函数

3:structsysfs_ops*sysfs_ops;//描述了sysfs文件读写时的特性

4:structattribute**default_attrs;//定义了该kobject相关的默认属性

5:};


而structkset的实现如下:

1:structkset{

2:structlist_headlist;//连接该集合(kset)中所有kobject对象

3:spinlock_tlist_lock;

4:structkobjectkobj;//该集合的基类

5:structkset_uevent_ops*uevent_ops;//uevent相关操作

6:};




看完主要的kobject的相关结构体,下面接着看kobject的常用的管理与操作:

voidkobject_init(structkobject*kobj,structkobj_type*ktype);


该函数用来初始化kobject,初始化并设置名称后,还需要为它设置kset和ktype字段。

kobject的引用计数:

主要有两个函数:

structkobject*kobject_get(structkobject*kobj);//增加一个引用计数


voidkobject_put(structkobject*kobj);//减少引用计数






回宿舍了此篇明天接着写·····



最后插入一段有意思的东西,大家应该写程序都写很久了,下面我说一个很简单的问题,这个问题就是写文章的时候,教研室的同学问的:

一个char类型的变量A,现在存值为255,用double类型强制转换以后A的值为多少?为什么?

就是提醒大家一下,学多了,也别忘了最基础的知识!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: