tinypilot icon indicating copy to clipboard operation
tinypilot copied to clipboard

HID descriptor problems when attached to some hardware KVM swtiches

Open WarheadsSE opened this issue 3 years ago • 15 comments

Description

Spun off from https://github.com/mtlynch/tinypilot/issues/78#issuecomment-783755302

Some hardware KVM switches seems to "take issue" with the combined mouse and keyboard HID descriptors provided through TinyPilot's use of libcomposite gadget behaviors. One particular case is interesting, because at least one

What's the behavior that you expect?

Keyboard & Mouse are able to be activated through init-usb-gadget script, and successfully pass through the KVM switch hardware to the end device

What's happening instead?

Only one device descriptor can be activated at a time, or neither will pass through.

What are the steps to reproduce this behavior?

  1. Attach TinyPilot to KVM swtich
  2. Observe "missing" keyboard / mouse on end device
  3. See errors in TinyPilot logs regarding writes of keypresses

Research

I've collected some notes in this Gist.

  • Kernel logs showing the difference in reports. Notice, the strings are missing when passing through the CKLau :thinking:
  • When both HID devices are activated, there is no kernel message. This seems to indicate an issue within the switch hardware/firmware, though due to a specific compatibility issue only yet observed here. Could be a HID definition compliance issue, or could be something more obscure like report_length misalignment. :shrug:
  • Included a full HID dump from a hardware combo device which "seemingly" has no issues when directly attached to the KVM switch.

WarheadsSE avatar Mar 01 '21 14:03 WarheadsSE

Which port of the CKLau KVM are you inserting the TinyPilot's USB into? The USB 2.0 port or one of the keyboard/mouse ports?

If it's helpful, I wrote this quick 'n dirty script that makes it easy to paste HID dumps into the init-usb-gadet script:

https://mtlynch.github.io/hid-formatter/

image

mtlynch avatar Mar 01 '21 22:03 mtlynch

I'd explicitly using only the keyboard input port. The USB 2.0 hub port on the front will not work for the remote triggering, which is exactly what I need. See location in basement rack: tinypilot-in-rack

That will come in handy. In the same spirit, a handy decoder! https://eleccelerator.com/usbdescreqparser/ This will take the output from usbhid-dump directly, and output the commented, readable form.

WarheadsSE avatar Mar 02 '21 15:03 WarheadsSE

I haven't forgotten this @mtlynch, just been a busy month!

WarheadsSE avatar Mar 31 '21 22:03 WarheadsSE

Coming back around to this today :wave:

Going to perform a full update, then apply the configuration of the "known good" from my earlier Gist, and see what turns up.

WarheadsSE avatar May 29 '21 23:05 WarheadsSE

python[1882]: [2021-05-29 19:55:21,983] ERROR in socket_api: Failed to forward mouse event: Failed to write to HID interface: /dev/hidg1. Is USB cable connected?

Bummers. I had to disable the mouse initialization, as with before. Now, though, I've got some other oddity, where key stroke repeat indefinitely. I'll have to hunt a bit to confirm if this is from these changes, or an updated version.

WarheadsSE avatar May 30 '21 00:05 WarheadsSE

I'll have to hunt a bit to confirm if this is from these changes, or an updated version.

I reset the keyboard HID descriptor to the one that comes out of the box, and this "behavior" went away. When using mine, I probably need an adjustment for report length.

WarheadsSE avatar May 30 '21 00:05 WarheadsSE

I've still made no further headway with the CKLau, when using the gadget driver.

WarheadsSE avatar May 30 '21 01:05 WarheadsSE

We recently discovered that the HID report length for the mouse was incorrect:

https://github.com/mtlynch/ansible-role-tinypilot/pull/134

Is that potentially related?

mtlynch avatar Jun 01 '21 22:06 mtlynch

@mtlynch Unfortunately, I do have this change in place, when I pulled from master. However, this does not solve the mystery issue. Still, somehow, the CKLau doesn't pass things along when using the gadget driver. I did go back and re-attach the same KB/Mouse combo dongle, just to be sure. It continues to work without issue.

WarheadsSE avatar Jun 02 '21 00:06 WarheadsSE

:thinking: I was staring at things again, when I noticed a subtle difference:

Observations

dongle

