Linux下荣耀MagicBook的触控板被错误识别为鼠标的临时解决方案
UPD 2023/11/28:补丁已并入内核主线,并在v6.6.3发布。以下解决方案不再需要。
TL;DR
安装软件包 hid-tools
,然后运行命令:
sudo hid-feature set -f 30000 3 $(sudo hid-feature list-devices | grep BLTP7853 | awk -F: '{print $1}')
问题现象
荣耀 MagicBook 笔记本安装了汇顶的触控板,此触控板在Linux下被识别为鼠标,导致无法使用触控板手势等功能。该触控板自称为 BLTP7853:00 347D:7853 Touchpad
,识别码为 347d:7853
。问题表现为此触控板被识别为了两个设备(见 /proc/bus/input/devices
),且有 Touchpad
字样的设备无数据。
`/proc/bus/input/devices` 中的部分输出
I: Bus=0018 Vendor=347d Product=7853 Version=0100
N: Name="BLTP7853:00 347D:7853 Mouse"
P: Phys=i2c-BLTP7853:00
S: Sysfs=/devices/pci0000:00/0000:00:15.0/i2c_designware.0/i2c-1/i2c-BLTP7853:00/0018:347D:7853.0001/input/input11
U: Uniq=
H: Handlers=event7 mouse0
B: PROP=0
B: EV=17
B: KEY=70000 0 0 0 0
B: REL=903
B: MSC=10
I: Bus=0018 Vendor=347d Product=7853 Version=0100
N: Name="BLTP7853:00 347D:7853 Touchpad"
P: Phys=i2c-BLTP7853:00
S: Sysfs=/devices/pci0000:00/0000:00:15.0/i2c_designware.0/i2c-1/i2c-BLTP7853:00/0018:347D:7853.0001/input/input12
U: Uniq=
H: Handlers=event8 mouse1
B: PROP=5
B: EV=1b
B: KEY=e520 10000 0 0 0 0
B: ABS=2e0800000000003
B: MSC=20
分析
由于 /dev/input/eventX
无输出,此问题显然与 X11 或者 libinput 无关,而是一个内核漏洞。其中模块 hid_multitouch
是头号怀疑对象。
(以下分析来自 @nexplorer-3e)在 Windows 设备管理器中,也存在两个设备:I2C HID Device
和 Microsoft Input Configuration Device
,且这两个设备的设备识别码均为 BLTP7853
。在微软的文档中有关于此的说明:触摸板必需 HID 顶级集合 - 输入模式功能报告。
触摸板必需 HID 顶级集合 - 输入模式功能报告 摘录
输入模式功能报告由主机传达给 Windows 精确式触摸板,用于指示应该将哪个顶级集合用于输入报告。 可将两个集合用于输入报告:鼠标集合和 Windows 精确式触摸板集合。
默认情况下,在进行冷启动/电源周期时,Windows 精确式触摸板应使用鼠标集合报告输入。 Windows 精确式触摸板在任何时候应仅使用一个给定集合报告数据,并且在从主机收到指示所需输入模式的相应功能报告后,应该只从另一个集合进行报告。
主机指定的用于输入模式的值(用法 0x52)决定了应该用于报告输入的集合。
输入模式值 | 输入报告 |
---|---|
0 | 鼠标集合 |
3 | Windows 精确式触摸板集合 |
主机可以在读取报表描述符后,随时向 Windows 精确式触摸板发出输入模式功能报告(包括可能通过活动集合报告数据时)。 如果报告数据时发生模式切换,则所有触点和按钮状态都应报告为向上弹起,并且所有使用该集合进行的报告都应停止。 在所有触点实际上都已向上弹起后,可以使用新指定的集合进行报告。 输入模式不应由 Windows 精确式触摸板跨电源周期或主机发起的重置(USB 重置、HID I2C HIR、HID SPI HIR)保留;但是输入模式可以跨任何设备发起的重置(例如 HID I2C DIR、HID SPI DIR 等)保留。
实验性解决方案
根据 @nexplorer-3e 提供的分析可知,我们只需将输入模式(Inputmode
)设置为 3
即可。借助 hid-tools 工具(在我的发行版上可直接使用 pacman
安装),我们可以方便的对其进行设置,使用下面命令即可
sudo hid-feature set -f <Inputmode feature id> 3 <device node path>
其中 <Inputmode feature id>
替换为输入模式功能编号(似乎总是 30000),<device node path>
替换为触控板设备的路径即可。
获得触控板设备的路径和输入模式功能编号
首先使用如下命令得到设备路径:
sudo hid-feature list-devices | grep BLTP7853
可得到类似于如下的输出:
/dev/hidraw1: BLTP7853:00 347D:7853
这说明在我的系统中,触控板设备的路径为 /dev/hidraw1
。然后使用命令
sudo hid-feature list /dev/hidraw0 | grep Inputmode
可得到类似于如下的输出:
30000 | 0 | Digitizers | Inputmode | [ 0, 10] | 1 | 8
输入模式功能编号为 30000
。
解决方案
@nexplorer-3e 已经向 LKML 提交了补丁,不过此补丁尚未合并入内核主线。
我们可以手工编译 hid-multitouch
模块来将此补丁应用到当前的内核中。首先查看内核版本(uname -r
),然后下载对应的内核源代码,注意通常需要从你的发行版而不是 kernel.org 上下载代码,因为发行版会应用一些额外的补丁。在我的例子中,我正在使用的内核是 6.6.1-1-MANJARO
,它的构建脚本来自于 core/linux66。
得到正在运行的内核的源代码后,打开 drivers/hid/hid-multitouch.c
并在注释 /* Ilitek dual touch panel */
前(大约在 2050 行,取决于具体的内核版本,也可添加在其他合理位置,添加在此处只是为了保证按照设备的字典序排列)添加如下代码:
/* HONOR GLO-GXXX panel */
{ .driver_data = MT_CLS_VTL,
HID_DEVICE(BUS_I2C, HID_GROUP_MULTITOUCH_WIN_8,
0x347d, 0x7853) },
然后获得正在运行的内核编译时的配置,这可以使用命令:
zcat /proc/config.gz > .config
并使用如下命令编译内核(请根据实际硬件情况调整编译线程数):
make prepare
make -j16
因为编译出的内核模块的 BTF 数据版本可能不能与正在运行的内核完全一致,故去除 BTF 信息:
objcopy --remove-section=.BTF drivers/hid/hid-multitouch.ko
最后使用编译出的模块替换原来的模块:
sudo modprobe -v -r hid-multitouch
sudo modprobe -v ./drivers/hid/hid-multitouch.ko
错误排查
如果 modprobe
报错,可使用命令
sudo dmesg
查看内核日志
确认无误后,可将模块文件放入系统目录以便在下次开机时自动装载:
zstd ./drivers/hid/hid-multitouch.ko -o hid-multitouch.ko.zst
cp /lib/modules/$(uname -r)/kernel/drivers/hid/hid-multitouch.ko.zst hid-multitouch.ko.zst.old # 可选,备份
sudo cp hid-multitouch.ko.zst /lib/modules/$(uname -r)/kernel/drivers/hid/
关于副作用
这会加载一个缺少签名,BTF的树外的模块进入内核,并使内核进入污染模式,这通常不是一个问题。