tiny-pilot / tinypilot

Use your Raspberry Pi as a browser-based KVM.
https://tinypilotkvm.com
MIT License
2.99k stars 249 forks source link

HID descriptor problems when attached to some hardware KVM swtiches #535

Open WarheadsSE opened 3 years ago

WarheadsSE commented 3 years ago

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.

mtlynch commented 3 years ago

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

WarheadsSE commented 3 years ago

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 commented 3 years ago

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

WarheadsSE commented 3 years ago

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 commented 3 years ago

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 commented 3 years ago

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 commented 3 years ago

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

mtlynch commented 3 years ago

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?

WarheadsSE commented 3 years ago

@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 commented 3 years ago

: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 commented 3 years ago

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.

mtlynch commented 3 years ago

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

Just to make sure I understand:

Is that correct?

WarheadsSE commented 3 years ago

@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.

pete-otaqui commented 3 years ago

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.

mtlynch commented 3 years ago

@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