Chinaunix首页 | 论坛 | 博客
  • 博客访问: 52245
  • 博文数量: 26
  • 博客积分: 10
  • 博客等级: 民兵
  • 技术积分: 10
  • 用 户 组: 普通用户
  • 注册时间: 2012-09-07 10:51
文章分类
文章存档

2016年(1)

2015年(15)

2014年(10)

我的朋友

分类: LINUX

2015-03-04 23:19:55

原文地址:linux下的按键驱动 作者:aiaixzh

最近在学习linux底层驱动,买了一个XC2440开发板,在韦东山程序的基础上写了一个按键驱动程序,移植起来还是挺费劲的,刚开始编译提示 找不到“TASK_INTERRUPTIBLE”,发现头文件没有包含 #include ,加了就可以了,接下来有新的问题了,中断注册失败,折腾了半天突然想了一下,可是开发板已经申请过了4个按键的中断号,接下来重新配置内核,取消了按键的配置(GPIO_BUTTONS),下载内核运行后,按键驱动可以了。但是触摸屏不能触摸了,就是按它没有反应了。底层驱动源代码如下:内核版本2.6.37.4
  1. #include <linux/module.h>
  2. #include <linux/kernel.h>
  3. #include <linux/fs.h>
  4. #include <linux/init.h>
  5. #include <linux/delay.h>
  6. #include <linux/irq.h>
  7. //#include <asm/irq.h>
  8. #include <mach/regs-gpio.h>
  9. #include <mach/hardware.h>
  10. #include <linux/device.h>
  11. #include <linux/gpio.h>

  12. #include <linux/interrupt.h>
  13. #include <asm/uaccess.h>

  14. #include <linux/device.h>
  15. #include <linux/miscdevice.h>
  16. #include <linux/sched.h>//TASK_INTERRUPTIBLE
  17. #include <linux/wait.h>

  18. #define DEVICE_NAME "keya" /* 加载模式后,执行”cat /proc/devices”命令看到的设备名称 */
  19. //#define BUTTON_MAJOR 236 /* 主设备号 */



  20. struct button_irq_desc {
  21.     int irq;
  22.     unsigned long flags;
  23.     char *name;
  24. };
  25. /*
  26. #define IRQF_TRIGGER_NONE 0x00000000
  27. #define IRQF_TRIGGER_RISING 0x00000001
  28. #define IRQF_TRIGGER_FALLING 0x00000002
  29. #define IRQF_TRIGGER_HIGH 0x00000004
  30. #define IRQF_TRIGGER_LOW 0x00000008
  31. */

  32. /* 用来指定按键所用的外部中断引脚及中断触发方式, 名字 */
  33. static struct button_irq_desc button_irqs [] = {
  34.     {IRQ_EINT4, IRQF_TRIGGER_FALLING, "KEY1"}, /* K1 */
  35.     {IRQ_EINT5, IRQF_TRIGGER_FALLING, "KEY2"}, /* K2 */
  36.     {IRQ_EINT6, IRQF_TRIGGER_FALLING, "KEY3"}, /* K3 */
  37.     {IRQ_EINT7, IRQF_TRIGGER_FALLING, "KEY4"}, /* K4 */
  38. };

  39. /* 按键被按下的次数(准确地说,是发生中断的次数) */
  40. static volatile int press_cnt [] = {0, 0, 0, 0};
  41. static volatile int const press_no [] = {1, 2, 3, 4};

  42. /* 等待队列:
  43.  * 当没有按键被按下时,如果有进程调用s3c24xx_buttons_read函数,
  44.  * 它将休眠
  45.  */
  46. static DECLARE_WAIT_QUEUE_HEAD(button_waitq);

  47. /* 中断事件标志, 中断服务程序将它置1,s3c24xx_buttons_read将它清0 */
  48. static volatile int ev_press = 0;

  49. static irqreturn_t buttons_interrupt(int irq, void *dev_id)
  50. {
  51.     volatile int *index= (volatile int *)dev_id;

  52.     //*press_cnta = *press_cnta + 1; //按键计数加1 //
  53.     if(*index==1) press_cnt[0]+=1;
  54.     else if(*index==2)press_cnt[1]+=1;
  55.     else if(*index==3)press_cnt[2]+=1;
  56.     else if(*index==4)press_cnt[3]+=1;
  57.     else             press_cnt[0]+=1;
  58.     ev_press = 1; // 表示中断发生了 //

  59.     wake_up_interruptible(&button_waitq); // 唤醒休眠的进程 //

  60.     return IRQ_RETVAL(IRQ_HANDLED);
  61. }


  62. /* 应用程序对设备文件/dev/buttons执行open(...)时,cd /sys/class/hwmon/hwmon0/device
  63.  * 就会调用s3c24xx_buttons_open函数
  64.  */
  65. static int s3c24xx_buttons_open(struct inode *inode, struct file *file)
  66. {
  67.     int i=0;
  68.     int err=0;
  69.     printk(DEVICE_NAME " open\n");

  70.     for (i = 0; i <sizeof(button_irqs)/sizeof(button_irqs[0]); i++)//button_irqs[i].flags
  71.     {
  72.         // 注册中断处理函数
  73.         err = request_irq(button_irqs[i].irq, buttons_interrupt, button_irqs[i].flags,
  74.         button_irqs[i].name, (void *)&press_no[i]);
  75.         //err = request_irq(IRQ_EINT4, buttons_interrupt, 2,"KEY1", NULL);
  76.         if (err)
  77.         break;
  78.     }

  79.     if (err)
  80.     {
  81.         // 释放已经注册的中断
  82.         printk(DEVICE_NAME " err\n");
  83.         i--;
  84.         for (; i >= 0; i--)
  85.         free_irq(button_irqs[i].irq, (void *)&press_cnt[i]);
  86.         return -EBUSY;
  87.     }

  88.     printk(DEVICE_NAME " openok\n");
  89.     return 0;
  90. }


  91. /* 应用程序对设备文件/dev/buttons执行close(...)时,
  92.  * 就会调用s3c24xx_buttons_close函数
  93.  */
  94. static int s3c24xx_buttons_close(struct inode *inode, struct file *file)
  95. {
  96.     int i;
  97.     printk (DEVICE_NAME " close\n");
  98.     for (i = 0; i < sizeof(button_irqs)/sizeof(button_irqs[0]); i++)
  99.     {
  100.         // 释放已经注册的中断
  101.         free_irq(button_irqs[i].irq, (void *)&press_no[i]);
  102.     }
  103.     
  104.     return 0;
  105. }


  106. /* 应用程序对设备文件/dev/buttons执行read(...)时,
  107.  * 就会调用s3c24xx_buttons_read函数
  108.  */
  109. static int s3c24xx_buttons_read(struct file *filp, char __user *buff, size_t count, loff_t *offp)
  110. {
  111.     unsigned long err;

  112.     // 如果ev_press等于0,休眠 //
  113.     wait_event_interruptible(button_waitq, ev_press);

  114.     // 执行到这里时,ev_press等于1,将它清0 //
  115.     if(ev_press)
  116.     {
  117.         ev_press = 0;
  118.         
  119.         // 将按键状态复制给用户,并清0 //
  120.         err = copy_to_user(buff, (const void *)press_cnt, min(sizeof(press_cnt), count));
  121.         memset((void *)press_cnt, 0, sizeof(press_cnt));
  122.         return 0;
  123.     }
  124.     return 1;
  125. }

  126. /* 这个结构是字符设备驱动程序的核心
  127.  * 当应用程序操作设备文件时所调用的open、read、write等函数,
  128.  * 最终会调用这个结构中的对应函数
  129.  */
  130. static struct file_operations s3c24xx_buttons_fops = {
  131.     .owner = THIS_MODULE, /* 这是一个宏,指向编译模块时自动创建的__this_module变量 */
  132.     .open = s3c24xx_buttons_open,
  133.     .release = s3c24xx_buttons_close,
  134.     .read = s3c24xx_buttons_read,
  135. };

  136. static struct miscdevice misc = {
  137.     .minor = MISC_DYNAMIC_MINOR,
  138.     .name = DEVICE_NAME,
  139.     .fops = &s3c24xx_buttons_fops,
  140. };

  141. /*
  142.  * 执行“insmod s3c24xx_buttons.ko”命令时就会调用这个函数
  143.  */
  144. static int __init s3c24xx_buttons_init(void)
  145. {
  146.     int ret;
  147.     
  148.     /* 注册字符设备驱动程序
  149.     * 参数为主设备号、设备名字、file_operations结构;
  150.     * 这样,主设备号就和具体的file_operations结构联系起来了,
  151.     * 操作主设备为BUTTON_MAJOR的设备文件时,就会调用s3c24xx_buttons_fops中的相关成员函数
  152.     * BUTTON_MAJOR可以设为0,表示由内核自动分配主设备号
  153.     
  154.     ret = register_chrdev(BUTTON_MAJOR, DEVICE_NAME, &s3c24xx_buttons_fops);
  155.     if (ret < 0)
  156.     {
  157.         printk(DEVICE_NAME " can't register major number\n");
  158.         return ret;
  159.     }*/

  160.     ret = misc_register(&misc);

  161.     printk (DEVICE_NAME " tinitialized\n");

  162.     return 0;
  163. }

  164. /*
  165.  * 执行”rmmod s3c24xx_buttons.ko”命令时就会调用这个函数
  166.  */
  167. static void __exit s3c24xx_buttons_exit(void)
  168. {
  169.     /* 卸载驱动程序 */
  170.     printk(DEVICE_NAME " exit\n");
  171.     //unregister_chrdev(BUTTON_MAJOR, DEVICE_NAME);
  172.     misc_deregister(&misc);
  173. }

  174. /* 这两行指定驱动程序的初始化函数和卸载函数 */
  175. module_init(s3c24xx_buttons_init);
  176. module_exit(s3c24xx_buttons_exit);

  177. /* 描述驱动程序的一些信息,不是必须的 */
  178. MODULE_AUTHOR(""); // 驱动程序的作者
  179. MODULE_DESCRIPTION("S3C2410/S3C2440 BUTTON Driver"); // 一些描述信息
  180. MODULE_LICENSE("GPL"); // 遵循的协议

应用层测试程序如下


#include
#include
#include
#include
#include

int main(int argc, char **argv)
{
 int i=0;
 int ret=0;
 int fd=-1;
 int press_cnt[4]={0,0,0,0};
 
 fd = open("/dev/keya", 0);  // 打开设备
 if (fd < 0)
 {
  printf("Can't open /dev/keya\n");
  return -1;
 }
 
 // 这是个无限循环,进程有可能在read函数中休眠,当有按键被按下时,它才返回
 while (1)
 {
  // 读出按键被按下的次数
  ret = read(fd, press_cnt, sizeof(press_cnt));
  if (ret ==0)
  {
  
   for (i = 0; i < sizeof(press_cnt)/sizeof(press_cnt[0]); i++)
   {
    // 如果被按下的次数不为0,打印出来
    if (press_cnt[i])
    printf("K%d has been pressed %d times!\n", i+1, press_cnt[i]);
   }
  }
  //sleep(1);
 }
 
 close(fd);
 return 0;   
}

 

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