【RK3588 Android驱动实战】USB TP XY轴反转?不用改TP固件!系统端改上报数据快速搞定
做嵌入式Android开发的同学,大概率遇到过USB触控面板(TP)的适配坑——比如XY轴反转:明明点屏幕左边,系统却识别成右边;向上滑动,页面反而向下走。最近在RK3588平台调试USB TP时,就碰到了这个问题,TP供应商给的方案是改TP端固件,但需要重新烧录TP程序、协调供应商联调,操作麻烦还耗时间。
后来我们换了个思路:直接在Android系统端修改TP上报的坐标数据,不用动TP硬件/固件,半小时就搞定了。今天就把这个实战方案拆解清楚,附上核心patch解析,希望能帮到有同样需求的同学。
一、问题回顾:RK3588 USB TP的“反向”烦恼
先明确下我们遇到的具体问题:
在RK3588 Android 12/13系统上,接入某款USB TP后,触控功能正常,但坐标映射完全反了——比如TP物理坐标的X轴(横向)对应系统的Y轴(纵向),且单轴方向还存在反转(比如按TP右侧,系统识别为左侧)。
最初联系TP供应商,得到的解决方案是:
1.提供TP的固件烧录工具;
2.修改TP内部的坐标映射参数;
3.重新烧录固件到TP芯片。
但这个方案有明显痛点:
•需额外安装烧录工具,部分工具还依赖Windows系统;
•烧录过程有风险,操作不当可能导致TP变砖;
•若后续换批次TP,可能需要重复适配,灵活性差。
既然TP是通过USB HID协议向系统上报坐标数据,那能不能在系统驱动层拦截并修改这些数据?答案是肯定的——这就是我们最终采用的方案。
二、核心方案
1.核心逻辑:hid-multitouch.c(坐标转换的关键)
文件路径: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);// 修改后(先转换坐标,再上报)intmax_x = input_abs_get_max(input, ABS_MT_POSITION_X);intmax_y = input_abs_get_max(input, ABS_MT_POSITION_Y);intnew_x = max_y - *slot->y;intnew_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);
这部分是核心,必须逐行理解:
步骤1:获取TP的最大坐标值
intmax_x = input_abs_get_max(input, ABS_MT_POSITION_X);intmax_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开始计数);
•为什么要获取最大值?因为后续要通过“最大值-原始坐标”实现单轴方向反转。
步骤2:坐标交换+方向反转
intnew_x = max_y - *slot->y;intnew_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,正好修正了轴反转问题。
步骤3:限制坐标范围(防异常)
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固件”方案效率高太多。
四、实用小贴士:适配其他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适配中还遇到过其他坑(比如多点触控失效、触控延迟),欢迎在评论区分享,我们一起探讨解决方案~
