portersky 1bcb038785 fix: preserve authentication transcript order
Defer RSA, ECDH, and handshake completion until after each received packet
has been added to the authentication transcript, matching the upstream
workqueue ordering and preventing the controller from rejecting host secret.

Co-Authored-By: openai/gpt-5.6-luna: fixed GIP authentication ordering
2026-08-29 14:13:13 +02:00
2026-08-17 14:18:03 +02:00
2026-08-29 13:36:54 +02:00
2026-08-29 13:36:54 +02:00
2026-08-17 14:18:03 +02:00
2026-08-29 13:36:54 +02:00

Xbox Wireless Dongle — macOS Port

User-space macOS app for the Xbox Wireless Dongle (MediaTek MT76xx). Ports the Linux kernel driver xone/ to macOS.

See PLAN.md for full architecture and implementation phases.


Building

Requires CMake ≥ 3.21, Xcode (or Command Line Tools), and Ninja. Swift is only supported by the Ninja and Xcode generators in CMake, so configure with one of them explicitly:

cmake -S . -B build -G Ninja -DBUILD_TESTING=ON
cmake --build build
./build/xone_app
cmake --build build --target check   # run the test suite

Layout (mirrors ../refix/):

  • deps/ — CMake modules: Platform.cmake, Flags.cmake, Sanitizers.cmake, FindUnity.cmake
  • src/{usb,mt76,gip,auth,hid} — C++ protocol stack (ported from medusalix/xone)
  • src/app/ — Swift app entry point + C ABI bridge (include/app/xone_api.h)
  • tests/ — Unity test suite (BUILD_TESTING=ON)

Investigation Checklist

These items need research on macOS before implementation can begin. Strike through or check off as each is resolved.

1. IOKit USB Access

  • IOUSBLib vs IOUSBFamily — Resolved: the SDK exposes only the struct-based IOUSBDeviceInterface / IOUSBInterfaceInterface (v197/v190) via IOCreatePlugInInterfaceForService() + QueryInterface. Implemented in src/usb/usb_transport.cpp.
  • USB device matching — Class match on IOUSBDevice plus a user-space VID/PID filter on the idVendor/idProduct properties (numeric registry matching proved unreliable). Verified with a physical dongle (PID 0x02E6).
  • Interface claiming — All interfaces are opened and pipes mapped by endpoint number + direction (EP 0x04 IN/OUT, EP 0x05 IN). Verified: opens cleanly with no driver conflict.
  • Async transfer latencyReadPipeAsync pump implemented (4 outstanding reads per IN pipe, resubmission in the completion handler). Latency tuning deferred to Phase 3 firmware load.
  • Device reconnect handlingkIOTerminatedNotification with a PID filter fires on unplug and chip re-enumeration. Reliability pending hardware.

2. Firmware Loading

  • Firmware binary availability — Run ../xone/install/firmware.sh (or ported scripts/download-firmware.sh) to confirm the Windows Update CAB URLs still work and firmware hashes match.
  • Firmware load sequence — Trace the Linux xone_mt76_load_firmware() flow: control request to enter firmware mode → bulk transfer in 0x3800-byte chunks → MCU completion poll → chip reset. Map each step to IOKit equivalents.
  • Post-firmware reconnect — After firmware loads, the chip resets and re-enumerates. Verify the USB device reappears with the same VID/PID and can be re-opened.

3. MT76 Register Access

  • Vendor request format — The Linux driver uses usb_control_msg() with vendor requests (bRequest 0x84/0x86 for register R/W). Confirm the exact bmRequestType, bRequest, wValue, wIndex, wLength values work via IOUSBDeviceInterface->DeviceRequest().
  • Register timing — Some register writes require delays between them. Test if usleep() in user-space provides sufficient precision, or if clock_nanosleep() is needed.
  • EFUSE read — Verify the EFUSE read sequence returns valid MAC address, chip ID, and TX power calibration data on macOS.

4. 802.11 Frame Handling

  • Beacon construction — The Linux driver builds raw 802.11 beacon frames with a Microsoft OUI (00:50:f2) information element. Verify the frame format matches what the MT76 chip expects (may include chip-specific headers before the 802.11 frame).
  • Frame encapsulation — The MT76 chip wraps 802.11 frames in a proprietary header. Reverse-engineer or confirm the header format from Linux driver source (xone_mt76_tx() / xone_mt76_rx()).
  • QoS data frames — Controller input/output uses 802.11 QoS data frames. Verify the frame construction and AES-CCMP encryption/decryption flow.

