触摸屏(典型 I2C + Input 子系统设备)从设备树解析到触摸事件上报
触摸屏(典型 I2C + Input 子系统设备)从设备树解析到触摸事件上报
以下是架构图,对触摸屏(典型I2C + Input子系统设备)从设备树解析到触摸事件上报的全流程详细拆解,包含文字讲解和配套流程图:
注:代码程序可以参考driver\input\touchscreen\gt9xx.c,驱动程序非常复杂是因为要兼容很多厂家的设备甚至升级固件之类的操作,通用的大致流程如下:
一、核心角色与职责
组件 | 作用 |
---|---|
设备树 | 描述硬件拓扑(I2C总线、触摸屏设备地址、中断号等) |
i2c_client | 代表I2C总线上的触摸屏设备,保存设备地址、总线适配器等信息 |
i2c_driver | 触摸屏驱动核心,负责匹配i2c_client、初始化硬件、创建Input子系统设备 |
input_dev | 向上抽象为输入设备(如触摸屏),提供事件上报接口(按键、绝对坐标等) |
input_handler | 输入事件处理器(如evdev ),负责接收input_dev事件并暴露给用户空间 |
二、全流程分步讲解(配流程图)
1. 设备树解析与 i2c_client
创建
流程:
细节:
- 设备树中定义触摸屏节点(示例片段):
i2c@12340000 { // I2C控制器节点touchscreen@38 { // 触摸屏子节点,地址0x38compatible = "vendor,touchscreen"; reg = <0x38>; // I2C设备地址interrupts = <IRQ_TYPE_EDGE_FALLING 25>; // 中断号}; };
- 内核启动时,I2C总线驱动解析设备树,为每个I2C设备创建
i2c_client
,填充设备地址、兼容字符串、中断等信息,注册到i2c_bus_type
总线。
2. i2c_driver
注册与匹配
流程:
细节:
- 驱动代码中定义
i2c_driver
:static const struct of_device_id touchscreen_of_match[] = {{ .compatible = "vendor,touchscreen" }, // 匹配设备树compatible{ }, };static struct i2c_driver touchscreen_i2c_driver = {.probe = touchscreen_probe, // 匹配成功后执行的函数.driver = {.name = "touchscreen",.of_match_table = touchscreen_of_match,}, };module_i2c_driver(touchscreen_i2c_driver); // 注册到I2C总线
- 匹配逻辑:
i2c_bus_type
遍历总线上的i2c_client
和已注册i2c_driver
,通过compatible
字符串匹配。匹配成功后,调用i2c_driver.probe
函数。
3. input_dev
创建与注册(在 probe
中完成)
流程:
细节:
probe
函数核心逻辑:static int touchscreen_probe(struct i2c_client *client, const struct i2c_device_id *id) {struct input_dev *input;int ret;// 1. 硬件初始化(如配置I2C寄存器、申请中断)ret = i2c_smbus_write_byte_data(client, 0x00, 0x01); // 示例写寄存器if (ret < 0) return ret;// 2. 分配input_devinput = devm_input_allocate_device(&client->dev);if (!input) return -ENOMEM;// 3. 设置input_dev属性input->name = "touchscreen";input->phys = "i2c-touchscreen/input0";input->id.bustype = BUS_I2C;// 4. 声明支持的事件类型(如绝对坐标、按键)__set_bit(EV_ABS, input->evbit); __set_bit(ABS_X, input->absbit);__set_bit(ABS_Y, input->absbit);__set_bit(EV_KEY, input->evbit);__set_bit(BTN_TOUCH, input->keybit);// 5. 注册input_dev到Input子系统ret = input_register_device(input);if (ret < 0) return ret;// 6. 保存input_dev到私有数据(供中断处理用)i2c_set_clientdata(client, input);// 7. 申请中断(触摸事件触发时调用中断处理函数)return devm_request_irq(&client->dev, client->irq, touchscreen_irq_handler, IRQF_TRIGGER_FALLING, "touchscreen", input); }
4. input_handler
自动匹配与关联
流程:
细节:
- Input子系统中,
input_handler
(如通用的evdev
处理器)会遍历所有input_dev
,根据input_dev
声明的事件类型(evbit
/keybit
等)自动匹配。 - 典型场景:
evdev
会匹配所有input_dev
,为每个设备创建/dev/input/eventX
节点,用户空间通过读取这些节点获取事件。
5. 触摸事件上报(中断触发)
流程:
细节:
- 中断触发:触摸屏幕时,硬件产生中断,触发
touchscreen_irq_handler
。 - 中断处理函数:
static irqreturn_t touchscreen_irq_handler(int irq, void *dev_id) {struct input_dev *input = dev_id;struct i2c_client *client = input_get_drvdata(input);u16 x, y;bool pressed;// 1. 从I2C设备读取触摸坐标、压力等数据i2c_smbus_read_i2c_block_data(client, 0x10, 4, buffer); // 示例读数据x = (buffer[0] << 8) | buffer[1];y = (buffer[2] << 8) | buffer[3];pressed = (buffer[0] & 0x80) ? 1 : 0; // 假设最高位表示按压// 2. 上报按键事件(按下/松开)input_report_key(input, BTN_TOUCH, pressed);// 3. 上报绝对坐标事件input_report_abs(input, ABS_X, x);input_report_abs(input, ABS_Y, y);// 4. 同步事件(通知用户空间数据已就绪)input_sync(input);return IRQ_HANDLED; }
- 用户空间读取:通过
libinput
或直接读/dev/input/eventX
,解析事件结构体(struct input_event
)获取坐标、按键状态。
三、完整流程图(合并版)
flowchart TBsubgraph 设备树解析A[设备树定义触摸屏节点] --> B[i2c总线驱动解析]B --> C[i2c_client创建并注册到i2c_bus_type]endsubgraph 驱动注册与匹配D[i2c_driver定义(含compatible)] --> E[i2c_driver注册到i2c_bus_type]E --> F{i2c_bus_type匹配}F -->|compatible一致| G[调用i2c_driver.probe]endsubgraph Input子系统初始化G --> H[硬件初始化(I2C、中断)]H --> I[input_dev分配+配置(事件类型)]I --> J[input_dev注册到Input子系统]J --> K{Input子系统匹配}K -->|事件类型匹配| L[input_handler(如evdev)关联]endsubgraph 触摸事件上报M[触摸屏幕触发硬件中断] --> N[中断处理函数调用]N --> O[读取I2C触摸数据(坐标、压力)]O --> P[input_event上报(按键、坐标)]P --> Q[input_sync同步事件]Q --> R[input_handler转发到/dev/input/eventX]R --> S[用户空间读取事件]end
四、关键总结
- 分层解耦:I2C总线负责硬件通信,Input子系统负责输入事件抽象,驱动只需关注“硬件数据读取”和“事件上报”。
- 自动匹配:通过
compatible
(I2C层)和事件类型
(Input层)实现驱动与设备、处理器的自动关联。 - 事件流:触摸动作→硬件中断→驱动读数据→
input_event
上报→input_handler
转发→用户空间消费。
理解这套流程后,无论是调试触摸屏驱动、扩展Input设备(如按键、传感器),还是优化事件响应,都能更清晰地定位问题~