事实上,电容触摸屏的驱动程序如下 linux 驱动框架的组合:
1,IIC 由于电容触摸,设备驱动 IC 基本都是 IIC 接口,所以大框架是 IIC 设备驱动。
2,中断引脚(INT)向 linux 内核报告触摸信息,需要使用 linux 中断驱动框架。在中断服务函数中完成坐标报告。
3,触摸屏的坐标信息、屏幕按下和提升信息都属于 linux 的 input 因此,子系统向 linux 内核上报触摸屏坐标信息必须使用 input 子系统。只是,我们必须遵循 linux 报告坐标信息。
我们应该已经明白了IIC还有驱动,中断驱动input子系统,唯一不清楚的可能是input如何在子系统中报告多点电容触摸信息。这与多点触摸协议有关。
老版本的linux内核不支持多点电容触摸(Multi-Touch),简称MT,后面的版本是新加的。MT协议分为两种类型,TypeA和TypeB,两种类型的区别如下:
TypeA:适用于无法区分或跟踪触摸点的原始数据(实际应用中很少)。
TypeB:适用于具有硬件跟踪和区分触摸点的触摸设备。这类设备是通过slot更新触摸点信息,FT5426属于这种类型,一般多点电容触摸IC都有这种能力。
通过一系列的触摸点信息通过触摸点信息ABS_MT事件上报给linux内核,只有ABS_MT事件用于多点触摸,ADS_MT事件如下:

