From 1bca6048a55ec0cf8c9402915868d5b90385a218 Mon Sep 17 00:00:00 2001 From: portersky Date: Sat, 29 Aug 2026 14:30:02 +0200 Subject: [PATCH] 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 --- PLAN.md | 124 +++++++++++++++++++++++++++++++------------------------- 1 file changed, 68 insertions(+), 56 deletions(-) diff --git a/PLAN.md b/PLAN.md index edadf74..a44fb78 100644 --- a/PLAN.md +++ b/PLAN.md @@ -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