按键驱动程序

来源:互联网 发布:mac safari无痕浏览 编辑:程序博客网 时间:2024/05/08 15:40







[html] view plaincopy
  1.    //misc_key.c  
  2.   1 #include <linux/module.h>  
  3.   2 #include <linux/kernel.h>  
  4.   3 #include <linux/fs.h>  
  5.   4 #include <linux/init.h>  
  6.   5 #include <linux/delay.h>  
  7.   6 #include <linux/poll.h>  
  8.   7 #include <linux/irq.h>  // #define S3C_EINT(x) ((x) + S3C_IRQ_EINT_BASE)   #define IRQ_EINT(x) S3C_EINT(x)  
  9.   8 #include <asm/irq.h>  
  10.   9 #include <asm/io.h>  
  11.  10 #include <linux/interrupt.h>  
  12.  11 #include <asm/uaccess.h>  
  13.  12 #include <mach/hardware.h>  
  14.  13 #include <linux/platform_device.h>  
  15.  14 #include <linux/cdev.h>  
  16.  15 #include <linux/miscdevice.h>  
  17.  16 #include <mach/map.h>  
  18.  17 #include <mach/regs-clock.h>  
  19.  18 #include <mach/regs-gpio.h>  
  20.  19 #include <plat/gpio-cfg.h>  
  21.  20 #include <mach/gpio-bank-n.h>  
  22.  21 #include <mach/gpio-bank-l.h>  //#define S3C64XX_GPLDAT (S3C64XX_GPL_BASE + 0x08)  
  23.  22   
  24.  23 #define DEVICE_NAME "button_by_hui"  
  25.  24   
  26.  25 struct button_irq_desc{  
  27.  26     int irq;  
  28.  27     int number;  
  29.  28     char *name;  
  30.  29 };  
  31.  30   
  32.  31 static struct button_irq_desc button_irqs[] = {  
  33.  32     {IRQ_EINT(0),  0, "KEY0"},  
  34.  33     {IRQ_EINT(1),  1, "KEY1"},  
  35.  34     {IRQ_EINT(2),  2, "KEY2"},  
  36.  35     {IRQ_EINT(3),  3, "KEY3"},  
  37.  36     {IRQ_EINT(4),  4, "KEY4"},  
  38.  37     {IRQ_EINT(5),  5, "KEY5"},  
  39.  38     {IRQ_EINT(19), 6, "KEY6"},  
  40.  39     {IRQ_EINT(20), 7, "KEY7"},  
  41.  40 };  
  42.  41 static volatile char key_values[] = {'0', '0', '0', '0', '0', '0', '0', '0'};  
  43.  42   
  44.  43 static DECLARE_WAIT_QUEUE_HEAD(button_waitq); /*定义一个新的等待队列的头*/  
  45.  44 static volatile int ev_press = 0;             /*判断是否有按键按下的标志位*/  
  46.  45   
  47.  46 static irqreturn_t buttons_interrupt(int irq, void *dev_id) /*中断处理函数*/  
  48.  47 {                                                   /*(void *)&button_irqs[i]申请中断时传进来的参数*/  
  49.  48     struct button_irq_desc *button_irqs = (struct button_irq_desc *)dev_id;  
  50.  49     int down;  
  51.  50     int number;  
  52.  51     unsigned tmp;  
  53.  52     udelay(0);  
  54.  53     number = button_irqs->number;  
  55.  54     switch(number) {  
  56.  55         case 0: case 1: case 2: case 3: case 4: case 5:  
  57.  56             tmp = readl(S3C64XX_GPNDAT);  //   
  58.  57             down = !(tmp & (1<<number));  
  59.  58             break;  
  60.  59         case 6: case 7:  
  61.  60             tmp = readl(S3C64XX_GPLDAT); /*(返回)从映射的I/O空间读取32位4字节的数值 */   
  62.  61             down = !(tmp & (1 << (number + 5)));  
  63.  62             break;  
  64.  63         default:  
  65.  64             down = 0;  
  66.  65     }  
  67.  66     if (down != (key_values[number] & 1)) {  
  68.  67         key_values[number] = '0' + down;  
  69.  68         ev_press = 1;  
  70.  69         wake_up_interruptible(&button_waitq);   /*唤醒阻塞(睡眠)的等待队列*/  
  71.  70     }  
  72.  71     /*  //means that we did have a valid interrupt and handled it  
  73.  72      *  #define IRQ_RETVAL(x) ((x) != IRQ_NONE )   //这个宏只是返回0或非0  
  74.  73      */  
  75.  74     return IRQ_RETVAL(IRQ_HANDLED);  
  76.  75 }  
  77.  76   
  78.  77 static int s3c64xx_buttons_open(struct inode *inode, struct file *file)  
  79.  78 {  
  80.  79     int i;  
  81.  80     int err = 0;  
  82.  81     for (i = 0; i < sizeof(button_irqs)/sizeof(button_irqs[0]); i++) {  
  83.  82         if (button_irqs[i].irq < 0) {  
  84.  83             continue;  
  85.  84         }                 /*中断号            处理函数           双延触发*/  
  86.  85         err = request_irq(button_irqs[i].irq, buttons_interrupt, IRQ_TYPE_EDGE_BOTH,    /*申请中断*/  
  87.  86                 button_irqs[i].name, (void *)&button_irqs[i]);  
  88.  87                 /*在proc/interrupts中显示中断拥有者   void *dev_id*/  
  89.  88         if (err)  
  90.  89             break;  
  91.  90     }  
  92.  91     if (err) {  /*出错处理 把之前分配的中断释放掉*/  
  93.  92         i--;  
  94.  93         for (; i >= 0; i--) {  
  95.  94             if (button_irqs[i].irq < 0){  
  96.  95                 continue;  
  97.  96             }  
  98.  97             disable_irq(button_irqs[i].irq);  
  99.  98             free_irq(button_irqs[i].irq, (void *)&button_irqs[i]);  
  100.  99         }  
  101. 100         return -EBUSY;  
  102. 101     }  
  103. 102     ev_press = 1;  
  104. 103     return 0;  
  105. 104 }  
  106. 105   
  107. 106 static int s3c64xx_buttons_close(struct inode *inode, struct file *file)  
  108. 107 {  
  109. 108     int i;  
  110. 109     for (i = 0; i < sizeof(button_irqs)/sizeof(button_irqs[0]); i++) {  
  111. 110         if (button_irqs[i].irq < 0) {  
  112. 111             continue;  
  113. 112         }  
  114. 113         free_irq(button_irqs[i].irq, (void *)&button_irqs[i]);  
  115. 114     }  
  116. 115     return 0;  
  117. 116 }  
  118. 117   
  119. 118 static int s3c64xx_buttons_read(struct file *filp, char __user *buff, size_t count, loff_t *offp)  
  120. 119 {  
  121. 120     unsigned long err;  
  122. 121     if (!ev_press) {  
  123. 122         if (filp->f_flags & O_NONBLOCK)  
  124. 123             return -EAGAIN;  
  125. 124         else{  
  126. 125             /*这个宏:使调用进程在等待队上睡眠,一直到修改了给定条件为止*/  
  127. 126             wait_event_interruptible(button_waitq, ev_press);  /*直到ev_press 为 1*/  
  128. 127         }  
  129. 128     }  
  130. 129     ev_press = 0;  
  131. 130     err = copy_to_user((void *)buff, (const void *)(&key_values), min(sizeof(key_values), count));  
  132. 131     return err ? -EFAULT : min(sizeof(key_values), count);  
  133. 132 }  
  134. 133   
  135. 134 static unsigned int s3c64xx_buttons_poll( struct file *file, struct poll_table_struct *wait)  
  136. 135 {  
  137. 136     unsigned int mask = 0;  
  138. 137     poll_wait(file, &button_waitq, wait);  
  139. 138     if (ev_press)  
  140. 139         mask |= POLLIN | POLLRDNORM;       ev_press = 0;  
  141. 140     return mask;  
  142. 141 }  
  143. 142   
  144. 143 static struct file_operations dev_fops = {  
  145. 144     .owner   = THIS_MODULE,  
  146. 145     .open    = s3c64xx_buttons_open,  
  147. 146     .release = s3c64xx_buttons_close,  
  148. 147     .read    = s3c64xx_buttons_read,  
  149. 148     .poll    = s3c64xx_buttons_poll,  
  150. 149 };  
  151. 150   
  152. 151 static struct miscdevice misc = { /*杂项字符设备结构体*/  
  153. 152     .minor = MISC_DYNAMIC_MINOR,  /*次设备号 表示自动分配*/  
  154. 153     .name  = DEVICE_NAME,         /*设备名*/  
  155. 154     .fops  = &dev_fops,           /*设备操作*/  
  156. 155 };  
  157. 156   
  158. 157 static int __init dev_init(void)  
  159. 158 {  
  160. 159     int ret;  
  161. 160     ret = misc_register(&misc);             /*注册一个混杂设备 在加载模块时会自动创建设备文件, 为主设备号为10的字符设备*/  
  162. 161     printk(DEVICE_NAME"\tinitialized\n");   /*无需mknod指令创建设备文件。因为misc_register()会调用class_device_create()或者device_create()*/  
  163. 162     return ret;  
  164. 163 }  
  165. 164   
  166. 165 static void __exit dev_exit(void)  
  167. 166 {  
  168. 167     misc_deregister(&misc);                 /*注销混杂设备 自动删除设备文件*/  
  169. 168 }  
  170. 169   
  171. 170 module_init(dev_init);  
  172. 171 module_exit(dev_exit);  
  173. 172 MODULE_LICENSE("GPL");  
  174. 173 MODULE_AUTHOR("FriendlyARM Inc.");  

