CTP多点触摸协议

 linux kernel 2.6.30 开始对多点触摸支持,最近高通要求所有 CTP 器件要用 协议上报数据,协议 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 还多的触控点。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值