尧图网站建设 尧图网络
  • 首页
  • 关于我们
  • 服务项目
  • 案例展示
  • 建站流程
  • 资讯中心
  • 联系我们
首页/资讯中心/详情

input 设备 - kernel 和 应用数据 交互

input 设备 - kernel 和 应用数据 交互
📅 发布时间:2026/6/26 7:30:25

我们先看些一个sensor report input 的 数据流程

[用户程序] ──ioctl(START)──> [内核态 驱动逻辑 sensor_enable]
│
▼
[内核态 驱动逻辑 schedule_delayed_work] ──每隔30ms──> [report]
│
┌───────────┬───────────┬───────────┬───────┘
▼ ▼ ▼ ▼
[ABS_X] [ABS_Y] [ABS_Z] [SYN]
└───────────┴───────────┴───────────┘
│
▼
[内核态 驱动逻辑------输入子系统队列]
│
▼
[用户态程序 read()] <── 循环读取每个 event

┌──────────────────────────────────────────────────────┐
│ 1. 用户调用 ioctl(GSENSOR_IOCTL_START) │
└────────────────────┬───────────────────────────────┘
│
▼
┌──────────────────────────────────────────────────────┐
│ 2. sensor_enable() → 启动定时任务 │
│ schedule_delayed_work(每 poll_delay_ms 执行) │
└────────────────────┬───────────────────────────────┘
│
▼
┌──────────────────────────────────────────────────────┐
│ 3. sensor_delaywork_func() → report() │
│ └── 读取硬件数据 → input_report_abs() ×3 │
│ └── input_sync() → 帧结束 │
└────────────────────┬───────────────────────────────┘
│
▼
┌──────────────────────────────────────────────────────┐
│ 4. 用户 read() → 获取 input_event │
│ └── 解析 ev.type/code/value │
└──────────────────────────────────────────────────────┘

核心流程(一句话)

用户通过 ioctl 启动传感器 → 内核定时读取硬件数据 → 通过 input_report_abs/input_sync 上报 → 用户 read() 获取数据

用户如何 获取数据的你 read eventX 这个设备

/* 打开传感器控制设备 */

gsensor_fd = open(GSENSOR_DEV, O_RDONLY);

/* 启动传感器 */

ioctl(gsensor_fd, GSENSOR_IOCTL_START)

input_fd = open(INPUT_DEV, O_RDONLY | O_NONBLOCK);

/* 主循环读取数据 */

while (running) {

ssize_t n = read(input_fd, &ev, sizeof(ev));

if (ev.type == EV_ABS) {

switch (ev.code) {

case ABS_X:

x = ev.value * SCALE; break;

case ABS_Y:

y = ev.value * SCALE; break;

case ABS_Z:

z = ev.value * SCALE; break;

}

} else if (ev.type == EV_SYN) {

// 收到syn 后,同步显示一次结果

printf("\r%.2f %.2f %.2f", x, y, z);

fflush(stdout);

}

}

------------------------------------------------------------------------------------

#include <linux/input.h>

struct input_event {
struct timeval time; // 时间戳(秒 + 微秒)
__u16 type; // 事件类型(如 EV_ABS、EV_SYN)
__u16 code; // 事件代码(如 ABS_X、ABS_Y)
__s32 value; // 事件值(传感器数据)
};

为什么每次读取都是固定大小

原因1:内核保证数据完整性

驱动调用input_report_abs()时,内核会将数据封装成完整的input_event结构:

// 驱动中的操作 input_report_abs(input_dev, ABS_X, 1234); // 生成一个 input_event input_sync(input_dev); // 生成另一个 input_event

每个事件都是独立的、完整的 24 字节数据块。

原因2:输入子系统的队列机制

内核维护一个事件队列,每个队列元素都是完整的input_event:

内核事件队列 ────────────── ┌─────────────────────────────┐ │ input_event #1 (24字节) │ ← read() 读取这里 ├─────────────────────────────┤ │ input_event #2 (24字节) │ ├─────────────────────────────┤ │ input_event #3 (24字节) │ └─────────────────────────────┘

原因3:用户程序的读取方式

struct input_event ev; ssize_t n = read(input_fd, &ev, sizeof(ev)); // 读取 24 字节 if (n == sizeof(ev)) { // 读取成功,ev 包含完整的事件数据 printf("type=%d, code=%d, value=%d\n", ev.type, ev.code, ev.value); }