测试程序:

[html] view plaincopy
  1.  //button_test.c  
  2. nbsp; 1 #include <stdio.h>  
  3.  2 #include <stdlib.h>  
  4.  3 #include <unistd.h>  
  5.  4 #include <sys/ioctl.h>  
  6.  5 #include <sys/types.h>  
  7.  6 #include <sys/stat.h>  
  8.  7 #include <fcntl.h>  
  9.  8 #include <sys/select.h>  
  10.  9 #include <sys/time.h>  
  11. 10 #include <errno.h>  
  12. 11   
  13. 12 int main(void)  
  14. 13 {  
  15. 14     int buttons_fd;  
  16. 15     char buttons[6] = {'0', '0', '0', '0', '0', '0'};  
  17. 16   
  18. 17     buttons_fd = open("/dev/button_by_hui", 0);  
  19. 18     if(buttons_fd < 0){  
  20. 19         perror("open device buttons");  
  21. 20         exit(1);  
  22. 21     }  
  23. 22   
  24. 23     printf("open /dev/button_by_hui ok\n please puton one key\n");  
  25. 24   
  26. 25     for(;;){  
  27. 26         char current_buttons[6];  
  28. 27         int count_of_changed_key;  
  29. 28         int i;  
  30. 29         if(read(buttons_fd, current_buttons, sizeof current_buttons) != sizeof current_buttons){  
  31. 30             perror("read buttons:");  
  32. 31             exit(1);  
  33. 32         }  
  34. 33   
  35. 34         for(i = 0count_of_changed_key = 0; i < sizeof buttons / sizeof buttons[0]; i++){  
  36. 35             if(buttons[i] != current_buttons[i]){  
  37. 36                 buttons[i] = current_buttons[i];  
  38. 37                 printf("%s key%d is %s", count_of_changed_key ? "," : "" ,   i+1,  buttons[i] == '0' ?  "up" : "down" );  
  39. 38                 count_of_changed_key++;  
  40. 39             }  
  41. 40         }  
  42. 41   
  43. 42         if(count_of_changed_key){  
  44. 43             printf("\n");  
  45. 44         }  
  46. 45     }  
  47. 46   
  48. 47     close(buttons_fd);  
  49. 48     return 0;  
  50. 49 }  


