LINUX INPUT SYSTEM(三)多点上报协议
多点协议
为多点触摸定义一种上报详细数据的方法。基于硬件能力划分:
Type A
匿名接触,所有的原始触摸数据发送给接收者
- 对于一个两点触控的触摸信息,type A设备的最小的事件序列
ABS_MT_POSITION_X x[0]
ABS_MT_POSITION_Y y[0]
SYN_MT_REPORT
ABS_MT_POSITION_X x[1]
ABS_MT_POSITION_Y y[1]
SYN_MT_REPORT
SYN_REPORT - 当第一个接触点离开后,事件序列如下:
ABS_MT_POSITION_X x[1]
ABS_MT_POSITION_Y y[1]
SYN_MT_REPORT
SYN_REPORT - 当第二个接触点离开后,事件序列如下:
SYN_MT_REPORT
SYN_REPORT
Type B(slot)
跟踪并识别每个触摸点,每个触摸点的单独更新,没有更新的点不需要上报
- 对于一个两点触控的触摸信息,type B设备的最小的事件序列
ABS_MT_SLOT 0
ABS_MT_TRACKING_ID 45
ABS_MT_POSITION_X x[0]
ABS_MT_POSITION_Y y[0]
ABS_MT_SLOT 1
ABS_MT_TRACKING_ID 46
ABS_MT_POSITION_X x[1]
ABS_MT_POSITION_Y y[1]
SYN_REPORT - id 45的触控点在x方向移动后的事件序列如下:
ABS_MT_SLOT 0
ABS_MT_POSITION_X x[0]
SYN_REPORT
slot 0对应的接触点离开,对应的事件序列如下:
ABS_MT_TRACKING_ID -1
SYN_REPORT
最后,第二个接触点离开后的事件序列如下:
ABS_MT_SLOT 1
ABS_MT_TRACKING_ID -1
SYN_REPORT
实例
根据硬件设备能力,由输入设备驱动程序指定一种协议(A/B)进行触摸消息上报
下面以协议b 为例,结合代码说明触摸屏多点上报的流程。
触摸屏设备驱动根据生命周期主要有三个阶段,如下:
驱动加载阶段
- 设备探测及设备初始化控制
-
这些同通用设备是一样的,上电复位控制,探测id ,注册中断,获取触摸屏信息等。
-
注册input device
设置input设备支持的事件类型、事件码、事件值的范围,input_id等信息input_dev = input_allocate_device(); input->name = touch_NAME; input->id.bustype = BUS_I2C; input->dev.parent = &(ts_data->client)->dev; input_mt_init_slots(input, max_slots, INPUT_MT_DIRECT); if (input_dev == NULL) { tp_log_err("allocate input device, error\n"); goto read_info_err; } input_set_abs_params(input, ABS_MT_POSITION_X, screen_min_x, screen_max_x, 0, 0); input_set_abs_params(input, ABS_MT_POSITION_Y, icreen_min_y, screen_max_y, 0, 0); input_set_abs_params(input, ABS_MT_PRESSURE, 0, 255, 0, 0); input_set_abs_params(input, ABS_MT_TOOL_TYPE , 0, MT_TOOL_MAX, 0, 0); //如设备支持不同触摸类型,需要上报此消息类型 ret = input_register_device(ilitek_data->input_dev); if (ret < 0) { tp_log_err("register input device, error\n"); }
读取输入事件以及上报消息阶段
一旦有输入事件,设备会产生中断,触发驱动程序读取内部信息,获知报点的相关信息,驱动程序再将这些消息通过多点协议格式进行上报
输入事件包括 按下 和抬起,驱动通过调用输入子系统提供的相关接口上报对应消息,对应的代码如下
static int touch_down(int id, int x, int y, int pressure)
{
struct input_dev *input = data->input_dev;
input_mt_slot(input, id); //上报 id
input_mt_report_slot_state(input, MT_TOOL_FINGER, true);//上报tool type 以及状态
#if !ROTATE_FLAG
input_event(input, EV_ABS, ABS_MT_POSITION_X, x);
input_event(input, EV_ABS, ABS_MT_POSITION_Y, y);
#else
input_event(input, EV_ABS, ABS_MT_POSITION_X, y);
input_event(input, EV_ABS, ABS_MT_POSITION_Y, x);
#endif
#ifdef REPORT_PRESSURE
input_event(input, EV_ABS, ABS_MT_PRESSURE, pressure);
#endif
update_input = 1;
}
static int touch_release(int id)
{
struct input_dev *input = data->input_dev;
if (data->touch_flag[id] == 1) {
tp_log_debug(PRINT_FINGER_REPORT,"release point id = %d\n", id);
input_mt_slot(input, id);
input_mt_report_slot_state(input, MT_TOOL_FINGER, false);
update_input = 1;
}
data->touch_flag[id] = 0;
return 0;
}
static void touch_input_sync(struct mxt_data *data)
if(update_input) {
input_mt_report_pointer_emulation(data->input_dev,
use_count);//根据多点slot ,模拟上报单点消息,以及BTN_TOUCH
input_sync(data->input_dev); //同步消息,告知接收者本次消息结束。
update_input = false;
}
static irqreturn_t process_input_messages(struct mxt_data *data)
{
read_input_message
...
if touch down
touch_down(id, x, y, pressure);
if touch release
touch_release(id);
if (data->update_input) {
touch_input_sync(data);
data->update_input = false;
}
}
驱动卸载阶段
略