static void gpio_keys_gpio_work_func(struct work_struct *work)
{
struct gpio_button_data *bdata= container_of(work, struct gpio_button_data, work);
gpio_keys_gpio_report_event(bdata); //上传input按键事件
if (bdata->button->wakeup)
pm_relax(bdata->input->dev.parent); //如果是唤醒源,则通知pm子系统,唤醒中断处理结束。
}
pm_stay_awake(); //在中断入口调用,告知启动唤醒
pm_relax(); //在中断出口调用,告知结束唤醒
pm_wakeup_event(struct device *dev, unsigned int msec);
//通知pm子系统在msec后处理唤醒事件, msec=0,则表示立即唤醒
static int gpio_keys_setup_key(struct platform_device *pdev,
struct input_dev *input,
struct gpio_button_data *bdata,
const struct gpio_keys_button *button)
{
const char *desc = button->desc ? button->desc : "gpio_keys"; //获取平台设备设置的名字
//… …
error = gpio_request_one(button->gpio, GPIOF_IN, desc);//申请button->gpio引脚,并将引脚设为输入引脚,名字设置为desc
if (button->debounce_interval)
{
bdata->timer_debounce =button->debounce_interval; //设置防抖动时间
}
irq = gpio_to_irq(button->gpio); //获取管脚对应的中断号
if (irq < 0)
{
//… …
goto fail;
}
bdata->irq = irq;
INIT_WORK(&bdata->work, gpio_keys_gpio_work_func);
//初始化bdata->work,使bdata->work与gpio_keys_gpio_work_func()函数关联起来
//后面当调用schedule_work(&bdata->work)时,便会执行gpio_keys_gpio_work_func()函数
setup_timer(&bdata->timer, gpio_keys_gpio_timer, (unsigned long)bdata);
//设置gpio_keys_gpio_timer()定时器超时函数,用来实现防抖动,函数参数为bdata
irqflags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING;
//中断标志位
isr = gpio_keys_gpio_isr;
input_set_capability(input, button->type ?: EV_KEY, button->code); //使input 支持EV_KEY键盘事件,并使键盘事件支持button->code按键值
error = request_any_context_irq(bdata->irq, isr, irqflags, desc, bdata);
//通过request_any_context_irq()函数注册按键中断:
//中断号为bdata->irq,中断名叫: button.desc("power key")
//中断标志位为(IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING)
//中断服务函数为gpio_keys_gpio_isr(),设置中断函数参数dev_id为bdata
return 0;
}
enable_irq_wake (bdata->irq);
//将要睡眠的中断号屏蔽掉,实现休眠时保持中断唤醒
disable_irq_wake(bdata->irq); //关闭唤醒
#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/sched.h>
#include <linux/pm.h