一、linux电容触摸屏驱动简介
1、多点触摸屏(MT)简介
电容多点触摸屏驱动由以下几种类型的驱动组成:
-
IIC 设备驱动,电容触摸 IC 基本都是 IIC 接口。
-
通过中断引脚 (INT) 向内核上报触摸信息,坐标的上报在中断服务函数中完成。
-
触摸屏的坐标信息、屏幕按下和抬起信息都属于 input 子系统,向内核上报触摸屏坐标信息要使用 input 子系统。
内核中有一份文档详细的讲解了多点电容触摸屏协议,文档路径为:Documentation/input/multi-touch-protocol.txt
如果使用 2.x 版本的内核可能找不到 MT 协议,MT协议被分为两种类型,TypeA 和 TypeB,两种类型区别如下:
TypeA:适用于触摸点不能被区分或者追踪,此类型的设备上报原始数据。
TypeB:适用于有硬件追踪并能区分触摸点的触摸设备,此类型设备通过 slot 更新某一个触摸点的信息。
1)ABS_MT事件
触摸点的信息通过一系列的 ABS_MT 事件上报给 linux 内核,只有 ABS_MT 事件是用于多点触摸的, ABS_MT 事件定义在文件 linux/input.h 中:
#define ABS_MT_SLOT 0x2f /* MT slot being modified */
#define ABS_MT_TOUCH_MAJOR 0x30 /* Major axis of touching ellipse */
#define ABS_MT_TOUCH_MINOR 0x31 /* Minor axis (omit if circular) */
#define ABS_MT_WIDTH_MAJOR 0x32 /* Major axis of approaching ellipse */
#define ABS_MT_WIDTH_MINOR 0x33 /* Minor axis (omit if circular) */
#define ABS_MT_ORIENTATION 0x34 /* Ellipse orientation */
#define ABS_MT_POSITION_X 0x35 /* Center X touch position */
#define ABS_MT_POSITION_Y 0x36 /* Center Y touch position */
#define ABS_MT_TOOL_TYPE 0x37 /* Type of touching device */
#define ABS_MT_BLOB_ID 0x38 /* Group a set of packets as a blob */
#define ABS_MT_TRACKING_ID 0x39 /* Unique ID of initiated contact */
#define ABS_MT_PRESSURE 0x3a /* Pressure on contact area */
#define ABS_MT_DISTANCE 0x3b /* Contact hover distance */
#define ABS_MT_TOOL_X 0x3c /* Center X tool position */
#define ABS_MT_TOOL_Y 0x3d /* Center Y tool position */
常用到的有:
ABS_MT_SLOT:用于上报触摸点 ID;
ABS_MT_POSITION_X:用于上报触摸点的 X 坐标;
ABS_MT_POSITION_Y:用于上报触摸点的 Y 坐标;
ABS_MT_TRACKING_ID:对于 TypeB 类型,使用 ABS_MT_TRACKING_ID 来区分触摸点。
2)input_mt_sync函数(用于TypeA)
对于 Type A 类型的设备,通过 input_mt_sync 函数来隔离不同的触摸点数据信息,函数会触发SYN_MT_REPORT 事件,此事件会通知接收者获取当前触摸数据,并且准备接收下一个触摸点数据,函数原型如下:
void input_mt_sync(struct input_dev *dev)
dev:具体的 input_dev 设备。
3)input_mt_slot函数(用于TypeB)
对于 Type A 类型的设备,通过 input_mt_slot 函数来区分不同的触摸点数据信息,input_mt_slot 函数会触发 ABS_MT_SLOT 事件,此事件会告诉接收者当前正在更新的是哪个触摸点 (slot) 的数据。函数原型如下:
void input_mt_slot(struct input_dev *dev, int slot)
dev:具体的 input_dev 设备。
slot:指定当前上报的是哪个触摸点信息。
不管是哪个类型的设备,最终都要调用 input_sync 函数来标识多点触摸信息传输完成。
对于 TypeA 设备,内核驱动需要一次性将触摸屏上所有的触摸点信息全部上报,每个触摸点的信息在本次上报事件流中的顺序不重要,因为事件的过滤和手指(触摸点)跟踪是在内核空间处理的。
对于 TypeB 设备,使用 slot 协议区分具体的触摸点, slot 需要用到 ABS_MT_TRACKING_ID 消息,这个 ID需要硬件提供,或者通过原始数据计算出来。
TypeB 设备驱动需要给每个识别出来的触摸点分配一个 slot,后面使用这个 slot 来上报触摸点信息。可以通过 slot 的 ABS_MT_TRACKING_ID 来新增、替换或删除触摸点。一个非负的 ID 表示一个有效的触摸点,-1 这个 ID 表示未使用 slot。一个以前不存在的 ID 表示这是一个新加的触摸点,一个 ID 如果再也不存在了就表示删除了。
如果硬件设备追踪到了比它正在上报的还要多的触摸点,那么驱动程序应该发送 BTN_TOOL_TAP 消息,并且调用input_mt_report_pointer_emulation 函数,将此函数的第二个参数 use_count 设置为 false。
4)TypeA触摸点信息上报时序
对于 TypeA 设备,发送触摸点信息的时序如下:
ABS_MT_POSITION_X x[0] //上报第一个触摸点的X坐标数据,通过 input_report_abs 函数实现,下面同理
ABS_MT_POSITION_Y y[0] //上报第一个触摸点的Y坐标数据
SYN_MT_REPORT //上报SYN_MT_REPORT事件,通过调用input_mt_sync函数来实现
ABS_MT_POSITION_X x[1] //上报第二个触摸点的X坐标数据
ABS_MT_POSITION_Y y[1] //上报第二个触摸点的Y坐标数据
SYN_MT_REPORT //上报SYN_MT_REPORT事件
SYN_REPORT //上报SYN_REPORT事件,通过调用input_sync函数实现
TypeA 设备上报触摸点示例代码:
static irqreturn_t st1232_ts_irq_handler(int irq, void *dev_id)
{
ret = st1232_ts_read_data(ts); //获取所有触摸点信息
if (ret < 0)
goto end;
/* multi touch protocol */
for (i = 0; i < MAX_FINGERS; i++) {
//轮流上报触摸点信息
if (!finger[i].is_valid)
continue;
input_report_abs(input_dev, ABS_MT_TOUCH_MAJOR, finger[i].t);
input_report_abs(input_dev, ABS_MT_POSITION_X, finger[i].x);
input_report_abs(input_dev, ABS_MT_POSITION_Y, finger[i].y);
input_mt_sync(input_dev); //隔离触摸点
count++;
}
/* SYN_REPORT */
input_sync(input_dev);
end:
return IRQ_HANDLED;
}
5)TypeB触摸点信息上报时序
对于 TypeB 设备,发送触摸点信息的时序如下:
ABS_MT_SLOT 0