i.MX6ULL终结者Linux 电容触摸屏实验Linux下电容触摸屏驱动框架

1 多点触摸协议详解

在前面的裸板实验中,已经详细讲解过了电容触摸驱动的基本原理,根据前面的实验可以总结出电容触摸屏驱动其实就是一下几种 linux 驱动框架的组合:
① IIC 设备驱动,因为电容触摸 IC 基本都是 IIC 接口的,因此大框架就是 IIC 设备驱动。
② 通过中断引脚(INT)向 linux 内核上报触摸信息,因此需要用到 linux 中断驱动框架。坐标的上报在中断服务函数中完成。
③ 触摸屏的坐标信息、屏幕按下和抬起信息都属于 linux 的 input 子系统,因此向 linux 内核上报触摸屏坐标信息就得使用 input 子系统。只是,我们得按照 linux 内核规定的规则来上报坐标信息。

在上面的驱动框架组合中我们发现I2C驱动、中断驱动、input子系统都已经学习了解过了,还没有学习过input子系统下的多点电容触摸协议,这个就是本章学习的重点,linux 内核中有一份文档详细的讲解了多点电容触摸屏协议,文档路径为:Documentation/input/multitouch-protocol.txt。
MT 协议被分为两种类型,TypeA 和 TypeB,这两种类型的区别如下:
TypeA:适用于触摸点不能被区分或者追踪,此类型的设备上报原始数据(此类型在实际使用中非常少!)。
Type B:适用于有硬件追踪并能区分触摸点的触摸设备,此类型设备通过 slot 更新某一个触摸点的信息,FT5426 就属于此类型,一般的多点电容触摸屏 IC 都有此能力。

触摸点的信息通过一系列的 ABS_MT 事件(有的资料也叫消息)上报给 linux 内核,只有ABS_MT 事件是用于多点触摸的,ABS_MT 事件定义在文件 linux/input.h 中,相关事件如下所示:

852 #define ABS_MT_SLOT 0x2f /* MT slot being modified */ 
853 #define ABS_MT_TOUCH_MAJOR 0x30 /* Major axis of touching ellipse */ 
854 #define ABS_MT_TOUCH_MINOR 0x31 /* Minor axis (omit if circular) */ 
855 #define ABS_MT_WIDTH_MAJOR 0x32 /* Major axis of approaching ellipse */ 
856 #define ABS_MT_WIDTH_MINOR 0x33 /* Minor axis (omit if circular) */ 
857 #define ABS_MT_ORIENTATION 0x34 /* Ellipse orientation */ 
858 #define ABS_MT_POSITION_X 0x35 /* Center X touch position */ 
859 #define ABS_MT_POSITION_Y 0x36 /* Center Y touch position */ 
860 #define ABS_MT_TOOL_TYPE 0x37 /* Type of touching device */
861 #define ABS_MT_BLOB_ID 0x38 /* Group a set of packets as a blob */ 
862 #define ABS_MT_TRACKING_ID 0x39 /* Unique ID of initiated contact */ 
863 #define ABS_MT_PRESSURE 0x3a /* Pressure on contact area */ 
864 #define ABS_MT_DISTANCE 0x3b /* Contact hover distance */ 
865 #define ABS_MT_TOOL_X 0x3c /* Center X tool position */ 
866 #define ABS_MT_TOOL_Y 0x3d /* Center Y tool position */

在上面这些众多的 ABS_MT 事件中,我们最常用的就是 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)的数据。

不管是哪个类型的设备,最终都要调用 input_sync()函数来标识多点触摸信息传输完成,告诉接收者处理之前累计的所有消息,并且准备好下一次接收。Type B 和 Type A 相比最大的区别就是 Type B 可以区分出触摸点, 因此可以减少发送到用户空间的数据。Type B 使用 slot 协议区分具体的触摸点,slot 需要用到 ABS_MT_TRACKING_ID 消息,这个 ID 需要硬件提供,或者通过原始数据计算出来。对于 TypeA 设备,内核驱动需要一次性将触摸屏上所有的触摸点信息全部上报,每个触摸点的信息在本次上报事件流中的顺序不重要,因为事件的过滤和手指(触摸点)跟踪是在内核空间处理的。
Type B 设备驱动需要给每个识别出来的触摸点分配一个 slot,后面使用这个 slot 来上报触摸点信息。可以通过 slot 的 ABS_MT_TRACKING_ID 来新增、替换或删除触摸点。一个非负数的 ID 表示一个有效的触摸点,-1 这个 ID 表示未使用 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。

2 Type A 触摸点信息上报时序

对于 Type A 类型的设备,发送触摸点信息的时序如下所示,这里以 2 个触摸点为例:

1 ABS_MT_POSITION_X x[0] 
2 ABS_MT_POSITION_Y y[0] 
3 SYN_MT_REPORT 
4 ABS_MT_POSITION_X x[1] 
5 ABS_MT_POSITION_Y y[1] 
6 SYN_MT_REPORT 
7 SYN_REPORT 

第 1 行,通过 ABS_MT_POSITION_X 事件上报第一个触摸点的 X 坐标数据,通过 input_report_abs 函数实现,下面同理。
第 2 行,通过 ABS_MT_POSITION_Y 事件上报第一个触摸点的 Y 坐标数据。
第 3 行,上报 SYN_MT_REPORT 事件,通过调用 input_mt_sync 函数来实现。
第 4 行,通过 ABS_MT_POSITION_X 事件上报第二个触摸点的 X 坐标数据。
第 5 行,通过 ABS_MT_POSITION_Y 事件上报第二个触摸点的 Y 坐标数据。
第 6 行,上报 SYN_MT_REPORT 事件,通过调用 input_mt_sync 函数来实现。
第 7 行,上报 SYN_REPORT 事件,通过调用 input_sync 函数实现。
我们在编写 TypeA 类型的多点触摸驱动的时候就需要按照上述代码中的时序上报坐标信息。Linux 内核里面也有 Type A 类型的多点触摸驱动,找到 st2332.c 这个驱动文件,路径为 drivers/input/touchscreen/st1232.c,找到 st1232_ts_irq_handler 函数,此函数里面就是上报触摸点坐标信息的。

103 static irqreturn_t st1232_ts_irq_handler(int irq, void *dev_id) 
104 {
    
...... 
111        ret = st1232_ts_read_data(ts); 
112        if (ret < 0) 
113            goto end; 
114 
115        /* multi touch protocol */ 
116     for (i = 0; i < MAX_FINGERS; i++) {
    
117            if (!finger[i].is_valid) 
118                continue; 
119 
120            input_report_abs(input_dev, ABS_MT_TOUCH_MAJOR, finger[i].t); 
121            input_report_abs(input_dev, ABS_MT_POSITION_X, finger[i].x); 
122            input_report_abs(
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值