Chinaunix首页 | 论坛 | 博客
  • 博客访问: 492219
  • 博文数量: 130
  • 博客积分: 2111
  • 博客等级: 大尉
  • 技术积分: 1373
  • 用 户 组: 普通用户
  • 注册时间: 2009-08-28 09:55
个人简介

IT民工

文章分类

全部博文(130)

文章存档

2021年(1)

2019年(1)

2017年(3)

2014年(1)

2013年(3)

2012年(2)

2011年(3)

2010年(2)

2009年(114)

分类: LINUX

2009-09-03 13:03:01

linux按键驱动讲解一[zt]
2008-04-07 11:42:36
linux键盘驱动(模块动态加载)一(开始)     -|jacketzhong 发表于 2006-8-29 10:24:00

     键盘在所有的驱动之中最为简单的一种,但它却包含了驱动的基本框架,对以后继续深入学习其他复杂的驱动大有裨益,以下便为你逐步剖析驱动的开发。采用的是查询方式。转载请注明出处:qiangren.blog.edu.cn

一.内核模块的注册和撤销

    在加载模块的时候,首先运行的是内核模块的注册函数。它的功能包括内核注册设备以及变量的初始化。

static int head,tail;

int  _init Keypad_init(void)

{

   int result;

   result=register_chrdev(KEY_LED_MAJOR,KEY_LED_NAME,&Keypad_fops);

  Keypad_clear();

  init_waitqueue_head(&queue);

  prink("%s %s initialized.\n",KEY_LED_NAME,KEY_LED_VERSION);//不能用prinf

 return 0;

}

module_init(Keypad_init);//加载模块

void _exit Keypad_cleanup(void)

{

   del_timer(&timer);

   unregister_chrdev(KEY_LED_MAJOR,KEY_LED_NAME);

   prink("Keypad driver removed \n");

}

module_exit(Keypad_cleanup);//卸载该模块

二.虚拟文件系统与硬件驱动的接口

static struct file_operations Keypad_fops={

  open:Keypad_open,

  read:Keypad_read,

  poll:Keypad_poll,

  fasync:Keypad_fasync,

 release:Keypad_release,

};

该接口定义完之后一些便是对这几个具体函数的实现了!现在我们一起进入下一步吧,是不是觉得其实没什么难度的呢?别那么早开心着呢?这几个函数的实 现时候,涉及到很多技术,包括内核定时器,*等待队列的具体实现(阻塞方式),异步方式的具体实现技巧,循环队列。看到这么多技术你是否感到很兴奋呢?以 下本人将以通俗的方式为你讲解,希望你能理解。

(更多的资讯欢迎登录:qiangren.blog.edu.cn

三.设备的打开操作接口函数具体实现(Keypad_open)

设备打开一般包括两大操作,一是完成设备的初始化,二是设备引用计数器加1

static int Keypad_open(struct inode *inode,struct file *filp)

{

  read_xy();

  try_module_get(THIS_MODULE);//此函数为linux 2.6内核增加的,不同于2.4内核,功能是计数器的值加1

  return 0;

}

static void read_xy(void)

{

  new_data();//获取键值函数

  keypad_starttimer();//开启内核定时器,在固定周期时间内获取键盘新的变化

}

以下实现键盘键值获取函数read_xy()

主要是从KEY_CS(对应的读入地址,之前可以根据具体的硬件设备定义,比如#define kEY_CS(*(volatile unsigned short *)(0xf820000))此处应该根据具体的不同而不同!

将读入的键值存入buf[]缓存中,环形缓冲的写指针是head,读指针是tail,前面已经定义过了

////////////////////////////////键盘事件的数据结构定义/////////////////////////////////

typedef struct{

  ulong status;//按键的值

  ulong click;//是否有按键按下,1表示有,0表示没有

}KEY_EVENT  

static KEY_EVENT cur_data,buf[BUFSIZE];//BUFSIZE为宏定义,用于定义环形缓冲的大小

static void new_data(void)

{

  if((KEY_CS & 0xff)!=0xff)  //从KEY_CS地址读入数据,若有一个为0则表示有一个按键被按下了(此处硬件电路为低电平有效)

  {

        switch(KEY_CS & 0xff){

             case ~KEY0 & 0xff:

                      cur_data.status=1;///////1被按下

                      break;

           

              case ~KEY1 & 0xff:

                      cur_data.status=2;//2被按下

                      break;

              /////////其他一样添加,懂吗??

         }

          cur_data.click=1;

     }

     else if(KEY_CS & 0xff==0xff){

         cur_data.click=0;

        cur_data.status=0;

     }

     if(head!=tail){////////循环队列缓冲区的应用在此开始了^_^

         int last=head--;

         if(last<0)////////若已经到了对首之前,则跳到队尾,以实现循环队列

            last=BUFSIZE-1;

     }

     //////按键信息存入循环队列缓冲区中

     buf[head]=cur_data;

    if(++head==BUFSIZE)

       head=0;

    if(head==tail && tail++=BUFSIZE)

      tail=0;

    if(fasync)

      kill_fasync(&fasyc,SIGIO,POLL_IN);

    wake_up_interruptible(&queue);

}

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