Linux应用程序——用户层检测按键输入状态

本文探讨了在Linux环境下,基于stm32mp157盘古开发板,如何在用户层检测按键输入状态。通过分析gpio-keys驱动,解释了设备树配置如何影响按键值,并展示了中断处理和事件上报的过程。测试显示,配置的GPIO电平会影响input返回的value值,而中断触发方式的配置可能被内核代码覆盖。结论是,确保配置gpiod,中断触发方式则不必过于关注。
摘要由CSDN通过智能技术生成

stm32mp157  盘古开发板  Linux内核版本4.19

目录

1、背景

2、测试情况:


1、背景

在我的博客《Linux驱动分析——input输入子系统》中已经大概了解了按键输入的来龙去脉,博客链接:https://blog.csdn.net/fang_yang_wa/article/details/113254396

2、测试情况:

应用层测试用代码:

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <linux/input.h>
#include <string.h>
 
#define KEY			"/dev/input/event0"
 
int main(void)
{
	int fd = -1, ret = -1;
	struct input_event ev;
	
	// 第1步:打开设备文件
	fd = open(KEY, O_RDONLY);
	if (fd < 0)
	{
		perror("open");
		return -1;
	}
	
	while (1)
	{
		// 第2步:读取一个event事件包
		memset(&ev, 0, sizeof(struct input_event));
		ret = read(fd, &ev, sizeof(struct input_event));
		if (ret != sizeof(struct input_event))
		{
			perror("read");
			close(fd);
			return -1;
		}
		
		// 第3步:解析event包,才知道发生了什么样的输入事件
		printf("-------------------------\n");
		printf("time.tv_sec: %llu\n", ev.time.tv_sec);
		printf("type: %hd\n", ev.type);
		printf("code: %hd\n", ev.code);
		printf("value: %d\n", ev.value);
		printf("\n");
	}

	// 第4步:关闭设备
	close(fd);
	
	return 0;
}

如上图设备树配置,按键按下返回0,按键抬起返回1(按键抬起状态为高电平)

如上图设备树配置,按键按下返回1,按键抬起返回0(按键抬起状态为高电平)由此可见这个设备树中gpios引脚配置的高低电平会影响input返回的value值

关于按键的设备树配置可通过博客了解:https://www.it610.com/article/1295820080185155584.htm     该链接中关键内容截图如下:

博客内容:

1.概述

  Gpio-keys 是基于input子系统实现的一个通用按键驱动,该驱动也符合linux驱动实现模型,即driver和device分离模型.一般按键驱动,都是基于gpio-keys进行开发的.

2. gpio-keys 代码分析(基于 linux 4.14.40)

 (1)整体来说分为以下四步

static int gpio_keys_probe(struct platform_device *pdev)
{
 
    ...........
    ...........
    /*第一,从设备树获取button,即gpio相关控制方式和属性*/
	pdata = gpio_keys_get_devtree_pdata(dev);
    ...........
    ...........
    /*第二,分配一个input 设备*/
	input = devm_input_allocate_device(dev);
    ...........
    ...........
    /*第三,注册gpio相关信息和分配资源*/
	for (i = 0; i < pdata->nbuttons; i++) {
		error = gpio_keys_setup_key(pdev, input, ddata,
					    button, i, child);
    }
    ...........
    ...........
    /*第四,注册input 设备到kernel*/
	error = input_register_device(input);
    ...........
    ...........
	return 0;
}

 (2)从注册一个input设备来看,二,四步是一个通用的步骤,第三步和第一步是关键,先看第三步.

static int gpio_keys_setup_key(struct platform_device *pdev,
				struct input_dev *input,
				struct gpio_keys_drvdata *ddata,
				const struct gpio_keys_button *button,
				int idx,
				struct fwnode_handle *child)
{

    .............
    .............
    /*第一,请求gpio并获取irq 资源*/
	error = devm_gpio_request_one(dev, button->gpio, flags, desc);

	irq = gpiod_to_irq(bdata->gpiod);
    .............
    .............
    /*第二,注册一个delayed work任务,这个任务的目的,当中断发生时,需要向
    通过input子系统发消息,这个过程有可能会sleep或者schedule,所以必须通一个
    delay work去完成这件事.
    */
    INIT_DELAYED_WORK(&bdata->work, gpio_keys_gpio_work_func);
	isr = gpio_keys_gpio_isr;
	irqflags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING;}
    .............
    .............
    /*第三,注册中断*/
	error = devm_request_any_context_irq(dev, bdata->irq, isr, irqflags,
					     desc, bdata);

	return 0;
}

 (3)下面来看中断和delay work做了什么事

static irqreturn_t gpio_keys_gpio_isr(int irq, void *dev_id)
{
	struct gpio_button_data *bdata = dev_id;
    ...............
    ...............
    /*中断中,唯一做的事,就是把delay work加入到了system_wq队列中去.还做了一个延迟
    这个延迟目的是为了去抖动.*/
	mod_delayed_work(system_wq,
			 &bdata->work,
			 msecs_to_jiffies(bdata->software_debounce));

	return IRQ_HANDLED;
}

static void gpio_keys_gpio_work_func(struct work_struct *work)
{
    /*调用上报消息,接着向下看*/
    ...........
	gpio_keys_gpio_report_event(bdata);
    ...........
}

static void gpio_keys_gpio_report_event(struct gpio_button_data *bdata)
{
    ............
    /*第一步,获取gpio 状态.*/
	state = gpiod_get_value_cansleep(bdata->gpiod);
	............
    /*发送消息到input*/
    input_event(input, type, *bdata->code, state);
	input_sync(input);
    ............
}
  • 5
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值