驱动之路#10:浅谈 Input 子系统 欢迎关注,每周更新!☞
本合集分享的是,我当初学习Linux驱动的来时路——《《驱动之路》开篇:自序&前言》。
正文
回答3个问题:
(1)什么是 Input 子系统?
(2)为什么需要 Input 子系统?
(3)如何使用 Input 子系统?
1 什么是 Input 子系统?
Input 子系统是 Linux 内核中一套统一管理输入设备的框架,主要是为了将键盘、鼠标、触摸屏、按键、摇杆等各类输入设备的硬件差异抽象化,为上层应用提供统一的输入事件接口(如 /dev/input/eventX),这样可以避免为每种设备单独编写驱动程序。 一句话总结其作用:“屏蔽硬件差异、提供统一接口”。
2 为什么需要 Input 子系统?
假如没有 Input 子系统,想要使用一个输入设备,我们需要为每一种设备单独编写完整的驱动程序,包括硬件初始化、数据读取、事件解析等所有逻辑。这是由于每个输入设备(比如 USB 键盘、GPIO 按键、I2C 触摸屏、红外遥控器)的通信协议、数据格式、触发方式都不同。
另外,每新增一种输入设备(如新型触摸屏)时,不仅要编写全新驱动,还可能与现有设备冲突,甚至需要修改上层应用才能适配。这样不仅导致 Linux 内核代码冗余严重,而且开发成本和维护成本极高。
面对以上种种问题,"封装"与"分层"这两大经典的程序设计思想再次发威,Input 子系统正是基于这样思想设计出来解决以上问题的。
Input 子系统有如下主要作用:
硬件差异屏蔽:不同输入设备的通信协议(如 USB、I2C、SPI、GPIO)和数据格式不同,Input 子系统通过统一的驱动模型,将底层硬件细节封装,上层无需关心设备是 USB 键盘还是 GPIO 按键;
统一事件接口:所有输入设备最终都通过 /dev/input/eventX节点暴露给用户空间,应用程序可通过标准的 read ()/poll () 等系统调用读取事件(如按键按下 / 松开、坐标移动、手势等);
事件标准化:定义了统一的事件类型(如 EV_KEY、EV_ABS、EV_REL)和事件码(如 KEY_0、ABS_X),确保不同设备的事件格式一致,上层应用可跨设备兼容。
3 如何使用 Input 子系统?
要想正确使用 Input 子系统,不得不理清其 3 层架构:事件处理层、核心层以及驱动层。核心源代码位于/drivers/input/目录。
事件处理层(evdev.c):接收核心层转发的事件,为上层应用提供访问接口(如/dev/input/eventX设备节点)。
核心层(input.c):管理所有输入设备,提供驱动注册 / 注销接口,转发驱动层事件到合适的事件层。
驱动层(输入设备驱动程序,如gpio_keys.c 等):直接操作硬件(如 GPIO 中断、读取电平),将硬件信号转换为 “标准化输入事件”。从底层硬件到上层应用链路如下:

从硬件底层到用户空间数据是如何层层传递的?假如用户空间直接访问/dev/input/event0设备节点,数据的流程大致如下:
(1)用户空间应用程序通过 read() 系统调用读取 /dev/input/eventX 设备节点。如果此时内核输入缓冲区中没有可用的事件数据,该 read() 调用会使应用程序进入休眠状态,等待数据到达。
(2)当用户进行操作(如触摸屏幕、按下按键)时,输入设备的硬件会产生一个中断信号(例如,触摸芯片的中断引脚电平发生变化)。
(3)当驱动程序检测到这个电平时,输入系统驱动层对应的驱动程序会调用中断处理函数:读取到数据,转换为标准的输入事件,向核心层汇报。
(4)Input 核心层接收到事件后,会根据设备和事件的类型,上报事件层——将其分发给已注册并匹配的事件处理器(Input Handler),例如 evdev_handler。当用户空间正在等待数据时,evdev_handler会把它唤醒,这样用户空间就可以获取到硬件底层的上报数据。
最后,了解下用户空间获得数据的两种方法:
直接访问设备节点(比如/dev/input/event0,1,2,...);
通过tslib、libinput 这类库来间接访问设备节点,这些库简化了对数据的处理。
如果想继续深入理解 Input 子系统是如何将不同输入设备的硬件差异统一成标准的输入事件?请听下回分解。
(完)
本人专注 Linux 驱动 & Linux/Android BSP 开发调试,可接外包项目/技术支持/问题定位。有需求或交个朋友可加微信:【Chen_WeChat2026】。
审核编辑 黄宇
全部0条评论
快来发表一下你的评论吧 !