RTL8821AU: partial bring-up — chip init OK, RX silent — WIP#30
Conversation
Ports the RTL8821AU (Jaguar 1T1R AC+BT combo, CHIP_8821) HAL onto current master following the ICType-based dispatch convention established by the 8814AU work in #23-#29. Bring-up reaches end-of-init on the TP-Link Archer T2U Plus (2357:0120) but the chip remains silent on bulk IN. HAL assets (verbatim from svpcom/rtl8812au v5.2.20 via #22): - hal/Hal8821APwrSeq.{c,h} — power on/off/disable/suspend/lps sequences - hal/Hal8821PhyReg.h — MAC / PHY / AGC / RadioA register tables - hal/hal8821a_fw.{c,h} — 8821a NIC firmware blob (signature 0x2101) Dispatch wiring (mirrors 8814AU pattern): - EepromManager::read_chip_version_8812a — VID:PID table for genuine 8821 SKUs (T2U Plus + canonical Realtek-numbered + common OEM rebadges). Sets ICType=CHIP_8821, RFType=RF_TYPE_1T1R. - HalModule::InitPowerOn / PHY_MACConfig8812 / PHY_BBConfig8812 / PHY_RF6052_Config_8812 — three-way branches (8814 / 8821 / 8812). - Four new HalModule helpers wrap the 8821 tables through PhyTableLoader. - HalModule::rtl8812au_hal_init — REG_USB_HRPWM=0x84 wake for CHIP_8821. - Firmware.h::PickFirmwareForChip returns 8821 blob for CHIP_8821; jaguar_fw_header_present accepts the 0x2100 signature. CONFIG_RTL8821A scoped tightly around hal8821a_fw.h include. - RadioManagementModule::phy_SetRFEReg8821 ported from #22, branched in PHY_SwitchWirelessBand8812. USB endpoint discovery (RtlUsbAdapter::InitDvObj): - Dynamic bulk IN endpoint selection instead of hardcoded 0x81. 8821AU exposes 0x84 (8812/8814 expose 0x81). - Bulk OUT endpoints stored in a vector; send_packet picks index 0 instead of hardcoded 0x02. 8821AU exposes 0x05/0x06/0x08/0x09 (8812 uses 0x02-0x05). DEVOURER_TX_EP env override still wins. - libusb_clear_halt on the IN endpoint after enumeration. - infinite_read rate-limits the error log + sleeps 50ms on rc<0. Caught a runaway-loop bug that previously generated 4.6 GB of logs in 15s when the device dropped off USB. Demos: - DEVOURER_VID env override (mirrors existing DEVOURER_PID). Needed for non-Realtek-VID dongles (T2U Plus is 2357:xxxx). - DEVOURER_USB_QUIET=1 downgrades libusb log to WARNING (was hardcoded DEBUG = ~7 MB / 15s, repeatedly filled /tmp on test machines). - Both demos fall back to direct libusb_open_device_with_vid_pid with env-provided VID:PID if not in kRealtekProductIds[]. What works on T2U Plus (verified on macOS, ch6/36/100): - Chip detection: CHIP_8821_Normal_Chip_TSMC_D_CUT_1T1R - 8821 power-on flow, firmware download (~30ms to FW ready) - MAC/BB/AGC/RadioA register tables via PhyTableLoader - RFE pinmux, band switch (2.4G + 5G), channel + TX power - USB endpoint discovery (IN 0x84, OUTs 0x05/0x06/0x08/0x09) - libusb_clear_halt + REG_USB_HRPWM=0x84 wake What's NOT working — the gap for follow-up: - Bulk-IN reads succeed at the USB layer but the chip never pushes data. 0 RX packets across 15s on ch100 even with the host Mac actively associated to a busy 5GHz AP. - TX path is wired (correct OUT EP) but unvalidated end-to-end — no peer sniffer in this session. Regression matrix (Linux trainer-arch, master vs feat/rtl8821au-support): Adapter RX TX ----- -- -- 8812AU (0bda:8812) 41 pkts/15s, 0 errors 15 prints rc=1, 0 fails 8814AU (0bda:8813) 0 pkts (matches master) rc=1, ~270-320 async fails (matches master) 8812AU + 8814AU code paths preserved end-to-end. Suggested next investigation: 1. usbmon trace of aircrack-ng/rtl8812au's RX bring-up on Linux against an 8821AU; diff post-fwdl register writes vs ours (REG_TRXDMA_CTRL, REG_USB_AGG_TH/TO, REG_RXDMA_AGG_PG_TH, REG_USB_SPECIAL_OPTION). 2. Compare register state post-init (kernel-driver readback vs our post-init pyusb dump). Same technique used for 8814AU. 3. Re-read #22's HalModule.cpp for any 8821-specific init steps that I didn't carry over when rewiring through ICType. Co-Authored-By: RomanLut <noreply@github.com> Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
## What this is
A manual-run Python orchestrator that compares devourer's userspace
stack against the kernel driver (mainline `rtw88` / out-of-tree
`aircrack-ng/rtl8812au`) on a host with two plugged-in USB Wi-Fi
adapters. Emits a markdown table — designed to paste into PR review
comments.
```
TX = devourer TX = kernel
RX = devourer [end-to-end dvr] [does dvr RX a kernel-TX frame?]
RX = kernel [does dvr emit [baseline / rig sanity]
valid frames?]
```
Each cell injects/receives the canonical beacon (SA `57:42:75:05:d6:00`,
matching `txdemo/main.cpp`) for `--duration` seconds and counts hits.
## Why now
PRs like #30 (RTL8821AU partial bring-up) need cross-driver validation:
\"does devourer's TX really emit valid frames?\" and \"can devourer RX a
frame the kernel driver knows works?\". Running these checks manually is
fiddly (modprobe / unbind / iw / tcpdump dance per cell); this script
does it in one command and prints a structured result.
This is **not** a 24x7 CI runner — too few PRs to justify the
infrastructure. It's a script the reviewer runs on demand on a test rig.
## Usage
```bash
cd /path/to/devourer && cmake --build build -j
sudo python3 tests/regress.py --channel 100
```
See [`tests/README.md`](tests/README.md) for full options + prereqs.
## First-run validation on trainer-arch
Arch Linux, kernel 6.x, USB hub with 0bda:8812 (8812AU) + 0bda:8813
(8814AU):
```
## Regression matrix — channel 100
- TX adapter: 0bda:8813 (RTL8814AU)
- RX adapter: 0bda:8812 (RTL8812AU)
| | TX = devourer | TX = kernel |
|---|---|---|
| RX = devourer | 0 hits / 10 TX (437 fail) / 10s ✗ | 0 hits / 0 TX / 0s ✗ |
| RX = kernel | 1 hits / 10 TX (351 fail) / 10s ✓ | 0 hits / 0 TX / 0s ✗ |
```
The **devourer-TX(8814) → kernel-RX(8812) cell passed** — independent
confirmation that #29's 8814AU TX bring-up really does land frames on
the air. The remaining cells correctly identified the rig's known
limitations: mainline `rtw88_8814au` can't probe this 8814AU dongle on
this kernel (`failed to download firmware`, probe error -22), and 8814AU
RX is a pre-existing TODO.
## Portability
- Tool paths resolved via `which` (no `/usr/bin/X` hardcoding)
- Wlan iface names discovered via `iw dev` (works for systemd `wlp*` and
classic `wlan*`)
- Kernel driver claiming each DUT read from sysfs (no hardcoded module
names)
- Preflight check prints distro-agnostic install hints if anything's
missing
- Tested on Arch; should work on any modern Linux with `iw`, `tcpdump`,
`python3-scapy`, `aircrack-ng`
## VM-readiness
The kernel-cell shell-outs all go through one function
(`run_kernel_cmd`). Today: local exec. To migrate the kernel driver into
a pinned-kernel VM (recommended once host kernel upgrades start breaking
the out-of-tree aircrack-ng driver), wrap that function with `ssh
trainer-vm sudo` and arrange USB hot-plug passthrough via libvirt. The
matrix orchestrator doesn't need to change.
## Known limitations (documented in README)
- Tests \"signal of life\", not throughput — air noise makes absolute
counts unreliable; default pass-threshold is 1 hit with guidance to bump
for higher-confidence runs.
- Sequential matrix takes ~100s for 4 cells (devourer fwdl warmup + 4 ×
~25s).
- Two-adapter scope today. Extending to >2 is a pairing loop in
`main()`.
- One known bug: `<devourer-tx>TX #N` prints are rate-limited so when
the chip is failing every send, the parser undercounts attempts.
Mitigated by surfacing failure count separately in the output.
## Test plan
- [x] Builds + runs on trainer-arch (Arch + kernel 6.x)
- [x] Markdown table emitted correctly
- [x] At least one cell passes against real hardware (8814 dvr-TX → 8812
kernel-RX)
- [ ] Validate on a different distro (Ubuntu / Fedora) — anyone with a
2-adapter rig
- [ ] Validate against the out-of-tree `aircrack-ng/rtl8812au` driver
instead of mainline rtw88
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Extends tests/regress.py with a --full-matrix mode that iterates every
ordered (TX, RX) pair of plugged-in DUTs across all four driver-side
combinations (kernel-only, devourer-TX/kernel-RX, kernel-TX/devourer-RX,
devourer-only) and emits one NxN table per mode instead of one 4-cell
table for a single pair. Useful for catching cross-chipset interop
regressions in PRs that touch shared HAL code.
Usage:
sudo python3 tests/regress.py --full-matrix --channel 100 \\
--vm-name devourer-testrig --vm-ssh <user>@<VM-IP>
For N adapters, runs N*(N-1)*4 cells total — at ~30-40s per cell in VM
mode that's ~16 min for N=3, manageable. Diagonal is blanked (same
physical adapter can't simultaneously TX and RX with one driver). The
script reuses run_cell as-is; the addition is just the outer pair loop,
result dict keyed by (tx_side, rx_side, tx_vidpid, rx_vidpid), and a
new emit_full_markdown that renders four NxN tables.
Also scrubs personal identifiers from earlier docs/scripts (PR #33):
- tests/setup_vm.sh now reads VM_USER from $SUDO_USER / $USER instead
of hardcoding a specific username
- tests/README.md + regress.py docstrings switch to <user>@<VM-IP>
placeholders in example commands
Validation on a 3-adapter rig (Ubuntu 22.04 VM with aircrack-ng/88XXau,
0bda:8812 + 0bda:8813 + 2357:0120, channel 100, 10s/cell):
## Kernel-only (rig sanity)
All 6 cross-chipset cells pass — 88XXau handles all three chipsets
cleanly in the pinned-kernel VM (88-271 hits per cell).
## devourer-TX → kernel-RX
devourer-TX confirmed for 8812 (4114, 4693 hits) AND 8821 (4341 hits
reaching 8814 kernel RX). 8814 TX flaky after passthrough cycles
(chip-state degradation across cell sequencing — known sensitive).
## kernel-TX → devourer-RX
Surprise — devourer-RX 8821 caught 200 frames from kernel-TX 8814,
contradicting PR #30's "RX silent" finding. devourer-RX 8812
confirmed (100 hits from each of 8814, 8821 TX). devourer-RX 8814
confirmed broken (0 hits all directions — known TODO).
## devourer ↔ devourer
All 0 — every cell hits at least one broken side (8814 RX or 8814 TX
degraded mid-run).
Net new product signal from the full matrix:
- devourer-TX 8821 actually works (was unvalidated since PR #30 had no
peer sniffer in that session — VM mode is the peer)
- devourer-RX 8821 works under at least one TX condition — reopen PR
#30's "RX silent" conclusion
- 8814 chip state degrades through repeated host↔VM passthrough — needs
investigation, may want a chip reset between cells
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Extends tests/regress.py with a --full-matrix mode that iterates every
ordered (TX, RX) pair of plugged-in DUTs across all four driver-side
combinations (kernel-only, devourer-TX/kernel-RX, kernel-TX/devourer-RX,
devourer-only) and emits one NxN table per mode instead of one 4-cell
table for a single pair. Useful for catching cross-chipset interop
regressions in PRs that touch shared HAL code.
Usage:
sudo python3 tests/regress.py --full-matrix --channel 100 \\
--vm-name devourer-testrig --vm-ssh <user>@<VM-IP>
For N adapters, runs N*(N-1)*4 cells total — at ~30-40s per cell in VM
mode that's ~16 min for N=3, manageable. Diagonal is blanked (same
physical adapter can't simultaneously TX and RX with one driver). The
script reuses run_cell as-is; the addition is just the outer pair loop,
result dict keyed by (tx_side, rx_side, tx_vidpid, rx_vidpid), and a
new emit_full_markdown that renders four NxN tables.
Also scrubs personal identifiers from earlier docs/scripts (PR #33):
- tests/setup_vm.sh now reads VM_USER from $SUDO_USER / $USER instead
of hardcoding a specific username
- tests/README.md + regress.py docstrings switch to <user>@<VM-IP>
placeholders in example commands
Validation on a 3-adapter rig (Ubuntu 22.04 VM with aircrack-ng/88XXau,
0bda:8812 + 0bda:8813 + 2357:0120, channel 100, 10s/cell):
## Kernel-only (rig sanity)
All 6 cross-chipset cells pass — 88XXau handles all three chipsets
cleanly in the pinned-kernel VM (88-271 hits per cell).
## devourer-TX → kernel-RX
devourer-TX confirmed for 8812 (4114, 4693 hits) AND 8821 (4341 hits
reaching 8814 kernel RX). 8814 TX flaky after passthrough cycles
(chip-state degradation across cell sequencing — known sensitive).
## kernel-TX → devourer-RX
Surprise — devourer-RX 8821 caught 200 frames from kernel-TX 8814,
contradicting PR #30's "RX silent" finding. devourer-RX 8812
confirmed (100 hits from each of 8814, 8821 TX). devourer-RX 8814
confirmed broken (0 hits all directions — known TODO).
## devourer ↔ devourer
All 0 — every cell hits at least one broken side (8814 RX or 8814 TX
degraded mid-run).
Net new product signal from the full matrix:
- devourer-TX 8821 actually works (was unvalidated since PR #30 had no
peer sniffer in that session — VM mode is the peer)
- devourer-RX 8821 works under at least one TX condition — reopen PR
#30's "RX silent" conclusion
- 8814 chip state degrades through repeated host↔VM passthrough — needs
investigation, may want a chip reset between cells
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
## What this is
Extends `tests/regress.py` with `--full-matrix`: iterates every ordered
(TX, RX) pair of plugged-in DUTs across all 4 driver-side combinations
(kernel-only / dvr-TX×kernel-RX / kernel-TX×dvr-RX / devourer-only) and
emits one NxN table per mode. Useful for catching cross-chipset interop
regressions in PRs that touch shared HAL code.
```bash
sudo python3 tests/regress.py --full-matrix --channel 100 \
--vm-name devourer-testrig --vm-ssh <user>@<VM-IP>
```
For N adapters → N×(N-1)×4 cells. ~16 min for N=3 in VM mode. Diagonal
blanked (same physical adapter can't simultaneously TX and RX with one
driver).
Also scrubs placeholder usernames from earlier docs/scripts
(`tests/setup_vm.sh` now reads `VM_USER` from `$SUDO_USER`/`$USER`
instead of hardcoding; READMEs + docstrings use `<user>@<VM-IP>`).
## Validation on a 3-adapter rig
Ubuntu 22.04 VM with aircrack-ng/88XXau, DUTs `0bda:8812 + 0bda:8813 +
2357:0120`, channel 100, 10s/cell:
### Kernel-only (rig sanity / cross-chipset kernel interop)
| TX \ RX | RTL8814AU | RTL8812AU | RTL8821AU |
|---|---|---|---|
| RTL8814AU | — | 99 hits ✓ | 271 hits ✓ |
| RTL8812AU | 243 hits ✓ | — | 270 hits ✓ |
| RTL8821AU | 260 hits ✓ | 88 hits ✓ | — |
**6/6 cells pass.** `88XXau` in the pinned-kernel VM gives full
cross-chipset kernel-side interop. Rig is sound.
### devourer-TX → kernel-RX (does devourer emit valid frames?)
| TX \ RX | RTL8814AU | RTL8812AU | RTL8821AU |
|---|---|---|---|
| RTL8814AU | — | 0 ✗ (2272 fail) | 0 ✗ (2322 fail) |
| RTL8812AU | **4114 ✓** | — | **4693 ✓** |
| RTL8821AU | **4341 ✓** | 0 ✗ | — |
- **devourer-TX 8812 validated** end-to-end at the wire — 4000+ hits to
each kernel RX peer
- **devourer-TX 8821 validated end-to-end** — 4341 hits reaching
kernel-RX 8814. New result: PR #30 had no peer sniffer to confirm; the
VM gives us one. The TX path that #30 wired works.
- 8814 TX flaky after the chip cycles through host↔VM passthroughs
(chip-state degradation across cell sequencing — single-cell tests in PR
#33 worked, this is a multi-cell wear issue)
### kernel-TX → devourer-RX (does devourer RX a known-good frame?)
| TX \ RX | RTL8814AU | RTL8812AU | RTL8821AU |
|---|---|---|---|
| RTL8814AU | — | **100 ✓** | **200 ✓** |
| RTL8812AU | 0 ✗ | — | 0 ✗ |
| RTL8821AU | 0 ✗ | **100 ✓** | — |
- **Surprise: devourer-RX 8821 caught 200 frames** from kernel-TX 8814 —
contradicts PR #30's "RX silent" finding. Reopen-worthy: 8821 RX may
actually be working under certain conditions and #30's session-local
conclusion was wrong.
- devourer-RX 8812 confirmed working (100 hits from each of 8814 and
8821 TX)
- devourer-RX 8814 confirmed broken — pre-existing TODO
### devourer ↔ devourer (end-to-end devourer)
All 0. Every cell hits at least one broken side (8814 RX broken or 8814
TX degraded mid-run).
## Net new product signal
1. **devourer-TX 8821 is working** — closes the gap PR #30 documented as
"wired but unvalidated"
2. **devourer-RX 8821 may actually be working** — at least one cell got
200 hits. PR #30's negative conclusion needs reopening.
3. **Chip state degrades through repeated passthrough** — devourer-TX
8814 is reliable in single-cell tests but flakes after several virsh
attach/detach cycles. Suggests we should consider a chip-reset /
power-cycle between cells in the orchestrator, or accept this as a known
limitation of the VM rig.
## What this PR doesn't touch
- The `--full-matrix` extension doesn't change any existing code path;
the single-pair mode (`--tx-pid`/`--rx-pid`) still works exactly as
before. Pure addition.
- Doesn't address the 8814 chip-state degradation (that's separate work
— possibly a `usbreset` between cells)
- Doesn't open the PR #30 reopen (that's a follow-up: rerun the 8821 RX
investigation with this rig)
## Test plan
- [x] `--full-matrix` runs end-to-end against 3 adapters in VM mode
- [x] All 4 NxN tables render correctly
- [x] Cell counts and per-pair timing match expected (~30-40s per cell)
- [x] Kernel-only baseline (6 cells) all pass
- [x] At least one cell in each non-trivial mode passes (validates
harness logic)
- [ ] Run on a different rig with different chipset combinations
- [ ] Validate on 4+ adapters (script supports it; not exercised here)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
Update: the "RX silent" conclusion in this PR appears to be wrong — RX path actually works under at least some conditions. The full-matrix regression rig (#34) was just run against a 3-adapter setup (0bda:8812 + 0bda:8813 + 2357:0120) with
So both halves of the 8821 path that this PR labelled as gaps are actually functional. Two follow-up questions worth pinning down:
Tracking the deeper investigation in #35. cc @RomanLut — this updates the situation since your #22 port. The dispatch is in master, and the RX path that we initially thought was broken seems to actually work — the chip just needs the right conditions / state. |
… RX asymmetry) (#37) ## Status: partial — register-state parity with kernel, but doesn't fix #30's 8812-peer asymmetry Brings devourer's `CHIP_8821` init register-write set into parity with `aircrack-ng/88XXau`'s post-fwdl monitor-mode bring-up, based on a usbmon-trace diff. Adds 13 missing post-fwdl writes, 17 BB/AGC value overrides, MAC-address programming, and corrects an earlier wrong guess at REG_USB_HRPWM. **This does NOT fix the asymmetry** (`devourer-RX 8821` catches kernel-TX 8814 frames but drops kernel-TX 8812 frames at 0/280) that #34 surfaced. The cheap "what's different at the register level" patches don't cross the threshold. Filing anyway because it's honest progress + brings the chip's baseline state into kernel parity, which the next fix attempt can build on. ## What this changes | Where | Change | |---|---| | `HalModule.cpp::rtl8812au_hal_init` | REG_USB_HRPWM for CHIP_8821: 0x84 → 0x00 (kernel writes 0; my earlier "leave LPS wake" guess was wrong) | | `HalModule.cpp::rtl8812au_hal_init` | CHIP_8821: program MAC address to REG_MACID (0x0610-0x0615). Kernel always does this even in monitor; some chip RX-path logic gates on MACID being non-zero. | | `HalModule.cpp::rtl8812au_hal_init` | CHIP_8821: 13 trace-derived post-fwdl writes (REG_AUTO_LLT region, REG_TX_PTCL_CTRL, NAV-related, 8821 BB high-addr block 0x1874-0x187f) | | `HalModule.cpp::rtl8812au_hal_init` | CHIP_8821: 17 BB/AGC value overrides (0x0830 PWED_TH, 0x0c20-0x0c44 AGC table, 0x0e90 TX power region) forced to kernel's observed runtime values | | `tests/inject_beacon.py` | `--rate` CLI arg (added during rate-decode hypothesis testing; useful diagnostic knob) | 8812AU + 8814AU paths untouched. ## Why the RX gap probably remains Aircrack-ng runs **phydm** — a runtime feedback loop that continually adjusts AGC / RX-gain based on observed signal quality. This PR sets the chip's *static* values to match kernel's post-init snapshot, but the chip needs the active loop to *maintain* them during RX. Without phydm running, the chip drifts back toward defaults that work for higher-SNR peers (8814) but not for 8812. Three follow-up paths to actually fix the asymmetry: 1. **Port phydm runtime** for 8821 (substantial — most of `aircrack-ng/hal/phydm/rtl8821a/`). Days of work, cleanest fix. 2. **Loop-replay**: capture kernel's full register sequence over a 5-second RX window (not just init) and replay periodically from devourer. Hacky but cheap. 3. **Accept devourer-RX 8821 as "works for some peers, not others"** until phydm is in. Document the limit in the adapter inventory. ## usbmon methodology (for future trace-diff work) Capture kernel side (in VM with `aircrack-ng/88XXau`): ```bash # On VM: sudo modprobe usbmon sudo bash -c "cat /sys/kernel/debug/usb/usbmon/0u > /tmp/trace_kernel.txt &" # Then attach DUT via virsh, bring up monitor mode, stop usbmon ``` Capture devourer side (on host): ```bash sudo bash -c "timeout 20 cat /sys/kernel/debug/usb/usbmon/Nu > /tmp/trace_dvr.txt" & sudo ./build/WiFiDriverDemo ... ``` Filter Realtek control writes: ```bash grep -E "S Co:.* 40 05 " trace.txt | awk '{print $8, $13}' ``` **Important encoding gotcha:** usbmon shows wire bytes in transmission order (= LE u32's byte sequence). To write the same value via `rtw_write32` on a LE host, the u32 value is read-as-LE — so the trace text `82824001` represents u32 `0x01408282` (NOT `0x82824001`). The first attempt at the post-fwdl writes in this PR used wrong-endian values and naturally had no effect; the fix was to byte-pair-reverse them. ## Validation Single-pair test on the trainer rig (Arch host, Ubuntu 22.04 VM with aircrack-ng/88XXau, channel 100, 10s): | Cell | Hits | Note | |---|---|---| | kernel-TX 8812 → kernel-RX 8821 (baseline) | 283 ✓ | rig sane | | devourer-TX 8821 → kernel-RX 8814 | 4663 ✓ | dvr-TX 8821 fine | | kernel-TX 8812 → devourer-RX 8821 | **0 ✗** | the asymmetry — unresolved | | devourer-TX 8821 → devourer-RX 8812 | **0 ✗** | same | Other chips untouched. ## Test plan - [x] Builds clean - [x] CHIP_8812 + CHIP_8814A paths unchanged - [x] CHIP_8821 init now writes the kernel-equivalent register set - [x] devourer-TX 8821 still works → kernel-RX 8814 (4663 hits) - [ ] dvr-RX 8821 ↔ 8812 — known *not* fixed by this PR - [ ] phydm runtime ported (follow-up) Refs #30 (initial 8821 port), #34 (full matrix that surfaced the asymmetry). 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Status: WIP — chip init succeeds, RX data flow still silent
Brings up the RTL8821AU end-to-end except for RX bulk-IN data flow. Posting so @RomanLut and others can continue the investigation from a clean checkpoint that builds against current master instead of resurrecting #22 (which deletes the 8814AU work and has a parallel dispatch enum that doesn't compose with the
ICType-based convention #23-#29 established).What works on T2U Plus 2357:0120 (verified on macOS)
CHIP_8821_Normal_Chip_TSMC_D_CUT_1T1Rrtl8821A_card_enable_flow)0x2101, FW ready in ~30msPhyTableLoader(same phydm conditional encoding as 8814AU)phy_SetRFEReg8821), band switch 2.4G/5G, channel + TX power table on ch6/36/100libusb_clear_halton IN +REG_USB_HRPWM=0x84LPS wakeWhat's NOT working
LIBUSB_ERROR_NOT_FOUND) but unvalidated end-to-end on 8821AU — no peer sniffer in this session.Regression matrix (Linux trainer-arch, master vs
feat/rtl8821au-support)0bda:8812)CHIP_8812detectedrc=1, 0 failures (2 runs)0bda:8813)rc=1, ~270-320 async failures (timing-variant)The new
CHIP_8821dispatch correctly routes 8812 → 8812 path and 8814 → 8814 path. No misrouting.Suggested next steps for whoever picks this up
aircrack-ng/rtl8812au's RX bring-up against an 8821AU on Linux; diff post-fwdl register writes vs ours (REG_TRXDMA_CTRL, REG_USB_AGG_TH/TO, REG_RXDMA_AGG_PG_TH, REG_USB_SPECIAL_OPTION).HalModule.cppfor any 8821-specific init steps I didn't carry over when rewiring throughICType.What this preserves
HAL_IC_TYPE_E/ICTypedispatch pattern; no parallel enumAttribution
8821a HAL data (
Hal8821APwrSeq,Hal8821PhyReg,hal8821a_fw) ported verbatim from @RomanLut's #22 (svpcom/rtl8812au v5.2.20). Wiring re-done to follow master's existing convention.Refs #20 (BadPotato1007's underlying request) and #22 (RomanLut's original port).
🤖 Generated with Claude Code