Chinaunix首页 | 论坛 | 博客
  • 博客访问: 479420
  • 博文数量: 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:05:12

linux按键驱动讲解三[zt]
2008-04-07 11:47:06
linux键盘驱动(模块动态加载)三     -|jacketzhong 发表于 2006-8-29 14:33:00

 转载请注明来源:qiangren.blog.edu.cn 更多的资讯欢迎登录:qiangren.blog.edu.cn

欢迎邮件交流:

上面如果你看得懂得话,那么可以进入下面的学习了,主要介绍的是内核定时器的使用,利用等待队列实现阻塞型I/O,poll系统调用,异步通知方 式,介绍完之后,我将给出一个应用实例,对于有使用过文件操作系统调用的来说,对我们所写的键盘驱动来说,他们基本上是一样的。废话少说,我们马上开始我 们精彩的驱动开发!

六.内核定时器的使用

    在该驱动中,我们假设对键盘的获取是以0.2s为周期执行。源代码如下

static struct timer_list timer;///////我们定义的定时器,也许你会问timer_list是什么来的,其实一看名称就应该就知道了,而为什么要用到list那么多定 时器呢?其实在linux中还有很多相同的定义,比如说信号,我们定义的也是信号集,你可以定义该list是一个元素的,也可以是多个的。所以对于 timer_list就可以这样描述:在未来某一个特定时刻执行某一系列特定任务的功能。下面我们还会给出内核中timer_list的具体描述,^_^ 好像我的话又说多了

static int Keypad_starttimer(void)

{

     init_timer(&timer);//初始化定时器结构

     timer.function=Keypad_timer;//超时服务程序

     timer.expires=jiffies+20;//当前时刻加0.2s

     add_timer(&timer);

     return 0;

}

///超时服务程序

static void Keypad_timer(unsigned long data)

{

    read_xy();

}

/////////接下来说下timer-list这个数据结构,如果你不感兴趣的话可以跳过,该结构在include\linux\timer.h中定义

struct timer_list

{

     struct list_head entry;

     unsigned long expries;

    spinlock_t lock;

    unsigned long magic;

    void (*function)(unsigned long);

    unsigner long data;

    struct tvec_t_base_s *base;

}

七.利用等待队列实现阻塞型I\O

     在用户程序执行读操作的时候有可能尚且没有数据可以读取,为此需要让read操作等待,直到有数据可以读取,这就是阻塞型i\o,阻塞型io可以通过使用 进程休眠方法实现。在无数据可以读取的时候,采用等待队列让进程休眠,直到有数据到达的时候才唤醒进程完成数据的读操作。

    在本驱动中的read,若循环队列缓冲区中没有数据,则进程进入休眠态,定时器函数每隔0.2s读取键值一次,将按键状态放入缓冲并且适时唤醒进程读取数据。

   等待队列的使用流程如下:

   1.声明一个等待队列

   2.把当前进程加入到等待队列中

   3.把进程的状态设置为TASK_INTERRUPTIBLE或TASK_UNINTERRUPTIBLE;

   4.调用schedule,以让出cpu

  5.检测所需要的资源是否可用,若是,把当前进程从等待队列中删除,否则转3循环

接下来我们在对read中有关等待队列阻塞实现做具体的解释

static ssize_t Keypad_read(struct file *filp,char *buf,ssize_t count,loff_t *l)

{

   DECLEARE_WAITQUEUE(wait,current);//声明等待队列,将当前进程加入到等待队列中

   KEY_EVENT t;

   ulong out_buf[2];

   if(head==tail)//当前循环队列中没有数据可以读取

   {

        if(filp->f_flags & O_NONBLOCK)//假如用户采用的是非堵塞方式读取

             return _EAGAIN;

       add_wait_queue(&queue,&wait);//将当前进程加入等待队列

       current->state=TASK_INTERRUPTIBLE;//设置当前进程的状态

       while((head==tail)&&!signal_pending(current))//假若还没有数据到循环队列并且当前进程没有受到信号(该类信号具体来说是未决的休眠)

        {

              shedule();//进程调度

              current->state=TASK_INTERRUPTIBLE;

        }

        current->state=TASK_RUNNING;//该进程恢复执行

        remove_wait_queue(&queue,&wait);//移出等待队列

        if(head==tail)

           return count;

        t=get_data();//调用get_data()函数,得到缓冲区中的数据,下面将给予详细的 介绍

        out_buf[0]=t.status;

        out_buf[1]=t.click;

        copy_to_user(buf,&out_buf,sizeof(out_buf));//将得到的键值拷贝到用户数据区

        return count;

      

   }

}

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