dtsi、gpio、key、input子系统、event解析、长按按键检测
key是嵌入式开发中常用到的东西,linux内核中也早已为我们做了一套成熟的机制。
linux内核下的 drivers/input/keyboard/gpio_keys.c实现了一个体系结构无关的GPIO按键驱动,使用此按键驱动,只需在相应的设备树定义相关的数据即可。驱动的实现非常简单,但是较适合于实现独立式按键驱动。
gpio-keys是基于input架构实现的一个通用GPIO按键驱动。该驱动基于platform_driver架构,实现了驱动和设备分离,符合Linux设备驱动模型的思想。工程中的按键驱动我们一般都会基于gpio-keys来写,所以我们有必要对gpio_keys进行分析。
此处我在应用层进行了处理,使其支持长按检测(我的程序设置为长按6S打印),尝试在驱动层修改消抖时间,实现的效果很差,所以放弃了。
gpio_keys {
compatible = "gpio-keys";
label = "gpio-keys";
pinctrl-names = "default";
pinctrl-0 = <&key_recovery_default>;
recovery {
label = "recovery";
gpios = <&tlmm 23 GPIO_ACTIVE_HIGH>;
linux,input-type = <1>;
linux,code = <115>;
/*这三项根据需求添加*/
gpio-key,wakeup;
debounce-interval = <15>;
linux,can-disable;
};
};
1、节点名字为“gpio-keys”。
2、gpio-keys 节点的 compatible 属性值一定要设置为“gpio-keys”。
3、所有的 KEY 都是 gpio-keys 的子节点,每个子节点可以用如下属性描述自己:
gpios:KEY 所连接的 GPIO 信息。
interrupts:KEY 所使用 GPIO 中断信息,不是必须的,可以不写。
label:KEY 名字
linux,code:KEY 要模拟的按键 可 以 直 接 填 数 字 \color{red}{可以直接填数字} 可以直接填数字
gpio-key,wakeup:可以被唤醒
debounce-interval:消抖时间
1、如果按键要支持连按的话要加入 autorepeat
这就是一个标准的 platform 驱动框架,如果要使用设备树来描述 KEY 设备信息的话,设备节点的 compatible 属性值要设置为“gpio-keys”。当设备和驱动匹配以后 gpio_keys_probe 函数就会执行
static struct platform_driver gpio_keys_device_driver = {
.probe = gpio_keys_probe,
.driver = {
.name = "gpio-keys",
.pm = &gpio_keys_pm_ops,
.of_match_table = gpio_keys_of_match,
}
};
设备树的解析,从设备树中获取到 KEY 相关的设备节点信息
static int gpio_keys_probe(struct platform_device *pdev)
{
if (!pdata) {
pdata = gpio_keys_get_devtree_pdata(dev);
if (IS_ERR(pdata))
return PTR_ERR(pdata);
}
}
ls -l /dev/input
hexdump /dev/input/event0
#define RECOVERY_KEY "/dev/input/event2"
#define RECOVERY_KEY_CODE 115
#define RECOVERY_KEY_PRESS 0
void recovery_key_press_timer(int sig)
{
if(SIGALRM == sig)
{
printf("alarm 6s.\n");
}
return;
}
static void read_recovery_key_event()
{
int fd = -1, ret = -1;
struct input_event ev;
fd = open(RECOVERY_KEY, O_RDONLY);
if (fd < 0)
{
printf("open RECOVERY_KEY event failed.\n");
return;
}
memset(&ev, 0, sizeof(struct input_event));
ret = read(fd, &ev, sizeof(struct input_event));
if (ret != sizeof(struct input_event))
{
printf("read RECOVERY_KEY event failed.\n");
close(fd);
}
if( (RECOVERY_KEY_CODE == ev.code) && (RECOVERY_KEY_PRESS == ev.value) )
{
printf("recovery-key press.\n");
alarm(6);
}
else
{
printf("recovery-key release.\n");
alarm(0);
}
close(fd);
}
int main(int argc, char **argv)
{
int rc = 0;
signal(SIGALRM, recovery_key_press_timer);
while(1)
{
read_recovery_key_event();
}
return 0;
}
LEDE/OpenWRT处理基于GPIO的Power键