r *desc= button->desc button->desc : "gpio_keys";//从loco_buttons数组中获得按键的描述名称
structdevice *dev = &pdev->dev;
unsignedlong irqflags;
intirq, error;
//传入参数: 过期时间,回调函数,上下文
//当计时器过期时,回调函数gpio_keys_timer将得到运行
setup_timer(&bdata->timer,gpio_keys_timer, (unsigned long)bdata);//初始化计时器
INIT_WORK(&bdata->work,gpio_keys_work_func);
error= gpio_request(button->gpio, desc);//请求使用GPIO
if(error < 0)
{
dev_err(dev,"failed to request GPIO %d, error %d\n",button->gpio, error);
gotofail2;
}
error= gpio_direction_input(button->gpio);//设置指定的GPIO为输入模式
if(error < 0)
{
dev_err(dev,"failed to configure direction for GPIO %d, error %d\n",
button->gpio,error);
gotofail3;
}
irq =gpio_to_irq(button->gpio);//获得GPIO对应的中断号
if (irq< 0)
{
error= irq;
dev_err(dev,"Unable to get irq number for GPIO %d, error %d\n",button->gpio,error);
gotofail3;
}
irqflags= IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING;
//irqflags= IRQF_TRIGGER_FALLING;//lqm changed.
/*
* If platform has specified that the buttoncan be disabled,
* we don't want it to share the interruptline.
*/
if(!button->can_disable)
irqflags|= IRQF_SHARED;
error= request_irq(irq, gpio_keys_isr, irqflags, desc, bdata);//请求按键中断
……
}
该函数使用了带定时器延时的中断机制,用于按键去抖动。即中断的执行在定时器到来之后执行,这样能够有效的去除按键抖动。同时,中断使用工作队列的机制。
整个按键中断的工作调用有点复杂,下面逐步解析:
首先,上面函数中setup_timer函数初始化定时器,第二个实参为一个名为gpio_keys_timer的函数,一旦计时器过期,该函数将得到运行。setup_timer函数需和mod_timer函数配合使用,在按键中断的顶半部,即gpio_keys_isr函数,会判断debounce_interval是否为0,若为非0,则调用mod_timer函数延时debounce_interval ms,再触发定时器中断,即gpio_keys_timer函数得到执行。否则,直接调度工作队列,执行中断底半部。
回到gpio_keys_setup_key函数,在初始化完计时器后,再调用INIT_WORK函数初始化工作队列,初始化函数有一个实参函数gpio_keys_work_func,即一旦调度相应队列名,该函数将得到执行。