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
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
@@ -15,12 +16,12 @@ User-space macOS app that speaks to the Xbox Wireless Dongle (MT76xx chip) and e
│ │ │ │
│ ┌────▼──────────────▼──────────────────────┐ │
│ │ GIP Protocol Layer │ │
│ │ (bus/protocol.c ported, pure C) │ │
│ │ (bus/protocol.c: ported, pure C) │ │
│ └──────────────────┬───────────────────────┘ │
│ │ │
│ ┌──────────────────▼───────────────────────┐ │
│ │ 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 2 (USB transport): probe/open, async read pump, vendor requests,
bulk write. Verified on hardware.
- Phase 3 (MT76 chip): register/EFUSE access, firmware load,
radio init (registers, crystal, MAC/BSSID, channel eval, beacon). Verified
end-to-end: `radio-init` completes, beacon TX enabled, FCE shows firmware
running.
- Phase 3 (MT76 chip): register/EFUSE access, firmware load, radio init
(registers, crystal, MAC/BSSID, channel eval, beacon), pairing mode,
controller association, GIP handshake + auth. Verified end-to-end on
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
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).
Then Phase 4 (HID) and Phase 5 (app polish).
**Immediate goal:** pair a controller and show it in the GUI. Exposing it as
a macOS HID device is deferred.
Remaining for Phase 3: host to controller TX over the data path (rumble,
LED). Then Phase 4 (HID) and Phase 5 (app polish); exposing the controller
as a macOS HID gamepad is the main user-visible gap.
## Directory Layout
@@ -64,6 +64,7 @@ macos/
│ ├── gip/ ← GIP protocol (port from bus/protocol.c)
│ ├── auth/ ← Auth + crypto (port from auth/)
│ ├── hid/ ← Virtual HID gamepad (new)
│ ├── cli/ ← C++ CLI for manual protocol sequences
│ └── app/ ← macOS app entry point + UI (new)
├── include/
│ ├── common/ ← Shared types, platform abstraction
@@ -80,7 +81,7 @@ macos/
## 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.
@@ -104,7 +105,7 @@ Extract the protocol logic from Linux kernel code into standalone C.
- Endianness helpers
- Memory allocator abstraction (so we can swap malloc if needed)
### Phase 2 USB Transport (new)
### Phase 2: USB Transport (new)
**src/usb/**
@@ -112,28 +113,29 @@ Extract the protocol logic from Linux kernel code into standalone C.
- Open device, claim interface (bInterfaceNumber = 1)
- `IOUSBDevInterface` for control transfers (vendor requests)
- `IOUSBInterfaceInterface` for bulk endpoints:
- EP 0x04 IN WLAN data (802.11 frames from controllers)
- EP 0x04 OUT Bulk out (commands to chip)
- EP 0x05 IN MCU commands (firmware load responses)
- EP 0x04 IN: WLAN data (802.11 frames from controllers)
- EP 0x04 OUT: Bulk out (commands to chip)
- EP 0x05 IN: MCU commands (firmware load responses)
- Async completion callbacks → callback/dispatch queue
- Device disconnect handling (chip reconnects during firmware load)
**Key IOKit APIs:**
- `IOServiceMatching("IOUSBDevice")` find dongle
- `IOUSBDeviceOpen` / `IOUSBInterfaceOpen` claim
- `DeviceRequest` control transfers (register R/W)
- `WritePipe` / `ReadPipe` bulk transfers
- `CreateInterruptEndpoint` for EP 0x05 (MCU)
- `IOServiceMatching("IOUSBDevice")`: find dongle
- `IOUSBDeviceOpen` / `IOUSBInterfaceOpen`: claim
- `DeviceRequest`: control transfers (register R/W)
- `WritePipe` / `ReadPipe`: bulk transfers
- `CreateInterruptEndpoint`: for EP 0x05 (MCU)
### Phase 3 MT76 Chip Protocol (port)
### Phase 3: MT76 Chip Protocol (port)
**src/mt76/**
- Port `transport/mt76.c` → replace USB calls with Phase 2 transport
- **Firmware loading:** send binary in 0x3800-byte chunks, poll for completion
- **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
- **Beacon transmission:** 802.11 beacons with Microsoft OUI IE
- **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
- `cfg80211_*` → nothing (no regulatory domain reporting needed)
### Phase 4 Virtual HID Gamepad (new)
### Phase 4: Virtual HID Gamepad (new)
**src/hid/**
- Expose controller as macOS HID device so games work natively
- Options:
- **HID Proxy Driver (DriverKit)** Maps USB device to virtual HID. Minimal kernel code. Preferred approach.
- **IOHIDSystem user-space** — Create virtual HID device entirely in user-space. May not work for all games.
- **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
- **HID Proxy Driver (DriverKit)**: Maps USB device to virtual HID.
Minimal kernel code. Preferred approach.
- **IOHIDSystem user-space**: Create virtual HID device entirely in
user-space. May not work for all games.
- **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
### Phase 5 macOS App (new)
### Phase 5: macOS App (new)
**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:
| PID | Dongle Type | Firmware File |
| ---- | ---------------------- | ------------- |
| all | Supported dongles | xow_dongle.bin |
| PID | Dongle Type | Firmware File |
| --- | ----------------- | -------------- |
| all | Supported dongles | xow_dongle.bin |
Downloaded via `scripts/download-firmware.sh` (port of `install/firmware.sh`).
## 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
| Linux source | Target | Notes |
| ----------------------- | -------------------------- | ---------------------------------- |
| `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_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.h` | `include/gip/protocol.hpp` | Clean up kernel types |
| `bus/bus.c` | `src/gip/bus.c` | Client lifecycle management |
| `auth/auth.c` | `src/auth/auth.c` | Pure crypto, mostly copy |
| `auth/auth.h` | `include/auth/auth.hpp` | Copy |
| `auth/crypto.c` | `src/auth/crypto.cpp` | AES-CCMP, mostly copy |
| `auth/crypto.h` | `include/auth/crypto.hpp` | Copy |
| `driver/gamepad.c` | N/A | Replaced by HID layer |
| Linux source | Target | Notes |
| ----------------------- | ---------------------------- | ---------------------------------- |
| `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_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.h` | `include/gip/protocol.hpp` | Clean up kernel types |
| `bus/bus.c` | `src/gip/bus.c` | Client lifecycle management |
| `auth/auth.c` | `src/auth/auth.c` | Pure crypto, mostly copy |
| `auth/auth.h` | `include/auth/auth.hpp` | Copy |
| `auth/crypto.c` | `src/auth/crypto.cpp` | AES-CCMP, mostly copy |
| `auth/crypto.h` | `include/auth/crypto.hpp` | Copy |
| `driver/gamepad.c` | N/A | Replaced by HID layer |
## Build System
- **CMake** or **Xcode project** either works
- **CMake** or **Xcode project**: either works
- Static library for protocol/auth layers
- 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