Skip to content

Fix GamepadUSBHostListener::unmount() not checking dev_addr#1680

Merged
arntsonl merged 1 commit into
OpenStickCommunity:mainfrom
94xhn:fix-gamepad-usb-host-unmount-dev-addr
Jul 20, 2026
Merged

Fix GamepadUSBHostListener::unmount() not checking dev_addr#1680
arntsonl merged 1 commit into
OpenStickCommunity:mainfrom
94xhn:fix-gamepad-usb-host-unmount-dev-addr

Conversation

@94xhn

@94xhn 94xhn commented Jul 18, 2026

Copy link
Copy Markdown
Contributor

GamepadUSBHostListener::unmount() shuts down and deletes _controller_host whenever it's non-null, without ever checking that the dev_addr being unmounted is the one it's actually hosting. Every other callback in this class (report_received, set_report_complete, get_report_complete) does compare _controller_dev_addr == dev_addr before touching the host, so this one method is the odd one out.

The reason this actually bites: USBHostManager broadcasts every HID/XInput unmount callback to all registered listeners, not just the one that owns that device. If someone has both the Keyboard Host addon and the Gamepad USB Host addon enabled (e.g. a hub feeding a keyboard/mouse plus a PS4/PS5/Switch Pro controller into the same host port), unplugging the keyboard fires unmount(keyboard_dev_addr) on every listener, including GamepadUSBHostListener. Since it never checks the address, it tears down its own still-connected controller session in response to an unrelated device going away — the controller has to be physically replugged to come back.

KeyboardHostListener::unmount() already handles this correctly by comparing against its own _keyboard_dev_addr/_mouse_dev_addr, and there's precedent for this exact class of bug being fixed there before (#1177). GamepadUSBHostListener is a newer file (from the USB Host Rework in #1672) that just never got the same guard added.

Fix is one line, adding the same address check the sibling methods already use:

void GamepadUSBHostListener::unmount(uint8_t dev_addr) {
    if ( _controller_host == nullptr || _controller_dev_addr != dev_addr ) return;
    ...

I don't have the pico-sdk/arm-none-eabi toolchain set up locally to build the full firmware, so I verified this with a small native harness instead: copied the current unmount() body and the USBHostManager broadcast loop verbatim into a standalone C++ program, mounted a fake keyboard and a fake controller with different dev_addrs, then fed the keyboard's dev_addr through the same broadcast-to-all-listeners path the real firmware uses. With the current code the controller host gets destroyed even though it wasn't the device that unmounted; with the one-line fix it's left alone, and unmounting the controller's own dev_addr still tears it down correctly.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice catch! Yep that's a bug in the gamepad usb host listener, we should absolutely be looking for this,

@arntsonl
arntsonl merged commit 5fb6404 into OpenStickCommunity:main Jul 20, 2026
57 of 112 checks passed
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

Successfully merging this pull request may close these issues.

2 participants