[PR #212] [MERGED] Add Original Xbox (Controller S) mode #243

Closed
opened 2026-10-22 05:08:08 +00:00 by roman · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/safijari/openpuck/pull/212
Author: @xbb
Created: 8/3/2026
Status: ✅ Merged
Merged: 8/21/2026
Merged by: @safijari

Base: main ← Head: feat/og-xbox-mode


📝 Commits (5)

  • aa5244f Centralize custom USB class-driver registration
  • 789f37e Add Original Xbox (Controller S) mode
  • 0f3ddf4 Add Original Xbox mode to the config panel and README
  • 1914e37 Add Original Xbox mode subsection in PROTOCOL.md
  • 3364f55 Merge main into feat/og-xbox-mode

📊 Changes

16 files changed (+914 additions, -29 deletions)

View changed files

📝 Makefile (+8 -2)
📝 OpenPuck/OpenPuck.ino (+15 -14)
📝 OpenPuck/config.h (+5 -1)
📝 OpenPuck/controllers.cpp (+3 -0)
➕ OpenPuck/mode_xbox_og.cpp (+804 -0)
➕ OpenPuck/mode_xbox_og.h (+15 -0)
📝 OpenPuck/mode_xinput.cpp (+2 -6)
📝 OpenPuck/serial_console.cpp (+1 -1)
➕ OpenPuck/usb_app_drivers.cpp (+12 -0)
➕ OpenPuck/usb_app_drivers.h (+9 -0)
📝 OpenPuck/usb_tx.h (+1 -0)
📝 OpenPuck/webusb_config.cpp (+20 -0)
📝 README.md (+2 -1)
📝 docs/BUILD_AND_DEPLOY.md (+1 -1)
📝 docs/PROTOCOL.md (+12 -0)
📝 docs/index.html (+4 -3)

📄 Description

Implements Original Xbox mode in mode_xbox_og.{cpp,h} as mode 10: the puck presents itself as a Controller S, with rumble. It reuses the existing Xbox mapping tab, reporting LB/RB as the console's White and Black buttons. It is selectable from the WebUSB panel and it keeps the wake mouse and the WebUSB interface, so the panel stays reachable while the mode is active.

Before accepting a controller, the console sends three XID requests over the control endpoint. These are vendor-type control requests, all of which TinyUSB routes to a single global callback that the Adafruit core already defines for WebUSB. A sketch can replace that callback wholesale, but it cannot extend it. If the requests are stalled, the console rejects the controller.
The build therefore links with -Wl,--wrap=tud_vendor_control_xfer_cb, causing the linker to route every call through a wrapper. The wrapper handles XID requests while this mode is active and delegates everything else to the original callback, preserving WebUSB support. The flag is included in both build recipes and in the arduino-cli command in docs/BUILD_AND_DEPLOY.md; omitting it causes the build to fail at link time.

The same single-global constraint applies to TinyUSB's other application hook. XInput already uses usbd_app_driver_get_cb for its interface driver, and the new Original Xbox XID mode needs the same hook. Because the hook is a single global returning one driver table, it moves to a small shared usb_app_drivers.cpp that returns both drivers. The XID driver is registered in every mode, but it only claims a 0x58/0x42 interface, which no other mode exposes, so existing behavior is unchanged.

Tested on an Original Xbox: it enumerates, and buttons, sticks and rumble work in game. Switching out of the mode while plugged into the console is clean.
While testing on the console, switching away from PS3 mode leaves the puck unresponsive and powers off the connected controller after a short delay. Replugging the puck only recovers it if another mode switch is performed immediately. This is not caused by the new mode; it also reproduces without this change.

LLM-assisted implementation.


🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/safijari/openpuck/pull/212 **Author:** [@xbb](https://github.com/xbb) **Created:** 8/3/2026 **Status:** ✅ Merged **Merged:** 8/21/2026 **Merged by:** [@safijari](https://github.com/safijari) **Base:** `main` ← **Head:** `feat/og-xbox-mode` --- ### 📝 Commits (5) - [`aa5244f`](https://github.com/safijari/openpuck/commit/aa5244f6733039a29e3a4ae239fd6a1b8f38ecb1) Centralize custom USB class-driver registration - [`789f37e`](https://github.com/safijari/openpuck/commit/789f37ecc4142ef41b4455bcaf88d99abf78c4be) Add Original Xbox (Controller S) mode - [`0f3ddf4`](https://github.com/safijari/openpuck/commit/0f3ddf4f16605c3542285139c122f18431854e4a) Add Original Xbox mode to the config panel and README - [`1914e37`](https://github.com/safijari/openpuck/commit/1914e3704538cb36d96354d893ec342a2a691f87) Add Original Xbox mode subsection in PROTOCOL.md - [`3364f55`](https://github.com/safijari/openpuck/commit/3364f55205e5bacbf1224a50881a5c3eccac5d3f) Merge main into feat/og-xbox-mode ### 📊 Changes **16 files changed** (+914 additions, -29 deletions) <details> <summary>View changed files</summary> 📝 `Makefile` (+8 -2) 📝 `OpenPuck/OpenPuck.ino` (+15 -14) 📝 `OpenPuck/config.h` (+5 -1) 📝 `OpenPuck/controllers.cpp` (+3 -0) ➕ `OpenPuck/mode_xbox_og.cpp` (+804 -0) ➕ `OpenPuck/mode_xbox_og.h` (+15 -0) 📝 `OpenPuck/mode_xinput.cpp` (+2 -6) 📝 `OpenPuck/serial_console.cpp` (+1 -1) ➕ `OpenPuck/usb_app_drivers.cpp` (+12 -0) ➕ `OpenPuck/usb_app_drivers.h` (+9 -0) 📝 `OpenPuck/usb_tx.h` (+1 -0) 📝 `OpenPuck/webusb_config.cpp` (+20 -0) 📝 `README.md` (+2 -1) 📝 `docs/BUILD_AND_DEPLOY.md` (+1 -1) 📝 `docs/PROTOCOL.md` (+12 -0) 📝 `docs/index.html` (+4 -3) </details> ### 📄 Description Implements Original Xbox mode in `mode_xbox_og.{cpp,h}` as `mode 10`: the puck presents itself as a _Controller S_, with rumble. It reuses the existing Xbox mapping tab, reporting LB/RB as the console's White and Black buttons. It is selectable from the WebUSB panel and it keeps the wake mouse and the WebUSB interface, so the panel stays reachable while the mode is active. Before accepting a controller, the console sends three XID requests over the control endpoint. These are vendor-type control requests, all of which TinyUSB routes to a single global callback that the Adafruit core already defines for WebUSB. A sketch can replace that callback wholesale, but it cannot extend it. If the requests are stalled, the console rejects the controller. The build therefore links with `-Wl,--wrap=tud_vendor_control_xfer_cb`, causing the linker to route every call through a wrapper. The wrapper handles XID requests while this mode is active and delegates everything else to the original callback, preserving WebUSB support. The flag is included in both build recipes and in the `arduino-cli` command in `docs/BUILD_AND_DEPLOY.md`; omitting it causes the build to fail at link time. The same single-global constraint applies to TinyUSB's other application hook. XInput already uses `usbd_app_driver_get_cb` for its interface driver, and the new Original Xbox XID mode needs the same hook. Because the hook is a single global returning one driver table, it moves to a small shared `usb_app_drivers.cpp` that returns both drivers. The XID driver is registered in every mode, but it only claims a `0x58`/`0x42` interface, which no other mode exposes, so existing behavior is unchanged. Tested on an Original Xbox: it enumerates, and buttons, sticks and rumble work in game. Switching out of the mode while plugged into the console is clean. While testing on the console, switching away from PS3 mode leaves the puck unresponsive and powers off the connected controller after a short delay. Replugging the puck only recovers it if another mode switch is performed immediately. This is not caused by the new mode; it also reproduces without this change. LLM-assisted implementation. --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
roman 2026-10-22 05:08:08 +00:00
Sign in to join this conversation.
No labels
pull-request
wontfix
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
safijari/openpuck#243
No description provided.