首先按键驱动的中断部分代码
static irqreturn_t s3c_button_intterupt(int irq,void *de_id) { int i; int found = 0; //通过found的值来判断是否产生了中断 struct s3c_button_platform_data *pdata = button_device.data; for(i=0; i<pdata->nbuttons; i++) { if(irq == pdata->buttons[i].nIRQ) { found = 1; break; } } if(!found) /* An ERROR interrupt */ return IRQ_NONE; /* Only when button is up then we will handle this event */ if(BUTTON_UP == button_device.status[i]) { button_device.status[i] = BUTTON_UNCERTAIN; mod_timer(&(button_device.timers[i]), jiffies+TIMER_DELAY_DOWN); // mod_timer()用于去抖动。因为按键按下时可能产生抖动 } return IRQ_HANDLED; }
定时器超时函数
<span style="color:#555555;">static void button_timer_handler(unsigned long data) { struct s3c_button_platform_data *pdata = button_device.data; int num =(int)data; int status = s3c2410_gpio_getpin( pdata->buttons[num].gpio ); if(LOWLEVEL == status) { if(BUTTON_UNCERTAIN == button_device.status[num]) /* Come from interrupt */ { //dbg_print("Key pressed!\n"); button_device.status[num] = BUTTON_DOWN; printk("%s pressed.\n", pdata->buttons[num].name); /* Wake up the wait queue for read()/poll() */ button_device.ev_press = 1; </span><span style="color:#ff0000;">//值为1表示事件发生</span><span style="color:#555555;"> wake_up_interruptible(&(button_device.waitq)); </span><span style="color:#ff0000;">//唤醒等待的操作,往下继续执行</span><span style="color:#555555;"> } /* Cancel the dithering */ mod_timer(&(button_device.timers[num]), jiffies+TIMER_DELAY_UP); } else { //dbg_print("Key Released!\n"); button_device.status[num] = BUTTON_UP; // enable_irq(pdata->buttons[num].nIRQ); } return ; }</span> 中断发生时,定时器去抖产生超时。超时期间执行本段函数。函数主要 用于检测按键是否有效 ,如果有效,则唤醒等待的队列。此处调用mod_timer()函数延时用于等待按键为电平为止,以便进入if语句唤醒队列。
open()函数
<span style="color:#555555;">static int button_open(struct inode *inode, struct file *file) { struct button_device *pdev ; struct s3c_button_platform_data *pdata; int i, result; pdev = container_of(inode->i_cdev,struct button_device, cdev); //获得cdev所在结构体首地址 pdata = pdev->data; file->private_data = pdev; </span><span style="color:#ff0000;"> /* Malloc for all the buttons remove dithering timer */</span><span style="color:#555555;"> pdev->timers = (struct timer_list *) kmalloc(pdata->nbuttons*sizeof(struct timer_list), GFP_KERNEL); if(NULL == pdev->timers) { printk("Alloc %s driver for timers failure.\n", DEV_NAME); return -ENOMEM; } memset(pdev->timers, 0, pdata->nbuttons*sizeof(struct timer_list)); </span><span style="color:#ff0000;">/* Malloc for all the buttons status buffer */</span><span style="color:#555555;"> pdev->status = (unsigned char *)kmalloc(pdata->nbuttons*sizeof(unsigned char), GFP_KERNEL); if(NULL == pdev->status) { printk("Alloc %s driver for status failure.\n", DEV_NAME); result = -ENOMEM; goto ERROR; } memset(pdev->status, 0, pdata->nbuttons*sizeof(unsigned char)); //初始化所有按键状态 init_waitqueue_head(&(pdev->waitq)); </span><span style="color:#ff0000;">//初始化等待队列</span><span style="color:#555555;"> for(i=0; i<pdata->nbuttons; i++) { </span><span style="color:#ff0000;">/* Initialize all the buttons status to UP */</span><span style="color:#555555;"> pdev->status[i] = BUTTON_UP; </span><span style="color:#ff0000;">/* Initialize all the buttons' remove dithering timer */</span><span style="color:#555555;"> setup_timer(&(pdev->timers[i]), button_timer_handler, i); </span><span style="color:#ff0000;">/* Set all the buttons GPIO to </span><span style="color:#cc33cc;">EDGE_FALLING </span><span style="color:#ff0000;">interrupt mode */</span><span style="color:#555555;"> s3c2410_gpio_cfgpin(pdata->buttons[i].gpio, pdata->buttons[i].setting); irq_set_irq_type(pdata->buttons[i].nIRQ, IRQ_TYPE_EDGE_FALLING); </span><span style="color:#ff0000;"> /* Request for button GPIO pin interrupt */</span><span style="color:#555555;"> result = request_irq(pdata->buttons[i].nIRQ, s3c_button_intterupt, IRQF_DISABLED, DEV_NAME, (void *)i); if( result ) { result = -EBUSY; goto ERROR1; } } return 0; ERROR1: kfree((unsigned char *)pdev->status); while(--i) { disable_irq(pdata->buttons[i].nIRQ); free_irq(pdata->buttons[i].nIRQ, (void *)i); } ERROR: kfree(pdev->timers); return result; } </span>open()函数理解起来其实很简单。无非就是做一些内存的分配,以及初始化工作。不过这里多引入了关于中断的注册,以及将中断设置为下降沿触发(EDGE_FALLING)。
read()函数
static int button_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { struct button_device *pdev = file->private_data; struct s3c_button_platform_data *pdata; int i, ret; unsigned int status = 0; pdata = pdev->data; dbg_print("ev_press: %d\n", pdev->ev_press); if(!pdev->ev_press) { if(file->f_flags & O_NONBLOCK) //O_NONBLOCK表示非阻塞 { dbg_print("read() without block mode.\n"); return -EAGAIN; } else { /* Read() will be blocked here */ dbg_print("read() blocked here now.\n"); wait_event_interruptible(pdev->waitq, pdev->ev_press); //将进程挂起 } } pdev->ev_press = 0; <pre name="code" class="cpp">for(i=0; i<pdata->nbuttons; i++) { dbg_print("button[%d] status=%d\n", i, pdev->status[i]); status |= (pdev->status[i]<<i); }</pre><br> ret = copy_to_user(buf, (void *)&status, min(sizeof(status), count)); //内核向用户传输数据 return ret ? -EFAULT : min(sizeof(status), count);} <pre></pre> <p><span style="font-size:18px"><strong> </strong></span><span style="font-size:14px"> 值得一提的是,如果文件以阻塞的方式打开的话,read()函数如果未读取到数据(按键状态)则会<strong><span style="color:#ff0000">发生阻塞</span></strong>,如果不引入中断概念,则cpu将永远阻塞在此处。此处,read函数调用wait_event_interruptible()将进程挂起,等待中断函数处理完成后唤醒,所以接下来介绍一个<span style="color:#ff0000">函数poll() </span>用于将一些操作丢进等待队列,待中断唤醒后方可继续执行。</span></p> <p><strong style="font-size:18px"> </strong><span style="font-size:14px">read()函数主要是用来读取按键,发生阻塞后等待中断返回唤醒。唤醒后继续执行下面函数:</span></p> <p><span style="font-size:14px"></span></p><pre name="code" class="cpp" style="color: rgb(85, 85, 85); font-size: 18px; font-weight: bold;">for(i=0; i<pdata->nbuttons; i++) { dbg_print("button[%d] status=%d\n", i, pdev->status[i]); status |= (pdev->status[i]<<i); }</pre> 并把内核数据传给用户空间,最后返回一个ret的值,ret储存了所有按键对应的status,每个按键对应一个值,所以应用定义按键时,需和此处的对应。分别对应1<<1,1<<2,1<<3,1<<4。<p></p> <p></p> <p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; font-family:'microsoft yahei'; line-height:35px"> <span style="font-weight:bold; font-size:18px">五、poll()函数:</span></p> <p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; font-family:'microsoft yahei'; line-height:35px"> <span style="font-size:18px"> </span><span style="font-size:14px">应用程序调用select()函数时会调用此函数用于监听函数。将设备信息丢入等待队列,便于唤醒后继续执行。<span style="color:rgb(51,51,51); font-family:arial,宋体,sans-serif; font-size:14px; text-indent:28px">此函数在</span><a target="_blank" href="http://baike.baidu.com/item/系统调用" style="color:rgb(19,110,194); text-decoration:none; font-family:arial,宋体,sans-serif; font-size:14px; text-indent:28px">系统调用</a><span style="color:rgb(51,51,51); font-family:arial,宋体,sans-serif; font-size:14px; text-indent:28px">select内部被使用,作用是把当前的</span><a target="_blank" href="http://baike.baidu.com/item/文件指针" style="color:rgb(19,110,194); text-decoration:none; font-family:arial,宋体,sans-serif; font-size:14px; text-indent:28px">文件指针</a><span style="color:rgb(51,51,51); font-family:arial,宋体,sans-serif; font-size:14px; text-indent:28px"><strong>挂到设备内部定义的等待</strong>,定义在</span><span style="color:rgb(54,46,43); font-family:Arial; font-size:18px">#include <poll.h>中。和epoll,select类似可用来查询某个或多个文件描述符的读取或写入是否被阻塞。如果驱动程序将poll的方法定义为NULL,则设备被认为可读也可写,并且不会阻塞。</span></span></p> <p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; font-family:'microsoft yahei'; line-height:35px"> <span style="font-size:14px"></span></p> <pre name="code" class="cpp">static unsigned int button_poll(struct file *file, poll_table * wait) { struct button_device *pdev = file->private_data; unsigned int mask = 0; poll_wait(file, &(pdev->waitq), wait); if(pdev->ev_press) { mask |= POLLIN | POLLRDNORM; /* The data aviable */ <span style="color:#ff0000;">//表示可读可写</span> } return mask; }</pre><br> <p> 相关测试程序以及select具体用法请参考第二篇:</p> <p><a target="_blank" href="http://blog.csdn.net/qicheng777/article/details/70229456">http://blog.csdn.net/qicheng777/article/details/70229456</a><br> </p> <p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; font-family:'microsoft yahei'; line-height:35px"> <span style="font-size:14px"> </span></p> <p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; font-family:'microsoft yahei'; line-height:35px"> <span style="font-size:18px"><strong><br> </strong><br> </span></p> <p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; color:rgb(85,85,85); font-family:'microsoft yahei'; font-size:15px; line-height:35px"> <br> </p>
