当前位置: 首页 > article >正文

【Linux】驱动程序同步和异步通知方式

一、应用程序APP,访问驱动程序/dev/input/enent1流程:

在这里插入图片描述

假设用户程序直接访问 /dev/input/event0 设备节点,或者使用 tslib 访问设备节点,数据的流程如下:

  1. APP 发起读操作,若无数据则休眠;
  2. 用户操作设备,硬件上产生中断。如用户点击触摸屏,产生SIGIO信号;
  3. 输入系统驱动层对应的驱动程序处理中断: 读取到数据,转换为标准的输入事件,向核心层汇报。 所谓输入事件就是一个“struct input_event”结构体
  4. 核心层可以决定把输入事件转发给上面哪个 handler 来处理。最常用的是 evdev_handler:它只是把 input_event 结构体保存在内核 buffer 等。
  5. 当 APP正在等待数据时,evdev_handler 会把它唤醒,这样 APP 就可以读取数据。 APP 对输入事件的处理: APP 获 得 数据 的 方 法 有 2 种 : 直 接 访 问 设 备 节 点 ( 比 如 /dev/input/event0,1,2,…),或者通过 tslib、libinput 这类库来间接访问设备节点。这些库简化了对数据的处理。



二、标准输入事件–struct input_event

/* The event structure itself */
struct input_event {
	struct timeval time;
	__u16 type;
	__u16 code;
	__s32 value;
};

在这里插入图片描述



三、驱动程序同步通知方式

所谓同步,就是“你慢我等你”。

fd = open("/dev/input/event1", O_RDWR | O_NONBLOCK);

设置驱动程序为“O_NONBLOCK”表示“非阻塞”。APP 调用 read 函数读取数据时,如果驱动程序中有数据,那么 APP 的 read函数会返回数据。如果驱动程序中没有数据,APP会阻塞。

#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <linux/input.h>
 
int main()
{
    const char *inputDevicePath = "/dev/input/event0";
 
    int inputDeviceFd = open(inputDevicePath, O_RDONLY);
 
    if (inputDeviceFd == -1)
    {
        perror("Failed to open input device");
        return 1;
    }
 
    struct input_event event;
 
    while (1)
    {
        ssize_t bytesRead = read(inputDeviceFd, &event, sizeof(event));
 
        if (bytesRead == -1)
        {
            perror("Failed to read input event");
            break;
        }
 
        if (bytesRead == sizeof(event))
        {
            // 处理输入设备事件
            printf("Event type: %d, code: %d, value: %d\n", event.type, event.code, event.value);
        }
    }
 
    close(inputDeviceFd);
 
    return 0;
}



四、驱动程序异步通知方式

所谓异步通知,就是 APP 可以忙自己的事,当驱动程序用数据时它会主动给APP 发信号,这会导致 APP 执行信号处理函数。

驱动程序发信号流程:

  1. 用户点击触摸屏,触摸屏上的驱动从硬件上获得数据,转化为标准输入事件–struct input_event event;
  2. 驱动程序发信号(SIGIO,驱动程序常用信号,表示有IO事件)给应用程序(APP)。怎么发?内核里提供有函数,内核自动处理。

应用程序要做的事情有这几件:

  1. 编写信号处理函数:
void my_sig_handler(int sig)
{
	struct input_event event;
	while (read(fd, &event, sizeof(event)) == sizeof(event))
	{
		printf("get event: type = 0x%x, code = 0x%x, value = 0x%x\n", event.type, event.code, event.value);		
	}
}
  1. 注册信号处理函数:
signal(SIGIO, my_sig_handler);
  1. 打开驱动程序:
fd = open("/dev/input/event0", O_RDWR);
  1. 把APP的进程 ID 告诉驱动,getpid()可以获得应用程序的进程id。这一步是核心,告诉驱动程序应该把信号发给哪个APP
fcntl(fd, F_SETOWN, getpid());
  1. 使能驱动的 FASYNC 功能:
flags = fcntl(fd, F_GETFL);
fcntl(fd, F_SETFL, flags | FASYNC);

驱动程序的信号发给APP的关键是:APP 要把自己的pid告诉驱动。 APP 收到后,执行信号处理函数。




参考链接:
Linux中如何获取输入设备(如触摸屏、按键等)的事件信息


http://www.kler.cn/a/147713.html

相关文章:

  • 《数学年刊A辑》
  • Odoo :一款免费开源的日化行业ERP管理系统
  • 物料数据对接:轻易云助力聚水潭与金蝶云星空集成方案
  • C++静态成员
  • RabbitMQ轻松构建高效可靠的消息队列系统
  • 利用编程语言和脚本编写技术,实现自动化渗透测试和安全工具的开发
  • JavaScript 的初步学习上篇
  • CSS-长度单位篇
  • 图像去噪——k-Sigma变换,模拟增益,噪声方差
  • 【音频】Glitch相关
  • app小程序定制的重点|软件定制开发|网站搭建
  • Mysql 高级日志binlog、undoLog、redoLog 详解
  • 问答社区运营的核心是什么?
  • docker介绍、部署与常用命令
  • git仓库如何撤销提交,恢复提交,重置版本命令
  • 蓝桥杯每日一题2023.11.23
  • 伦敦金新手和有经验的投资者 他们有什么不同?
  • 免费部署开源大模型 ChatGLM-6B
  • python pdf转txt文本、pdf转json
  • OWASP TOP 10 2021 对应的CWE缺陷(官方)
  • 接口幂等+防重复提交+失败重试
  • 【01】ES6:ECMAScript 介绍
  • 获取WordPress分类链接
  • 基于springboot+maven的个人理财管理系统
  • 打造企业AI数字人专属IP的重要性
  • Unity播放网络视频