在上面众多AMS_MT在事件中,我们最常用的是AMS_MT_SLOT,AMS_MT_POSITION_X,AMS_MT_POSITION_Y和AMS_MT_TRACKING_ID。其中ABS_MT_POSITION_X 和 ABS_MT_POSITION_Y 用 来 上报 触 摸点 的 (X,Y) 坐 标 信息 , ABS_MT_SLOT 用 来 上 报 触 摸 点 ID ,对于 Type B 类 型 的 设 备 ,需 要 用 到ABS_MT_TRACKING_ID 区分触摸点的事件。
对于TypeA通过类型设备input_mt_sync该函数的原型如下:
这个函数只有一个参数,类型是input_dev,指定具体的input_dev设备,input_mt_sync函数会触发SYN_MT_REPORT该事件将通知接受者获取当前的触摸数据,并准备接收下一个触摸点信息。
对于TypeB类型的设备,报告触摸点信息时需要通过input_mt_slot哪个触摸点区分函数?,函数原型如下:
第二个参数slot指定当前报告的触摸点信息,input_mt_slot函数会触发ABS_MT_SLOT事件将告诉接收者目前更新了哪个触点(slot)的数据。
无论哪种设备,最终都需要调用input_sync识别多点触摸信息传输,告诉接收者处理之前积累的所有信息,并准备下一次接收。Type B 和 Type A 最大的区别是 Type B 触摸点可以区分, 因此可以减少发送到用户空间的数据。Type B 使用 slot 协议区分具体的触摸点,slot需要用到AMS_MT_TRACKING_ID消息,这个ID硬件提供或通过原始数据计算。
Type B 设备驱动需要分配每个被识别的触摸点 slot,以后用这个slot报告触摸点信息。可以通过slot的ABS_MT_TRACKING_ID添加、替换或删除非负值的触摸点ID表示有效的触摸点-1ID表示未使用slot。以前不存在的ID这意味着这是一个新的触摸点,一个ID若不再存在,则表示删除。
一些设备识别或跟踪的触摸点信息比他报告的要多(与相应的设备有关),这些设备驱动器应分配硬件报告的每个触摸点 Type B 的 slot。一旦检测到某个 slot 相关触点 ID 变化,驱动 这个应该改变 slot 的 ABS_MT_TRACKING_ID,使这个 slot 失效。如果硬件设备跟踪的触摸点比他正在报告的更多,则应发送驱动程序 BTN_TOOL_*TAP 消息,并且调用input_mt_report_pointer_emulation函数,该函数的第二个参数 use_count 设置为 false。
对于TypeA以两个触摸点为例:
第 1 行,ABS_MT_POSITION_X 事件报告了第一个触摸点的第一个触摸点 X 坐标数据,通过 input_report_abs 函数实现,下面也是如此。
第 7 行,上报 SYN_REPORT 事件,通过调用 input_sync 函数实现。这个是上报完每一轮触摸点信息就调用一次,比如上报3个触摸点信息,将3个触摸点信息上报完在调用这个就好。也就是发送一个SYN_REPORT事件。
对于Type B 类型的设备,发送触摸点信息的时序如下所示,这里以 2 个触摸点为例:
第1行,上报ABS_MT_SLOT事件,也就是触摸点对应的SLOT,每次上报一个触摸点坐标之前要先使用input_mt_slot函数上报当前触摸点SLOT,触摸点SLOT其实就是触摸点ID,由硬件提供。
第2行,根据TypeB的要求,每个SLOT必须关联一个AMS_MT_TRACKING_ID来完成对触摸点的增加,替换,或删除。具体用到的函数就是input_mt_solt_state,如果添加一个新的触摸点,那么此函数的第三个参数active要设置为true,,linux 内核会自动分配一个 ABS_MT_TRACKING_ID 值,不需要用户去指定具体的 ABS_MT_TRACKING_ID 值。
第 3 行,上报触摸点 0 的 X 轴坐标,使用函数 input_report_abs 来完成。
当一个触摸点移除以后,同样需要通过 SLOT 关联的 ABS_MT_TRACKING_ID 来处理,需要通过ABS_MT_TRACKING_ID事件发送一个-1给内核,方法很简单,同样使用input_mt_report_slot_state函数来完成,只需要将第三个参数active设置为false即可,不需要手动设置为-1,时序如下所示:
//在中断处理函数里面,我们需要将读取到的数据上报,但是需要按照上报时序来完成
//主要看硬件可以是几点触发器,触发就循环多少次
//下面是一个简略的中断处理函数,可以大致看出上报流程
static irqreturn_t ft5x06_handler(int irq, void *dev_id)
{
/* 读取FT5X06触摸点坐标从0X02寄存器开始,连续读取29个寄存器 */
ret = ft5x06_read_regs(multidata, FT5X06_TD_STATUS_REG, rdbuf, FT5X06_READLEN);
/* 上报每一个触摸点坐标 */
for (i = 0; i < 5; i++) {
u8 *buf = &rdbuf[i * tplen + offset];
/* 以第一个触摸点为例,寄存器TOUCH1_XH(地址0X03),各位描述如下:
* bit7:6 Event flag 0:按下 1:释放 2:接触 3:没有事件
* bit5:4 保留
* bit3:0 X轴触摸点的11~8位。
*/
type = buf[0] >> 6; /* 获取触摸类型 */
if (type == TOUCH_EVENT_RESERVED)
continue; //当硬件得到的信息时没有按下的话就终结本次循环,无需上报
/* 我们所使用的触摸屏和FT5X06是反过来的 */
x = ((buf[2] << 8) | buf[3]) & 0x0fff;
y = ((buf[0] << 8) | buf[1]) & 0x0fff;
/* 以第一个触摸点为例,寄存器TOUCH1_YH(地址0X05),各位描述如下:
* bit7:4 Touch ID 触摸ID,表示是哪个触摸点
* bit3:0 Y轴触摸点的11~8位。
*/
id = (buf[2] >> 4) & 0x0f;
down = type != TOUCH_EVENT_UP;
input_mt_slot(multidata->input, id);
input_mt_report_slot_state(multidata->input, MT_TOOL_FINGER, down);
if (!down)
continue;
input_report_abs(multidata->input, ABS_MT_POSITION_X, x);
input_report_abs(multidata->input, ABS_MT_POSITION_Y, y);
}
//这个函数就是硬件的追踪的点比上报的多的话就为false,当不是的话就位ture
input_mt_report_pointer_emulation(multidata->input, true);
//在5点信息全部上报完的时候,再执行下面的函数,表示本次信息全部上报完成
input_sync(multidata->input);
}
MT设备对应的input_dev,因为MT设备隶属于input_dev
设备要使用slot数量,也就是触摸点的数量
其他一些flags信息,可设置如下所示:
可以采样‘|’运算来同时设置多个flags标识
0,成功;负值,失败。
2,input_mt_slot函数
此函数用于TypeB类型,此函数用于产生ABS_MT_SLOT事件,告诉内核当前上报的是哪个触摸点的坐标数据。
MT设备对应的input_dev
当前发送的是哪个slot的坐标信息,也就是那个触摸点,那就是硬件发送过来的信息ID
3,input_mt_report_slot_state函数
此函数用于TypeB类型,用于产生ABS_MT_TRACKING_ID 和 ABS_MT_TOOL_TYPE事件给slot关联一个ABS_MT_TRACKING_ID ,ABS_MT_TOOL_TYPE 事 件 指 定 触 摸 类 型 ( 是 笔 还 是 手 指 等 )。函数原型如下:
MT设备对应的input_dev。
触摸类型,可以选择MT_TOOL_FINGER(手指)、MT_TOOL_PEN(笔)或MT_TOOL_PALM(手掌),对于多点电容触摸屏来说一般都是手指。
ture,连续触摸,input子系统内核汇自动分配一个ABS_MT_TRACKING_ID给slot。false,触摸点抬起。表示某个触摸点无效了,input子系统就会给内核分配一个-1给slot,表示触摸点移除。
4,input_report_abs函数
TypeA 和 Type B 类型都使用此函数上报触摸点坐标信息,通过ABS_MT_POSITION_X 和ABS_MT_POSITION_Y 事 件 实 现 X 和 Y 轴 坐 标 信 息 上 报 。函数定义如下:
mt设备对应的input_dev
要上报的是什么数据,要设置为ABS_MT_POSITION_X或 ABS_MT_POSITION_Y,也就是X轴或者Y轴坐标点数据。
具体的X轴和Y轴坐标点数值
5,input_mt_report_pointer_emulation函数
如果追踪到的触摸点数量多于当前上报的数量,驱动程序使用 BTN_TOOL_TAP 事件来通知用户空间当前追踪到的触摸点总数量,然后调用 input_mt_report_pointer_emulation 函数将 use_count 参数设置为 false。否则的话将 use_count 参数设置为 true,表示当前的触摸点数量(此函数会获取到具体的触摸点数量,不需要用户给出)。
MT设备对应的input_dev
true,有效的触摸点数量;flase,追踪到的触摸点数量多于当前上报的数量
多点电容需要用到那些框架呢?我们需要注意以下几点:
- 多点电容触摸芯片的接口,一般都为I2C接口,因此驱动主框架肯定是I2C
- linux里面一般都是通过中断来上报触摸点坐标信息的,因此需要中断框架
- 多点电容触摸属于input子系统,因此还要用到input子系统框架
- 在中断处理程序中按照linux的MT协议上报坐标信息