<电容触摸屏驱动框架>
电容触摸屏驱动其实是以下几种 linux 驱动框架的组合:
① IIC 设备驱动,因为电容触摸 IC 基本都是 IIC 接口的,因此大框架就是 IIC 设备驱动。
② 通过中断引脚(INT)向 linux 内核上报触摸信息,因此需要用到 linux 中断驱动框架。坐标的上报在中断服务函数中完成。
③ 触摸屏的坐标信息、屏幕按下和抬起信息都属于 linux 的 input 子系统,因此向 linux 内核上报触摸屏坐标信息就得使用 input 子系统。
1. 多点触摸(MT)协议详解
1). MT 协议被分为两种类型,TypeA 和 TypeB,这两种类型的区别如下:
TypeA:适用于触摸点不能被区分或者追踪,此类型的设备上报原始数据(此类型在实际使用中非常少!)。
TypeB:适用于有硬件追踪并能区分触摸点的触摸设备,此类型设备通过 slot 更新某一个触摸点的信息。
2). 触摸点的信息通过一系列的 ABS_MT 事件(有的资料也叫消息)上报给 linux 内核,
只有ABS_MT 事件是用于多点触摸的,ABS_MT 事件定义在文件 include/uapi/linux/input.h 中。
在众多的 ABS_MT 事件中,最常用的就是 ABS_MT_SLOT 、ABS_MT_POSITION_X 、ABS_MT_POSITION_Y 和 ABS_MT_TRACKING_ID 。
ABS_MT_SLOT:用来上报触摸点 ID
ABS_MT_POSITION_X/ABS_MT_POSITION_Y:用来上报触摸点的 (X,Y) 坐标信息
ABS_MT_TRACKING_ID:对于 Type B 类型设 备,用来区分触摸点
3). 对于 TypeA 类型的设备,通过 input_mt_sync()函数来隔离不同的触摸点数据信息:
void input_mt_sync(struct input_dev *dev)
input_mt_sync()会触发 SYN_MT_REPORT 事件,通知接收者获取当前触摸数据,并且准备接收下一个触摸点数据。
对于 TypeB 类型的设备,上报触摸点信息的时候需要通过 input_mt_slot()函数区分是哪一个触摸点:
void input_mt_slot(struct input_dev *dev, int slot)
input_mt_slot()函数会触发 ABS_MT_SLOT 事件,此事件会告诉接收者当前正在更新的是哪个触摸点(slot)的数据。
不管是哪个类型的设备,最终都要调用 input_sync()函数来标识多点触摸信息传输完成,
告诉接收者处理之前累计的所有消息,并且准备好下一次接收。
4). 对于 TypeA 设备,内核驱动需要一次性将触摸屏上所有的触摸点信息全部上报,
每个触摸点的信息在本次上报事件流中的顺序不重要,因为事件的过滤和手指(触摸点)跟踪是在内核空间处理的。
5). TypeB 设备驱动需要给每个识别出来的触摸点分配一个 slot,后面使用这个 slot 来上报触摸点信息。
可以通过 slot 的 ABS_MT_TRACKING_ID 来新增、替换或删除触摸点。一个非负数的 ID 表示一个有效的触摸点,-1 这个 ID 表示未使用 slot。
6). 有些设备识别或追踪的触摸点信息要比他上报的多,这些设备驱动应该给硬件上报的每个触摸点分配一个 Type B 的 slot。
一旦检测到某一个 slot 关联的触摸点 ID 发生了变化,驱动就应该改变这个 slot 的 ABS_MT_TRACKING_ID,使这个 slot 失效。
如果硬件设备追踪到了比他正在上报的还要多的触摸点,那么驱动程序应该发送 BTN_TOOL_*TAP 消息,并且调用
input_mt_report_pointer_emulation()函数,将此函数的第二个参数 use_count 设置为 false。
7). TypeA 触摸点信息上报时序(以 2 个触摸点为例)
ABS_MT_POSITION_X x[0] → 对应 input_report_abs函数
ABS_MT_POSITION_Y y[0] → 对应 input_report_abs函数
SYN_MT_REPORT → 对应 input_mt_sync函数
ABS_MT_POSITION_X x[1] → 对应 input_report_abs函数
ABS_MT_POSITION_Y y[1] → 对应 input_report_abs函数
SYN_MT_REPORT → 对应 input_mt_sync函数
SYN_REPORT → 对应 input_sync函数
8). TypeB 触摸点信息上报时序
ABS_MT_SLOT 0 → 对应 input_mt_slot函数
ABS_MT_TRACKING_ID 45 → 对应 input_mt_report_slot_state函数
ABS_MT_POSITION_X x[0] → 对应 input_report_abs函数
ABS_MT_POSITION_Y y[0] → 对应 input_report_abs函数
ABS_MT_SLOT 1 → 对应 input_mt_slot函数
ABS_MT_TRACKING_ID 46 → 对应 input_mt_report_slot_state函数
ABS_MT_POSITION_X x[1] → 对应 input_report_abs函数
ABS_MT_POSITION_Y y[1] → 对应 input_report_abs函数
SYN_REPORT → 对应 input_sync函数
9). MT 其他事件的使用
ABS_MT_TOOL_TYPE 事件用于上报触摸工具类型,目前的协议支持MT_TOOL_FINGER(手指)、MT_TOOL_PEN(笔)
和 MT_TOOL_PALM(手掌)这三种触摸设备类型,使用 input_mt_report_slot_state 函数来完成上报触摸工具类型工作。
2. 多点触摸所使用到的 API 函数
input_mt_init_slots 函数
用于初始化 MT 的输入 slots
input_mt_slot 函数
用于 Type B 类型,此函数用于产生 ABS_MT_SLOT 事件,上报触摸点坐标数据
input_mt_report_slot_state 函数
用于 Type B 类型,用于产生 ABS_MT_TRACKING_ID 和 ABS_MT_TOOL_TYPE事件
input_report_abs 函数
TypeA 和 Type B 类型都使用此函数上报触摸点坐标信息
input_mt_report_pointer_emulation 函数
追踪到的触摸点数量多于当前上报的数量,
驱动程序使用 BTN_TOOL_TAP 事件来通知用户空间当前追踪到的触摸点总数量,
然后调用 input_mt_report_pointer_emulation 函数将 use_count 参数设置为 false。
3. devm_request_threaded_irq 函数:
①用于申请中断,作用和 request_irq 函数类似。
②此函数的作用是中断线程化。
中断线程化以后中断将作为内核线程运行,而且也可以被赋予不同的优先级,任务的优先级可能比中断线程的优先级高,
这样做的目的就是保证高优先级的任务能被优先处理。虽然中断下半部可以被延迟处理,但是依旧先于线程执行,
中断线程化可以让这些比较耗时的下半部与进程进行公平竞争。
要注意,并不是所有的中断都可以被线程化,重要的中断就不能这么操作,需要自己根据实际情况去衡量。
4. 在 linux 内核中有很多的申请资源类的 API 函数都有对应的“devm_”前缀版本,
使用“devm_”前缀的函数申请到的资源可以由系统自动释放,不需要我们手动处理。
带有“devm_”前缀的都是一些和设备资源管理有关的函数。