Skip to content

Fix libusb_bulk_transfer timeout on some Android devices#19

Merged
josephnef merged 2 commits into
OpenIPC:masterfrom
floppyhammer:fix-no-video-on-some-android-devices
Mar 24, 2026
Merged

Fix libusb_bulk_transfer timeout on some Android devices#19
josephnef merged 2 commits into
OpenIPC:masterfrom
floppyhammer:fix-no-video-on-some-android-devices

Conversation

@floppyhammer

Copy link
Copy Markdown
Contributor

@josephnef
josephnef merged commit bbc7385 into OpenIPC:master Mar 24, 2026
5 checks passed
@floppyhammer
floppyhammer deleted the fix-no-video-on-some-android-devices branch March 25, 2026 02:40
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>
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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

No Video on MediaTek Device (Samsung Galaxy A15)?

2 participants