91 lines
4.7 KiB
C++
91 lines
4.7 KiB
C++
#ifndef IRTL_RADIO_H
|
|
#define IRTL_RADIO_H
|
|
|
|
#include "IRadio.h"
|
|
|
|
#include "AdapterHealth.h" /* EfuseStability */
|
|
#include "RxSense.h" /* RxEnergy */
|
|
|
|
/* IRtlRadio is the Realtek-family extension of IRadio: the members whose
|
|
* semantics are defined by Realtek silicon (phydm false-alarm / CCA / IGI / NHM
|
|
* counters, the EFUSE logical map and its 0x8129 EEPROM id, the AFE crystal-cap
|
|
* register, the rtw canary register set) rather than by a vendor-neutral
|
|
* concept. Every Realtek backend derives from it:
|
|
* - RtlJaguarDevice — Realtek "Jaguar" wave-1 (8812AU/8811AU/8821AU/8814AU)
|
|
* - RtlJaguar2Device — Realtek "Jaguar2" (8822BU/8812BU)
|
|
* - RtlJaguar3Device — Realtek "Jaguar3" (8822CU/8812EU/8822EU)
|
|
* - Rtl8733bDevice — Realtek HALMAC 87xx 11n (RTL8731BU/RTL8733BU)
|
|
* - RtlKestrelDevice — Realtek G6 11ax (RTL8852BU/RTL8852CU)
|
|
*
|
|
* WiFiDriver::CreateRadio returns an IRadio; a caller that needs one of these
|
|
* members dynamic_casts to IRtlRadio and treats nullptr as "not a Realtek
|
|
* radio" — skip the feature with one diagnostic, never fake a reading.
|
|
* Per-generation research helpers (BB-debug-port reads, the 8814 queue poller,
|
|
* the CW tone) stay on the concrete classes: the same convention one level
|
|
* further down. Every member here keeps the IRadio rule — virtual with a
|
|
* not-ported default, never pure. */
|
|
class IRtlRadio : public IRadio {
|
|
public:
|
|
/* Crystal (XTAL) load-capacitance trim — the CFO lever. Writes the AFE
|
|
* crystal-cap field (a per-chip register), pulling the chip's reference
|
|
* oscillator a few ppm to align a marginal TX/RX crystal pair; the payoff
|
|
* is narrowband at the edge of its CFO budget (5 MHz at 5 GHz). `cap` is a
|
|
* raw trim code in [0, GetAdapterCaps().xtal_cap_max]; cap < 0 reverts to
|
|
* the efuse/default value. Both physical caps (Xi/Xo) are set together.
|
|
* Returns the applied code, or -1 when unsupported. Sticky across channel
|
|
* changes (an AFE register, untouched by the RF retune). */
|
|
virtual int SetXtalCap(int cap) {
|
|
(void)cap;
|
|
return -1;
|
|
}
|
|
|
|
/* Current crystal-cap code (the last SetXtalCap value, or the efuse default
|
|
* at bring-up). -1 when unsupported. */
|
|
virtual int GetXtalCap() { return -1; }
|
|
|
|
/* Frame-free RX energy / channel-busy snapshot (see RxSense.h) — the read side
|
|
* of the DEVOURER_CW_TONE emitter, used for spectrum-sensing / interferer
|
|
* detection. Reads the chip's phydm false-alarm + CCA counters, DIG/IGI, and
|
|
* (when asked) the NHM power histogram. FA/CCA counts are the delta since the
|
|
* previous call. Default returns an all-invalid snapshot; each generation
|
|
* overrides with a real reader.
|
|
*
|
|
* `with_nhm` is a cost decision, not a preference: the NHM read arms a ~2 ms
|
|
* measurement window and then polls a ready bit at 1 ms granularity
|
|
* (src/NhmReader.h), so it dominates the call — the scalar FA/CCA/IGI path is
|
|
* a handful of register reads. Pass false for the throwaway read that resets
|
|
* the delta counters before an observation window, and for any caller
|
|
* sampling faster than a few times a second. */
|
|
virtual RxEnergy GetRxEnergy(bool with_nhm) { (void)with_nhm; return {}; }
|
|
|
|
/* Perform `reads` fresh PHYSICAL EFUSE logical-map reads (each pass re-runs
|
|
* the efuse-controller read sequence — not the cached shadow) and
|
|
* cross-compare them. Dying silicon returns different content per read;
|
|
* healthy silicon is byte-identical every time. Post-bring-up only: returns
|
|
* supported=false before Init/InitWrite (on the 8814AU a pre-fwdl EFUSE
|
|
* read breaks the RSVD-page firmware download). Control-plane threading
|
|
* contract applies (same as SetMonitorChannel). */
|
|
virtual devourer::EfuseStability ProbeEfuseStability(int reads = 4) {
|
|
(void)reads;
|
|
return {};
|
|
}
|
|
|
|
/* Dump the chip's canary register set (BB / MAC / per-path RF) to the
|
|
* diagnostic plane. Reads only — no writes, no calibration, no bring-up.
|
|
*
|
|
* The point is that it is callable on a device that has NOT been Init'ed, so
|
|
* a chip left in whatever state a previous session abandoned it in can be
|
|
* inspected AS IT IS. Every other path into this driver reconfigures the chip
|
|
* on the way in, which destroys exactly the evidence a state bug leaves
|
|
* behind. Pair it with an open that skips libusb_reset_device
|
|
* (claim_interface_then_reset's `do_reset=false`) — a USB reset re-runs the
|
|
* chip's own boot and is just as destructive.
|
|
*
|
|
* Output format matches DEVOURER_DUMP_CANARY, so two dumps diff directly with
|
|
* tests/canary_diff.py. Reading a powered-down chip yields garbage or throws;
|
|
* interpreting that is the caller's job. No-op where unsupported (default). */
|
|
virtual void DumpChipState() {}
|
|
};
|
|
|
|
#endif /* IRTL_RADIO_H */
|