atar-axis / xpadneo

Advanced Linux Driver for Xbox One Wireless Controller (shipped with Xbox One S)
https://atar-axis.github.io/xpadneo/
GNU General Public License v3.0
2.01k stars 113 forks source link

Xbox Series 2 Controller input stops during rumble if attenuation isn't disabled #243

Closed schmitmd closed 3 years ago

schmitmd commented 4 years ago

Version of xpadneo

Latest master branch, commit 041e8d8cc9a1ec3184a12fe057b8d7d568e72f23

Severity / Impact

The controller is essentially unusable if the workaround is not employed.

Describe the bug

After game startup, if rumble is encountered, the controller stops responding and often gets "stuck" sending the same input as whatever was last pressed.

Steps to Reproduce

With an Xbox Elite Series 2 controller bound via Bluetooth (no USB dongle in my case), begin any game and play for a minute or two until the controller rumbles, most noticeably while holding the left trigger. New input will cease to work and there will often be a continuation of whatever the last controller state was (i.e. if you were holding the left trigger, the input will seem as though you never let go).

Expected behavior

The controller rumbles and continues with normal game input.

Screenshots/Gifs

System information

Linux myhost 5.8.7-arch1-1 #1 SMP PREEMPT Sat, 05 Sep 2020 12:31:32 +0000 x86_64 GNU/Linux

Link to output of xxd -c20 -g1 /sys/module/hid_xpadneo/drivers/hid:xpadneo/0005:045E:*/report_descriptor | tee >(cksum)

Controller and Bluetooth information

Link to output of sudo btmon | tee xpadneo-btmon.txt

Link to output of dmesg | egrep -i 'hid|input|xpadneo' | tee xpadneo-dmesg.txt

There is no USB dongle involved, the pairing is via Bluetooth connection to the laptop's 8087:0aaa Intel Corp. Bluetooth 9460/9560 Jefferson Peak (JfP) Bluetooth chip.

Additional context

Issue created per instructions in https://github.com/atar-axis/xpadneo/pull/144#issuecomment-688076456 @kakra , I tried values 10L, 20L, 30L, 50L, (and even 100L, just in case) for XPADNEO_RUMBLE_THROTTLE_DELAY as instructed, but saw no discernible change in behavior. The workaround below, however is 100% reproducible, as far as I can tell. I would really like to be as helpful as I can in this and hope that the information herein is useful. Please let me know if there's anything I can do to provide more, or if I should test a branch/commit & report my findings. I can do a short screencast if you think it'd be helpful, but I'm imagining that logging output will be more so. Thank you so much for this project!!!

Workaround

The workaround to fix this behavior is to set the rumble attenuation to 100 either by using the configure.sh script, or running echo "100,0"|sudo tee /sys/module/hid_xpadneo/parameters/rumble_attenuation

kakra commented 4 years ago

I wonder if XBS2 controller needs other timings but as you pointed out in the additional context, that seems to make no difference. I'd probably need such a controller myself to figure this out - or maybe @medusalix from the xow project has some ideas.

kakra commented 4 years ago

From my tests, this controller seems to crash its firmware, then reboots into a safe mode with rumble completely disabled (unless you manually turn it off and back on instead of waiting for auto-reconnect).

Some more ideas, please use current master for it:

What happens if you attenuate the triggers by some percentage instead of using 100%? E.g., we could try rumble_attenuation=0:50 to make the triggers expose only 50% strength (while the main motors stay at 100% strength aka 0% attenuation). If it still occurs, does rumble_attenuation=0,100 work around this problem?

You reported 100,0 as a work-around which would disable rumble of the main motors, too: The values are cumulative: The first attenuation value reduces rumble strength globally while the second value is applied to the triggers only after the global attenuation. So 100,0 effectively disables all rumble motors, while 0,100 only disables the trigger motors. A value of 50,50 would reduce rumble strength to 50% with the triggers getting another 50% (effectively reducing them to 25% strength, or 75% attenuated).

Also, if this problem is only triggered by the triggers (yeah, funny), another work-around should be to use trigger_rumble_mode=2 which sets the triggers to 0 strength, effectively setting the motor programming bits to always 0 for those two.

The internal protocol seems to work like this: The rumble protocol defines 4 bits, one for each motor. It also has 4 fields, one per each motor, that defines strength, pulse intervals, and loop count per motor. If a bit is set, that sets the parameters for a motor, otherwise that motor is left untouched (no matter the parameters). That also means, if we don't set a bit, that motor continues to play the effect it was programmed with before. So each motor seems to be a separate thread in the firmware running independent from the others. That's open to racing bugs... Thus, I already implemented NOT reprogramming all motors every time: When the rumble parameters didn't change, I just clear the bit to leave that motor alone. This already improved things but the final fix was keeping reprogramming intervals above 10ms (which is also the resolution of the pulse parameters in a rumble packet). This is quite obviously a race condition in the firmware.

I'm still not sure what we can learn from this for the trigger rumble and why it is so problematic for the XBE2 model.

For the XB1S, the rumble programming seems to be fixed. It still experiences disconnects, tho. But I attribute that to the Bluetooth stack itself, not related to rumble programming. But I'm not 100% sure, we may still miss some work-around, and maybe XBE2 is specifically susceptible to it because it removed this HID spamming behavior.

Or maybe MS just wants to keep their secrets to make life of open source developers more headache-prone. But that is very speculative... It also makes no sense, as making open source driver programming easy creates them another source of profit because they could sell Xbox controllers to Linux users, too (even without bothering about making their own driver). And the protocol format itself is really not such a secret as the GIP API more or less reflects that byte by byte. Otherwise, all those clones (e.g., 8BitDo) would not exist - which are more a profit threat.

kakra commented 4 years ago

I tested Borderlands 3: The controller immediately crashes when rumble is played - no matter if the triggers are involved. So we're seeing a different bug maybe. It is also possible that it bypassed the driver using raw HID mode of SDL2, I'll have to test it: Rumble work-arounds in SDL2 are incomplete. Also, the observed behavior was very different: The controller didn't disconnect at all, Bluetooth was still connected. It just didn't report any input at all any longer. Something is crashing the controller very hard here. If the issue comes from SDL2 raw mode, it can be resolved by removing this line from /etc/udev/rules.d/98-xpadneo.rules:

ACTION=="add", DRIVERS=="xpadneo", SUBSYSTEM=="input", TAG+="uaccess", MODE="0664", ENV{LIBINPUT_IGNORE_DEVICE}="1"

Run sudo udevadm control -R and reconnect the controller to apply.

From this observation, I suspect that our rumble code isn't even involved which would also explain why @schmitmd didn't see a difference adjusting the timing values: At least the rumble timing should've become very laggy when increasing the value but I didn't explicitly ask for it.

@schmitmd When the problem occurs, do you see the following message in dmesg?

[12954.423138] xpadneo 0005:045E:0B05.0018: throttling rumble reprogramming

This warning will trigger once per module load when a game sends rumble commands too fast. This ("once") means you'll have to try from a fresh reboot or rmmod hid-xpadneo before turning the controller on. Then start the game and see if this message appears. If it doesn't, our work-around does not kick in and something is bypassing the driver for rumble programming which is most likely a recent SDL2 version (which may come with Steam itself as part of the Steam Runtime).

kakra commented 3 years ago

This is not a Linux specific bug, it also happens in Windows when connect the controller via Bluetooth. Closing in favor of #247 as that includes some important links already.

kakra commented 3 years ago

Closing as duplicate of #272.