Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Udev rules cause wheel to stop working when plugged in a second time #132

Open
Kimplul opened this issue Dec 7, 2024 · 9 comments
Open

Comments

@Kimplul
Copy link
Owner

Kimplul commented Dec 7, 2024

Rather strange, but something in the udev rules file causes the T248 to stop sending input to at least some SDL programs when it's unplugged and plugged back in. Does not happen without the rules file.

Should probably check if the same happens with the T300, and if so, what rule exactly is causing this.

@Kimplul
Copy link
Owner Author

Kimplul commented Dec 8, 2024

Apparently TAG+="uaccess" is messing things up. Really weird.

Also worth noting that apparently the uaccess tag should be set in a rule with leading number less than 73 (as mentioned here), and if I rename 99-thrustmaster.rules to 71-thrustmaster.rules, SDL stops registering input completely.

@Kimplul
Copy link
Owner Author

Kimplul commented Dec 8, 2024

@kevenwyld @irseny Hello again, I recently thought that it's a bit silly to require users to copy udev rules by hand so I tried providing a .rules file that combines fixes that have come up. Turns out, however, that the rule @kevenwyld reported in #54 (comment) in fact kind of has the opposite effect as intended, at least on Debian and Gentoo (haven't tested others yet). In the Arch wiki there's an example rule with

SUBSYSTEMS=="usb", ...

instead of

KERNELS=="hidraw*", ...

which doesn't seem to cause problems for Gentoo at least. Would you mind checking if it works for your systems? I'm not really familiar enough with udev to tell if this is doing something obviously different, if it is I should maybe dig deeper into SDL and try to figure out what exactly is going wrong down there. evtest, jstest and https://hardwaretester.com/gamepad all seem to work just fine so there seems to be some fairly subtle detail going wrong here.

@kevenwyld
Copy link

Interesting, thanks for digging into this! I totally missed the difference in SYBSYSTEMS and the section regarding file ordering (I'm guessing because I was burying my head in the sand, since they are pretty obvious lol). I will test with my t300 though I'm not sure I ever ran into this second connection issue.

@irseny
Copy link

irseny commented Dec 9, 2024

@Kimplul The existence of the rules file does not make a distinguishable difference in my case. I can see uaccess on the hidraw device applying:
crw-rw----+ 1 root plugdev 243, 15 Dec 9 21:01 hidraw15 vs rw-rw-r-- 1 root plugdev 243, 15 Dec 9 21:14 hidraw15 previously. Since my user is part of the plugdev group the device would be accessible anyway.

Though looking at udevadm info -a -n /dev/input/event27 the hidraw does not seem to be a parent of the input device, so would SDL try to access that at all?

The T300 is detected as joystick device, maybe by the ENV{ID_INPUT_JOYSTICK} test in 70-uaccess.rules on Debian 12. The uaccess command is applied to the input device in 73-seat-late.rules.

An Arch wiki like rule with SUBSYSTEM=="usb" applies to a couple of devices in the chain. Here the tag should be added to one device with driver usb, then usbhid, one up the chain is your tmff2 and above that the input subsystem.

I can successfully test the device with fftest, jstest and evtest, disconnecting and connecting again multiple times. However the device is not usable with wine. Opening the joystick tester wine control the wheel is recognized (without FFB capabilities) but the configurator does not receive any events. This continues to apply when I:

  • Copy over the rule, reload and reconnect
  • Use an existing wine prefix
  • Use a new wine prefix
  • Use an ACC wine prefix with wine from Proton 8
  • Run ACC and then open the joystick tester
  • Rename the file to 70-thrustmaster.rules, reload and reconnect
  • Change KERNELS=="hidraw*" to SUBSYSTEMS=="usb", ...

So in regard to your question, I do not have any additional issues from the rule :)

@Kimplul
Copy link
Owner Author

Kimplul commented Dec 11, 2024

Thanks for checking, @irseny.

Though looking at udevadm info -a -n /dev/input/event27 the hidraw does not seem to be a parent of the input device, so would SDL try to access that at all?

At least according to https://wiki.archlinux.org/title/Gamepad SDL{2,3} first tries to use HIDAPI for a device, and the README in https://github.com/libsdl-org/SDL/tree/main/src/hidapi refers to a udev example rules file that applies the uaccess tag to hidraw* for some matching vendor/product ID.

