feat: add IOKit-based USB transport
Replace the stub probe with a real IOKit/IOUSBFamily transport: discovery by VID/PID, device and interface connections, vendor control requests on EP0, bulk writes to EP 0x04 OUT, and an async read pump (EP 0x05 IN / EP 0x04 IN) on a dedicated CFRunLoop thread with disconnect notification. Add the test_usb suite, link IOKit/CoreFoundation into xone_usb, and update the README investigation checklist. Co-Authored-By: qwen3.8-27b@q2_k_xl: implemented USB transport layer
This commit is contained in:
@@ -36,11 +36,11 @@ 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.
|
||||
- [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.
|
||||
|
||||
### 2. Firmware Loading
|
||||
|
||||
@@ -108,11 +108,11 @@ Strike through or check off as each is resolved.
|
||||
|
||||
| Linux API | macOS Replacement | Status |
|
||||
|-----------|-------------------|--------|
|
||||
| `usb_control_msg()` | `IOUSBDeviceInterface->DeviceRequest()` | ☐ Investigate |
|
||||
| `usb_bulk_msg()` | `IOUSBInterfaceInterface->WritePipe()` / `ReadPipe()` | ☐ Investigate |
|
||||
| `usb_submit_urb()` | `ReadPipeAsync()` + `CFRunLoopSource` | ☐ Investigate |
|
||||
| `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) |
|
||||
| `kzalloc` / `kfree` | `malloc` / `free` | ✅ Straightforward |
|
||||
| `spin_lock_irqsave` | `pthread_mutex_t` or lock-free | ☐ Design |
|
||||
| `spin_lock_irqsave` | `std::mutex` / `std::condition_variable` | ✅ Done (`usb_transport.cpp`) |
|
||||
| `msleep` / `mdelay` | `usleep()` / `clock_nanosleep()` | ☐ Test timing |
|
||||
| `crypto_shash_*` | CommonCrypto / Security.framework | ✅ Done (`auth/crypto.cpp`) |
|
||||
| `input_register_device()` | HID Proxy Driver / IOHIDSystem | ☐ Investigate |
|
||||
@@ -128,6 +128,6 @@ Strike through or check off as each is resolved.
|
||||
|
||||
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
|
||||
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