docs: bring PLAN.md in line with style guide

Replace em dashes with colons throughout, wrap prose and list lines at
80 columns (Goal, Phase 4 options, Known Challenges), refresh the
current status section now that pairing and the RX data path are done,
and add src/cli to the directory layout. Table alignment was also
normalized as a side effect of the file rewrite.

Co-Authored-By: qwen3.8-27b@q3_k_xl: reformatted PLAN.md per style guide
This commit is contained in:
portersky
2026-08-29 14:30:02 +02:00
parent 51192023aa
commit 1bca6048a5
+68 -56
View File
@@ -1,8 +1,9 @@
# Xbox Wireless Dongle macOS Port # Xbox Wireless Dongle: macOS Port
## Goal ## Goal
User-space macOS app that speaks to the Xbox Wireless Dongle (MT76xx chip) and exposes connected controllers as HID gamepads. User-space macOS app that speaks to the Xbox Wireless Dongle (MT76xx chip)
and exposes connected controllers as HID gamepads.
## Architecture ## Architecture
@@ -15,12 +16,12 @@ User-space macOS app that speaks to the Xbox Wireless Dongle (MT76xx chip) and e
│ │ │ │ │ │ │ │
│ ┌────▼──────────────▼──────────────────────┐ │ │ ┌────▼──────────────▼──────────────────────┐ │
│ │ GIP Protocol Layer │ │ │ │ GIP Protocol Layer │ │
│ │ (bus/protocol.c ported, pure C) │ │ │ │ (bus/protocol.c: ported, pure C) │ │
│ └──────────────────┬───────────────────────┘ │ │ └──────────────────┬───────────────────────┘ │
│ │ │ │ │ │
│ ┌──────────────────▼───────────────────────┐ │ │ ┌──────────────────▼───────────────────────┐ │
│ │ MT76 Chip Protocol Layer │ │ │ │ MT76 Chip Protocol Layer │ │
│ │ (transport/mt76.c ported, USB calls) │ │ │ │ (transport/mt76.c: ported, USB calls) │ │
│ └──────────────────┬───────────────────────┘ │ │ └──────────────────┬───────────────────────┘ │
│ │ │ │ │ │
│ ┌──────────────────▼───────────────────────┐ │ │ ┌──────────────────▼───────────────────────┐ │
@@ -40,18 +41,17 @@ User-space macOS app that speaks to the Xbox Wireless Dongle (MT76xx chip) and e
- Phase 1 (GIP + auth): ported and unit-tested. - Phase 1 (GIP + auth): ported and unit-tested.
- Phase 2 (USB transport): probe/open, async read pump, vendor requests, - Phase 2 (USB transport): probe/open, async read pump, vendor requests,
bulk write. Verified on hardware. bulk write. Verified on hardware.
- Phase 3 (MT76 chip): register/EFUSE access, firmware load, - Phase 3 (MT76 chip): register/EFUSE access, firmware load, radio init
radio init (registers, crystal, MAC/BSSID, channel eval, beacon). Verified (registers, crystal, MAC/BSSID, channel eval, beacon), pairing mode,
end-to-end: `radio-init` completes, beacon TX enabled, FCE shows firmware controller association, GIP handshake + auth. Verified end-to-end on
running. hardware: live controller input is shown in the app (RX data path).
- C API + Swift app: async session (fast probe; firmware + radio on a worker - C API + Swift app: async session (fast probe; firmware + radio on a worker
thread), state display (idle/starting/ready/error). thread), state display (idle/starting/ready/error), controller list with
live input monitor.
Remaining for Phase 3: controller association and the data path (design below). Remaining for Phase 3: host to controller TX over the data path (rumble,
Then Phase 4 (HID) and Phase 5 (app polish). LED). Then Phase 4 (HID) and Phase 5 (app polish); exposing the controller
as a macOS HID gamepad is the main user-visible gap.
**Immediate goal:** pair a controller and show it in the GUI. Exposing it as
a macOS HID device is deferred.
## Directory Layout ## Directory Layout
@@ -64,6 +64,7 @@ macos/
│ ├── gip/ ← GIP protocol (port from bus/protocol.c) │ ├── gip/ ← GIP protocol (port from bus/protocol.c)
│ ├── auth/ ← Auth + crypto (port from auth/) │ ├── auth/ ← Auth + crypto (port from auth/)
│ ├── hid/ ← Virtual HID gamepad (new) │ ├── hid/ ← Virtual HID gamepad (new)
│ ├── cli/ ← C++ CLI for manual protocol sequences
│ └── app/ ← macOS app entry point + UI (new) │ └── app/ ← macOS app entry point + UI (new)
├── include/ ├── include/
│ ├── common/ ← Shared types, platform abstraction │ ├── common/ ← Shared types, platform abstraction
@@ -80,7 +81,7 @@ macos/
## Implementation Phases ## Implementation Phases
### Phase 1 Foundation (Linux → C library) ### Phase 1: Foundation (Linux → C library)
Extract the protocol logic from Linux kernel code into standalone C. Extract the protocol logic from Linux kernel code into standalone C.
@@ -104,7 +105,7 @@ Extract the protocol logic from Linux kernel code into standalone C.
- Endianness helpers - Endianness helpers
- Memory allocator abstraction (so we can swap malloc if needed) - Memory allocator abstraction (so we can swap malloc if needed)
### Phase 2 USB Transport (new) ### Phase 2: USB Transport (new)
**src/usb/** **src/usb/**
@@ -112,28 +113,29 @@ Extract the protocol logic from Linux kernel code into standalone C.
- Open device, claim interface (bInterfaceNumber = 1) - Open device, claim interface (bInterfaceNumber = 1)
- `IOUSBDevInterface` for control transfers (vendor requests) - `IOUSBDevInterface` for control transfers (vendor requests)
- `IOUSBInterfaceInterface` for bulk endpoints: - `IOUSBInterfaceInterface` for bulk endpoints:
- EP 0x04 IN WLAN data (802.11 frames from controllers) - EP 0x04 IN: WLAN data (802.11 frames from controllers)
- EP 0x04 OUT Bulk out (commands to chip) - EP 0x04 OUT: Bulk out (commands to chip)
- EP 0x05 IN MCU commands (firmware load responses) - EP 0x05 IN: MCU commands (firmware load responses)
- Async completion callbacks → callback/dispatch queue - Async completion callbacks → callback/dispatch queue
- Device disconnect handling (chip reconnects during firmware load) - Device disconnect handling (chip reconnects during firmware load)
**Key IOKit APIs:** **Key IOKit APIs:**
- `IOServiceMatching("IOUSBDevice")` find dongle - `IOServiceMatching("IOUSBDevice")`: find dongle
- `IOUSBDeviceOpen` / `IOUSBInterfaceOpen` claim - `IOUSBDeviceOpen` / `IOUSBInterfaceOpen`: claim
- `DeviceRequest` control transfers (register R/W) - `DeviceRequest`: control transfers (register R/W)
- `WritePipe` / `ReadPipe` bulk transfers - `WritePipe` / `ReadPipe`: bulk transfers
- `CreateInterruptEndpoint` for EP 0x05 (MCU) - `CreateInterruptEndpoint`: for EP 0x05 (MCU)
### Phase 3 MT76 Chip Protocol (port) ### Phase 3: MT76 Chip Protocol (port)
**src/mt76/** **src/mt76/**
- Port `transport/mt76.c` → replace USB calls with Phase 2 transport - Port `transport/mt76.c` → replace USB calls with Phase 2 transport
- **Firmware loading:** send binary in 0x3800-byte chunks, poll for completion - **Firmware loading:** send binary in 0x3800-byte chunks, poll for completion
- **EFUSE read:** MAC address, chip ID, crystal trim, TX power calibration - **EFUSE read:** MAC address, chip ID, crystal trim, TX power calibration
- **Radio init:** ~80 hardcoded register writes (AGC, EDCA, TX power, protection) - **Radio init:** ~80 hardcoded register writes (AGC, EDCA, TX power,
protection)
- **Channel evaluation:** cycle through 12 channels, pick highest power - **Channel evaluation:** cycle through 12 channels, pick highest power
- **Beacon transmission:** 802.11 beacons with Microsoft OUI IE - **Beacon transmission:** 802.11 beacons with Microsoft OUI IE
- **Pairing mode:** rotate channels every 2s when pairing enabled - **Pairing mode:** rotate channels every 2s when pairing enabled
@@ -149,20 +151,23 @@ Extract the protocol logic from Linux kernel code into standalone C.
- `ieee80211_*` → custom 802.11 frame builders - `ieee80211_*` → custom 802.11 frame builders
- `cfg80211_*` → nothing (no regulatory domain reporting needed) - `cfg80211_*` → nothing (no regulatory domain reporting needed)
### Phase 4 Virtual HID Gamepad (new) ### Phase 4: Virtual HID Gamepad (new)
**src/hid/** **src/hid/**
- Expose controller as macOS HID device so games work natively - Expose controller as macOS HID device so games work natively
- Options: - Options:
- **HID Proxy Driver (DriverKit)** Maps USB device to virtual HID. Minimal kernel code. Preferred approach. - **HID Proxy Driver (DriverKit)**: Maps USB device to virtual HID.
- **IOHIDSystem user-space** — Create virtual HID device entirely in user-space. May not work for all games. Minimal kernel code. Preferred approach.
- **Gamepad wrapper** — Lower-level, translate input events to HID reports. - **IOHIDSystem user-space**: Create virtual HID device entirely in
- Map Xbox controller buttons/sticks/triggers to standard Xbox 360/One HID report descriptor user-space. May not work for all games.
- Handle force feedback (rumble) — send back to dongle via GIP - **Gamepad wrapper**: Lower-level, translate input events to HID reports.
- Map Xbox controller buttons/sticks/triggers to standard Xbox 360/One HID
report descriptor
- Handle force feedback (rumble): send back to dongle via GIP
- Battery status reporting - Battery status reporting
### Phase 5 macOS App (new) ### Phase 5: macOS App (new)
**src/app/** **src/app/**
@@ -282,46 +287,53 @@ on first packet, so a fresh adapter yields its single client on demand.
Firmware binaries are downloaded from Microsoft Windows Update driver catalog: Firmware binaries are downloaded from Microsoft Windows Update driver catalog:
| PID | Dongle Type | Firmware File | | PID | Dongle Type | Firmware File |
| ---- | ---------------------- | ------------- | | --- | ----------------- | -------------- |
| all | Supported dongles | xow_dongle.bin | | all | Supported dongles | xow_dongle.bin |
Downloaded via `scripts/download-firmware.sh` (port of `install/firmware.sh`). Downloaded via `scripts/download-firmware.sh` (port of `install/firmware.sh`).
## Known Challenges ## Known Challenges
1. **USB timing** MT76 is timing-sensitive. User-space USB on macOS may have different latency than Linux kernel URBs. May need careful tuning of `usleep` values. 1. **USB timing**: MT76 is timing-sensitive. User-space USB on macOS may
have different latency than Linux kernel URBs. May need careful tuning
of `usleep` values.
2. **Chip reconnect** During firmware load, the dongle disconnects and reconnects. IOKit needs to handle this gracefully (close, wait, reopen, re-claim). 2. **Chip reconnect**: During firmware load, the dongle disconnects and
reconnects. IOKit needs to handle this gracefully (close, wait, reopen,
re-claim).
3. **Virtual HID** Games expect a real HID device. HID Proxy Driver (DriverKit) is the cleanest path but requires a minimal kernel extension. 3. **Virtual HID**: Games expect a real HID device. HID Proxy Driver
(DriverKit) is the cleanest path but requires a minimal kernel extension.
4. **5GHz regulatory** The dongle uses 5GHz channels. macOS may have regulatory restrictions. May need to limit to 2.4GHz only. 4. **5GHz regulatory**: The dongle uses 5GHz channels. macOS may have
regulatory restrictions. May need to limit to 2.4GHz only.
5. **Audio** Headset audio is complex (real-time PCM streaming). Lower priority, tackle after gamepad works. 5. **Audio**: Headset audio is complex (real-time PCM streaming). Lower
priority, tackle after gamepad works.
## Source Files to Port ## Source Files to Port
| Linux source | Target | Notes | | Linux source | Target | Notes |
| ----------------------- | -------------------------- | ---------------------------------- | | ----------------------- | ---------------------------- | ---------------------------------- |
| `transport/mt76.c` | `src/mt76/mt76.c` | Replace USB calls, remove cfg80211 | | `transport/mt76.c` | `src/mt76/mt76.c` | Replace USB calls, remove cfg80211 |
| `transport/mt76.h` | `include/mt76/mt76.hpp` | Clean up kernel types | | `transport/mt76.h` | `include/mt76/mt76.hpp` | Clean up kernel types |
| `transport/mt76_defs.h` | `include/mt76/mt76_defs.hpp` | Mostly copy (register defs) | | `transport/mt76_defs.h` | `include/mt76/mt76_defs.hpp` | Mostly copy (register defs) |
| `bus/protocol.c` | `src/gip/protocol.c` | Replace kernel alloc/lock/debug | | `bus/protocol.c` | `src/gip/protocol.c` | Replace kernel alloc/lock/debug |
| `bus/protocol.h` | `include/gip/protocol.hpp` | Clean up kernel types | | `bus/protocol.h` | `include/gip/protocol.hpp` | Clean up kernel types |
| `bus/bus.c` | `src/gip/bus.c` | Client lifecycle management | | `bus/bus.c` | `src/gip/bus.c` | Client lifecycle management |
| `auth/auth.c` | `src/auth/auth.c` | Pure crypto, mostly copy | | `auth/auth.c` | `src/auth/auth.c` | Pure crypto, mostly copy |
| `auth/auth.h` | `include/auth/auth.hpp` | Copy | | `auth/auth.h` | `include/auth/auth.hpp` | Copy |
| `auth/crypto.c` | `src/auth/crypto.cpp` | AES-CCMP, mostly copy | | `auth/crypto.c` | `src/auth/crypto.cpp` | AES-CCMP, mostly copy |
| `auth/crypto.h` | `include/auth/crypto.hpp` | Copy | | `auth/crypto.h` | `include/auth/crypto.hpp` | Copy |
| `driver/gamepad.c` | N/A | Replaced by HID layer | | `driver/gamepad.c` | N/A | Replaced by HID layer |
## Build System ## Build System
- **CMake** or **Xcode project** either works - **CMake** or **Xcode project**: either works
- Static library for protocol/auth layers - Static library for protocol/auth layers
- macOS app bundle for the final product - macOS app bundle for the final product
- Minimum macOS: 12.0 (Monterey) for modern IOKit/DriverKit support - Minimum macOS: 12.0 (Monterey): for modern IOKit/DriverKit support
## Dependencies ## Dependencies