一、概念

      应用程序使用API接口,如open、read等来最终操作驱动,有两种结果--成功和失败。成功,很好处理,直接返回想要的结果;但是,失败,是继续等待,还是返回失败类型呢?  如果继续等待,将进程休眠,那么这类驱动设计就是阻塞式的;如果不等待,返回失败的类型(原因),那么这类驱动的设计就是非阻塞式的。

      在应用程序打开驱动文件的时候,可以通过参数向驱动传递使用驱动的方式(阻塞或者非阻塞),通过flags这个参数来传递。当flags中包含“O_NONBLOCK”,就是非阻塞,否则就是阻塞式的。

fd = open("/dev/xxx", O_RDWR | O_NONBLOCK);

二、具体实现

      以按键驱动为例进行说明,主要是利用互斥锁功能来实现。

1、实现open函数的阻塞非阻塞功能

static DECLARE_MUTEX(buttons_lock); 

static int buttons_open(struct inode *inode, struct file *file)
{    
    if (file->f_flags & O_NONBLOCK)
    {
        if (down_trylock(&buttons_lock))
        return -EBUSY;
    }
    else
    {
        down(&buttons_lock);
    }
    ............
    return 0;
}            

      open()函数的目的是打开驱动文件/dev/buttons,而通常驱动文件允许打开的进程数量是有限制的,本例中是独占式的,所以需要利用互斥锁。函数down_trylock()和函数down(),分别具有非阻塞和阻塞的特性,所以利用这种特性,很容易实现open()函数的需求。

      注意在buttons_close()函数,不要忘记调用up(&buttons_lock)把互斥锁释放。

2、实现read函数的阻塞非阻塞功能

static int buttons_read(struct file *filp, char __user *buff, 
                                         size_t count, loff_t *offp)
{
    unsigned long err;
    
    if (filp->f_flags & O_NONBLOCK)
    {
        if(0 == ev_press)
        {
            return -EAGAIN;
        }
    }
    else
    {
        /* 如果没有按键动作, 休眠 */
        wait_event_interruptible(button_waitq, ev_press);
    }

    /* 执行到这里时,ev_press等于1,将它清0 */
    ev_press = 0;

    /* 将按键状态复制给用户,并清0 */
    err = copy_to_user(buff, &keys_val, count);

    return err ? -EFAULT : 0;
}

      read()函数的目的是来读取/dev/buttons文件,所收到的按键键值。当被按下,中断程序令ev_press置1,读取完之后清0。

      显然,如果已经被按下,已经存入了键值,那么read函数很容易成功返回。但是,如果没有按键按下,这个时候阻塞的处理就是继续等待,将进程休眠;而非阻塞则是返回-EAGAIN,重新来读。

 

参考资料:韦东山linux教学视频

posted on 2017-05-27 16:15  amanlikethis  阅读(1024)  评论(0编辑  收藏  举报