Chinaunix首页 | 论坛 | 博客
  • 博客访问: 263675
  • 博文数量: 52
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 277
  • 用 户 组: 普通用户
  • 注册时间: 2016-06-09 10:57
文章分类

全部博文(52)

文章存档

2016年(52)

我的朋友

分类: LINUX

2016-09-24 16:44:29

        接着上篇博客,下图为设备驱动的初始化函数和退出函数。

                            
                            

        第44行定义整形变量 err ,用来保存错误码。

        第45行是一个调试函数,他与函数pr_devel 差不多,对应的输出级别都为7级。

        第47到51行为动态分配设备号,函数第一个参数为输出型参数,用于存放分配到的设备号。第二个参数为要注册的次设备号的起始值,第三个参数为要注册的设备号的个数,第四个参数表示设备号的名称。此处kpad.dev存放分配到的设备号,次设备号的起始值为0,分配个数为1,设备的名称为“kpad”。需要注意的是分配设备号时内核自动决定的实际上是主设备号,所属的次设备号的起始值和个数都是由用户提供的。最终由第一个参数存储的是分配到的第一个设备号。分配到的设备号为以注册状态,不需要再调用注册设备号的接口函数进行注册

        其中49行中为 “-err”,而不是err是因为上篇博客已经说过,内核的函数在失败时返回的是一个负数,代表失败的原因,称为错误码,内核的错误码都是以宏的形式定义在头文件中,这些宏定义都是正数,所以返回时要加一个负号。

        第50行也是需要注意学习的,这是goto语句的一个非常经典的用法。用于错误处理的,经常放在函数体的最后。第74到81都是错误处理的情况。75行为释放所分配的内存,78行为注销所注册的设备号。上述的各个清理操作按初始化时的倒序排列,错处时跳到相应的位置。这是驱动编程中的常用的做法。

        第53行输出调试信息,主设备号和次设备号。主设备号由函数MAJOR()获得,次设备号由函数MINOR()函数获得。

        第55到60行为分配内核缓冲区。其中58行 “-ENOMEM”  此错误号表示内存不足,要加负号

        第62行为保存分配的缓冲区的长度。

        第63和64行为初始化字符设备的内容。cdev_init()函数有两个参数,第一个为需要初始化的字符设备,第二个参数为字符设备所支持的一系列文件操作。这样设备和文件操作就联系起来了。原型为cdev_init(struct cdev  *cdev,  const struct file_operations  *fops);初始化字符设备实际上就是对cdev参数所指向的结构体中的成员进行初始化,结构体cdev的定义如下:
                                        
                                      

其中标有  “内部使用”  的成员为内核管理字符设备所使用的成员,在驱动中一般不要对其进行修改。owner成员指向一个struct  module 型的结构体,这个结构体用于管理内核模块的,对应于每一个加载的模块都有一份相应的数据。owner成员的主要用途是正确处理模块的引用计数,当字符设备被打开使用时,它所属的模块的引用计数将增加。而引用计数为0 的模块才能被卸载。初始化字符设备的函数并没有设置这个成员,需要另外赋值,一般情况下都会赋值为THIS_MODULE,这是一个宏,代表本模块。其中64行即为对这个成员的赋值。 

        第66行为注册字符设备,初始化或创建得到的字符设备还仅仅是一个结构体变量,要使内核中真正产生一个字符设备,需要将其注册。从此这个字符设备就和设备号绑定了。

        截止到目前为止。kpad设备的设备号和设备都已经向内核注册好了,设备所支持的文件爱操作也规划好了,下面的内容就是一些列的文件操作的实现。从上面的内容可以看出,驱动注册的步骤为:首先是对设备号的处理(分配、注册),然后初始化字符设备(cdev 成员的初始化,所支持的文件操作),最后是注册字符设备(把字符设备和设备号绑定了 cdev_add函数),内核提供了很多函数,要注意不同函数的搭配。

        至于一系列的文件操作,将在下篇文章介绍。

阅读(1213) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~