Skip to content

Support the Bluetooth Xbox 0x02FD pad and fix Xbox tray display#6

Merged
NicolasPogorzelski merged 2 commits into
mainfrom
xbox-bt-support
Jul 15, 2026
Merged

Support the Bluetooth Xbox 0x02FD pad and fix Xbox tray display#6
NicolasPogorzelski merged 2 commits into
mainfrom
xbox-bt-support

Conversation

@NicolasPogorzelski

Copy link
Copy Markdown
Owner

Problem

A Bluetooth Xbox Wireless Controller reporting product 0x02FD paired and connected (BlueZ showed it Connected with the HID service) but produced no input device at all — no event*, js*, or hidraw*. It was invisible to the tray and to every application (tested in RetroArch). Two DualSense pads and a sibling Xbox pad (0x02E0) on the same host worked.

Root cause is below this project, in the kernel HID layer: the 0x02FD firmware advertises a truncated HID report descriptor (five COLLECTIONs opened, only three closed). hid_open_report() rejects it, so no driver binds:

unbalanced collection at end of report description
... probe with driver <x> failed with error -22

The working 0x02E0 sibling ships a well-formed 306-byte descriptor ending in … 81 02 c0; the only structural difference is the two missing END_COLLECTION bytes. This is a per-firmware bug Microsoft fixed later, but that update is only reachable via Windows / an Xbox console.

Changes

feat(install) — HID-BPF descriptor fixup. A HID_BPF_RDESC_FIXUP program (hid-bpf/) appends the two missing END_COLLECTION bytes, producing exactly the balanced descriptor the working pad already has. install.sh builds it against the running kernel's BTF and installs it via udev-hid-bpf; a missing build toolchain is a skip-with-warning so DualSense-only setups are unaffected. The program matches 0x028E (xpadneo rewrites 0x02FD → 0x028E in its probe before we attach) with 0x02FD as a fallback, scoped to Bluetooth, and guards on the exact broken descriptor so fixed-firmware pads and unrelated 0x028E devices are untouched. Full rationale in docs/decisions/xbox-02fd-hid-bpf.md.

fix(manager) — Xbox tray display. xpadneo rewrites both BT Xbox pads to 0x028E, so the old 0x028E → "Xbox 360" name mislabelled every BT Xbox pad; dropped it so they fall back to the accurate kernel name (Xbox Wireless Controller), disambiguated by player number. A single-choice family (Xbox: native only) now renders as a static disabled line instead of a lone always-checked radio; it reverts to radios automatically if a second mode is enabled.

Verification

  • Freshly power-cycled 0x02FD pad comes up unaided via the real path (xpadneo's failing probe first, then the udev rule): descriptor 308 bytes / balanced, hid-generic binds, js0 appears.
  • Full fleet live: two DualSense + 0x02E0 (xpadneo) + 0x02FD (fixed) all adopted with correct independent names; service healthy.
  • All five unit tests, shellcheck, and scripts/validate-repo.sh pass.

…ptor fixup

The Bluetooth Xbox Wireless Controller reporting product 0x02FD ships a
truncated HID report descriptor (five COLLECTIONs opened, three closed).
The kernel rejects it, so no driver binds and the pad produces no input
device at all -- invisible to the tray and to every application, while a
sibling pad reporting 0x02E0 works.

Add a HID-BPF report-descriptor fixup that appends the two missing
END_COLLECTION bytes, yielding the balanced descriptor the working pad
already has; the only content lost is the tail of one force-feedback
field the firmware had already truncated. install.sh builds it against
the running kernel's BTF and installs it via udev-hid-bpf, treating a
missing build toolchain as a skip-with-warning so DualSense-only setups
are unaffected.

The program matches product 0x028E -- xpadneo rewrites 0x02FD to 0x028E
in its probe before we are attached -- with 0x02FD as a fallback, scoped
to Bluetooth, and guards on the exact broken descriptor so pads on fixed
firmware and unrelated 0x028E devices are left alone.
xpadneo rewrites both Bluetooth Xbox pads (0x02E0 and 0x02FD) to product
0x028E, so keying a display name on 0x028E mislabelled every Bluetooth
Xbox pad as 'Xbox 360'. Drop that mapping and fall back to the accurate
kernel name ('Xbox Wireless Controller'); two such pads share a base name
and are disambiguated by player number, like identical DualSense pads.

Render a single-choice family (Xbox: native only) as a static, disabled
line instead of a lone always-checked radio that does nothing when
clicked. It reverts to per-mode radios automatically if a second mode is
ever enabled for the family. Update the multi-pad menu test accordingly.
@NicolasPogorzelski
NicolasPogorzelski merged commit 4ab764a into main Jul 15, 2026
2 checks passed
@NicolasPogorzelski
NicolasPogorzelski deleted the xbox-bt-support branch July 15, 2026 05:37
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.

1 participant