轮询操作:(也可以在驱动中增加异步通知 这样应用程序调用时就更加强大了 如,按键按下灯亮的操作)

[html] view plaincopy
  1.  1 /*测试程序:该程序用于监控 key 的是否可读(按下)状态*/  
  2.  2 #include<stdio.h>  
  3.  3 #include<sys/select.h>  
  4.  4 #include<fcntl.h>  
  5.  5   
  6.  6 int main(void)  
  7.  7 {  
  8.  8     int fd;  
  9.  9     fd_set rfds; /*读文件描述符集*/  
  10. 10       
  11. 11     /*以非阻塞的方式打开 设备文件*/  
  12. 12     fd = open("/dev/button_by_hui", O_RDONLY | O_NONBLOCK);  
  13. 13     if(fd != -1){  
  14. 14         while(1){  
  15. 15             FD_ZERO(&rfds); /*清除一个文件描述符集*/  
  16. 16             FD_SET(fd, &rfds); /*将一个文件描述符 加入 文件描述符集中*/  
  17. 17               
  18. 18 /*最高文件描述符+1 要监控的 读    写     异常  等待超时返回*/  
  19. 19             select(fd + 1, &rfds, NULL, NULL, NULL); /*该函数最终调用poll*/  
  20. 20               
  21. 21             /*数据可获得*/  
  22. 22             if(FD_ISSET(fd, &rfds))  
  23. 23                 printf("Poll monitor:button can be read\n");  
  24. 24         }         
  25. 25     }else{  
  26. 26         printf("Device open failure\n");  
  27. 27     }     
  28. 28     return 0;  
  29. 29 }     



原创粉丝点击