Seems Wine/Proton uses SDL2 for joystick input (https://gitlab.winehq.org/wine/wine/-/wikis/Building-Wine), so I would assume that if SDL doesn't work, Wine/Proton breaks as well. I'm not entirely certain why not having uaccess to the hidraw device for the wheel wouldn't work though, since SDL allegedly should fall back to using evdev in that case.

There's also https://github.com/Grumbel/sdl-jstest that checks the input via SDL, it's not available as a Debian package but would you mind checking that one as well? If Wine doesn't work for you, I would expect sdl2-jstest to not work either, and then we can maybe at least tie some threads together.

The T300 is detected as joystick device, maybe by the ENV{ID_INPUT_JOYSTICK} test in 70-uaccess.rules on Debian 12. The uaccess command is applied to the input device in 73-seat-late.rules.

Yeah, I guess if for example the Steam Deck doesn't have that rule, adding it explicitly grants uaccess and the provided fix works. Applying the uaccess tag twice seems to break SDL, which is kind of the weird part here. I don't know enough about udev (or possibly systemd?) internals to know what significance that might have, nor do I really understand how that ties in with SDL at the moment.

An Arch wiki like rule with SUBSYSTEM=="usb" applies to a couple of devices in the chain. Here the tag should be added to one device with driver usb, then usbhid, one up the chain is your tmff2 and above that the input subsystem.

If you mean that the rule is a bit of a shotgun approach, I suppose I can't really disagree. Not entirely certain that's the solution that'll stick, but for now I'm more in a debugging mindset and mostly just curious if it'll work at all.

@irseny
Copy link

irseny commented Dec 11, 2024

@Kimplul

There's also https://github.com/Grumbel/sdl-jstest that checks the input via SDL, it's not available as a Debian package but would you mind checking that one as well? If Wine doesn't work for you, I would expect sdl2-jstest to not work either, and then we can maybe at least tie some threads together.

Thanks for specifically mentioning sdl2-jstest. I thought I had already tested it but initially did not notice that it builds two executables. So while sdl-jstest works I can reproduce similar issues with sdl2-jstest. The device is detected

./sdl-jstest --list
Found 1 joystick(s)

Joystick Name:     'Thrustmaster Thrustmaster T300RS Racing wheel'
Joystick Number:    0
Number of Axes:     4
Number of Buttons: 13
Number of Hats:     1
Number of Balls:    0

But it does not collect any meaningful events:

 ./sdl2-jstest --event 0
Joystick Name:     'Thrustmaster T300RS Racing wheel'
Joystick GUID:     0300991c4f0400006eb6000000016800
Joystick Number:    0
Number of Axes:     6
Number of Buttons: 15
Number of Hats:     0
Number of Balls:    0
GameControllerConfig:
  missing (see 'gamecontrollerdb.txt' or SDL_GAMECONTROLLERCONFIG)

Entering joystick test loop, press Ctrl-c to exit
SDL_JOYDEVICEADDED which:0
SDL_CONTROLLERDEVICEADDED which:0
Error: Unhandled event type: 1543 <-- battery level event, value 4 (wired)

The unhandeled event looks out of place. Printing some more information with SDL it turns out to be a battery level indicator. I have not seen similar events while interacting with /dev/input/eventX before. Would that be something coming from the hidraw device? I cannot tell how to get something meaningful out of it (is it for power control?) or where the hidraw comes from in the first place. Could the creation be triggered by a udev TAG?

So I deleted the hidraw device and voila sdl2-jstest begins to receive events and wine as well.
This seems to be what caused my T300 to stop working back in #54.

The hidraw device is part of the plugdev group with read and write access, others can read too. By default it does not have ACLs. Revoking write access is enough to get a working T300 🎉

Yeah, I guess if for example the Steam Deck doesn't have that rule, adding it explicitly grants uaccess and the provided fix works. Applying the uaccess tag twice seems to break SDL, which is kind of the weird part here. I don't know enough about udev (or possibly systemd?) internals to know what significance that might have, nor do I really understand how that ties in with SDL at the moment.

I have not tried the double application yet and will try to test it in the next days.

@Kimplul
Copy link
Owner Author

Kimplul commented Dec 12, 2024

Would that be something coming from the hidraw device?

I believe so, at least based on the GUID you posted, SDL seems to think that the wheel is supported by HIDAPI, which uses hidraw. 68 in the GUID string corresponds to h in ASCII, which apparently means that HIDAPI is being used for the wheel: https://github.com/libsdl-org/SDL/blob/2635239bbcbfdc9208427e7b18a26b771a2f6ac9/src/joystick/SDL_joystick.c#L3133

I suspect that SDL is misidentifying the wheel for some other controller, and is incorrectly interpreting the HID descriptors the wheel sends out since HIDAPI should only be available for some specific controllers explicitly supported by SDL: https://github.com/libsdl-org/SDL/blob/2635239bbcbfdc9208427e7b18a26b771a2f6ac9/src/joystick/hidapi/SDL_hidapijoystick.c#L40 Don't know which one though or why, I'll look into it.

I cannot tell how to get something meaningful out of it (is it for power control?) or where the hidraw comes from in the first place. Could the creation be triggered by a udev TAG?

I suspect the battery level event is garbage as per above, and I believe hidraw devices are automatically created by the kernel for HID devices, but I'm not entirely sure.

@irseny
Copy link

irseny commented Dec 12, 2024

I believe so, at least based on the GUID you posted, SDL seems to think that the wheel is supported by HIDAPI, which uses hidraw. 68 in the GUID string corresponds to h in ASCII, which apparently means that HIDAPI is being used for the wheel

@Kimplul Yes seems so. This is the normal GUID again:
0300991c4f0400006eb6000000016800
Two bytes change when the hidraw is deleted.
0300991c4f0400006eb6000011010000

The documentation you linked indicates that hidraw will become the new default. I understand that as "independent of the specific vid:pid":

Unlike SDL2 (when it uses /dev/hidraw* which is its preferred way in 2023), xboxdrv and /dev/input/* provide incorrect values for the right stick's X axis (it's always ≤0). Probably a bug in hid-nintendo or something. For this reason xboxdrv is unusable in most games when in Switch mode.

But actually the hidraw, which is created for two other test devices (another wheel and a cheap old gamepad) is not used by SDL. This reflects in their GUIDs:

030055fa8f0e00001200000010010000
0300bbe2b70e00000600000011010000

The devices are no longer detected by sdl2-jstest when I delete the corresponding /dev/input/eventX

When I instead delete the /dev/input/eventX for the T300 and leave its hidraw in place, it is still recognized by sdl2-jstest.
So as you said, someway SDL tells itself to use hidapi on this device specifically. Unfortunately I do not have a device to test if SDL can use hidapi here successfully at all.

@Kimplul
Copy link
Owner Author

Kimplul commented Dec 19, 2024

I ended up having a busier end of semester than expected so I didn't really have time to look into this at any depth, and I'm about to leave for my winter holiday so I'll be away from my wheels for a little while. I'll pick this up after new years, if someone else wants to have a go before then feel free. Happy holidays!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants