input_handler和input_dev详解
文章目录
- 🧩 背景:Linux 输入子系统结构图
- 1️⃣ struct input\_dev — 表示一个输入设备
- 🧷 关键字段简要说明:
- 📌 设备驱动中怎么使用它?
- 2️⃣ struct input\_handler — 表示一个处理 input\_dev 的 handler(协议驱动)
- 🧷 关键字段简要说明:
- 📌 它的作用是什么?
- 3️⃣ struct input\_handle — input\_dev 与 input\_handler 的桥梁
- 🔗 它们之间的协作流程(简化)
- 🧪 举个实际场景:evdev handler 处理触摸屏 input\_dev
- 🧠 总结
🧩 背景:Linux 输入子系统结构图
Linux 输入子系统主要由以下几部分组成:
+----------------+| input_event | ← 用户空间读取设备事件+----------------+↑+----------------+| input_handler | ← 处理 input_dev 事件(例如 evdev, mousedev)+----------------+↑+----------------+| input_dev | ← 设备驱动注册的输入设备+----------------+
input_dev
由设备驱动注册,
input_handler
由上层“协议”驱动注册(比如 evdev/mousedev/joydev)
两者配对后,用户程序就可以通过/dev/input/eventX
获取事件。
1️⃣ struct input_dev — 表示一个输入设备
该结构体定义于 <linux/input.h>
,是设备驱动(比如触摸屏、按键、鼠标)注册输入设备时要填充的核心结构体。
🧷 关键字段简要说明:
struct input_dev {const char *name; // 设备名称const char *phys; // 物理路径(例如 "usb-0000:00:1d.0-1/input0")const char *uniq; // 唯一标识(可选)struct input_id id; // 设备ID信息(vendor, product, version等)unsigned long evbit[BITS_TO_LONGS(EV_CNT)]; // 支持的事件类型(比如按键、相对坐标等)unsigned long keybit[BITS_TO_LONGS(KEY_CNT)]; // 支持的按键种类(比如 KEY_A、KEY_B)unsigned long relbit[BITS_TO_LONGS(REL_CNT)]; // 支持的相对坐标事件(比如鼠标移动)unsigned long absbit[BITS_TO_LONGS(ABS_CNT)]; // 支持的绝对坐标事件(比如触摸屏)struct input_mt *mt; // 多点触控支持int (*open)(struct input_dev *dev); // 当 handler 打开时调用void (*close)(struct input_dev *dev); // 当 handler 关闭时调用struct input_dev_poller *poller; // 轮询器支持(可选)void *private; // 设备私有数据...
};
📌 设备驱动中怎么使用它?
- 初始化
input_dev
,设置支持的事件类型、设备 ID、名字等; - 使用
input_register_device()
注册; - 使用
input_report_key()
、input_sync()
上报事件。
举例:
input_dev->name = "My Button Device";
set_bit(EV_KEY, input_dev->evbit);
set_bit(KEY_ENTER, input_dev->keybit);input_register_device(input_dev);
2️⃣ struct input_handler — 表示一个处理 input_dev 的 handler(协议驱动)
input_handler
结构体由上层协议驱动(比如 evdev、mousedev)注册,用于接收输入事件并提供给用户空间。
🧷 关键字段简要说明:
struct input_handler {const char *name; // 处理器名称(如 "evdev")bool (*match)(struct input_handler *, struct input_dev *); // 判断是否匹配某个 input_devint (*connect)(struct input_handler *, struct input_dev *, const struct input_device_id *);void (*disconnect)(struct input_handle *);void (*start)(struct input_handle *); // 可选const struct input_device_id *id_table; // 支持的设备类型表struct list_head h_list; // handler 链表节点struct list_head node; // 全局 handler 链表...
};
📌 它的作用是什么?
- 系统启动时,协议驱动注册
input_handler
; - 当驱动注册一个
input_dev
后,input core 会尝试用每个 handler 去 match 它; - 匹配成功后,调用
connect()
绑定,生成/dev/input/eventX
节点; - 用户空间可以通过 read
/dev/input/eventX
获取事件。
3️⃣ struct input_handle — input_dev 与 input_handler 的桥梁
在 handler
和 dev
匹配并 connect 成功之后,会创建 input_handle
结构体来维护它们之间的绑定关系。
struct input_handle {void *private; // 私有数据int open; // 被打开次数const char *name; // 名称struct input_dev *dev; // 指向 input_devstruct input_handler *handler;// 指向 input_handlerstruct list_head d_node; // 挂到 dev 的 handle 链表struct list_head h_node; // 挂到 handler 的 handle 链表
};
🔗 它们之间的协作流程(简化)
【驱动层】
1. 驱动注册 input_dev(input_register_device)【协议层】
2. handler 注册 input_handler(input_register_handler)【input core】
3. 自动匹配 input_handler 与 input_dev
4. 成功后调用 handler->connect()
5. 创建 input_handle → 建立 dev 和 handler 的关联
6. 用户可通过 /dev/input/eventX 读取事件
🧪 举个实际场景:evdev handler 处理触摸屏 input_dev
- 驱动注册了一个 input_dev,支持 EV_ABS(ABS_X、ABS_Y);
- evdev 的 handler->match() 成功匹配;
- handler->connect() 被调用,创建 input_handle;
- evdev 创建
/dev/input/eventX
; - 用户程序可以通过这个节点读到触摸坐标事件。
🧠 总结
结构体 | 定义者 | 作用 |
---|---|---|
input_dev | 设备驱动 | 描述一个输入设备 |
input_handler | 协议驱动 | 匹配、处理 input_dev |
input_handle | input core | 管理 handler 和 dev 的连接关系 |
input_dev
是设备,input_handler
是处理器,input_handle
是它们的桥梁。