驱动:8.3设备的非阻塞方式访问

应用程序:

fd = open("/dev/mybuttons",O_RDONLY); //阻塞方式
fd = open("/dev/mybuttons",O_RDNLY|O_NONBLOCK);//非阻塞方式

驱动程序:

也需要支持非阻塞方式

代码示例:

#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/interrupt.h>
#include <linux/uaccess.h>
#include <mach/platform.h>
#include <linux/sched.h>
#include <linux/gpio.h>

MODULE_LICENSE("GPL");

struct cdev btn_cdev;
dev_t dev;
struct class *cls;

/*定义一个信号量*/
struct semaphore btn_sem;
/*定义按键键值缓冲区*/
unsigned char key_buf;
/*表示按键缓冲区中是否有键值 0,无键值  1,有键值*/
volatile unsigned int ev_press = 0;
/*定义一个等待队列头*/
wait_queue_head_t btn_wqh;

typedef struct btn_desc
{
    unsigned char code;//按键编码值
    int irq;
    char *name;
    int gpio;//管脚编号
}btn_desc_t;
btn_desc_t buttons[]=
{
    {0x10, IRQ_GPIO_A_START+28, "up", PAD_GPIO_A+28},
    {0x20, IRQ_GPIO_B_START+30, "down", PAD_GPIO_B+30},
    {0x30, IRQ_GPIO_B_START+31, "left", PAD_GPIO_B+31},
    {0x40, IRQ_GPIO_B_START+9, "right", PAD_GPIO_B+9},
};
struct timer_list btn_timer;//延时去抖

int btn_open(struct inode *inode, struct file *filp)
{
    /*获取信号量*/
    //down(&btn_sem);
    if(down_interruptible(&btn_sem))
    {
        return -ERESTARTSYS;
    }
    return 0;
}
int btn_close(struct inode *inode, struct file *filp)
{
    up(&btn_sem);
    return 0;
}
ssize_t btn_read(struct file *filp, char __user *buf, size_t len, loff_t *offset)
{
    int ret = 0;

    //if(用户空间打开设备时使用O_NONBLOCK参数 && 没有数据供用户空间读)
    if((filp->f_flags&O_NONBLOCK)  && (ev_press==0))
    {
        return -EAGAIN;
    }

    /*有数据就直接返回给用户空间 无数据就睡眠等待
     *等待过程中一旦有数据可供用户空间读,就唤醒睡眠进程
     *将数据返回到用户空间
     * */
    wait_event_interruptible(btn_wqh, ev_press);
    
    /*将键值拷贝到用户空间内存*/
    ret = copy_to_user(buf, &key_buf, len);

    ev_press = 0;

    return len;
}

struct file_operations btn_fops =
{
    .owner = THIS_MODULE,
    .open = btn_open,
    .release = btn_close, 
    .read   = btn_read, 
};

irqreturn_t btn_isr(int irq, void *dev)
{
    /*传递了按键的描述信息*/
    btn_timer.data = (unsigned long)dev;
    /*修改定时器的超时时间*/
    mod_timer(&btn_timer, jiffies+HZ/100);

    return IRQ_HANDLED;
}
void btn_timer_func(unsigned long data)
{
    int stat = 0;
    /*获取哪个按键触发*/
    btn_desc_t *pdata = (btn_desc_t *)data;
    stat = gpio_get_value(pdata->gpio);
    /*保存按键值*/
    key_buf = pdata->code + stat;
    ev_press = 1;//按键缓冲区中有键值
    /*唤醒因无键值而睡眠的进程*/
    wake_up_interruptible(&btn_wqh);
}
int __init btn_drv_init(void)
{
    int ret = 0;
    int i = 0;
    /*申请设备号*/
    alloc_chrdev_region(&dev, 0, 1, "mybuttons");
    /*初始化cdev*/
    cdev_init(&btn_cdev, &btn_fops);
    /*注册cdev*/
    cdev_add(&btn_cdev, dev, 1);
    /*创建设备文件*/
    cls = class_create(THIS_MODULE, "buttons");
    device_create(cls, NULL, dev, NULL, "mybuttons");
    /*初始化信号量*/
    sema_init(&btn_sem, 1);
    /*初始化等待队列头*/
    init_waitqueue_head(&btn_wqh);
    /*注册中断*/
    for(; i<ARRAY_SIZE(buttons); i++)
    {
        ret = request_irq(buttons[i].irq, btn_isr, 
        IRQF_TRIGGER_FALLING|IRQF_TRIGGER_RISING, 
        buttons[i].name, buttons+i);
    }
    /*初始化timer*/
    init_timer(&btn_timer);
    btn_timer.function = btn_timer_func;
    return 0;
}
void __exit btn_drv_exit(void)
{
    int i = 0;
    /*停止定时器*/
    del_timer(&btn_timer);

    for(; i<ARRAY_SIZE(buttons); i++)
    {
        /*注销中断*/
        free_irq(buttons[i].irq, buttons+i);
    }
    /*销毁设备文件*/
    device_destroy(cls, dev);
    class_destroy(cls);
    /*注销cdev*/
    cdev_del(&btn_cdev);
    /*注销设备号*/
    unregister_chrdev_region(dev, 1);
}
module_init(btn_drv_init);
module_exit(btn_drv_exit);

原理:

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值