No0ne / ps2x2pico

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

SGI O2 Ctrl acts as CAPS Lock - Scan Code Set 3 not supported #38

Closed bstrobel closed 1 month ago

bstrobel commented 1 month ago

I have 2 SGI O2s that work well with any standard PC PS/2 keyboard that I have. When connecting them to my ps2x2pico adapter everything seemed to work until I pressed the Ctrl key. It acts as if it were the CAPS Lock key.

To debug this issue I connected a serial debug terminal and added these log messages in ps2kb.c image image

I found out that the O2 requests Scan Code Set 3:

...
kb_receive(byte = f0, prev_byte = f5) 
kb_send(byte = fa) 
kb_receive(byte = 3, prev_byte = f0) 
kb_send(byte = fa) 
...

This corresponds to the observed behaviour since make code 0x14 is Ctrl in Scan Code Set 2 and Caps Lock in Scan Code Set 3.The former is the one that is widely used and also used in your translation table in the code I assume.

So to support such old and rare hardware the proper selection and mapping of the 3 scan code sets should be implemented. I assume there is more fancy retro equipment out there that does similar things

If you're ok with it, I can do this. But no problem if you want to implement this yourself.

No0ne commented 1 month ago

Ah ok, I don't have any machines that request scancode set 3, so thats why its not implemented. But I think this should be fairly easy as only the mapping arrays must be swapped.

I'm currently out of freetime, feel free to send a pull request. If not I'll implement this eventually but can't say when.

bstrobel commented 1 month ago

Ok, I just wanted to make sure that we don't do double work. So I will work on that.

BTW It seems there are more problems SGI and/or scan code set 3 related. Typematic repeat doesn't work. After 4 repeated characters the O2 just sends a reinit sequence to the keyboard and only prints 2 of the 4 characters. I analyzed it with a logic analyzer and ps2x2pico seems to do everything correctly as far as I can see.

All of this works with an old PC keyboard though. My plan is to use the LA to analyze the communication with this kb and see what needs to be implemented how. The issue is the PS/2 decoder in PulseView is broken. I think I will need to fix this first.

I googled a bit about this topic and it seems the scan code set 3 behaviour has a few more differences than just a different mapping. It was the "real" PS/2 mode and was probably made intentionally incompatible to the original PC as the whole PS/2 computer system was meant to be. And SGI picked it up obviously.

I also don't have a lot of time to spare but I'm also very keen on getting the O2s connected to the KVM. So please be patient. :)

No0ne commented 1 month ago

Cool! I used the PS/2 analyzer in Logic2 (works 95%).

bstrobel commented 1 month ago

I'm currently working through your code and the tinyusb examples to make sense of it before I actually start to implement my changes.

I have a few small questions.

  1. You explicitly check for 0 in the report[1] field which is reserved: image This means you ignore all reports that have this field set to something else than 0. This looks to me as if you wanted to filter out some erroneous messages. Do you have any documentation on this or why are you doing this?
  2. I'd like to add a few debug outputs which could be quite verbose and thus could potentially impose performance degradations (no idea how serial output is handled in the Pico). That's why I'd like to wrap them in a #ifdef TRACE or something. You ok with that?
  3. Since I'm in the 'scan code set change business' anyway I will also add Scan Code Set 1 just for completeness. But I have no hardware to test this. Ok?

Scan Code Set 3 has few extended features that are also utilized in part by SGI. For instance it is possible to disable BRAKE codes and typematic per key. Also BRAKE codes are handled differently and there are no extended codes. I will implement everything according to the documentation and test with the SGI O2. This also means more code changes than you might have expected.

Please let me know what you think

No0ne commented 1 month ago

Sorry for the late reply, I'm currently really out of time :(

  1. Don't remember where I read about this second byte being zero. Maybe this check is wrong, you may remove it.
  2. No problem, just add debugging stuff.
  3. Yeah no problem, the more feature complete, the better!

Did not read any Scan Code Set 3 stuff, but theres also stuff which alters repeat and break codes in Set 2 which is not yet implemented.

bstrobel commented 1 month ago

Thanks NoOne! :) In the meantime I implemented set 3 and and set 1 and did a bit refactoring. I smoke tested it with my Pentium PC and my SGI O2. Seems everything works so far. I think there is some more things to investigate and correctly, like media keys, Europe1 and Europe2 keys in set 3, host command resend (0xfe) which is unclear how it should work in reality. All of this should improve compatibility.

Here is my code: fork of your repo I didn't issue a pull request yet since I think it needs a bit more work before being merged.

I also added a lot of debug messages that are quite helpful in my eyes. I think they are also helpful if other people are having problems and we're asked for help. For instance the vendor name and device name are printed in clear text along with the vid and pid of the device when mounted.

This could help identifying the problem when using usb kvm switches. For instance the problem with my kvm switch had a quite unexpected source. I have a cheap VGA2HDMI converter which needs power from USB to work. The quick solution was to connect its USB plug to the kvm switch which has 4 ports. This works in general but I it was causing the issues with ps2x2pico! I didn't know that this USB plug is not only carrying the power lines but is fully featured. The VGA2HDMI adapter registers on USB as a mass storage device without a connected media and a HID device. Seems this is a weird firmware update interface (or something vicous... :) ). Anyway it prevents ps2x2pico from working. Maybe we should think of vid/pid blacklisting?

Another example: I connected a Logitech USB receiver to ps2x2pico expecting it to be just one device. But this is what ps2x2pico sees:

HID(1,0,KEYBOARD) mounted
 ID: 046d:c52b
 Manufacturer: Logitech
 Product:      USB Receiver

HID(1,1,MOUSE) mounted
 ID: 046d:c52b
 Manufacturer: Logitech
 Product:      USB Receiver

HID(1,2,NONE) mounted
 ID: 046d:c52b
 Manufacturer: Logitech
 Product:      USB Receiver

HID(2,3,KEYBOARD) mounted
 ID: 413c:2003
 Manufacturer: Dell
 Product:      Dell USB Keyboard

So it registers in fact as 3 devices although only a mouse is connected. The Dell keyboard is in fact a real keyboard.

I didn't change anything essential on the usb side of things, just the logs. I upgrade tinyusb lib to the latest release version 0.16.0. Initially I had checked out master but I went back to the release version when I experienced strange behaviour. It mostly works but occasionally I get messages like

[0:1] Control STALLED, xferred_bytes = 0
21 0A 00 00 01 00 00 00 

from tinyusb (these are not my log messages!). I didn't investigate yet what it means.

In my fork I added a few links in Readme.md to a resource that I used in earlier projects. It describes the usage of set 3 better and has decent set 3 table.

Anyway it is quite fun to work on this and it is cool to work on the O2 with a decent keyboard. :D

No0ne commented 1 month ago

Thanks for the PR, is this issue now fully resolved?

bstrobel commented 1 month ago

Yes, the issue is resolved.

No0ne commented 1 month ago

very cool, thanks for the support!