本文共 6581 字,大约阅读时间需要 21 分钟。
转自:
linux kernel 2.6.30开始对多点触摸支持,最近高通要求所有CTP器件要用B 协议上报数据,协议A/B(slot)分析如下:
一、文档 多点触摸协议文档 kernel/Documentation/input/multi-touch-protocol.txt 二、协议分析 基于硬件的能力,触摸协议分为两种类型: type A: 只能处理匿名接触,描述了如何把所有原始触摸数据发给接收者。 type B: 有能力跟踪并识别每个触摸点的设备,描诉了如何把每个触摸点的单独跟 新通过事件slot发给接收者。 两种协议的使用: Protocol Example A: -------------------- type A设备的最小的事件序列看起来就像下面这样 (可以通过adb shell getevent -lt /dev/input/event0 查看 eventX对应触摸屏): 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 手抬起的时候是如下样子: SYN_MT_REPORT SYN_REPORT 只有SYNC,没有其它任何信息,系统就会认为此次事件为UP。 系统以SYN_MT_REPORT为一个点信息的结尾,收到一个点之后并不会立即处理, 而是一个事件完成之后才会处理, SYN_REPORT就是这个事件的标志。A协议比较简单,我们也可以发现在上面的序列 中根本就没有轨迹跟踪的信息, 有的只是点坐标等信息,报上去的信息简单粗暴不需要什么顺序,系统根本无法识 别报上的点是属于哪一条线的, 事件过滤和手指跟踪的工作留给用户空间来实现。 Protocol Example B: ------------------- type B设备的最小的事件序列看起来就像下面这样: ABS_MT_SLOT 0 ABS_MT_TRACKING_ID 46 ABS_MT_POSITION_X x[0] ABS_MT_POSITION_Y y[0] ABS_MT_SLOT 1 ABS_MT_TRACKING_ID 47 ABS_MT_POSITION_X x[1] ABS_MT_POSITION_Y y[1] SYN_REPORT 手抬起的时候如下样子: ABS_MT_SLOT 0 ABS_MT_TRACKING_ID -1 SYN_REPORT ABS_MT_SLOT 1 ABS_MT_TRACKING_ID -1 SYN_REPORT 对于协议B,内核驱动应该把每一个识别出的触控和一个slot相关联,并使用该 slot来传播触摸状态的改变,通过修改关联 slot的ABS_MT_TRACKING_ID来达到对触摸点的创建,替换和销毁。上报 ABS_MT_TRACKING_ID -1 系统会清除对应的ID和slot, 再次按下手指时分配新ID值(ID值是每次+1的) 和协议A相比没有SYN_MT_REPORT,那么它用什么来跟踪当前点属于哪一条线呢,用 的就是ABS_MT_TRACKING_ID,当前序列中 某点的ID值,如果与前一次序列中某点的ID值相等,那么他们就属于同一条线,应 用层就不用在去劳心劳神的算那个点是那条线上 的啦。如果按下并一直按同一个点,那么input子系统会做个处理来屏蔽上下两次 相同的点,减少IO的负担。 协议B明显优越于协议A,但注意协议B是需要硬件支持的,ID值并不是随便赋值 的,而是硬件上跟踪了点的轨迹,比如按下一个点 硬件会跟踪这个点的ID,只要不抬起上报的点都会和这个ID相关。 三、代码编写 Protocol A: ------------------------------------------------------------------------------------- 注册: set_bit(EV_SYN, input_dev->evbit); set_bit(EV_KEY, input_dev->evbit); set_bit(EV_ABS, input_dev->evbit); set_bit(INPUT_PROP_DIRECT, input_dev->propbit); input_set_abs_params(input_dev, ABS_MT_POSITION_X, 0, sensor_max_x, 0, 0); input_set_abs_params(input_dev, ABS_MT_POSITION_Y, 0, sensor_max_y, 0, 0); input_register_device(input_dev); 上报: for (finger = 0; finger < num_of_fingers; finger++) { ...//读取计算x、y坐标,id值,触摸的状态 if (finger_down) { input_report_abs(input_dev, ABS_MT_POSITION_X, x); input_report_abs(input_dev, ABS_MT_POSITION_Y, y); input_mt_sync(input_dev); } else { input_mt_sync(input_dev); } input_sync(input_dev); 如果注册了ABS_MT_PRESSURE,上报时就要上报ABS_MT_PRESSURE。 如果注册了BTN_TOUCH, 上报时就要上报BTN_TOUCH, 1:按下 0:抬起 上报log: 按下一个点抬起 [ 140.781791] EV_ABS ABS_MT_POSITION_X 00000148 [ 140.781801] EV_ABS ABS_MT_POSITION_Y 0000044f [ 140.781805] EV_SYN SYN_MT_REPORT 00000000 [ 140.781807] EV_SYN SYN_REPORT 00000000 [ 140.796553] EV_SYN SYN_MT_REPORT 00000000 [ 140.796563] EV_SYN SYN_REPORT 00000000 按下两个点抬起 [ 245.011718] EV_ABS ABS_MT_POSITION_X 00000102 [ 245.011757] EV_ABS ABS_MT_POSITION_Y 000003d0 [ 245.011771] EV_SYN SYN_MT_REPORT 00000000 [ 245.011785] EV_ABS ABS_MT_POSITION_X 00000220 [ 245.011798] EV_ABS ABS_MT_POSITION_Y 00000419 [ 245.011810] EV_SYN SYN_MT_REPORT 00000000 [ 245.011819] EV_SYN SYN_REPORT 00000000 [ 245.025296] EV_SYN SYN_MT_REPORT 00000000 [ 245.025311] EV_SYN SYN_MT_REPORT 00000000 [ 245.025313] EV_SYN SYN_REPORT 00000000 Protocol B: ---------------------------------------------------------------------------------- 注册: set_bit(EV_SYN, input_dev->evbit); set_bit(EV_KEY, input_dev->evbit); set_bit(EV_ABS, input_dev->evbit); set_bit(INPUT_PROP_DIRECT, input_dev->propbit); input_set_abs_params(input_dev, ABS_MT_POSITION_X, 0, sensor_max_x, 0, 0); input_set_abs_params(input_dev, ABS_MT_POSITION_Y, 0, sensor_max_y, 0, 0); input_mt_init_slots(input_dev, num_of_fingers); //和A相比多注册slot input_register_device(input_dev); 如果注册了ABS_MT_PRESSURE,上报时就要上报ABS_MT_PRESSURE。 上报: for (finger = 0; finger < num_of_fingers; finger++) { ...//读取计算x、y坐标和id,触摸的状态 input_mt_slot(input_dev, id); if (finger_down) { input_mt_report_slot_state(input_dev, MT_TOOL_FINGER, 1); input_report_abs(input_dev, ABS_MT_POSITION_X, x); input_report_abs(input_dev, ABS_MT_POSITION_Y, y); } else { //finger_up input_mt_report_slot_state(ip_dev, MT_TOOL_FINGER, 0); } } input_mt_report_pointer_emulation(input_dev, false); input_sync(input_dev); 上报log: 按下一个点抬起 [ 78.541863] EV_ABS ABS_MT_TRACKING_ID 00000007 按下分配ID [ 78.541928] EV_ABS ABS_MT_POSITION_X 0000021b [ 78.541944] EV_ABS ABS_MT_POSITION_Y 00000442 [ 78.541981] EV_SYN SYN_REPORT 00000000 [ 78.605574] EV_ABS ABS_MT_TRACKING_ID ffffffff 抬起释放ID ID=-1释放 [ 78.605595] EV_SYN SYN_REPORT 00000000 再次按下一个点抬起 [ 98.324526] EV_ABS ABS_MT_TRACKING_ID 00000008 按下分配ID 上一次的ID +1 [ 98.324590] EV_ABS ABS_MT_POSITION_X 000000c8 [ 98.324605] EV_ABS ABS_MT_POSITION_Y 0000037a [ 98.324641] EV_SYN SYN_REPORT 00000000 [ 98.388583] EV_ABS ABS_MT_TRACKING_ID ffffffff 抬起释放ID ID=-1释放 [ 98.388603] EV_SYN SYN_REPORT 00000000 两个点同时按下抬起 [ 208.775409] EV_ABS ABS_MT_SLOT 00000000 多点时标示 属于哪个slot 标示slot 0 [ 208.775462] EV_ABS ABS_MT_TRACKING_ID 0000000e 分配ID [ 208.775484] EV_ABS ABS_MT_POSITION_X 00000215 [ 208.775498] EV_ABS ABS_MT_POSITION_Y 0000037c [ 208.775533] EV_SYN SYN_REPORT 00000000 [ 208.859516] EV_ABS ABS_MT_SLOT 00000001 标示slot 1 [ 208.859534] EV_ABS ABS_MT_TRACKING_ID 0000000f 分配ID 上一 次ID +1 [ 208.859538] EV_ABS ABS_MT_POSITION_X 000000e6 [ 208.859541] EV_ABS ABS_MT_POSITION_Y 0000031f [ 208.859550] EV_SYN SYN_REPORT 00000000 [ 208.873597] EV_ABS ABS_MT_SLOT 00000000 [ 208.873637] EV_ABS ABS_MT_TRACKING_ID ffffffff 释放slot0 的ID [ 208.873659] EV_ABS ABS_MT_SLOT 00000001 [ 208.873667] EV_ABS ABS_MT_TRACKING_ID ffffffff 释放slot1 的ID [ 208.873688] EV_SYN SYN_REPORT 00000000 代码分析: input_mt_slot()根据ID注册一个slot static inline void input_mt_slot(struct input_dev *dev, int slot) { input_event(dev, EV_ABS, ABS_MT_SLOT, slot); } input_mt_report_slot_state()分配ABS_MT_TRACKING_ID void input_mt_report_slot_state(struct input_dev *dev, unsigned int tool_type, bool active) { struct input_mt_slot *mt; int id; if (!dev->mt || !active) { //如果active 为0就上报 ABS_MT_TRACKING_ID = -1表示手指抬起 input_event(dev, EV_ABS, ABS_MT_TRACKING_ID, -1); return; } mt = &dev->mt[dev->slot]; id = input_mt_get_value(mt, ABS_MT_TRACKING_ID); if (id < 0 || input_mt_get_value(mt, ABS_MT_TOOL_TYPE) != tool_type)//如果是从新触摸的点即上一次ABS_MT_TRACKING_ID=-1 id = input_mt_new_trkid(dev); //就从新分配ABS_MT_TRACKING_ID, 新ID上在上一次的基础上+1 //如果手指没抬起,即ABS_MT_TRACKING_ID大于0,ABS_MT_TRACKING_ID本次并没 有改变即还在一个轨迹上 input_event(dev, EV_ABS, ABS_MT_TRACKING_ID, id); input_event(dev, EV_ABS, ABS_MT_TOOL_TYPE, tool_type); } input_mt_report_pointer_emulation(input_dev, false); 文档中写函数是用来 检测驱动是否能报告比slot还多的触控点。本文转自张昺华-sky博客园博客,原文链接:http://www.cnblogs.com/sky-heaven/p/5413724.html,如需转载请自行联系原作者