Chinaunix首页 | 论坛 | 博客
  • 博客访问: 255967
  • 博文数量: 65
  • 博客积分: 2599
  • 博客等级: 少校
  • 技术积分: 710
  • 用 户 组: 普通用户
  • 注册时间: 2010-05-04 10:49
文章分类

全部博文(65)

文章存档

2015年(4)

2013年(2)

2012年(4)

2011年(51)

2010年(4)

分类: LINUX

2011-03-17 15:49:22

1. 模块初始化:
module_init(scull_init_module);
这指定了模块的初始化函数为scull_init_module,当insmod的时候就会自动执行这个函数,
当这个函数执行完毕之后,整个模块就准备就绪,当然整个驱动程序连同设备就能够为用户提供服务了!
scull_init_module
@1:申请设备号:
@2:申请设备:
       通过kmalloc向OS申请描述设备所需要的内存,并且用memset清零。因为可能同时申请多个设备共享一个主设备号,也就是多个设备共享一份驱动程序代码。
@3:软件设备结构初始化:
       @3.1:初始化和设备自身逻辑以及软件设计相关的部分,和实现逻辑以及设计相关
       @3.2:初始化和Linux Kernel接口相关的部分
                 这部分主要的工作有:
                  1.准备好和file_operations结构相关的函数,设备需要哪个函数实现哪个,不需要全部实现。
                         struct file_operations scull_ops = {
                                .owner   = THIS_MODULE,
                                .read    = scull_read,
                                .write   = scull_write,
                                .open    = scull_open,
                                .release = scull_release
                           };
                         这是最基本的四个函数,不能少的!
                 2.调用cdev_init函数
                       首先,将cdev交给Kernel完成初始化
                        然后,将自己实现的file_operations方法和cdev关联
                 3.调用cdev_add函数
                       将初始化好的cdev添加到Kernel中,着一个步骤完成之后,用户就可以访问设备了,所以必须确                          保,在调用cdev_add之前,一切准备就绪。
@4:错误处理
       在以上步骤中,涉及到申请内存,使用Kernel的设施,所以就有可能出现错误,这时候,必须进行错误处理。
       在出错时,一般将特定的错误码保存到retval之类的变量中,然后采用goto语句跳转到错误处理函数,这个函数主要的作用就是撤销已经申请的资源!往往将这个函数单独实现,在模块清除函数中也会调用它。对于simple_scull来说,由于极其简单,这个scull_cleanup_module既是模块清除函数,也是错误处理函数。我个人觉得,模块的清除函数中应该只释放模块初始化函数申请的资源。其他的资源,例如由open函数申请的,就应该由release函数释放,应该有一个对应关系,这样代码更清晰!

2. 模块清除函数:
module_exit(scull_cleanup_module);
指定模块的清除函数,它负责释放有module_init指定的函数申请的所有资源,清除驱动程序和内核的接口设施,包括设备号和设备,将硬件设备调整到一个合适状态。
@1:注销和Kernel接口的设施
         cdev_del
@2:释放由module_init申请的资源
@3:注销设备号

3. 和file_operations相关的函数:
没有必要实现其中的所有方法,这个和硬件设备有关,也和驱动程序设计相关,我觉得也和上层软件使用的API相关。
@1 scull_open:
      主要提供驱动程序自身的初始化能力,因为如果设备没有被打开,就表示没有人使用它,那么提前为它分配任何功能性的资源就是一种不明智的选择,只有到了必须分配的时候在分配!open的时候,就必须分配了!
     @1.1 检查硬件设备状态,是否可以工作,是否就绪
     @1.2 如果设备是第一次被打开,那么进行设备初始化
     @1.3 根据需要,可能要更新file_operations指针
             例如,不同的次设备号,表示不同的操作方式或者配置方式,这时候就需要提供不同的方法。
     @1.4 分配,并且填写filp->private_data中的数据结构(他就是一个指针)
            这里面方的内容根据需要,自行决定。
            一般为了方便,会将cdev结构指针放入其中。
            还应该根据打开文件的方式作相应的调整,例如:只读形式打开,那么应该将文件长度减为零。
@2 scull_release:
     @2.1 释放由open申请的资源,以及保存在filp->private中的所有内容。
     @2.2 在最后一次关闭的时候,关闭设备。
     并不是每一个close都会导致release方法的执行,Kernel保存file结构使用inode的计数,只有为0的时候,才会调用release方法。      
@3 scull_write:
      @3.1 申请用于缓存用户空间数据的内存
      @3.2 使用合适的方法,将数据写入硬件设备。
       @3.3 更新文件当前位置指针f_pos以及和用来表示设备的数据结构中的相应描述信息(scull_dev)
      注意copy_from_user的时候
@4 scull_read:
      @4.1 根据文件当前位置指针f_pos和count,从设备中读取数据
      @4.2 将数据拷贝到用户空间copy_to_user
      在read和write方法中,检查读写位置的合法性以及count字段,由于库函数在返回数据不足的时候会重新继续读取,所以,驱动程序即使一次没有返回count个字节,也不会出现问题,但是多次系统调用的开销需要考虑。
     注意write和read的返回值,同时也要注意上层应用是否需要使用可以阻塞的方法,这时候,是否有需要实现其他的readv和writev方法。

 simple_scull.zip   
阅读(803) | 评论(0) | 转发(0) |
0

上一篇:vim 代码折叠

下一篇:printk函数

给主人留下些什么吧!~~