【RK3588 Android驱动实战】USB TP XY轴反转?不用改TP固件!系统端改上报数据快速搞定 电子说
做嵌入式 Android 开发的同学,大概率遇到过 USB 触控面板(TP)的适配坑 —— 比如XY 轴反转:明明点屏幕左边,系统却识别成右边;向上滑动,页面反而向下走。最近在 RK3588 平台调试 USB TP 时,就碰到了这个问题,TP 供应商给的方案是改 TP 端固件,但需要重新烧录 TP 程序、协调供应商联调,操作麻烦还耗时间。
后来我们换了个思路:直接在 Android 系统端修改 TP 上报的坐标数据,不用动 TP 硬件 / 固件,半小时就搞定了。今天就把这个实战方案拆解清楚,附上核心 patch 解析,希望能帮到有同样需求的同学。
先明确下我们遇到的具体问题:
在 RK3588 Android 12/13 系统上,接入某款 USB TP 后,触控功能正常,但坐标映射完全反了—— 比如 TP 物理坐标的 X 轴(横向)对应系统的 Y 轴(纵向),且单轴方向还存在反转(比如按 TP 右侧,系统识别为左侧)。
最初联系 TP 供应商,得到的解决方案是:
1.提供 TP 的固件烧录工具;
2.修改 TP 内部的坐标映射参数;
3.重新烧录固件到 TP 芯片。
但这个方案有明显痛点:
•需额外安装烧录工具,部分工具还依赖 Windows 系统;
•烧录过程有风险,操作不当可能导致 TP 变砖;
•若后续换批次 TP,可能需要重复适配,灵活性差。
既然 TP 是通过 USB HID 协议向系统上报坐标数据,那能不能在系统驱动层拦截并修改这些数据?答案是肯定的—— 这就是我们最终采用的方案。
文件路径:kernel-5.10/drivers/hid/hid-multitouch.c

这是 USB HID 多点触控驱动的核心文件,我们的坐标反转 + 交换逻辑就加在这里。TP 上报的原始 X/Y 坐标会经过这个文件处理后,再传递给 Android 输入子系统,所以在这里修改数据最直接有效。
先看原代码和修改后的对比:
// 原代码(直接上报原始坐标)input_event(input, EV_ABS, ABS_MT_POSITION_X, *slot->x);input_event(input, EV_ABS, ABS_MT_POSITION_Y, *slot->y);// 修改后(先转换坐标,再上报)int max_x = input_abs_get_max(input, ABS_MT_POSITION_X);int max_y = input_abs_get_max(input, ABS_MT_POSITION_Y);int new_x = max_y - *slot->y;int new_y = *slot->x;new_x = clamp_val(new_x, 0, max_y);new_y = clamp_val(new_y, 0, max_x);input_event(input, EV_ABS, ABS_MT_POSITION_X, new_x);input_event(input, EV_ABS, ABS_MT_POSITION_Y, new_y);
这部分是核心,必须逐行理解:
int max_x = input_abs_get_max(input, ABS_MT_POSITION_X);int max_y = input_abs_get_max(input, ABS_MT_POSITION_Y);
•input_abs_get_max:Linux 输入子系统提供的 API,用于获取指定输入设备(这里是 USB TP)的 “绝对坐标最大值”;
•比如 TP 的分辨率是 1920x1080,那么max_x=1919,max_y=1079(坐标从 0 开始计数);
•为什么要获取最大值?因为后续要通过“最大值 - 原始坐标” 实现单轴方向反转。
int new_x = max_y - *slot->y;int new_y = *slot->x;
这两行是解决“XY 轴反转” 的关键,我们用一个实际例子理解:
假设 TP 原始上报坐标是(x=200,y=500),且 TP 的max_x=1919,max_y=1079:
•原逻辑:系统收到 X=200,Y=500(对应错误的轴映射);
•新逻辑:
new_x = 1079 - 500 = 579(用 Y 轴最大值减原始 Y,实现 Y 轴反转,再作为新 X);
new_y = 200(直接把原始 X 作为新 Y,实现 XY 轴交换);
最终系统收到 X=579,Y=200,正好修正了轴反转问题。
new_x = clamp_val(new_x, 0, max_y);new_y = clamp_val(new_y, 0, max_x);
•clamp_val:Linux 内核的工具函数,作用是 “将数值限制在指定范围内”(小于最小值则取最小值,大于最大值则取最大值);
•为什么需要?防止 TP 上报异常数据(比如负数、超出最大值),导致系统识别到 “无效坐标”,出现触控漂移或无响应;
•比如 new_x 计算后是 - 10,会被修正为 0;若 new_x 是 1080(超过 max_y=1079),会被修正为 1079。
修改完上述 3 个文件后,按以下步骤验证:
1.重新编译 RK3588 内核;
2.将编译后的内核镜像(boot.img)烧录到 RK3588 开发板;
3.接入 USB TP,测试触控功能。
验证结果:
•单点触控:点击屏幕任意位置,光标精准对应,无偏移;
•滑动操作:向上 / 下 / 左 / 右滑动,页面滚动方向完全正确;
•多点触控:双指缩放图片、双指旋转,功能正常无异常;
•边缘测试:点击 TP 边缘区域,无 “超出范围” 或 “无响应” 问题。
整个适配过程从修改代码到验证通过,流程简单,比供应商提供的 “改 TP 固件” 方案效率高太多。
这个方案的优势在于“通用性”—— 如果后续换其他型号的 USB TP,只要遇到类似的 “轴反转” 或 “方向反” 问题,都可以参考这个思路修改,只需调整hid-multitouch.c中的坐标转换公式:
|
问题类型
|
调整思路
|
示例公式(假设原始 x/y,max_x/max_y)
|
|
仅 XY 轴交换
|
new_x = 原始 y;new_y = 原始 x
|
new_x=*slot->y; new_y=*slot->x
|
|
仅 X 轴方向反
|
new_x = max_x - 原始 x;new_y = 原始 y
|
new_x=max_x-*slot->x; new_y=*slot->y
|
|
仅 Y 轴方向反
|
new_x = 原始 x;new_y = max_y - 原始 y
|
new_x=*slot->x; new_y=max_y-*slot->y
|
|
XY 轴交换 + 双轴方向反
|
new_x = max_y - 原始 y;new_y = max_x - 原始 x
|
new_x=max_y-*slot->y; new_y=max_x-*slot->x
|
修改前必做的准备:
用getevent命令查看 TP 的原始坐标数据(Android 终端执行getevent -l),确认原始 x/y 的范围和上报规律,再针对性调整公式,避免盲目修改。
这次 RK3588 USB TP 的适配,本质上是 “绕开硬件限制,用软件灵活解决问题”。在嵌入式开发中,我们常会遇到 “硬件端修改麻烦” 的场景,此时不妨多想想:
•驱动层能不能拦截数据做处理?
•系统层有没有 API 能适配需求?
•应用层能不能通过配置兼容差异?
毕竟,软件的灵活性才是嵌入式开发的“核心优势”。如果大家在 TP 适配中还遇到过其他坑(比如多点触控失效、触控延迟),欢迎在评论区分享,我们一起探讨解决方案~
全部0条评论
快来发表一下你的评论吧 !