Linux Input子系统第二篇之A/B(Slot)协议

本文深入探讨Linux Input子系统中的A/B(Slot)协议,分析两种协议在数据上报机制上的区别,尤其聚焦于B协议在多点触摸场景下如何通过slot和tracking ID实现轨迹跟踪,对比A协议在处理多指滑动时的复杂性。

https://www.cnblogs.com/ljf181275034/articles/3343222.html添加链接描述

Linux Input子系统第二篇之A/B(Slot)协议

这段时间一直在忙工作的事情,Input子系统的第二篇博客姗姗来迟了。
将A/B协议这部分单独拿出来说一方面是因为这部分内容是比较容易忽视的,周围大多数用到input子系统的开发人员也不甚理解;另一方面是由于这部分知识一旦扩展到TP(触摸屏Touch Panel)的多点触摸就要与Middleware/Framework一起结合起来看才能完全掌握,复杂性所在。这里的Middleware/Framework是针对android来说的,本人从事android这几个层次的工作,所以就从android的角度来讲讲这部分内容,其他系统虽然代码不同,但原理上是完全一样的。
B协议又称为slot协议,那么input子系统里面使用的slot是什么,A/B协议究竟是如何划分的?
slot直译为位置、槽,有两层含义,一层是位置,另一层是容器。在Input子系统中,它扮演的就是这两个角色。它产生于这样一个背景:
如果从Device获取的当前数据与上一个数据相同,我们有必要再上报当前数据吗?如果我们不管两次数据是否一致都上报,那就是A协议;如果我们选择不上报,那么既然需要比较,总需要把上一次数据存起来吧,slot就是做这个事情的,显然这就是Slot(B)协议。
其实到这里,对TP不感兴趣的童鞋可以不继续向下看了,了解了两个协议的区别看或者写一般模块的代码不会有问题了。需要注意的是,想要测试Device驱动的input部分是否正常的时候,假如使用的是B协议,input_report数据的时候要记得每次都要report不同的值,否则在HAL层是看不到数据不停上报的,因为前后两个数据相同的时候,B协议是不会上报到系统的。另外,在上层测试数据上报频率的时候,采用 数据总量/时间差 的方法,如果驱动采用的是B协议,测试结果也是不准确的。
下面要说的与TP的多点触摸(MT Multi-touch)的功能关系密切,没有兴趣的可以略过。由于这部分代码不从事TP或者android的人是不会接触到的,所以代码就不贴出来了,有兴趣的童鞋可以单独交流O(∩_∩)O~
我们都知道,在支持MT的手机上多指滑动的时候,多条手指滑动过的轨迹彼此是不相交的,这也是我们所期望的。但这个功能究竟是如何实现的呢?看了上面的分析应该就知道,A/B两种协议方式都可以实现该功能。
A协议不会使用slot,多指处理中,它的报点序列如下(每一个序列都以input_report_***函数实现):

点击(此处)折叠或打开

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为一次事件的结尾。也就是说多指触摸的时候,android的中间件部分每收到一次SYN_MT_REPORT就形成一个点信息,收到一个点之后并不会立即处理,而是一个事件完成之后才会处理,SYN_REPORT就是这个事件的标志。A协议比较简单,我们也可以发现在上面的序列中根本就没有轨迹跟踪的信息,有的只是点坐标等信息,那么系统如果去判断当前的多个点各属于哪一条线呢?
   我们假设前一次事件共有5个点,本次触摸也有5个点,系统会分别计算前一次5个点与本次5个点的距离,distance[prev_i, curr_j] (i=0,1,...,4; j=0,1,...4),这样会产生总共5*5=25个数字。然后对这25个数字进行排序,android用的是堆排序。(我们在系统上如果用多指,一般最多也是双值,也就是4个数据,这里采用了堆排序,不知是出于什么情况考虑,感觉换个方法可能更实用些。)下面的任务就是判断哪些当前点与前一次的点最近,那么赋予它们相同的id,应用收到这个信息后,就可以知道当前点属于哪条线了。
   手抬起来的时候又用什么样的序列来通知系统呢,

点击(此处)折叠或打开

SYN_MT_REPORT
SYN_REPORT

   只有SYNC,没有其它任何信息,系统就会认为此次事件为UP。
   B协议使用了slot,还有一个新面孔TRACKING_ID.

点击(此处)折叠或打开

ABS_MT_SLOT 0
ABS_MT_TRACKING_ID **
ABS_MT_POSITION_X x[0]
ABS_MT_POSITION_Y y[0]
ABS_MT_SLOT 1
ABS_MT_TRACKING_ID **
ABS_MT_POSITION_X x[1]
ABS_MT_POSITION_Y y[1]
SYN_REPORT

  没有SYN_MT_REPORT,那么它用什么来跟踪当前点属于哪一条线呢,用的就是ABS_MT_TRACKING_ID,当前序列中某点的ID值,如果与前一次序列中某点的ID值相等,那么他们就属于同一条线。既然如此,那么android系统中还需要做排序等运算吗?当然不需要。那么手指全部抬起的时候序列又是怎样的呢?      

