一、 Linux 下电容触摸屏驱动框架简介
1、多点触摸(MT)协议详解
电容触摸屏驱动其实就是以下几种 linux 驱动框架的组合:
①、IIC 设备驱动,因为电容触摸 IC 基本都是 IIC 接口的,因此大框架就是 IIC 设备驱动。
②、通过中断引脚(INT)向 linux 内核上报触摸信息,因此需要用到 linux 中断驱动框架。坐标的上报在中断服务函数中完成。
③、触摸屏的坐标信息、屏幕按下和抬起信息都属于 linux 的 input 子系统,因此向 linux 内核上报触摸屏坐标信息就得使用 input 子系统。只是,我们得按照 linux 内核规定的规则来上报坐标信息。
MT(Multi-touch,简称 MT) 协议被分为两种类型,TypeA 和 TypeB,这两种类型的区别如下:
TypeA:适用于触摸点不能被区分或者追踪,此类型的设备上报原始数据(此类型在实际使用中非常少!)。
Type B:适用于有硬件追踪并能区分触摸点的触摸设备,此类型设备通过 slot 更新某一个触摸点的信息,FT5426 就属于此类型,一般的多点电容触摸屏 IC 都有此能力。
ABS_MT 事件定义在文件 include/uapi/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 、ABS_MT_POSITION_X 、 ABS_MT_POSITION_Y 和 ABS_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()函数来隔离不同的触摸点数据信息,此函数原型如下所示:
void input_mt_sync(struct input_dev *dev)
此函数只要一个参数,类型为 input_dev,用于指定具体的 input_dev 设备。input_mt_sync()函数会触发 SYN_MT_REPORT 事件,此事件会通知接收者获取当前触摸数据,并且准备接收下一个触摸点数据。
对于 Type B 类型的设备,上报触摸点信息的时候需要通过 input_mt_slot()函数区分是哪一个触摸点,input_mt_slot()函数原型如下所示:
void input_mt_slot(struct input_dev *dev, int slot)
此函数有两个参数,第一个参数是 input_dev 设备,第二个参数 slot 用于指定当前上报的是哪个触摸点信息。input_mt_slot()函数会触发 ABS_MT_SLOT 事件,此事件会告诉接收者当前正在更新的是哪个触摸点(slot)的数据。
TypeA 设备,内核驱动需要一次性将触摸屏上所有的触摸点信息全部上报,每个触摸点的信息在本次上报事件流中的顺序不重要,因为事件的过滤和手指(触摸点)跟踪是在内核空间处理的。
Type B 设备驱动需要给每个识别出来的触摸点分配一个 slot,后面使用这个 slot 来上报触摸点信息。可以通过 slot 的 ABS_MT_TRACKING_ID 来新增、替换或删除触摸点。一个非负数的 ID 表示一个有效的触摸点,-1 这个 ID 表示未使用 slot。一个以前不存在的 ID 表示这是一个新加的触摸点,一个 ID 如果再也不存在了就表示删除了。
Type B 和 Type A 相比最大的区别就是 Type B 可以区分出触摸点, 因此可以减少发送到用户空间的数据。
2、Type A 触摸点信息上报时序
对于 Type A 类型的设备,发送触摸点信息的时序如下所示,这里以 2 个触摸点为例:
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]
ABS_MT_POSITION_Y y[1]
SYN_MT_REPORT
SYN_REPORT
具体实现代码如下:
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); //发送一个SYN_REPORT 事件
end:
return IRQ_HANDLED;
}
3、Type B 触摸点信息上报时序
对于 Type B 类型的设备,发送触摸点信息的时序如下所示,这里以 2 个触摸点为例:
ABS_MT_SLOT 0
ABS_MT_TRACKING_ID 45
ABS_MT_POSITION_X x[0]
ABS_MT_POSITION_Y y[0]
ABS_MT_SLOT 1
ABS_MT_TRACKING_ID 46
ABS_MT_POSITION_X x[1]
ABS_MT_POSITION_Y y[1]
SYN_REPORT
第 1 行,上报 ABS_MT_SLOT 事件,也就是触摸点对应的 SLOT。每次上报一个触摸点坐标之前要先使用input_mt_slot函数上报当前触摸点SLOT,触摸点的SLOT其实就是触摸点ID,需要由触摸 IC 提供。
第 2 行,根据 Type B 的要求,每个 SLOT 必须关联一个 ABS_MT_TRACKING_ID,通过修改 SLOT 关联的 ABS_MT_TRACKING_ID 来完成对触摸点的添加、替换或删除。具体用到的函数就是 input_mt_report_slot_state,如果是添加一个新的触摸点,那么此函数的第三个参数active 要设置为 true,linux 内核会自动分配一个 ABS_MT_TRACKING_ID 值,不需要用户去指定具体的 ABS_MT_TRACKING_ID 值。
第 3 行,上报触摸点 0 的 X 轴坐标,使用函数 input_report_abs 来完成。
第 4 行,上报触摸点 0 的 Y 轴坐标,使用函数 input_report_abs 来完成。
第 5 - 8行,和第 1~4 行类似,只是换成了上报触摸点 0 的(X,Y)坐标信息
第 9 行,当所有的触摸点坐标都上传完毕以后就得发送 SYN_REPORT 事件,使用 input_sync函数来完成。
当一个触摸点移除以后,同样需要通过 SLOT 关联的 ABS_MT_TRACKING_ID 来处理,时序如下所示:
ABS_MT_TRACKING_ID -1
SYN_REPORT
第 1 行,当一个触摸点(SLOT)移除以后,需要通过 ABS_MT_TRACKING_ID 事件发送一个-1 给内核。方法很简单,同样使用 input_mt_report_slot_state 函数来完成,只需要将此函数的第三个参数 active 设置为 false 即可,不需要用户手动去设置-1。
第 2 行,当所有的触摸点坐标都上传完毕以后就得发送 SYN_REPORT 事件。
用于上报 ili210x触摸坐标信息的,函数内容如下所示:
static void ili210x_report_events(struct input_dev *input,const struct touchdata *touchdata)
{
int i;
bool touch;
unsigned int x, y;
const struct finger *finger;
for (i = 0; i < MAX_TOUCHES; i++) //实现所有触摸点上报
{
input_mt_slot(input, i); //上 报 ABS_MT_SLOT 事件
finger = &touchdata->finger[i];
touch = touchdata->status & (1 << i);
input_mt_report_slot_state(input, MT_TOOL_FINGER, touch);//上报ABS_MT_TRACKING_ID 事件,也就是给 SLOT 关联一个 ABS_MT_TRACKING_ID
if (touch)
{
x = finger->x_low | (finger->x_high << 8);
y = finger->y_low | (finger->y_high << 8);
input_report_abs(input, ABS_MT_POSITION_X, x);
input_report_abs(input, ABS_MT_POSITION_Y, y);
}
}
input_mt_report_pointer_emulation(input, false);
input_sync(input); //上报 SYN_REPORT 事件
}
4、多点触摸所使用到的 API 函数
4.1、input_mt_init_slots 函数
input_mt_init_slots 函数用于初始化 MT 的输入 slots,编写 MT 驱动的时候必须先调用此函数初始化 slots,此函数定义在文件 drivers/input/input-mt.c 中,函数原型如下所示:
int input_mt_init_slots( struct input_dev *dev, unsigned int num_slots,unsigned int flags)
函数参数和返回值含义如下:
dev: MT 设备对应的 input_dev,因为 MT 设备隶属于 input_dev。
num_slots:设备要使用的 SLOT 数量,也就是触摸点的数量。
flags:其他一些 flags 信息,可设置的 flags 如下所示:
#define INPUT_MT_POINTER 0x0001 /* pointer device, e.g. trackpad */
#define INPUT_MT_DIRECT 0x0002 /* direct device, e.g. touchscreen */
#

文章详细介绍了Linux下电容触摸屏驱动的工作原理,包括IIC设备驱动、中断驱动框架和input子系统。重点讲解了多点触摸(MT)协议的TypeA和TypeB类型,以及它们在上报触摸点信息时的时序。同时,提到了用于上报触摸信息的关键API函数如input_mt_init_slots、input_mt_slot、input_mt_report_slot_state、input_report_abs等。此外,还展示了驱动编写的基本框架和中断处理程序中的坐标上报流程。
最低0.47元/天 解锁文章
3226

被折叠的 条评论
为什么被折叠?



