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结构体的实现如下:
Kobject是基础的结构,它保持设备模型在一起.初始地它被作为一个简单的引用计数,但是它的责任已随时间增长,并且因此有了它自己的战场.structkobject所处理的任务和它的支持代码现在包括:
对象的引用计数
常常,当一个内核对象被创建,没有方法知道它会存在多长时间.一种跟踪这种对象生命周期的方法是通过引用计数.当没有内核代码持有对给定对象的引用,那个对象已经完成了它的有用寿命并且可以被删除.
sysfs表示
在sysfs中出现的每个对象在它的下面都有一个kobject,它和内核交互来创建它的可见表示.
数据结构粘和
设备模型是,整体来看,一个极端复杂的由多级组成的数据结构,各级之间有许多连接.kobject实现这个结构并且保持它在一起.
热插拔事件处理
kobject子系统处理事件的产生,事件通知用户空间关于系统中硬件的来去.
你可能从前面的列表总结出kobject是一个复杂的结构.这可能是对的.通过一次看一部分,但是,是有可能理解这个结构和它如何工作的.摘自——《Linux设备驱动程序(第三版)》361页
在我们进入细节前,值得花些时间理解如何使用kobjects.而且过程中会发现很多有意思的东西。如果你看被kobjects处理的函数列表,你会看到它们都是代表其他对象进行的服务.一个kobject,换句话说,对其自己很少感兴趣;它存在仅仅为了结合一个高级对象到设备模型。
因此,对于内核代码它很少(甚至不知道)创建一个孤立的kobject;相反,kobject被用来控制存取更大的,特定域的对象.。
为此,kobject被嵌入到其他结构中.如果你习惯以面向对象的术语考虑事情,kobject可被看作一个顶级的,抽象类,其他的类自它而来.一个kobject实现一系列功能,这些功能对自己不是特别有用而对其他对象是好的.C语言不允许直接表达继承,因此其他的技术--例如将一个结构嵌入另一个。(看到这大家可能有点糊涂,怀疑C语言真的有这么厉害么?其实C语言真的很厉害,以前我看过一本《C算法》(第一卷)的书,很棒,里面有很多实例都是用C语言实现面向对象编程。)
在上一篇记录中有一个十分关键的结构体:
从中可以看到,里面嵌入了kobject结构体,如果需要使用该结构体,只需要访问kobject成员就能获得嵌入的kobject对象。但是我们在使用kobject代码时经常遇到相反的问题:对于给定的一个kobject指针,如何获取包含它的结构体指针呢?必然要抛弃一些比较简单的想法(比如你假设kobject处于包含其结构体的开始位置),此时怎么办呢?Linux黑客们帮我们写了一个十分给力的宏,也许学C语言的时候,你还没发现宏的好处,这里我们研究一下这个有意思的宏:container_of宏。
在linux内核中经常用到container_of,它被定义在:
linux/include/linux/kernel.h 中,原型为:
指针ptr指向结构体type中的成员member;通过指针ptr,返回结构体type的起始地址。
这个宏一看就很厉害吧,下***体说说实现的原理。
这里,要说明的是,((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结构体:
而structkset的实现如下:
看完主要的kobject的相关结构体,下面接着看kobject的常用的管理与操作:
该函数用来初始化kobject,初始化并设置名称后,还需要为它设置kset和ktype字段。
kobject的引用计数:
主要有两个函数:
回宿舍了此篇明天接着写·····
最后插入一段有意思的东西,大家应该写程序都写很久了,下面我说一个很简单的问题,这个问题就是写文章的时候,教研室的同学问的:
一个char类型的变量A,现在存值为255,用double类型强制转换以后A的值为多少?为什么?
就是提醒大家一下,学多了,也别忘了最基础的知识!
下面开始继续我的笔记···
上次写到structcdev,这次接着从structkobject开始记录:
Linux2.6引入新的设备管理机制kobject,通过这个数据结构使所有的设备在底层都具有统一的接口,kobject提供基本的对象管理,是构成Linux2.6设备模型的核心结构,它与sysfs文件系统紧密关联,每个在内核中注册的kobject对象都对应与sysfs文件系统的一个目录。多花一些时间来研究kobject是十分有意义的工作。下面我仔细研究了一下:
Kobject通常通过kset组织成层次化的结构,kset是具有相同类型的kobject的集合。在Linux2.6.30内核
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,它被定义在:
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的值为多少?为什么?
就是提醒大家一下,学多了,也别忘了最基础的知识!
相关文章推荐
- Linux设备驱动程序系列(二) 字符设备驱动程序(1)
- Linux设备驱动程序第三版学习(1)-字符设备驱动程序源码分析
- Linux设备驱动程序——简单字符设备驱动程序
- LINUX设备驱动程序笔记(三)字符设备驱动程序
- linux设备驱动程序第二版 字符设备驱动程序
- linux设备驱动程序第二版 字符设备驱动程序的扩展操作
- Linux设备驱动程序第三版学习(9)- 高级字符驱动程序操作(续4) - llseek定位设备
- linux设备驱动程序——字符设备驱动程序
- Linux设备驱动程序第三版学习(9)- 高级字符驱动程序操作(续4) - llseek定位设备
- Linux设备驱动程序第三版学习(1)-字符设备驱动程序源码分析
- Linux设备驱动程序第三版学习(1)-字符设备驱动程序源码分析
- 《Linux设备驱动程序》读书笔记:字符设备驱动程序(一)
- 《Linux设备驱动程序》——字符设备驱动程序
- Linux设备驱动程序第三版学习(1)(2)-字符设备驱动程序源码分析
- 字符设备驱动程序之二
- linux 字符设备驱动程序原理
- 07-S3C2440驱动学习(一)嵌入式linux字符设备驱动-查询+中断+引入poll机制的按键驱动程序
- 字符设备驱动之register_chrdev_region()系列
- 字符设备驱动程序
- LINUX字符设备驱动程序实例(scull)