No0ne / ps2x2pico

USB keyboard/mouse to PS/2 interface converter using a Raspberry Pi Pico
MIT License
196 stars 35 forks source link

HyperX Alloy FPS Mechanical Gaming Keyboard not working #40

Closed bstrobel closed 2 weeks ago

bstrobel commented 1 month ago

I mentioned it in my pull request. My HyperX Alloy FPS Mechanical Gaming Keyboard is behaving strangely.

Symptoms:

It is register correctly:

HID(2,3,KEYBOARD) mounted
 ID: 0951:16b7
 Manufacturer: Kingston
 Product:      HyperX Alloy FPS Mechanical Gaming Keyboard

But when a key is pressed all the events are recognized as mouse events although they come from the dev_addr/instance that was identified as KEYBOARD (i.e. dev_addr=2, instance=3 in the above example). The mouse cursor jumps wildly across the screen and ps2x2pico hangs eventually.

Investigation

I did some investigation and found out that the events identified as mouse events are actually keyboard events, but not from the simplified boot protocol that tinyusb uses but with a real HID event descriptor. They are 16 bytes long, not 8 and they have different but correct format. I wrote some code to decode them and could reliably identify all keypresses, except the EUROPE_1 and EUROPE_2 keys (these are the keys that are not present on US american keyboards, but on many european ones). The latter two keys were send in the 8 byte long boot protocol, but with the modifier bit field always 0.

So my assumption is that the keyboard in question does not support the old boot protocol but only the full featured HID protocol. Tinyusb is not able to cope with this. The tinyusb function tuh_hid_interface_protocol(dev_addr, instance) to identify the protocol of the event (i.e. if it is mouse or keyboard) is not compatible with the full protocol mode and falsely claims that it is a mouse event.

The lock up of ps2x2pico is probably due to concurrency issues. Could be due to calling the ms_usb_receive(report) function while the previous call is not finished or maybe due to a tinyusb problem where they are overrun by the events and ps2x2pico is not consuming them fast enough.

This little project here really ignited my interest and I want to dive deeper into this USB stuff. So I will continue to work on this. So maybe there will be another pull request in the future for this.

No0ne commented 1 month ago

Hu ha sounds complicated, but boot mode won't cut it in the long run I guess. Would also solve this on the mouse side: https://github.com/No0ne/ps2x2pico/issues/35 and https://github.com/No0ne/ps2x2pico/issues/3

Thanks for future PRs!

bstrobel commented 1 month ago

I have the feeling that tinyusb is quite incomplete in this regard (USB host and boot mode vs. full), and I"m not sure this is a priority for them. They wrote somewhere in the comments that they switch each mouse and keyboard into boot mode when connecting. But I need to read more of the USB docs and tinyusb code before deciding what to do. I also plan to contact them and ask them about their plans. But only after I know enough to ask them educated questions... ;-)

No0ne commented 2 weeks ago

Did you find out anything new on this issue? I'm nearly finished with the ps2 input feature, please pull as some files are renamed now.

bstrobel commented 2 weeks ago

I investigated this some time ago and then traveled for a few weeks. I found out how to configure tinyusb to set report protocol instead of boot protocol when configuring a hid device:

tuh_hid_set_default_protocol(HID_PROTOCOL_REPORT);
tusb_init();

I implemented a rough parsing of the report that the keyboard is sending (just hardcoded, without actually parsing the report descriptor).

But I noticed that this keyboard is not sending europe_1 and europe_2 keys when I do this. And since I live in Germany I need them. I think the keyboard has weird bugs, that might be triggered when the report protocol is explicitly requested. I traced the USB communication of this kb and a few others I have on Linux to have something to compare to and Linux never sets the protocol explicitly. It just requests the report descriptors and then the keyboard sense also the events for the europe keys happily...

Anyway this is the only kb that is not working for me, which is not a big issue to me. I'm a bit fed up with the topic at the moment. ;) I suggest to leave this issue open since it is not fixed and I will come back when I have time and you haven't fixed it yourself yet by implementing proper report descriptor parsing and setting of the mode.

0x504B0304 commented 2 weeks ago

Have you ever noticed that there is a full hid report parser just in raspcerry pi pico-sdk? https://github.com/bluekitchen/btstack/blob/72ef1732c954d938091467961e41f4aa9b976b34/src/btstack_hid_parser.c It's very easy to port it into this project.

bstrobel commented 2 weeks ago

No, I indeed have never noticed this parser. :D But this still doesn't solve the fundamental problem of the seemingly very buggy firmware of this keyboard. There are 2 bugs I did identify:

  1. In boot protocol mode (which it supports according to its descriptors) it sends the report not in boot format but in its own report format.
  2. If report protocol mode is set it sends the event in its report format but omits the europe_1 and europe_2 keys. (deal breaker for me)

It seems to work fine if the protocol mode is not set explicitly though. This is what I saw when I traced the communication in Linux using Wireshark.

To solve this I would need to patch tinyusb to never set the protocol mode and issue a PR for it. I simply do not want to do this just for one buggy keyboard. (I simply don"t use it here. I have too many keyboards anyway...) But if there are more keyboards that have similar bugs it might be worth the effort.

Another question is if we would start to use the HIDs in report mode and drop the boot protocol mode. This indeed is something to consider. But I think this decision is up to NoOne as the maintainer of this project. I suggest to open a new issue for this.

My day job is currently consuming most of my time so I can't work on this during the next few months. Still I would do this when I have more time to burn.

0x504B0304 commented 2 weeks ago

Yeah, there are quite a lot of HID devices not following the standard HID specification. Many of them just never had a boot mode, even though they claimed to support it in their descriptor. However, I'm very surprised that Linux and Windows' HID drivers always make the right choice on whether to set the device into report mode. I cannot see any reason from the USB traffic; maybe it needs digging into the kernel source to understand.

bstrobel commented 2 weeks ago

As I said my assumption is that at least Linux is not setting the mode and it just uses the device as is (i.e. in report protocol mode). In Linux it is quite easy to capture the USB traffic with Wireshark. Don't know about Windows. Haven't looked at this yet.

Though I'm 100% sure all manufactures test their devices with Windows and most of them with Linux. So it would be best to copy Windows or at least Linux. I also started digging into the Linux kernel sources already. I think Linux is the best source to copy you can get.

So yes in my eyes there is definitely a case to move away from boot proctol mode for this project.

No0ne commented 2 weeks ago

Yes totally agree, this would also help/fix #3 #23 and #35, but it is also too difficult for me right now.

Thanks for the research, I'll close this for now and open it when its relevant again.