a7d7d0f25336c25303f65643a47b6aa90ce75655
Add the CMake build for the Swift + C++ macOS port, mirroring the refix layout: deps/ modules (Platform, Flags, Sanitizers, FindUnity), per-module static libraries (usb, auth, mt76, gip, hid, api), a Swift app entry point with a pure C bridge header, and a Unity test suite behind BUILD_TESTING. Swift requires the Ninja or Xcode generator; a guard in CMakeLists.txt rejects anything else. Co-Authored-By: qwen (qwen/qwen3.8-27b@q2_k_xl): scaffolded CMake build + tests
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.cmakesrc/{usb,mt76,gip,auth,hid}— C++ protocol stack (ported frommedusalix/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 — macOS deprecated
IOUSBLib(UserClient-based) in favor ofIOUSBFamilydirect interfaces. Determine which API set is available on target macOS version (12.0+). - USB device matching — Verify
IOServiceMatching("IOUSBDevice")withkUSBVendorString/kUSBProductStringkeys works for PID0x02FE. Test with actual dongle plugged in. - Interface claiming — The dongle uses interface 1 (WLAN). Confirm
IOUSBInterfaceOpen()succeeds without conflicting with any built-in macOS driver. Check if macOS auto-loads any driver for this VID/PID combo. - Async transfer latency — The MT76 chip is timing-sensitive. Measure
ReadPipeAsync/WritePipelatency vs Linuxusb_bulk_msg. May need to tuneusleepvalues in firmware loading and register polling. - Device reconnect handling — During firmware load, the dongle disconnects and reconnects. Test that
IOServicenotification callbacks fire correctly and that re-opening the device works reliably.
2. Firmware Loading
- Firmware binary availability — Run
../xone/install/firmware.sh(or portedscripts/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 exactbmRequestType,bRequest,wValue,wIndex,wLengthvalues work viaIOUSBDeviceInterface->DeviceRequest(). - Register timing — Some register writes require delays between them. Test if
usleep()in user-space provides sufficient precision, or ifclock_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 — Decide between:
- CommonCrypto (system, zero deps) —
CCryptorCreate()for AES-CTR/CBC - Security.framework (system) —
SecKeyReffor ECDH key exchange - libcrypto/OpenSSL (Homebrew) —
EVP_*APIs, more familiar but external dep
- CommonCrypto (system, zero deps) —
- CCMP mode implementation — AES-CCMP = AES-CTR encryption + AES-CBC-MAC authentication. Neither CommonCrypto nor OpenSSL has a direct CCMP API. Need to implement the mode manually (encrypt then MIC, or verify MIC then decrypt).
- ECDH key exchange — The authentication handshake uses ECDH (P-256 curve). Test
SecKeyCreateWithData()+SecKeyCopyKeyExchangeResult()on macOS for key agreement.
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
IOHIDManagerand 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/AUOutputUnitfor headset playback andAURecordingCallback/AUInputUnitfor 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.
9. Regulatory / Legal
- 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() |
☐ Investigate |
usb_bulk_msg() |
IOUSBInterfaceInterface->WritePipe() / ReadPipe() |
☐ Investigate |
usb_submit_urb() |
ReadPipeAsync() + CFRunLoopSource |
☐ Investigate |
kzalloc / kfree |
malloc / free |
✅ Straightforward |
spin_lock_irqsave |
pthread_mutex_t or lock-free |
☐ Design |
msleep / mdelay |
usleep() / clock_nanosleep() |
☐ Test timing |
crypto_shash_* |
CommonCrypto / Security.framework | ☐ Choose backend |
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
- Plug in the dongle, run
system_profiler SPUSBDataType— confirm it's detected - Check
log show --predicate 'subsystem == "com.apple.iokit"'— see if macOS loads any driver - Write a minimal IOKit test program to open the device and read its descriptors
- Try a vendor control request (register read) to verify USB communication works
- Attempt firmware load with the binary from
firmware/directory
Description
Languages
C++
86.7%
Swift
8.3%
CMake
2.9%
C
1.5%
Shell
0.6%