首先按键驱动的中断部分代码
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>
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/%E7%B3%BB%E7%BB%9F%E8%B0%83%E7%94%A8" 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/%E6%96%87%E4%BB%B6%E6%8C%87%E9%92%88" 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>