Fix libusb_bulk_transfer timeout on some Android devices#19
Merged
josephnef merged 2 commits intoMar 24, 2026
Merged
Conversation
This was referenced Jul 20, 2026
Closed
widgetii
pushed a commit
that referenced
this pull request
Jul 20, 2026
…host fix (#314) Some MediaTek Android xhci/usbfs stacks (Dimensity 810, Helio G99, MT6765) never complete a bulk-IN read larger than 16 KB — LIBUSB_ERROR_TIMEOUT forever, zero RX with a green init (OpenIPC/PixelPilot#6). floppyhammer's #19 fixed this with 16 KB host reads plus ≤16 KB device-side RX aggregation; the async-ring rewrites (#158/#164/#168) and the #213 transport split (40e3a2a) kept the aggregation half but regressed the host reads to 32 KB URBs on every 11ac generation. PixelPilot#104 shipped the first Android build of the async ring and the no-video reports came straight back. - Jaguar1/2/3 RX rings: 16 KB URBs (DeviceConfig::Rx::urb_bytes, env DEVOURER_RX_URB_BYTES, clamped >= 4096). Free on healthy hosts: with aggregates capped ≤16 KB a 32 KB URB never filled past 16 KB anyway — each aggregate ends its URB via short packet. - Jaguar2/3 halmac agg page-threshold 0x05 (20 KB) -> 0x03 (≤12 KB): an aggregate must never span two URBs or the next_offset walk breaks. Deliberate divergence from the kernel's 0x05, documented at both sites. - Kestrel untouched: the 8852C RXAGG LEN_TH (~20 KB) requires its 32 KB ring; the knob is documented as 11ac-only. - Docs: CLAUDE.md hardware gotcha + performance-tuning.md lever entry. ctest 36/36. Desktop bench (regress 2x2, goodput A/B) and on-device MTK validation via PixelPilot#6 volunteers tracked in #314. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
3 tasks
josephnef
added a commit
that referenced
this pull request
Jul 20, 2026
…host fix (#314) Some MediaTek Android xhci/usbfs stacks (Dimensity 810, Helio G99, MT6765) never complete a bulk-IN read larger than 16 KB — LIBUSB_ERROR_TIMEOUT forever, zero RX with a green init (OpenIPC/PixelPilot#6). floppyhammer's #19 fixed this with 16 KB host reads plus ≤16 KB device-side RX aggregation; the async-ring rewrites (#158/#164/#168) and the #213 transport split (40e3a2a) kept the aggregation half but regressed the host reads to 32 KB URBs on every 11ac generation. PixelPilot#104 shipped the first Android build of the async ring and the no-video reports came straight back. - Jaguar1/2/3 RX rings: 16 KB URBs (DeviceConfig::Rx::urb_bytes, env DEVOURER_RX_URB_BYTES, clamped >= 4096). Free on healthy hosts: with aggregates capped ≤16 KB a 32 KB URB never filled past 16 KB anyway — each aggregate ends its URB via short packet. - Jaguar2/3 halmac agg page-threshold 0x05 (20 KB) -> 0x03 (≤12 KB): an aggregate must never span two URBs or the next_offset walk breaks. Deliberate divergence from the kernel's 0x05, documented at both sites. - Kestrel untouched: the 8852C RXAGG LEN_TH (~20 KB) requires its 32 KB ring; the knob is documented as 11ac-only. - Docs: CLAUDE.md hardware gotcha + performance-tuning.md lever entry. ctest 36/36. Desktop bench (regress 2x2, goodput A/B) and on-device MTK validation via PixelPilot#6 volunteers tracked in #314. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
josephnef
added a commit
that referenced
this pull request
Jul 20, 2026
…host fix (#317) Closes #314. ## What Restores the host-side half of @floppyhammer's MediaTek no-video fix (#19), lost when the RX path moved to the async URB ring and the #213 transport split deleted `RtlUsbAdapter.cpp`: - **Jaguar1/2/3 RX rings: 16 KB URBs** (was 32 KB), via new `DeviceConfig::Rx::urb_bytes` (env `DEVOURER_RX_URB_BYTES`, clamped ≥ 4096). - **Jaguar2/3 halmac agg page-threshold `0x05` → `0x03`** (20 KB → ≤12 KB): an aggregate must never span two URBs or the `next_offset` walk breaks. Deliberate divergence from the kernel's value, documented at both sites. - **Kestrel untouched**: the 8852C RXAGG LEN_TH (~20 KB) requires its 32 KB ring; the knob is documented 11ac-only. - Docs: `CLAUDE.md` hardware gotcha + `docs/performance-tuning.md` lever entry. ## Why it's free on healthy hosts The device-side aggregation caps (Jaguar1 `rxagg_usb_size` 0x3/0x1 — the surviving half of #19) mean every aggregate is ≤16 KB and ends its URB via short packet: a 32 KB URB never filled past 16 KB. The URB size change costs nothing; it only removes the shape MediaTek hosts can't complete. ## The regression chain 1. PixelPilot#6 (Sept 2024): no video on MTK devices; `libusb_bulk_transfer` → `LIBUSB_ERROR_TIMEOUT` forever ([diagnosis](OpenIPC/PixelPilot#6 (comment)) by @floppyhammer, Jan 2025). 2. #19 (`bbc7385`, Mar 2026): 16 KB reads + ≤16 KB aggregation. Validated on-device by two reporters. PixelPilot#97 pins it. 3. #158/#164/#168 async ring + #213 split (`40e3a2a`): aggregation half survives, host reads regress to 32 KB. 4. PixelPilot#104 (Jul 13): first Android build of the async ring. Jul 19: no-video reports return on the same devices. ## Validation - [x] ctest 36/36 green (Linux, system toolchain) - [x] Desktop bench: `tests/regress.py` matrices + delivery A/B 32K-vs-16K URBs — parity on J1/J2/J3 (table below) - [ ] On-device MTK: PixelPilot test APK to the #6 volunteers (Dimensity 810 + MT6765), plus one Snapdragon no-regression check 🤖 Generated with [Claude Code](https://claude.com/claude-code) ## Bench results (2026-07-20, local rig) Delivery A/B, devourer-RX cells, 15 s flood cells (`tests/regress.py`, `DEVOURER_RX_URB_BYTES` control arm): | RX chip (gen) | TX | ch | 16 KB URBs | 32 KB URBs | 16 KB repeat | |---|---|---|---|---|---| | RTL8812AU (J1) | 8821AU devourer flood | 6 | 7400/8000 | 7400/8000 | 7200/8000 | | RTL8812AU (J1) | 8821AU kernel | 6 | 300/327 | 300/333 | 300/324 | | RTL8812BU (J2, agg 0x03) | 8812AU devourer flood | 36 | 8400/8500 | 8400/8500 | — | | RTL8812EU (J3, agg 0x03) | 8812AU devourer flood | 36 | 8200/8500 | 8200/8500 | — | | RTL8812EU (J3, agg 0x03) | 8812AU kernel | 36 | 300/315 | 300/320 | — | Drift between arms matches the kernel-RX control cells (7217→7401→7355) — the URB size is invisible on healthy hosts, as predicted: with ≤16 KB aggregates each aggregate ends its URB via short packet, so a 32 KB buffer never filled past 16 KB. The J2/J3 agg `0x05→0x03` change shows no delivery cost (98.8% / 96.5% flood delivery, in line with this rig's history). Full 2×2 kernel-driver matrices pass on J1/J2 (ch 6 + ch 36); the J3 kernel cells are structurally absent (no kernel driver for the EU on this host). No 8814AU on the rig today — its delta is nil by construction (DMA-agg is 2 KB, far under either URB size; the multi-URB pool is untouched). Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes OpenIPC/PixelPilot#6.