点击(此处)折叠或打开

ABS_MT_SLOT 0
ABS_MT_TRACKING_ID -1
SYN_REPORT
ABS_MT_SLOT 1
ABS_MT_TRACKING_ID -1
SYN_REPORT

  这里上报的ABS_MT_TRACKING_ID为-1,也只有这里该值才可以小于零,收到该值,系统就会清除对应的ID。看似简单的两个协议内容到这里就分析完毕了。
  看了上面的分析,明显可以看出B协议要由于A协议,但事实上并不如此简单。B协议需要硬件上的支持,ID值并不是随便赋值的,而是硬件上跟踪了点的轨迹;如果硬件上满足不了这个条件,那么采用B协议只能闹成笑话。另外,B协议的复杂性如果掌握不好往往会带来一些莫名其妙的问题,比如如果因为某些因素(同步等),在UP的时候少清除了一个slot的信息,那么下次单击的时候你也会惊奇地发现竟然有两个点(采用了B协议,slot已经保存了点信息,除非明确清除)。
<think>好的,我现在需要回答用户的问题:“如何在Linux内核中实现多点触控(Multitouch)协议的支持?”用户已经提供了一些站内引用,我需要结合这些引用和之前的对话内容来组织回答。 首先,回顾用户提供的引用内容。引用[1]提到Linux内核文档中的多点触摸协议(MT协议),分为TypeA和TypeB,文档路径是Documentation/input/multitouch-protocol.txt。引用[2]则讨论了在i.MX6UL平台上使用嵌入式QT实现电容屏多点触控,前提是驱动已经支持,并且上报触控数据。用户现在想知道具体的实现方法和步骤。 接下来,我需要回忆之前作为面试官列出的问题,其中第一个相关问题就是如何在Linux内核中支持多点触控协议。之前的回答可能已经部分涉及,但用户现在需要更详细的步骤。 我需要考虑用户可能的背景:可能是驱动开发者,需要在内核中实现MT协议支持。因此,回答需要技术细节,包括协议类型、驱动开发步骤、代码示例、设备树配置、测试方法等。 根据引用[1],MT协议分为TypeA和TypeB,需要解释这两种类型的区别和应用场景。然后,步骤可能包括选择协议类型、初始化输入设备、上报触摸点数据、处理同步事件等。同时,要引用内核文档中的内容。 引用[2]提到驱动需要支持多点触控并向应用层上报数据,这可能涉及到输入子系统的使用,比如input_dev结构体、上报ABS_MT事件等。需要详细说明这些API的使用方法,如input_mt_init_slots、input_report_abs_slot等。 此外,设备树的配置也是关键,比如在设备树中指定触摸控制器、中断、I2C通信等。需要给出一个设备树节点的例子,说明各个参数的作用。 测试部分,用户可能需要使用工具如evtest或编写应用层代码来验证驱动是否正确工作。需要提到这些工具的使用方法,以及如何观察上报的数据。 最后,确保回答结构清晰,分步骤说明,并包含代码示例和实际操作的命令,这样用户能逐步实现。同时,要标注引用来源,如引用[1]和之前的回答中的引用[^1]和[^4]等。 需要检查是否有遗漏的关键点,例如同步事件的处理(如SYN_MT_REPORT和SYN_REPORT),以及TypeB中的跟踪ID管理。此外,功耗优化或错误处理是否需要提及?根据用户的问题,可能不需要深入,但简要提到可能更好。 现在组织内容: 1. 协议概述:TypeA和TypeB的区别。 2. 实现步骤: a. 选择协议类型 b. 初始化输入设备和MT slots c. 上报触摸点数据 d. 处理同步事件 3. 代码示例:展示关键函数和结构体使用。 4. 设备树配置:节点示例。 5. 测试与调试:工具使用。 6. 注意事项:如协议选择、固件要求、性能优化。 确保每个部分都结合引用和内核文档,保持技术准确性。例如,在TypeB中使用input_mt_slotinput_mt_report_slot_state,这些函数的具体用法需要正确描述。 可能还需要提到多点触控协议在输入子系统中的位置,如何通过input子系统将事件传递到用户空间,以及Android或QT等上层应用如何处理这些事件,如引用[2]中提到的QT应用依赖于驱动支持。 最后,总结关键点,确保用户能够按照步骤实现,并知道如何验证和调试驱动。</think>### Linux内核中实现多点触控(Multitouch)协议的方法与步骤 在Linux内核中实现多点触控(Multitouch, MT)协议支持,需遵循输入子系统的多点触控协议规范,并结合硬件特性进行驱动开发。以下是具体实现方法: --- #### **1. 协议类型选择** Linux内核的多点触控协议分为**TypeA**和**TypeB**两类[^1]: - **TypeA**:以顺序方式上报所有触控点,每次上报后需发送`SYN_MT_REPORT`信号标记单点结束,最后通过`SYN_REPORT`提交整个事件包。 - **适用场景**:触控点数量固定或无需动态跟踪触控点ID的硬件。 - **TypeB**:通过`ABS_MT_TRACKING_ID`为每个触控点分配唯一ID,支持动态增删触控点,直接使用`input_mt_report_slot_state()`上报数据。 - **适用场景**:支持动态触控点跟踪的电容屏(如手机、平板)。 --- #### **2. 驱动实现核心步骤** ##### **(1) 初始化输入设备与MT协议** ```c // 创建输入设备 struct input_dev *input = input_allocate_device(); input->name = "Capacitive Touchscreen"; input->id.bustype = BUS_I2C; // 根据硬件接口选择I2C/SPI // 设置输入事件类型 __set_bit(EV_ABS, input->evbit); // 配置多点触控参数(TypeB为例) input_set_abs_params(input, ABS_MT_POSITION_X, 0, SCREEN_MAX_X, 0, 0); input_set_abs_params(input, ABS_MT_POSITION_Y, 0, SCREEN_MAX_Y, 0, 0); input_set_abs_params(input, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0); // 触点面积 // 初始化MT Slots(TypeB必须) input_mt_init_slots(input, MAX_TOUCH_POINTS, INPUT_MT_DIRECT); ``` ##### **(2) 上报触控点数据** - **TypeA示例**: ```c for (int i = 0; i < num_points; i++) { input_report_abs(input, ABS_MT_POSITION_X, x[i]); input_report_abs(input, ABS_MT_POSITION_Y, y[i]); input_mt_sync(input); // 发送SYN_MT_REPORT } input_sync(input); // 发送SYN_REPORT ``` - **TypeB示例**: ```c for (int slot = 0; slot < num_points; slot++) { input_mt_slot(input, slot); input_mt_report_slot_state(input, MT_TOOL_FINGER, true); // 触点状态 input_report_abs(input, ABS_MT_POSITION_X, x[slot]); input_report_abs(input, ABS_MT_POSITION_Y, y[slot]); } input_sync(input); // 提交事件包 ``` ##### **(3) 中断处理与数据解析** - 在中断处理函数中读取硬件寄存器或I2C/SPI数据,解析触控点坐标、压力值等信息。 - 若使用TypeB协议,需维护`ABS_MT_TRACKING_ID`以跟踪触点生命周期(如新增、移动、释放)。 --- #### **3. 设备树(Device Tree)配置** 在设备树中定义触摸控制器节点,指定协议类型、中断引脚、I2C地址等参数: ```dts &i2c1 { touchscreen@5d { compatible = "vendor,capacitive-touch"; reg = <0x5d>; interrupt-parent = <&gpio1>; interrupts = <9 IRQ_TYPE_EDGE_FALLING>; touchscreen-size-x = <800>; touchscreen-size-y = <480>; linux,input-mt-protocol = <2>; // 2表示TypeB协议[^1] }; }; ``` --- #### **4. 测试与调试** - **工具验证**: - 使用`evtest`工具查看原始输入事件: ```bash evtest /dev/input/eventX ``` - 检查是否上报`ABS_MT_POSITION_X/Y`及`SYN_REPORT`事件。 - **内核调试**: - 通过`dmesg`查看驱动加载日志,确认设备树解析正确。 - 使用`sysfs`接口(如`/sys/class/input/eventX/device/matrix`)校准坐标。 --- #### **5. 关键注意事项** 1. **协议选择**:电容屏优先使用TypeB协议以支持动态触点跟踪;电阻屏可选TypeA。 2. **固件要求**:部分触摸芯片需先加载固件才能启用多点触控功能[^2]。 3. **性能优化**:减少中断延迟,使用高精度定时器(`hrtimer`)优化事件上报频率[^4]。 --- ### 示例代码片段(TypeB协议) ```c static void touch_irq_handler(int irq, void *dev_id) { struct touch_data *data = read_touch_registers(); for (int i = 0; i < data->num_points; i++) { input_mt_slot(input_dev, i); input_mt_report_slot_state(input_dev, MT_TOOL_FINGER, data->points[i].active); if (data->points[i].active) { input_report_abs(input_dev, ABS_MT_POSITION_X, data->points[i].x); input_report_abs(input_dev, ABS_MT_POSITION_Y, data->points[i].y); } } input_sync(input_dev); } ``` ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值