按键驱动程序设计笔记

<P>/*本来友善的程序是检测上升沿和下降沿的, 
  1. 当按下按键,输出  KEY? down 
  2. 当弹下按键,输出  KEY? up    
  3.  
  4. 现在修改成只检测下降沿按下的 
  5. */  
  6.   
  7.   
  8.   
  9. #include <linux/module.h>/*模块有关的*/   
  10. #include <linux/kernel.h>/*内核有关的*/   
  11. #include <linux/fs.h>/*文件系统有关的*/   
  12. #include <linux/init.h>/*init*/   
  13. #include <linux/delay.h> /*delay*/   
  14. #include <linux/poll.h>/*poll*/   
  15. #include <linux/irq.h>/*中断*/   
  16. #include <asm/irq.h>/*中断*/   
  17. #include <linux/interrupt.h>/*linux中断*/   
  18. #include <asm/uaccess.h>/*uaccess*/   
  19. #include <mach/regs-gpio.h> /*寄存器设置*/   
  20. #include <mach/hardware.h>/*hardware*/   
  21. #include <linux/platform_device.h>   
  22. #include <linux/cdev.h>   
  23. #include <linux/miscdevice.h>   
  24. #include <linux/sched.h>   
  25. #include <linux/gpio.h>   
  26.   
  27. #define DEVICE_NAME     "button"   
  28.   
  29.   
  30.   
  31. struct button_irq_desc {  
  32.     int irq;/*中断号*/  
  33.     int pin;/*中断控制的寄存器*/  
  34.     int pin_setting; /*中断的引脚*/  
  35.     int number;/*按键编号*/  
  36.     char *name;/*按键名称*/  
  37. };  
  38.   
  39. static struct button_irq_desc button_irqs [] = {  
  40.     {IRQ_EINT8 , S3C2410_GPG(0) ,  S3C2410_GPG0_EINT8  , 0, "KEY0"},  
  41.     {IRQ_EINT11, S3C2410_GPG(3) ,  S3C2410_GPG3_EINT11 , 1, "KEY1"},  
  42.     {IRQ_EINT13, S3C2410_GPG(5) ,  S3C2410_GPG5_EINT13 , 2, "KEY2"},  
  43.     {IRQ_EINT14, S3C2410_GPG(6) ,  S3C2410_GPG6_EINT14 , 3, "KEY3"},  
  44.     {IRQ_EINT15, S3C2410_GPG(7) ,  S3C2410_GPG7_EINT15 , 4, "KEY4"},  
  45.     {IRQ_EINT19, S3C2410_GPG(11),  S3C2410_GPG11_EINT19, 5, "KEY5"},  
  46. };  
  47. /*存放按键操作结果*/  
  48. static volatile char key_values [] = {'0''0''0''0''0''0'};  
  49. /*创建一个等待队列*/  
  50. static DECLARE_WAIT_QUEUE_HEAD(button_waitq);  
  51. /*按键标志位*/  
  52. static volatile int ev_press = 0;  
  53.   
  54.   
  55. static irqreturn_t buttons_interrupt(int irq, void *dev_id)  
  56. {  
  57. /*这里注意*/  
  58.     struct button_irq_desc *button_irqs = (struct button_irq_desc *)dev_id;  
  59.     
  60.     if ('0'== key_values[button_irqs->number]) { // Changed   
  61.   
  62.         
  63.   
  64.         key_values[button_irqs->number] =  '1';  
  65.   
  66.     }  
  67.   
  68.     else if('1' == key_values[button_irqs->number]){  
  69.   
  70.         key_values[button_irqs->number] = '0';  
  71.   
  72.     }  
  73.     ev_press = 1;  
  74.     wake_up_interruptible(&button_waitq);//有数据可读,唤醒读进程   
  75.       
  76.     return IRQ_RETVAL(IRQ_HANDLED);  
  77. }  
  78.   
  79.   
  80. static int s3c24xx_buttons_open(struct inode *inode, struct file *file)  
  81. {  
  82.     int i;  
  83.     int err = 0;  
  84.       
  85.     for (i = 0; i < sizeof(button_irqs)/sizeof(button_irqs[0]); i++)   
  86.    {  
  87.     if (button_irqs[i].irq < 0)  
  88.     {  
  89.         continue;  
  90.     }  
  91.     /* 
  92.     int request_irq(unsigned int irq, void (*handler)(int, void*, struct pt_regs *), unsigned long flags, const char *devname, void *dev_id) 
  93.  
  94.     返回0表示成功,或者返回一个错误码 
  95.  
  96.     参数: 
  97.     irq:中断号 
  98.     handler:中断处理函数 
  99.     flags:与中断管理有关的各种选项 
  100.     devname:设备名 
  101.     dev_id:共享中断时使用 
  102.  
  103.     不同中断号注册同一中断处理函数buttons_interrupt 
  104.      
  105.     IRQ_TYPE_EDGE_BOTH (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING) 
  106.     上升沿或者下降沿产生中断 
  107.  
  108.     (void *)&button_irqs[i]   把结构体数组变量地址给void *dev_id 
  109.      
  110.  
  111.     */  
  112.         err = request_irq(button_irqs[i].irq, buttons_interrupt, IRQ_TYPE_EDGE_RISING,   
  113.                           button_irqs[i].name, (void *)&button_irqs[i]);  
  114.         if (err)  
  115.             break;  
  116.     }  
  117.   
  118.     if (err) {  
  119.         i--;  
  120.         for (; i >= 0; i--) {  
  121.         if (button_irqs[i].irq < 0) {  
  122.         continue;  
  123.         }  
  124.         disable_irq(button_irqs[i].irq);  
  125.             free_irq(button_irqs[i].irq, (void *)&button_irqs[i]);  
  126.         }  
  127.         return -EBUSY;  
  128.     }  
  129.   
  130.     ev_press = 1;//按下   
  131.       
  132.     return 0;  
  133. }  
  134.   
  135.   
  136. static int s3c24xx_buttons_close(struct inode *inode, struct file *file)  
  137. {  
  138.     int i;  
  139.       
  140.     for (i = 0; i < sizeof(button_irqs)/sizeof(button_irqs[0]); i++) {  
  141.     if (button_irqs[i].irq < 0) {  
  142.         continue;  
  143.     }  
  144.     free_irq(button_irqs[i].irq, (void *)&button_irqs[i]);  
  145.     }  
  146.   
  147.     return 0;  
  148. }  
  149.   
  150. /*read函数读取key_values数组的结果*/  
  151. /*由它读取键盘输入的结果*/  
  152. /*实质上就是读取key_values数组的值*/  
  153. /*它完成了键盘作为输入设备的核心功能*/  
  154. /*数组是否可读,要根据标志位ev_press来判断*/  
  155. /*如果数组可读,则读取数据到用户buffer中*/  
  156. /*如果数组不可读,则读进程进入等待队列,等待到数组可读为止*/  
  157. /*等待队列机制,是中断管理中常用到的机制*/  
  158. /*因为有些进程经常需要等待某一事件的发生*/  
  159.   
  160. static int s3c24xx_buttons_read(struct file *filp, char __user *buff, size_t count, loff_t *offp)  
  161. {  
  162.     unsigned long err;  
  163.   
  164.           
  165.     if (!ev_press) {//没按下时   
  166.     /*看看用户有没有要求不阻塞*/  
  167.         if (filp->f_flags & O_NONBLOCK)  
  168.             return -EAGAIN;  
  169.         else  
  170.             /*阻塞在button_waitq  等待队列上*/  
  171.             /*此时没数据可读,让读进程阻塞掉*/  
  172.             wait_event_interruptible(button_waitq, ev_press);//ev_press=1时,返回   
  173.     }  
  174.     //这时是ev_press = 1   
  175.     ev_press = 0;  
  176. /*把键值读到用户*/  
  177.     err = copy_to_user(buff, (const void *)key_values, min(sizeof(key_values), count));  
  178.   
  179.     return err ? -EFAULT : min(sizeof(key_values), count);  
  180. }  
  181.   
  182. static unsigned int s3c24xx_buttons_poll( struct file *file, struct poll_table_struct *wait)  
  183. {  
  184.     unsigned int mask = 0;  
  185.     poll_wait(file, &button_waitq, wait);  
  186.     if (ev_press)//为1的时候按键按下   
  187.         mask |= POLLIN | POLLRDNORM;  
  188.     return mask;  
  189. }  
  190.   
  191.   
  192. static struct file_operations dev_fops = {  
  193.     .owner   =   THIS_MODULE,  
  194.     .open    =   s3c24xx_buttons_open,  
  195.     .release =   s3c24xx_buttons_close,   
  196.     .read    =   s3c24xx_buttons_read,  
  197.     .poll    =   s3c24xx_buttons_poll,  
  198. };  
  199.   
  200. static struct miscdevice misc = {  
  201.     .minor = MISC_DYNAMIC_MINOR,//动态次设备号   
  202.     .name = DEVICE_NAME,  
  203.     .fops = &dev_fops,//关联文件操作   
  204. };  
  205.   
  206. static int __init dev_init(void)  
  207. {  
  208.     int ret;  
  209. /*混杂设备注册*/  
  210.     ret = misc_register(&misc);  
  211.   
  212.     printk (DEVICE_NAME"\tinitialized\n");  
  213.   
  214.     return ret;  
  215. }  
  216.   
  217. static void __exit dev_exit(void)  
  218. {  
  219.     misc_deregister(&misc);  
  220. }  
  221.   
  222. module_init(dev_init);  
  223. module_exit(dev_exit);  
  224. MODULE_LICENSE("GPL");  
  225. MODULE_AUTHOR("Bai");  
  226. </P><P>  
  227.  </P> 测试程序:<PRE class=cpp name="code">#include <stdio.h>  
  228. #include <stdlib.h>   
  229. #include <unistd.h>   
  230. #include <sys/ioctl.h>   
  231. #include <sys/types.h>   
  232. #include <sys/stat.h>   
  233. #include <fcntl.h>   
  234. #include <sys/select.h>   
  235. #include <sys/time.h>   
  236. #include <errno.h>   
  237.    
  238. int main(void)  
  239. {  
  240.       int buttons_fd;  
  241.       char buttons[6] = {'0''0''0''0''0''0'};  
  242.       buttons_fd = open("/dev/button", 0);  
  243.   
  244.       if (buttons_fd < 0) {  
  245.              perror("open device buttons");  
  246.   
  247.              exit(1);  
  248.       }  
  249.   
  250.       for (;;) {  
  251.              char current_buttons[6];  
  252.              int i;  
  253.   
  254.              if (read(buttons_fd, current_buttons, sizeof current_buttons) != sizeof current_buttons) {  
  255.                     perror("read buttons:");  
  256.                     exit(1);  
  257.   
  258.              }  
  259.              for (i = 0; i < sizeof buttons / sizeof buttons[0]; i++) {  
  260.   
  261.                     if (buttons[i] != current_buttons[i]) {  
  262.   
  263.                            buttons[i] = current_buttons[i];  
  264.   
  265.                            printf("The %d key is pressed!\n",i+1);  
  266.   
  267.                     }  
  268.   
  269.              }                      
  270.       }  
  271.   
  272.       close(buttons_fd);  
  273.       return 0;  
  274.   
  275. }  
  276. </PRE>  
  277. <P><BR>  
  278.  </P>  
  279. <P></P>  
  280. <P><SPAN style="FONT-SIZE: 13px"><SPAN style="FONT-SIZE: 13px">1.中断处理函数</SPAN></SPAN></P>  
  281. <P><SPAN style="FONT-SIZE: 13px"><SPAN style="FONT-SIZE: 13px">static irqreturn_t buttons_interrupt(int irq, void *dev_id);</SPAN></SPAN></P>  
  282. <P><SPAN style="FONT-SIZE: 13px"><SPAN style="FONT-SIZE: 13px">    每次按键触发中断,进入中断处理函数,进行相关操作。</SPAN></SPAN></P>  
  283. <P></P>  
  284. <P><SPAN style="FONT-SIZE: 13px"> </SPAN></P>  
  285. <P><SPAN style="FONT-SIZE: 13px">    中断资源弥足珍贵,最好选择在打开设备即需要使用时注册,而不是装载模块时,若退出模块时请切记释放中断资源。</SPAN></P>  
  286. <P><SPAN style="FONT-SIZE: 13px"> </SPAN></P>  
  287. <P><SPAN style="FONT-SIZE: 13px">2.工作队列</SPAN></P>  
  288. <P></P>  
  289. <P><SPAN style="FONT-SIZE: 13px"><SPAN style="FONT-SIZE: 13px">static DECLARE_WAIT_QUEUE_HEAD(button_waitq);</SPAN></SPAN></P>  
  290. <P><SPAN style="FONT-SIZE: 13px"><SPAN style="FONT-SIZE: 13px">    创建了一个等待队列,每当有一按键按下,激活队列中一个等待的任务。</SPAN></SPAN></P>  
  291. <P><SPAN style="FONT-SIZE: 13px"></SPAN></P>  
  292. <P><SPAN style="FONT-SIZE: 13px"><SPAN style="FONT-SIZE: 13px">poll_wait(file, &button_waitq, wait);<BR>  
  293.     监测进程队列button_waitq里的进程,如果ev_press置1,就跳出等待。 </SPAN></SPAN></P>  
  294. <P><SPAN style="FONT-SIZE: 13px"></SPAN></P>  
  295. <P><SPAN style="FONT-SIZE: 13px"><SPAN style="FONT-SIZE: 13px">wait_event_interruptible(button_waitq, ev_press);<BR>  
  296.     等待,当ev_press为1时,跳出。   </SPAN></SPAN></P>  
  297. <P><SPAN style="FONT-SIZE: 13px"></SPAN></P>  
  298. <P><SPAN style="FONT-SIZE: 13px"><SPAN style="FONT-SIZE: 13px">wake_up_interruptible(&button_waitq);   </SPAN></SPAN></P>  
  299. <P><SPAN style="FONT-SIZE: 13px"><SPAN style="FONT-SIZE: 13px">    数组可读,唤醒休眠的进程。   </SPAN></SPAN></P>  
  300. <P><SPAN style="FONT-SIZE: 13px"><IMG alt="" src="http://hi.csdn.net/attachment/201110/11/0_1318293851lCk2.gif"></SPAN></P>  
  301. <DIV>  
  302. <P>当加进<SPAN style="FONT-FAMILY: Times New Roman">udelay(20000);</SPAN><SPAN style="FONT-FAMILY: 宋体">消抖动时,出现错误,没网上,有空再搞搞</SPAN></P>  
  303. <P>insmod button.ko</P>  
  304. <P>button: Unknown symbol __bad_udelay</P>  
  305. <P>insmod: cannot insert 'button.ko': unknown symbol in module or invalid paramete</P>  
  306. </DIV>  
  307. <P> </P>  
  308. <PRE></PRE>  
  309. <PRE></PRE>  
  310. <PRE></PRE>  
  311. <PRE></PRE>  
  312. <PRE></PRE>  
  313. <PRE></PRE>  
  314. <PRE></PRE>  

http://blog.csdn.net/jianchi88/article/details/6857923

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值