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

【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中如何获取输入设备(如触摸屏、按键等)的事件信息

相关文章:

  • 【开源】基于JAVA的天然气工程运维系统
  • vuepress-----3、导航栏
  • HTML新手入门笔记整理:HTML常用标签总结表
  • 分布式定时任务系列6:XXL-job触发日志过大引发的CPU告警
  • 进阶C语言-字符函数和字符串函数
  • 播放器开发(四):多线程解复用与解码模块实现
  • 量子力学应用:探索科技前沿的奇幻之旅
  • 数据分片在分布式 SQL 数据库中的工作原理
  • 李宏毅2020机器学习课程笔记(二)- 深度学习
  • java开发中各个环境的适用场景
  • 【研究中2】sql server权限用户设置
  • 火柴人版王者-Java
  • Ubuntu 环境下 NFS 服务安装及配置使用
  • php.ini文件中XDebug的配置
  • 如何使用Windows自带的IIS服务搭建本地站点并远程访问
  • ES6指北【2】—— 箭头函数
  • 「译」Node.js Streams 基础
  • iOS筛选菜单、分段选择器、导航栏、悬浮窗、转场动画、启动视频等源码
  • java架构面试锦集:开源框架+并发+数据结构+大企必备面试题
  • java中具有继承关系的类及其对象初始化顺序
  • mysql外键的使用
  • node和express搭建代理服务器(源码)
  • Otto开发初探——微服务依赖管理新利器
  • Promise面试题,控制异步流程
  • Ruby 2.x 源代码分析:扩展 概述
  • Transformer-XL: Unleashing the Potential of Attention Models
  • VUE es6技巧写法(持续更新中~~~)
  • 给github项目添加CI badge
  • 解决iview多表头动态更改列元素发生的错误
  • 设计模式 开闭原则
  • 无服务器化是企业 IT 架构的未来吗?
  • 译自由幺半群
  • 这几个编码小技巧将令你 PHP 代码更加简洁
  • HanLP分词命名实体提取详解
  • ​直流电和交流电有什么区别为什么这个时候又要变成直流电呢?交流转换到直流(整流器)直流变交流(逆变器)​
  • # Pytorch 中可以直接调用的Loss Functions总结:
  • #Linux杂记--将Python3的源码编译为.so文件方法与Linux环境下的交叉编译方法
  • #NOIP 2014# day.1 生活大爆炸版 石头剪刀布
  • #QT(智能家居界面-界面切换)
  • (1)Android开发优化---------UI优化
  • (android 地图实战开发)3 在地图上显示当前位置和自定义银行位置
  • (动手学习深度学习)第13章 计算机视觉---图像增广与微调
  • (附源码)计算机毕业设计SSM智慧停车系统
  • (一)80c52学习之旅-起始篇
  • (一一四)第九章编程练习
  • (转)大型网站的系统架构
  • .babyk勒索病毒解析:恶意更新如何威胁您的数据安全
  • .net CHARTING图表控件下载地址
  • .NET Framework杂记
  • .net web项目 调用webService
  • .NET/C# 获取一个正在运行的进程的命令行参数
  • .NET开发不可不知、不可不用的辅助类(一)
  • .NET开源项目介绍及资源推荐:数据持久层
  • /var/log/cvslog 太大
  • [ vulhub漏洞复现篇 ] Apache APISIX 默认密钥漏洞 CVE-2020-13945