新的 TrueOS 安装;键盘不能正常工作

cha*_*sys 6 freebsd usb trueos

我昨天安装了一个新的 TrueOS 实例(一个 FreeBSD 变体),并插入了一个 USB 键盘(罗技 G510)。它在安装环境中,在首次启动设置期间运行良好,直到新实例重新启动。在这一点上,它似乎完全停止发送输入,从它在 BSD 的启动时模块加载阶段被识别开始,因为那是 Scroll Lock 停止工作的时候。但是,LCD 屏幕和背光灯是打开的,如果我插入另一个键盘,它会跟踪状态变化(Caps/NumLock 等)并且它在 Windows/Linux 和我的笔记本电脑上运行良好。

我尝试了在 BIOS 中打开/关闭 Legacy USB 和 Hand-off 的各种组合,并使用不同的端口,但都无济于事。不同的 USB 键盘(下面日志中的“供应商 0x1241 USB 键盘”)无论哪种方式都可以正常工作。USB 鼠标一直有效。没有 PS/2 端口。

知道这里发生了什么,以及如何解决它?谢谢!

% dmesg | grep kb
kbd1 at kbdmux0
atkbdc0: <Keyboard controller (i8042)> at port 0x60,0x64 on isa0
atkbd0: <AT Keyboard> irq 1 on atkbdc0
kbd0 at atkbd0
atkbd0: [GIANT-LOCKED]
ukbd0 on uhub5
ukbd0: <vendor 0x1241 USB Keyboard, class 0/0, rev 1.10/2.80, addr 2> on usbus6
kbd2 at ukbd0
ukbd1 on uhub0
ukbd1: <Logitech G510 Gaming Keyboard, class 0/0, rev 2.00/1.65, addr 2> on usbus0
kbd3 at ukbd1

% ll /dev/*kb*
crw-------  1 root  wheel  0x47 Oct 31 10:46 /dev/atkbd0
lrwxr-xr-x  1 root  wheel     6 Oct 31 10:46 /dev/kbd0 -> atkbd0
lrwxr-xr-x  1 root  wheel     7 Oct 31 10:46 /dev/kbd1 -> kbdmux0
lrwxr-xr-x  1 root  wheel     5 Oct 31 10:46 /dev/kbd2 -> ukbd0
lrwxr-xr-x  1 root  wheel     5 Oct 31 10:46 /dev/kbd3 -> ukbd1
crw-------  1 root  wheel  0x25 Oct 31 10:46 /dev/kbdmux0
crw-------  1 root  wheel  0x62 Oct 31 10:46 /dev/ukbd0
crw-------  1 root  wheel  0x6a Oct 31 10:46 /dev/ukbd1
Run Code Online (Sandbox Code Playgroud)

Jde*_*eBP 6

精确

发生的事情实际上很简单:为了提供真正的 N 键翻转以及所有这些额外的游戏和其他键,罗技已经调整了它通过 USB 报告键盘输入事件的方式。FreeBSD 内核中内置的 USB 输入报告解析库不支持此功能。如果您没有过滤内核消息输出,您会看到类似的消息

hid_get_item: 项目数 (991) 截断为 255 
hid_get_item: 项目数 (257) 截断为 255 
或者

hid_get_item:364:项目数被截断为 255

细节

USB 输入报告协议允许 USB HID 具有两组,每组最多 65531 个密钥。当前的 USB 标准定义了第一组中键 4 ( A a) 到 231 ( ⌘ Right GUI)的代码。一个“游戏键盘”的按键比这多得多,其中大部分都不符合标准的键码,实际上无论如何都可能进入第二组。

USB HID从概念上将键盘活动报告为一个巨大的位图,每个键一位,描述键盘上所有键的当前向上/向下状态。虽然这确实是 8 个修饰键的情况,代码为 224 到 231,但通常其他键以倒置数组的形式报告。从设备通过线路到 USB 主机的键盘输入报告包括位图中设置为 1的位的索引

这种倒排的形式节省了空间。我现在正在输入此答案的 126 键多媒体键盘每个输入报告需要 16 个字节才能以位图形式报告整个键盘。然而,对于倒排数组,它仅使用 8 个字节,其中 6 个是非修饰键的数组索引。

这种倒排数组形式的问题在于,人们不会无所事事:

  • 它限制翻滚。 使用完整位图,您将拥有真正的 N 键翻转(受键盘矩阵本身的任何硬件限制)。对于倒排数组形式,数组索引的数量限制了翻转量。通常,由于 USB HID 标准实际上在附录中描述了这种“启动”报告格式,因此 USB HID 键盘在其报告中提供了 6 个数组索引,最多允许同时按下 6 个(非修饰符)键。
  • 它限制了关键代码。 数组索引通常是 8 位整数。使它们更宽,以便它们可以容纳 256 个以上的键代码,并且要么报告 6 个同时按下(非修饰符)键需要 8 个字节以上,要么将可报告的同时按下的键数减少到小于6.

    不幸的是,游戏键盘需要能够报告远远超过 256 个键码。从上述日志摘录中可以看出,罗技游戏键盘的键码在一种情况下高达 257,在另一种情况下高达 991。这并不意味着它有 257 和 991 个键。这意味着密钥代码值的范围很广。

FreeBSD 内核的局限性,更具体地说是链接到 FreeBSD 内核的精简版 libusb,有些微妙。正如经常报道的那样,它们不是位图大小的限制。它们是 USB 术语中对输入项报告计数的限制。FreeBSD 将报告计数上限设置为 255,如果实际报告计数大于 255,则打印上述消息。

这对后果直位表格式和键盘输入的反转阵列形式。

  • 对于直位图形式,意味着大于 255 的位图将在第 255 个键码处被截断。即只考虑位图的前 64 个字节。这限制了将被识别的键代码的范围。
  • 对于倒排数组形式,这意味着将只使用前 255 个数组索引。当然,前 255 个数组索引可以包含任何键码。这限制了有效的翻转量。

对于前者来说,这只是一个比后者更大的问题。在这很重要的情况下,没有人会使用倒排数组形式而不是位图形式。用255个数组索引倒置阵列是大量比等价的位图形式有效的空间,如相同大小的位图可以代表8倍,与真实的N-密钥滚动许多关键码。

因此,罗技希望报告 257 或 991 键代码范围内的任何键代码,以使所有额外的键都起作用。(为什么这样拆分,与不同类型按键的编码归为不同的“页面”,以及输入项不能跨越多个“页面”的方式有关。这是USB的奥秘,超出了本文的范围答案。)而且它想给人们带来的不仅仅是 6 键翻转。

为此,它切换到使用位图和大量报告计数的 USB输入报告描述符格式。(USB 允许 HID 有多种输入报告格式,它们可以在它们之间切换。)FreeBSD 内核不喜欢这样,问题随之而来。

本地修复是强制 Logitech 键盘继续使用“引导”输入报告描述符格式,该格式提供 6 键翻转并且无法发送键盘上任何额外键的代码,而不是其“本机”报告描述符格式。这可以在每个系统引导程序中使用该usbconfig命令完成,并为其提供add_quirk UQ_KBD_BOOTPROTO子命令。

Bodge 是将这个怪癖放入已经存在的预定义怪癖列表中,该列表内置于 FreeBSD 内核中,并由内核神奇地应用于匹配的 USB 设备。

服务修复是修复内核中减少的 libusb,使其不会将报告计数限制在 255。没有人这样做过,尽管在 FreeBSD 邮件列表之一上对其进行了简要和表面的讨论。