每次读取恰好是一个完整的input_event结构体。


数据读取的时序

驱动端 用户端 ─────── ────── │ │ │ input_report_abs(ABS_X, 1234) │ │ ↓ │ │ 写入队列: [time][EV_ABS][ABS_X][1234] │ │ │ input_report_abs(ABS_Y, -56) │ │ ↓ │ │ 写入队列: [time][EV_ABS][ABS_Y][-56] │ │ │ input_sync() │ │ ↓ │ │ 写入队列: [time][EV_SYN][0][0] │ │ │ read(&ev, 24) → ev = [time][EV_ABS][ABS_X][1234] │ │ │ read(&ev, 24) → ev = [time][EV_ABS][ABS_Y][-56] │ │ │ read(&ev, 24) → ev = [time][EV_SYN][0][0]

在你的代码中的应用

struct input_event ev; // 固定大小 24 字节 while (running) { ssize_t n = read(input_fd, &ev, sizeof(ev)); // 每次读取 24 字节 if (n != sizeof(ev)) continue; // 确保读取完整 // 解析固定格式的数据 if (ev.type == EV_ABS) { switch (ev.code) { case ABS_X: x = ev.value * SCALE; break; case ABS_Y: y = ev.value * SCALE; break; case ABS_Z: z = ev.value * SCALE; break; } } }

总结

是的!struct input_event是固定大小的结构体(24字节),每次读取都是按照固定格式。

这是 Linux 输入子系统的设计原则:

  1. 统一格式:所有输入设备(键盘、鼠标、传感器)都使用相同的input_event结构
  2. 固定大小:保证数据的完整性和可预测性
  3. 顺序读取:用户程序按顺序读取每个完整的事件

这就是为什么你可以直接用read(input_fd, &ev, sizeof(ev))来读取传感器数据!

相关新闻

  • 三维拟线性波动方程全局解存在性:加权Strichartz估计与能量控制
  • 图论中的完美匹配重配置:从2-switch到k-switch的连通性探索
  • 如何从卫星瓦片拼接出一张高清区域影像?

最新新闻

  • VMware上K8s集群安全基线不达标?——CIS Kubernetes Benchmark v1.8 + vSphere 7.0合规加固 checklist(含自动审计脚本下载通道)
  • 页式虚存模拟实验:从地址转换到置换算法的完整实现与调试
  • 【计算机毕业设计】基于SpringBoot的校园捐赠系统
  • Langfuse实战:构建LLM应用的可观测性与提示词优化体系
  • 机房运维太痛苦?实测智能巡检告警方案,实现“机器代人”新高度
  • 探索Ryujinx:在PC上体验Nintendo Switch游戏的开源模拟器

日新闻

  • Qwen2.5-Turbo百万上下文实战指南:百炼平台长文本处理全解析
  • 怎么监控对标账号更新,2026年作者监控工作流,5款深度对比
  • EdgeRemover:专业级Windows Edge浏览器管理工具,彻底解决顽固软件卸载难题

周新闻

  • Visual C++运行库修复终极指南:5分钟快速解决Windows软件启动错误
  • 手把手教你构建统计局地区经济数据爬虫:从环境搭建到数据持久化全指南
  • 2026多Agent深度解析:用AI团队替代单一模型,四种架构实战落地

月新闻

  • 【总结】入门篇:50句话让你记住架构核心概念
  • WeChatMsg技术方案解析:实现Mac微信数据自主管理的完整解决方案
  • WeChatMsg:革新性微信数据备份方案,打造你的专属数字记忆库

关于尧图

  • 公司简介
  • 团队介绍
  • 企业文化
  • 荣誉资质

服务项目

  • 定制开发
  • 电商建站
  • UI 设计
  • 运维服务

快速链接

  • 案例展示
  • 建站流程
  • 常见问题
  • 资讯中心

联系方式

  • 📍北京市朝阳区互联网产业园 A 座 10 层
  • 📞400-888-8888
  • ✉️contact@rkmt.cn
  • 🕐周一至周日 9:00-21:00

© 2024 北京尧图网络科技有限公司 版权所有 | 京 ICP 备 XXXXXXXX 号