a7d7d0f253
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
132 lines
8.7 KiB
Markdown
132 lines
8.7 KiB
Markdown
# Xbox Wireless Dongle — macOS Port
|
|
|
|
User-space macOS app for the Xbox Wireless Dongle (MediaTek MT76xx).
|
|
Ports the Linux kernel driver [`xone/`](../xone/) to macOS.
|
|
|
|
See [PLAN.md](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:
|
|
|
|
```sh
|
|
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** — macOS deprecated `IOUSBLib` (UserClient-based) in favor of `IOUSBFamily` direct interfaces. Determine which API set is available on target macOS version (12.0+).
|
|
- [ ] **USB device matching** — Verify `IOServiceMatching("IOUSBDevice")` with `kUSBVendorString`/`kUSBProductString` keys works for PID `0x02FE`. 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`/`WritePipe` latency vs Linux `usb_bulk_msg`. May need to tune `usleep` values in firmware loading and register polling.
|
|
- [ ] **Device reconnect handling** — During firmware load, the dongle disconnects and reconnects. Test that `IOService` notification callbacks fire correctly and that re-opening the device works reliably.
|
|
|
|
### 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** — Decide between:
|
|
- **CommonCrypto** (system, zero deps) — `CCryptorCreate()` for AES-CTR/CBC
|
|
- **Security.framework** (system) — `SecKeyRef` for ECDH key exchange
|
|
- **libcrypto/OpenSSL** (Homebrew) — `EVP_*` APIs, more familiar but external dep
|
|
- [ ] **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](https://developer.apple.com/documentation/coreaudio/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.
|
|
|
|
### 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
|
|
|
|
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. Write a minimal IOKit test program to open the device and read its descriptors
|
|
4. Try a vendor control request (register read) to verify USB communication works
|
|
5. Attempt firmware load with the binary from `firmware/` directory
|