5. AES-CCMP Encryption

  • Crypto backend choice — CommonCrypto (SHA-256/HMAC), Security.framework (RSA PKCS#1), and a self-contained P-256 ECDH (no public macOS C API for EC key agreement). Implemented in src/auth/crypto.cpp.
  • CCMP mode implementation — Not needed on the host: AES-CCMP runs on the MT76 chip; the host only installs keys via WCID registers (xone_mt76_set_client_key).
  • ECDH key exchange — P-256 implemented and validated against OpenSSL-derived test vectors (tests/test_crypto.cpp).

6. Virtual HID Gamepad

  • HID Proxy Driver feasibility — Research Apple's HID Proxy Driver (DriverKit). Can we create a virtual Xbox controller that games recognize natively?
  • IOHIDDevice user-space alternative — Can we create a virtual HID device entirely in user-space? Test with IOHIDManager and see if games (Steam, Game Center) recognize it.
  • HID report descriptor — Write an Xbox 360/One-compatible HID report descriptor. Test with existing Xbox controller (via Bluetooth) to capture the exact report format macOS expects.
  • Force feedback — Can the virtual HID device receive rumble commands from games and relay them to the controller via GIP?

7. Core Audio (Headset Support)

  • Audio Unit setup — Test creating an AURenderCallback / AUOutputUnit for headset playback and AURecordingCallback / AUInputUnit for mic input.
  • Latency requirements — The GIP protocol sends audio in 8ms intervals. Can Core Audio maintain this latency without glitches?
  • Format negotiation — The headset negotiates audio format (sample rate, channels) via GIP. Map GIP audio formats to Core Audio AudioStreamBasicDescription.

8. Build System

  • CMake vs Xcode — CMake is simpler for the C library portions, but Xcode is needed for the macOS app bundle and any DriverKit extension. Decide on primary build system.
  • Minimum macOS version — Target 12.0 (Monterey) for modern IOKit/DriverKit. Verify all APIs are available.
  • Code signing — IOKit USB access may require specific entitlements (com.apple.kpi.iokit, com.apple.security.device.usb). DriverKit requires notarization. Plan for development vs distribution signing.
  • 5GHz channel restrictions — macOS enforces regulatory domain for 5GHz. The dongle may try to use channels blocked in the current region. May need to limit to 2.4GHz only or find a way to override.
  • Firmware license — The firmware binaries are from Microsoft Windows Update. Confirm they can be redistributed with the macOS port (the Linux driver includes them with a disclaimer).

10. Testing Hardware

  • Dongle — Xbox Wireless Dongle (PID 0x02FE preferred, 0x02E6 also works)
  • Controller — Xbox One or Series X|S controller (for pairing and input testing)
  • Headset — Xbox Wireless Headset (optional, for audio testing)
  • macOS machine — Intel or Apple Silicon (test both if possible, IOKit may differ)

Quick Reference

Linux API macOS Replacement Status
usb_control_msg() IOUSBDeviceInterface->DeviceRequest() Done (send_vendor_request)
usb_bulk_msg() WritePipe() / ReadPipeAsync() Done (bulk_write, reader thread)
usb_submit_urb() ReadPipeAsync() + CFRunLoopSource Done (reader thread)
kzalloc / kfree malloc / free Straightforward
spin_lock_irqsave std::mutex / std::condition_variable Done (usb_transport.cpp)
msleep / mdelay usleep() / clock_nanosleep() ☐ Test timing
crypto_shash_* CommonCrypto / Security.framework Done (auth/crypto.cpp)
input_register_device() HID Proxy Driver / IOHIDSystem ☐ Investigate
snd_pcm_* Core Audio (Audio Units) ☐ Investigate
request_firmware() File I/O (fopen/fread) Straightforward
cfg80211_* Nothing (no regulatory reporting) Remove
bus_register() Custom client management Redesign
device_create() / sysfs Nothing (no sysfs) Remove

First Steps on macOS

  1. Plug in the dongle, run system_profiler SPUSBDataType — confirm it's detected
  2. Check log show --predicate 'subsystem == "com.apple.iokit"' — see if macOS loads any driver
  3. Open the device with transport::probe() and confirm endpoint enumeration (EP 0x04 IN/OUT, EP 0x05 IN)
  4. Try a vendor control request (register read) to verify USB communication works
  5. Attempt firmware load with the binary from firmware/ directory
S
Description
No description provided
Readme 648 KiB
Languages
C++ 86.7%
Swift 8.3%
CMake 2.9%
C 1.5%
Shell 0.6%