linux_davinci按键驱动

来源:互联网 发布:js拼接字符串不用循环 编辑:程序博客网 时间:2024/06/11 13:50
     linux_davinci按键驱动 2013-05-07 09:59:31分类: LINUX一、概述该按键驱动原理虽简单,但是在处理中却运用到了Linux驱动中中断的一些关键技术,比如“顶半部”和“底半部”使用,等待队列的设置。这里“顶半部”即中断处理函数运行时间很短,基本就做了两件事:1、关中断;2、调用定时器。具体代码如下:二、需要的结构定义#define STATUS_NOKEY 0 //无按键状态,按键抬起#define STATUS_DOWNX 1 //有按键状态,但不确定#define STATUS_DOWN 2 //等释放状态,确定按下#define BUF_HEAD (keydev.buf[keydev.head])#define BUF_TAIL (keydev.buf[keydev.tail])#define INCBUF(x,mod) ((++(x)) & ((mod)-1))#define MAX_BUTTON_BUF    16 //按键缓冲区大小#define BUTTON_MAJOR    232         // major device NO./* 主设备号 */#define DEVICE_NAME    "Key-IN1" /*定义设备驱动的名字,或设备节点名称*/#define RTU_KEY_IN1    GPIO_TO_PIN(6, 10)struct button_irq_desc {    int irq;    unsigned long flags;    char *name;};/* 用来指定按键所用的外部中断引脚及中断触发方式, 名字 */static struct button_irq_desc button_irqs[] = {    {gpio_to_irq(RTU_KEY_IN1),IRQF_TRIGGER_FALLING, "KEY_IN1"}, /* K1 */};//按键结构体typedef struct key_dev{    unsigned int keyStatus; //按键状态        unsigned char buf[MAX_BUTTON_BUF];//按键缓冲区        unsigned int head,tail;//按键缓冲区头和尾        wait_queue_head_t wq;//等待队列        struct timer_list key_timer;//按键去抖定时器        struct cdev cdev;//cdev结构体} KEY_DEV;static KEY_DEV keydev;static struct class *buttons_class;三、具体实现static unsigned char get_key(int irqno){     return (gpio_get_value(RTU_KEY_IN1) >> 10);//返回的数值是寄存器IN_DATA67的数值,取第10位的值,即GPIO6_10的数值}static void (*keyEvent)(unsigned long key);static void keyEvent_raw(unsigned long key){    BUF_HEAD=key;//添加到buffer头    keydev.head=INCBUF(keydev.head,MAX_BUTTON_BUF);    wake_up_interruptible(&keydev.wq);//唤醒等待队列}static irqreturn_t buttons_interrupt(int irq,void *dev_id){//    disable_irqs();//关闭中断,转入查询状态    keydev.keyStatus=STATUS_DOWNX;//转为不确定状态    keydev.key_timer.data=get_key(irq)|(irq<<8);//低8位存放键值,高位存放中断号    keydev.key_timer.expires=jiffies+HZ/50;//延迟20ms    add_timer(&keydev.key_timer);//启动定时器    return IRQ_HANDLED;}static int buttons_open(struct inode *inode,struct file *file){    int i;    int ret=0;        for (i = 0; i <sizeof(button_irqs)/sizeof(button_irqs[0]); i++)    {    // 注册中断处理函数,设置GP6[10]IO口为中断下降沿有效的触发方式         ret = request_irq(gpio_to_irq(RTU_KEY_IN1), buttons_interrupt, button_irqs[i].flags, button_irqs[i].name, (void *)&button_irqs[i]);        if(ret)        {            break;        }    }        if(ret)    {//中断申请失败处理,释放已经注册的中断        i--;                for(; i>= 0; i--)            free_irq(gpio_to_irq(RTU_KEY_IN1), (void *)&button_irqs[i]);                return -EBUSY;    }        keydev.head=keydev.tail=0;//清空按键动作缓冲区    keyEvent=keyEvent_raw; //函数指针指向按键处理函数    return 0;}static void key_timer_handler(unsigned long key){    if( get_key(key) == (key & 0xff) )    {//仍处于按下状态        if(keydev.keyStatus==STATUS_DOWNX){//从中断进入            keydev.keyStatus=STATUS_DOWN;            keydev.key_timer.expires=jiffies+HZ/5;//延迟200毫秒            keyEvent(key & 0xff);//记录键值,唤醒等待队列            add_timer(&keydev.key_timer);        }        else{//keyStatus=STATUS_DOWN            keydev.key_timer.expires=jiffies+HZ/5;//延迟200毫秒            add_timer(&keydev.key_timer);        }    }    else{//键已抬起        keydev.keyStatus=STATUS_NOKEY;//        enable_irqs();//使能irq    }}static void keyEvent_dummy(unsigned long key) {}static int buttons_close(struct inode *inode,struct file *filp){    keyEvent=keyEvent_dummy;//函数指针指向空函数    return 0;}static unsigned char keyRead(void){    unsigned char key_ret;    key_ret=BUF_TAIL;    keydev.tail=INCBUF(keydev.tail,MAX_BUTTON_BUF);    return key_ret;}static ssize_t buttons_read(struct file *filp,char *buffer,size_t count,loff_t *ppos){    static unsigned char key_ret;    unsigned long flag; retry:    if(keydev.head!=keydev.tail){//当前循环队列中有数据        local_irq_save(flag); //进入临界区,关闭中断         key_ret=keyRead();//读取按键        local_irq_restore(flag); //退出临界区         copy_to_user(buffer,(char *)&key_ret,1);        return 1;    }    else {        if(filp->f_flags & O_NONBLOCK) //若用户采用非阻塞方式读取            return -EAGAIN;        interruptible_sleep_on(&keydev.wq);//采用阻塞方式读取        goto retry;    }    return 0;}static struct file_operations buttons_fops ={    .owner = THIS_MODULE,    .open = buttons_open, /*open()*/    .release = buttons_close, /*release()*/    .read = buttons_read, /*read()*/}; static void buttons_setup_cdev(void)/* 初始化并注册cdev */{    int err,devno = MKDEV(BUTTON_MAJOR,0);    cdev_init(&keydev.cdev,&buttons_fops);    keydev.cdev.owner = THIS_MODULE;    keydev.cdev.ops = &buttons_fops;    err = cdev_add(&keydev.cdev, devno, 1);    if (err)        printk(KERN_NOTICE "Error %d adding utukey", err);}static struct gpio gpios_6_array[] ={    { GPIO_TO_PIN(6, 10), GPIOF_IN,"RTU_KEY_IN1"},};static int __init buttons_init(void){    int result;    dev_t devno = MKDEV(BUTTON_MAJOR,0);//用主次设备号生成设备号        //申请GPIO,并设置为输入    int ret = gpio_request_array(gpios_6_array, ARRAY_SIZE(gpios_6_array));    if (ret < 0)    {        printk(KERN_ALERT "Cannot open GPIO 6_array\n");        gpio_free_array(gpios_6_array, ARRAY_SIZE(gpios_6_array));     }        /* 申请设备号 */    if (BUTTON_MAJOR)        result = register_chrdev_region(devno, 1, DEVICE_NAME);    else//动态申请设备号    {        result = alloc_chrdev_region(&devno, 0, 1, DEVICE_NAME);        int button_major = MAJOR(devno);        printk(KERN_INFO "Todo: mknod /dev/%s c %d 0\n", DEVICE_NAME, button_major);    }     if (result < 0)        return result;        buttons_setup_cdev();    keydev.head=keydev.tail=0;//初始化按键缓冲区    keydev.keyStatus=STATUS_NOKEY;//初始化按键状态    init_waitqueue_head(&keydev.wq);//初始化等待队列    init_timer(&keydev.key_timer);//初始化定时器,实现软件去抖    keydev.key_timer.function=key_timer_handler;        //生成sysfs文件系统所需的class和属性文件    buttons_class = class_create(THIS_MODULE,DEVICE_NAME);    if(IS_ERR(buttons_class))    {        printk(KERN_ALERT"err:fail in buttons_class!\n");        return -1;    }    device_create(buttons_class,NULL,MKDEV(BUTTON_MAJOR,0),NULL,DEVICE_NAME);    printk(KERN_WARNING"buttons Module initialed!\n");}static void __exit buttons_exit(void){    cdev_del(&keydev.cdev); // 注销cdev    unregister_chrdev_region(MKDEV(BUTTON_MAJOR, 0), 1); // 释放设备号    device_destroy(buttons_class,MKDEV(BUTTON_MAJOR,0));    class_destroy(buttons_class);}module_init(buttons_init);module_exit(buttons_exit);MODULE_AUTHOR("WBL"); MODULE_DESCRIPTION("Davinci BUTTON Driver"); MODULE_LICENSE("GPL");

               
原创粉丝点击