-
Notifications
You must be signed in to change notification settings - Fork 1.7k
USB: NKRO
https://web.archive.org/web/20190428204254/https://www.elitekeyboards.com/switchhitter.php
https://geekhack.org/index.php?topic=34670.0
https://github.com/DIGImend/usbhid-dump
You can see report data in stream mode of usbhiddump.
$ sudo usbhid-dump -d feed:caaa -es
Starting dumping interrupt transfer stream
with 1 minute timeout.
005:091:003:STREAM 1624765630.955897
00 10 00 40 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
005:091:003:STREAM 1624765630.970874
00 90 00 40 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
005:091:003:STREAM 1624765631.054870
00 90 40 40 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
https://github.com/tmk/tmk_keyboard/issues/475
This is really good writeup of this issue and the commit fixed it at Dec 29, 2014. Current Linux(4.0 and up ?) doesn't have this issue.
https://github.com/torvalds/linux/commit/6ce901eb61aa30ba8565c62049ee80c90728ef14 https://github.com/torvalds/linux/commit/8e7b341037db1835ee6eea64663013cbfcf33575#diff-f35f6b78ead6796aeaf38a7414178d43
HID usage Backslash(0x31) and Non-US Hash(0x32) are translated into one Linux internal keycode(43) in Linux kernel, also Delete(0x4C), Clear(0x9C) and Keypad Clear(0xD8) are translated into one keycode(111). Those keys can't be distinguished each other on Linux input system by design(not bug), this fact itself is not problem. The problem is Linux cannot handle event of those keys in NKRO report correctly.
https://github.com/tmk/tmk_keyboard/issues/117#issuecomment-51674009
Some keyboard firmwares like Soarer's, kiibohd and keyboardio use tricky keyboard report to work around this problem.
Soarer's Converter USB Descriptor
The trick removes the 'Non-US Hash' and 'Clear' from its report to prevent Linux bug, but this can cause new issue.
https://github.com/keyboardio/Kaleidoscope/issues/273
As for TMK just use 6KRO if you have this problem with NKRO.
Windows had weird problem with custom keyboard report other than boot keyboard(6KRO) report.
It seems Microsoft fixed it and Windows has no problem with NKRO report as of today.(2017/12/31)
The good news is that we reported the bug, and it has been identified and corrected, and the fix should be available in a future Windows update. - Dec 5, 2010
http://forums.anandtech.com/showpost.php?p=30873364&postcount=17
const USB_Descriptor_HIDReport_Datatype_t PROGMEM NKROReport[] =
{
HID_RI_USAGE_PAGE(8, 0x01), /* Generic Desktop */
HID_RI_USAGE(8, 0x06), /* Keyboard */
HID_RI_COLLECTION(8, 0x01), /* Application */
HID_RI_USAGE_PAGE(8, 0x07), /* Key Codes */
HID_RI_USAGE_MINIMUM(8, 0xE0), /* Keyboard Left Control */
HID_RI_USAGE_MAXIMUM(8, 0xE7), /* Keyboard Right GUI */
HID_RI_LOGICAL_MINIMUM(8, 0x00),
HID_RI_LOGICAL_MAXIMUM(8, 0x01),
HID_RI_REPORT_COUNT(8, 0x08),
HID_RI_REPORT_SIZE(8, 0x01),
HID_RI_INPUT(8, HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE),
HID_RI_USAGE_PAGE(8, 0x08), /* LEDs */
HID_RI_USAGE_MINIMUM(8, 0x01), /* Num Lock */
HID_RI_USAGE_MAXIMUM(8, 0x05), /* Kana */
HID_RI_REPORT_COUNT(8, 0x05),
HID_RI_REPORT_SIZE(8, 0x01),
HID_RI_OUTPUT(8, HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE | HID_IOF_NON_VOLATILE),
HID_RI_REPORT_COUNT(8, 0x01),
HID_RI_REPORT_SIZE(8, 0x03),
HID_RI_OUTPUT(8, HID_IOF_CONSTANT),
HID_RI_USAGE_PAGE(8, 0x07), /* Key Codes */
HID_RI_USAGE_MINIMUM(8, 0x00), /* Keyboard 0 */
HID_RI_USAGE_MAXIMUM(8, (NKRO_EPSIZE-1)*8-1), /* Keyboard Right GUI */
HID_RI_LOGICAL_MINIMUM(8, 0x00),
HID_RI_LOGICAL_MAXIMUM(8, 0x01),
HID_RI_REPORT_COUNT(8, (NKRO_EPSIZE-1)*8),
HID_RI_REPORT_SIZE(8, 0x01),
HID_RI_INPUT(8, HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE),
HID_RI_END_COLLECTION(0),
}
Soarer's Converter USB Descriptor
I watched HID reports from soarer's with usbhid-dump
on Linux(or in report mode) the converter always sends two reports from interface 0(boot) and 2(NKRO) at same time. Interface0(boot keyboard) sends reports in boot protocol format(6KRO). Because report descriptor of interface0 declares Input data as "Constant", in the result OS ignores reports from this interface and uses only NKRO report.
$ sudo usbhid-dump -d16c0:047d -i0 -es -t10000
$ sudo usbhid-dump -d16c0:047d -i2 -es -t10000
Decent host can read the report descriptor correctly, ignores Boot report and uses only NKRO report, while crappy host(or BIOS) cannot read the report descriptor, ignores NKRO report and uses only Boot report.
I didn't confirm but I guess the converter stops interface2(NKRO) when BIOS/UEFI requests boot mode.
It doesn't seem to have switching method between NKRO and Boot keyboard.
Also refer this: http://deskthority.net/workshop-f7/soarer-desparately-needed-t9322-30.html#p210886
In theory, the keyboard should come up in NKRO with an NKRO descriptor and advertise boot mode capability on ONE endpoint, the BIOS should request boot mode, and then the keyboard should switch to boot mode. However, some BIOSes assume that a keyboard that advertises boot mode actually is running in boot mode, and fail to request it (which is a safe assumption on 99.9% of keyboards, but violates the spec). If a BIOS follows the spec and requests that the boot mode endpoint switch to boot mode, I believe Soarer is shutting down the NKRO endpoint.
Then, per the spec, once the OS comes up and resets all USB devices, it'll parse all the descriptors. His boot mode endpoint intentionally
doesn't have a descriptor(has Constant descriptor), because there is no way to reliably sense that there's a real OS here, but his NKRO endpoint has one, so the OS ignores everything coming from the boot mode endpoint (but it still has to be sent in case a BIOS sees boot mode capability and assumes it's good to go).
Quote from v1.11 changes:
Prevented debug and rawhid output when keyboard_protocol is not set (i.e. in BIOS mode).
http://www.realforce.co.jp/en/products/realforce_rgb/
Interface0
Boot keyboard + 6KRO report descriptor
Modifiers 1byte + constant 1byte + keys 6 bytes = 8
Endpoint 1IN
PacketSize 8
Interval 1
Interface1
Multimeida
ReportID=1 + consumer 1byte =2
ReportID=2 + constant 1byte + NKRO keyboard 232bits(0-231[Right GUI]) = 31
ReportID=3 + consumer 1byte =2
Endpoint 2IN
PakcetSize 32
Interval 1
Interface2
Vendor specific
64byte report
Endopoint 3IN/4OUT
PakcetSize 64
Interval 1
Use Boot keyboard interface until its report is full and NKRO keyboard interface is used only when Boot report is not enough. Modifiers is always registered with Boot report. No switching function between Boot and NKRO keyboard.
Modifiers don't affect on keys of NKRO keyboard interface with some OS such as MacOS?