type
date
slug
category
icon
password
Input 子系统结构和工作流1. 输入系统架构2. 核心数据结构2.1 输入设备结构体 (input_dev)2.2 事件处理程序结构体 (input_handler )2.3 输入事件结构体 (input_event)3. 注册与匹配流程3.1 注册 input_dev3.2 注册 input_handler3.3 设备与处理程序匹配过程3.4 事件处理流程输入子系统 evdev.c 文件详细分析1. 架构概述2. 关键数据结构2.1 evdev 结构体2.2 evdev_client 结构体3. 时序交互图4. 输入设备创建的主要工作流程4.1 模块初始化4.2 设备连接4.3 设备打开4.4 事件处理4.5 读取事件4.6 写入事件5. 总结
Input 子系统结构和工作流
1. 输入系统架构
Linux Input 子系统是一个处理输入设备的框架,它通过三个核心组件实现:
input_dev
、input_handler
和 input_handle
。2. 核心数据结构
input_dev
代表物理输入设备(如键盘、鼠标),input_handler
代表处理输入事件的处理程序,而 input_handle
则是连接两者的桥梁。2.1 输入设备结构体 (input_dev)
- 设备能力位图:用于表示设备支持的事件类型和事件代码
事件类型和代码含义说明
- evbit :表示设备支持的事件类型
- EV_KEY :按键事件
- EV_REL :相对坐标事件(如鼠标移动)
- EV_ABS :绝对坐标事件(如触摸屏)
- EV_SW :开关事件
- EV_LED :LED灯事件
- EV_SND :声音事件
- EV_FF :力反馈事件
- EV_SYN :同步事件,用于标记事件包的结束
- keybit :当支持 EV_KEY 时,表示设备支持的按键
- KEY_A 到 KEY_Z :字母键
- KEY_0 到 KEY_9 :数字键
- BTN_LEFT 、 BTN_RIGHT :鼠标按钮
- BTN_TOUCH :触摸事件
- relbit :当支持 EV_REL 时,表示设备支持的相对坐标
- REL_X 、 REL_Y :X和Y轴相对移动
- REL_WHEEL :滚轮移动
- absbit :当支持 EV_ABS 时,表示设备支持的绝对坐标
- ABS_X 、 ABS_Y :X和Y轴绝对位置
- ABS_PRESSURE :压力值
- ABS_MT_POSITION_X 、 ABS_MT_POSITION_Y :多点触控位置
h_list
是一个input_handle 链表头(区别input_handler),用于管理连接到该设备的所有处理程序(handlers)
2.2 事件处理程序结构体 (input_handler )
- id_table :用于设备ID与处理程序ID表比较,表明支持哪些input_dev
- match :在 id_table 表比较后调用,用于执行设备和处理程序之间的精细匹配
- connect :当处理程序连接到输入设备时调用,负责处理程序与设备建立连接
- void *private :处理程序的私有数据指针,可用于存储驱动程序特定的数据
- filter :事件过滤回调函数,如果返回 true ,则事件会被过滤掉
- event :单个事件处理回调函数,当输入设备产生事件时被调用。注意此函数在中断禁用和设备事件锁持有的情况下调用,因此不能休眠
- events :批量事件处理回调函数,用于一次处理多个输入事件,提高效率
- disconnect :当处理程序与输入设备断开连接时调用
- start :在 connect() 方法之后以及当"抓取"设备的进程释放设备时,由输入核心调用
- legacy_minors :由使用传统次设备号范围的驱动程序设置为 true
- minor :此驱动程序可以提供的32个传统次设备号范围的起始值
- name :处理程序的名称,将显示在 /proc/bus/input/handlers 中
- h_list :与处理程序 input_handler 关联的所有句柄 input_handle 链表头,与input_dev中h_list关联。
- node :用于将驱动程序放置到全局 input_handler_list 链表中的节点
2.3 输入事件结构体 (input_event)
输入事件通过
input_event
结构体在内核和用户空间之间传递:3. 注册与匹配流程
3.1 注册 input_dev
3.2 注册 input_handler
3.3 设备与处理程序匹配过程
3.4 事件处理流程
输入子系统 evdev.c 文件详细分析
evdev.c 是 Linux 输入子系统中的核心文件,它实现了字符设备接口,允许用户空间程序访问原始输入事件。
1. 架构概述
2. 关键数据结构
2.1 evdev 结构体
2.2 evdev_client 结构体
3. 时序交互图
- APP调用open函数打开
/dev/input/event0
- 在驱动程序
evdev_open
里,创建一个evdev_client,表示一个"客户"
- APP调用read/poll读取、等待数据
- 没有数据时休眠:
wait_event_interruptible(evdev->wait, ...)
- 点击、操作输入设备,产生中断
- 在中断服务程序里
- 从硬件读取到数据
- 使用以下函数上报数据
- input_event做什么?
- 从
dev->h_list
中取出input_handle
,从input_handle
取出input_handler
- 优先调用
input_handler->filter
来处理 - 如果没有
input_handler->filter
或者没处理成功 - 调用
input_handler->events
- 没有
input_handler->events
的话,调用input_handler->event
- 以evdev.c为例
- 它有
evdev_events
:用来处理多个事件 - 也有
evdev_event
:实质还是调用evdev_events
- 唤醒"客户":
wake_up_interruptible(&evdev->wait);
4. 输入设备创建的主要工作流程
4.1 模块初始化
evdev 模块在初始化时注册一个输入处理程序:
4.2 设备连接
当输入设备注册时,输入核心会调用
evdev_connect
函数创建对应的 evdev 设备:4.3 设备打开
当用户空间程序打开设备节点时,会调用
evdev_open
函数:4.4 事件处理
当输入设备产生事件时,输入核心会调用
evdev_event
或 evdev_events
函数:4.5 读取事件
用户空间程序通过
read
系统调用读取事件:4.6 写入事件
用户空间程序可以通过
write
系统调用注入事件:5. 总结
evdev.c 实现了 Linux 输入子系统中的字符设备接口,它是用户空间程序访问输入设备事件的主要方式。主要功能包括:
- 为每个输入设备创建对应的字符设备节点
- 管理用户空间程序与输入设备的连接
- 提供事件缓冲和过滤机制
- 支持多种时钟类型的时间戳
- 实现设备独占(grab)机制
- 提供丰富的 ioctl 接口用于查询和控制设备
通过这些功能,evdev 模块使得用户空间程序能够以统一的方式访问各种输入设备,是 Linux 输入子系统的关键组成部分。
- Author:felixfixit
- URL:http://www.felixmicrospace.top/1da4d032dcc1802d86e0f06b7ab1928a
- Copyright:All articles in this blog, except for special statements, adopt BY-NC-SA agreement. Please indicate the source!