docs: mark USB matching and claiming hardware-verified
Discovery, interface claiming, and vendor control requests are confirmed working on a physical dongle (PID 0x02E6, MT7612 chip). Async latency tuning and reconnect reliability remain open for Phase 3. Co-Authored-By: qwen3.8-27b@q2_k_xl: verified transport on hardware
This commit is contained in:
@@ -36,29 +36,57 @@ Strike through or check off as each is resolved.
|
||||
|
||||
### 1. IOKit USB Access
|
||||
|
||||
- [x] **IOUSBLib vs IOUSBFamily** — Resolved: the SDK exposes only the struct-based `IOUSBDeviceInterface` / `IOUSBInterfaceInterface` (v197/v190) via `IOCreatePlugInInterfaceForService()` + `QueryInterface`. Implemented in `src/usb/usb_transport.cpp`.
|
||||
- [x] **USB device matching** — `IOServiceMatching("IOUSBDevice")` with `kUSBVendorString`/`kUSBProductString` keys, implemented in `dongle_present()`. No-dongle case verified; plugged-in case pending hardware.
|
||||
- [x] **Interface claiming** — All interfaces are opened and pipes mapped by endpoint number + direction (EP 0x04 IN/OUT, EP 0x05 IN). Driver conflict check pending hardware.
|
||||
- [ ] **Async transfer latency** — `ReadPipeAsync` pump implemented (4 outstanding reads per IN pipe, resubmission in the completion handler). Latency tuning deferred to Phase 3 firmware load.
|
||||
- [x] **Device reconnect handling** — `kIOTerminatedNotification` with a PID filter fires on unplug and chip re-enumeration. Reliability pending hardware.
|
||||
- [x] **IOUSBLib vs IOUSBFamily** — Resolved: the SDK exposes only the
|
||||
struct-based `IOUSBDeviceInterface` / `IOUSBInterfaceInterface` (v197/v190)
|
||||
via `IOCreatePlugInInterfaceForService()` + `QueryInterface`. Implemented in
|
||||
`src/usb/usb_transport.cpp`.
|
||||
- [x] **USB device matching** — Class match on `IOUSBDevice` plus a user-space
|
||||
VID/PID filter on the `idVendor`/`idProduct` properties (numeric registry
|
||||
matching proved unreliable). Verified with a physical dongle (PID 0x02E6).
|
||||
- [x] **Interface claiming** — All interfaces are opened and pipes mapped by
|
||||
endpoint number + direction (EP 0x04 IN/OUT, EP 0x05 IN). Verified: opens
|
||||
cleanly with no driver conflict.
|
||||
- [ ] **Async transfer latency** — `ReadPipeAsync` pump implemented (4
|
||||
outstanding reads per IN pipe, resubmission in the completion handler).
|
||||
Latency tuning deferred to Phase 3 firmware load.
|
||||
- [x] **Device reconnect handling** — `kIOTerminatedNotification` with a PID
|
||||
filter fires on unplug and chip re-enumeration. Reliability pending hardware.
|
||||
|
||||
### 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.
|
||||
- [ ] **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.
|
||||
- [ ] **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.
|
||||
- [ ] **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
|
||||
|
||||
@@ -73,41 +101,66 @@ Strike through or check off as each is resolved.
|
||||
|
||||
### 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?
|
||||
- [ ] **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`.
|
||||
- [ ] **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.
|
||||
- [ ] **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).
|
||||
- [ ] **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)
|
||||
- [ ] **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)
|
||||
- [ ] **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()` | ✅ Done (`send_vendor_request`) |
|
||||
| `usb_bulk_msg()` | `WritePipe()` / `ReadPipeAsync()` | ✅ Done (`bulk_write`, reader thread) |
|
||||
| `usb_submit_urb()` | `ReadPipeAsync()` + `CFRunLoopSource` | ✅ Done (reader thread) |
|
||||
@@ -126,8 +179,12 @@ Strike through or check off as each is resolved.
|
||||
|
||||
## 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. Open the device with `transport::probe()` and confirm endpoint enumeration (EP 0x04 IN/OUT, EP 0x05 IN)
|
||||
4. Try a vendor control request (register read) to verify USB communication works
|
||||
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. Open the device with `transport::probe()` and confirm endpoint enumeration
|
||||
(EP 0x04 IN/OUT, EP 0x05 IN)
|
||||
4. Try a vendor control request (register read) to verify USB communication
|
||||
works
|
||||
5. Attempt firmware load with the binary from `firmware/` directory
|
||||
|
||||
Reference in New Issue
Block a user