# dongle, through CKLau
D:  Ver= 2.00 Cls=00(>ifc ) Sub=00 Prot=00 MxPS=32 #Cfgs=  1
P:  Vendor=04ca ProdID=006d Rev=00.16
C:  #Ifs= 2 Cfg#= 1 Atr=a0 MxPwr=50mA
I:  If#=0x0 Alt= 0 #EPs= 1 Cls=03(HID  ) Sub=01 Prot=01 Driver=usbhid
I:  If#=0x1 Alt= 0 #EPs= 1 Cls=03(HID  ) Sub=01 Prot=02 Driver=usbhid
# dongle, direct
D:  Ver= 2.00 Cls=00(>ifc ) Sub=00 Prot=00 MxPS=32 #Cfgs=  1
P:  Vendor=04ca ProdID=006d Rev=00.16
S:  Manufacturer=USB Device
S:  Product=USB Device
C:  #Ifs= 2 Cfg#= 1 Atr=a0 MxPwr=50mA
I:  If#=0x0 Alt= 0 #EPs= 1 Cls=03(HID  ) Sub=01 Prot=01 Driver=usbhid
I:  If#=0x1 Alt= 0 #EPs= 1 Cls=03(HID  ) Sub=01 Prot=02 Driver=usbhid

TinyPilot

# TinyPilot, through CKLau
D:  Ver= 2.00 Cls=00(>ifc ) Sub=00 Prot=00 MxPS=64 #Cfgs=  1
P:  Vendor=1d6b ProdID=0104 Rev=01.00
C:  #Ifs= 1 Cfg#= 1 Atr=80 MxPwr=250mA
I:  If#=0x0 Alt= 0 #EPs= 2 Cls=03(HID  ) Sub=01 Prot=01 Driver=usbhid
# TinyPilot, direct
D:  Ver= 2.00 Cls=00(>ifc ) Sub=00 Prot=00 MxPS=64 #Cfgs=  1
P:  Vendor=1d6b ProdID=0104 Rev=01.00
S:  Manufacturer=tinypilot
S:  Product=Multifunction
S:  SerialNumber=6b65796d696d6570690
C:  #Ifs= 2 Cfg#= 1 Atr=80 MxPwr=250mA
I:  If#=0x0 Alt= 0 #EPs= 2 Cls=03(HID  ) Sub=01 Prot=01 Driver=usbhid
I:  If#=0x1 Alt= 0 #EPs= 2 Cls=03(HID  ) Sub=00 Prot=00 Driver=usbhid

Differences

Note: The CKLau (apparently) always strips the Manufacturer/Product/Serial strings.

item dongle gadget
Atr a0 80
MxPwer 50 250
EPs (endpoints) 1 2
Protocol/SubClass of Mouse 02,01 00,00

I tried adjusting Protocol/SubClass, but this had no effect while going through the CKLau.

WarheadsSE avatar Jun 02 '21 01:06 WarheadsSE

Based on the differences above:

  1. I was able to set/reduce the MaxPower configuration with no issue.
  2. I was able to set the attributes with no issue.
  3. I was able to update the Protocol/Subclass for the mouse without issue.

In looking into the Endpoints, this is not something that can be controlled by the consumer of libcomposite, as it is statically set within f_hid.c to 2.

WarheadsSE avatar Jun 02 '21 03:06 WarheadsSE

Thanks for sharing these findings, @WarheadsSE. This is very helpful.

Just to make sure I understand:

  • TinyPilot keyboard and mouse works when you connect directly to the target system.
  • TinyPilot doesn't work if you connect to the target system via the CKLau KVM
  • You can make either keyboard or mouse work through the CKLau KVM by deleting either the mouse or keyboard HID descriptor in init-usb-gadget
  • You have a hardware keyboard/mouse dongle that works when you connect it directly to the target system or through the CKLau KVM
  • From the target system's perspective, the dongle and the TinyPilot differ in only four field values
  • If you change init-usb-gadget's HID field settings to match the known-working keyboard-mouse dongle, it still doesn't work.
  • The only setting you can't change on the TinyPilot to match the dongle is the Endpoints value, which is hardcoded in the Linux USB gadget driver.

Is that correct?

mtlynch avatar Jun 08 '21 19:06 mtlynch

@mtlynch My apologies that it took me so long to get back to you.

You're spot on. This is looking more like a firmware limitation of the CKLau switch itself, isolated down to the support endpoint count.

WarheadsSE avatar Jun 13 '21 02:06 WarheadsSE

Out of curiosity, how would one disable the mouse completely? I have a slightly unusual device that accepts a hardware keyboard but is not functional with TinyPilot, and I wanted to try "only emulating a single device" as a first step in debugging.

pete-otaqui avatar Jul 07 '21 20:07 pete-otaqui

@pete-otaqui - As far as I know, this isn't possible with the Linux USB gadget driver (which is how TinyPilot emulates USB devices). It always presents itself to the target machine as a USB hub with one or more devices attached. You can emulate a USB hub + USB keyboard by deleting the lines in /opt/tinypilot-privileged/init-usb-gadget that relate to the mouse or /dev/hidg1.

You can see the file here:

https://github.com/tiny-pilot/ansible-role-tinypilot/blob/c565b6020c419db31d3fb94c86f5cf019c56908c/files/init-usb-gadget

mtlynch avatar Jul 12 '21 21:07 mtlynch