Chinaunix首页 | 论坛 | 博客
  • 博客访问: 14306
  • 博文数量: 6
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 2
  • 用 户 组: 普通用户
  • 注册时间: 2013-07-14 23:04
文章分类
文章存档

2013年(6)

我的朋友

分类: LINUX

2013-07-14 23:08:21

原文地址:linux_davinci按键驱动 作者:wangbaolin719


  1. 一、概述
  2. 该按键驱动原理虽简单,但是在处理中却运用到了Linux驱动中中断的一些关键技术,比如“顶半部”和“底半部”使用,等待队列的设置。
  3. 这里“顶半部”即中断处理函数运行时间很短,基本就做了两件事:1、关中断;2、调用定时器。具体代码如下:

  4. 二、需要的结构定义
  5. #define STATUS_NOKEY 0 //无按键状态,按键抬起
  6. #define STATUS_DOWNX 1 //有按键状态,但不确定
  7. #define STATUS_DOWN 2 //等释放状态,确定按下

  8. #define BUF_HEAD (keydev.buf[keydev.head])
  9. #define BUF_TAIL (keydev.buf[keydev.tail])
  10. #define INCBUF(x,mod) ((++(x)) & ((mod)-1))
  11. #define MAX_BUTTON_BUF    16 //按键缓冲区大小
  12. #define BUTTON_MAJOR    232         // major device NO./* 主设备号 */
  13. #define DEVICE_NAME    "Key-IN1" /*定义设备驱动的名字,或设备节点名称*/
  14. #define RTU_KEY_IN1    GPIO_TO_PIN(6, 10)

  15. struct button_irq_desc {
  16.     int irq;
  17.     unsigned long flags;
  18.     char *name;
  19. };

  20. /* 用来指定按键所用的外部中断引脚及中断触发方式, 名字 */
  21. static struct button_irq_desc button_irqs[] = {
  22.     {gpio_to_irq(RTU_KEY_IN1),IRQF_TRIGGER_FALLING, "KEY_IN1"}, /* K1 */
  23. };

  24. //按键结构体
  25. typedef struct key_dev{
  26.     unsigned int keyStatus; //按键状态    
  27.     unsigned char buf[MAX_BUTTON_BUF];//按键缓冲区    
  28.     unsigned int head,tail;//按键缓冲区头和尾    
  29.     wait_queue_head_t wq;//等待队列    
  30.     struct timer_list key_timer;//按键去抖定时器    
  31.     struct cdev cdev;//cdev结构体
  32. } KEY_DEV;

  33. static KEY_DEV keydev;
  34. static struct class *buttons_class;

  35. 三、具体实现
  36. static unsigned char get_key(int irqno)
  37. {
  38.     return (gpio_get_value(RTU_KEY_IN1) >> 10);//返回的数值是寄存器IN_DATA67的数值,取第10位的值,即GPIO6_10的数值
  39. }

  40. static void (*keyEvent)(unsigned long key);

  41. static void keyEvent_raw(unsigned long key)
  42. {
  43.     BUF_HEAD=key;//添加到buffer头
  44.     keydev.head=INCBUF(keydev.head,MAX_BUTTON_BUF);
  45.     wake_up_interruptible(&keydev.wq);//唤醒等待队列
  46. }

  47. static irqreturn_t buttons_interrupt(int irq,void *dev_id)
  48. {
  49. //    disable_irqs();//关闭中断,转入查询状态
  50.     keydev.keyStatus=STATUS_DOWNX;//转为不确定状态
  51.     keydev.key_timer.data=get_key(irq)|(irq<<8);//低8位存放键值,高位存放中断号
  52.     keydev.key_timer.expires=jiffies+HZ/50;//延迟20ms
  53.     add_timer(&keydev.key_timer);//启动定时器
  54.     return IRQ_HANDLED;
  55. }

  56. static int buttons_open(struct inode *inode,struct file *file)
  57. {
  58.     int i;
  59.     int ret=0;
  60.     
  61.     for (i = 0; i <sizeof(button_irqs)/sizeof(button_irqs[0]); i++)
  62.     {    // 注册中断处理函数,设置GP6[10]IO口为中断下降沿有效的触发方式
  63.         ret = request_irq(gpio_to_irq(RTU_KEY_IN1), buttons_interrupt, button_irqs[i].flags, button_irqs[i].name, (void *)&button_irqs[i]);
  64.         if(ret)
  65.         {
  66.             break;
  67.         }
  68.     }
  69.     
  70.     if(ret)
  71.     {//中断申请失败处理,释放已经注册的中断
  72.         i--;        
  73.         for(; i>= 0; i--)
  74.             free_irq(gpio_to_irq(RTU_KEY_IN1), (void *)&button_irqs[i]);        
  75.         return -EBUSY;
  76.     }
  77.     
  78.     keydev.head=keydev.tail=0;//清空按键动作缓冲区
  79.     keyEvent=keyEvent_raw; //函数指针指向按键处理函数
  80.     return 0;
  81. }


  82. static void key_timer_handler(unsigned long key)
  83. {
  84.     if( get_key(key) == (key & 0xff) )
  85.     {//仍处于按下状态
  86.         if(keydev.keyStatus==STATUS_DOWNX){//从中断进入
  87.             keydev.keyStatus=STATUS_DOWN;
  88.             keydev.key_timer.expires=jiffies+HZ/5;//延迟200毫秒
  89.             keyEvent(key & 0xff);//记录键值,唤醒等待队列
  90.             add_timer(&keydev.key_timer);
  91.         }
  92.         else{//keyStatus=STATUS_DOWN
  93.             keydev.key_timer.expires=jiffies+HZ/5;//延迟200毫秒
  94.             add_timer(&keydev.key_timer);
  95.         }
  96.     }
  97.     else{//键已抬起
  98.         keydev.keyStatus=STATUS_NOKEY;
  99. //        enable_irqs();//使能irq
  100.     }
  101. }

  102. static void keyEvent_dummy(unsigned long key) {}

  103. static int buttons_close(struct inode *inode,struct file *filp)
  104. {
  105.     keyEvent=keyEvent_dummy;//函数指针指向空函数
  106.     return 0;
  107. }

  108. static unsigned char keyRead(void)
  109. {
  110.     unsigned char key_ret;
  111.     key_ret=BUF_TAIL;
  112.     keydev.tail=INCBUF(keydev.tail,MAX_BUTTON_BUF);
  113.     return key_ret;
  114. }

  115. static ssize_t buttons_read(struct file *filp,char *buffer,size_t count,loff_t *ppos)
  116. {
  117.     static unsigned char key_ret;
  118.     unsigned long flag;
  119. retry:
  120.     if(keydev.head!=keydev.tail){//当前循环队列中有数据
  121.         local_irq_save(flag); //进入临界区,关闭中断
  122.         key_ret=keyRead();//读取按键
  123.         local_irq_restore(flag); //退出临界区
  124.         copy_to_user(buffer,(char *)&key_ret,1);
  125.         return 1;
  126.     }
  127.     else {
  128.         if(filp->f_flags & O_NONBLOCK) //若用户采用非阻塞方式读取
  129.             return -EAGAIN;
  130.         interruptible_sleep_on(&keydev.wq);//采用阻塞方式读取
  131.         goto retry;
  132.     }
  133.     return 0;
  134. }


  135. static struct file_operations buttons_fops =
  136. {
  137.     .owner = THIS_MODULE,
  138.     .open = buttons_open, /*open()*/
  139.     .release = buttons_close, /*release()*/
  140.     .read = buttons_read, /*read()*/
  141. };

  142. static void buttons_setup_cdev(void)/* 初始化并注册cdev */
  143. {
  144.     int err,devno = MKDEV(BUTTON_MAJOR,0);
  145.     cdev_init(&keydev.cdev,&buttons_fops);
  146.     keydev.cdev.owner = THIS_MODULE;
  147.     keydev.cdev.ops = &buttons_fops;
  148.     err = cdev_add(&keydev.cdev, devno, 1);
  149.     if (err)
  150.         printk(KERN_NOTICE "Error %d adding utukey", err);
  151. }
  152. static struct gpio gpios_6_array[] =
  153. {
  154.     { GPIO_TO_PIN(6, 10), GPIOF_IN,"RTU_KEY_IN1"},
  155. };

  156. static int __init buttons_init(void)
  157. {
  158.     int result;
  159.     dev_t devno = MKDEV(BUTTON_MAJOR,0);//用主次设备号生成设备号
  160.     
  161.     //申请GPIO,并设置为输入
  162.     int ret = gpio_request_array(gpios_6_array, ARRAY_SIZE(gpios_6_array));
  163.     if (ret < 0)
  164.     {
  165.         printk(KERN_ALERT "Cannot open GPIO 6_array\n");
  166.         gpio_free_array(gpios_6_array, ARRAY_SIZE(gpios_6_array));
  167.     }
  168.     
  169.     /* 申请设备号 */
  170.     if (BUTTON_MAJOR)
  171.         result = register_chrdev_region(devno, 1, DEVICE_NAME);
  172.     else//动态申请设备号
  173.     {
  174.         result = alloc_chrdev_region(&devno, 0, 1, DEVICE_NAME);
  175.         int button_major = MAJOR(devno);
  176.         printk(KERN_INFO "Todo: mknod /dev/%s c %d 0\n", DEVICE_NAME, button_major);
  177.     }
  178.     if (result < 0)
  179.         return result;
  180.     
  181.     buttons_setup_cdev();
  182.     keydev.head=keydev.tail=0;//初始化按键缓冲区
  183.     keydev.keyStatus=STATUS_NOKEY;//初始化按键状态
  184.     init_waitqueue_head(&keydev.wq);//初始化等待队列
  185.     init_timer(&keydev.key_timer);//初始化定时器,实现软件去抖
  186.     keydev.key_timer.function=key_timer_handler;
  187.     
  188.     //生成sysfs文件系统所需的class和属性文件
  189.     buttons_class = class_create(THIS_MODULE,DEVICE_NAME);
  190.     if(IS_ERR(buttons_class))
  191.     {
  192.         printk(KERN_ALERT"err:fail in buttons_class!\n");
  193.         return -1;
  194.     }
  195.     device_create(buttons_class,NULL,MKDEV(BUTTON_MAJOR,0),NULL,DEVICE_NAME);
  196.     printk(KERN_WARNING"buttons Module initialed!\n");
  197. }

  198. static void __exit buttons_exit(void)
  199. {
  200.     cdev_del(&keydev.cdev); // 注销cdev
  201.     unregister_chrdev_region(MKDEV(BUTTON_MAJOR, 0), 1); // 释放设备号
  202.     device_destroy(buttons_class,MKDEV(BUTTON_MAJOR,0));
  203.     class_destroy(buttons_class);
  204. }

  205. module_init(buttons_init);
  206. module_exit(buttons_exit);

  207. MODULE_AUTHOR("WBL");
  208. MODULE_DESCRIPTION("Davinci BUTTON Driver");
  209. MODULE_LICENSE("GPL");

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