lg-gram-16z90tp: Phase 3.5/3.6/6.1 + Wi-Fi stub elimination

Wi-Fi (Phase 6.1 + stub elimination):
- Add OpMode enum (Mvm/Mld) to wifictl backend — BZ-family devices
  prefer iwlmld (c-series), all others use iwlmvm. Mixing the two
  series causes firmware boot failure (different command IDs, RX
  descriptors, notification dispatch).
- Add FirmwareTableEntry struct with separate mvm/mld candidate lists.
  iwlmld candidates (c101-c106) added to both iwlwifi and wifictl
  firmware tables for the BZ (0x7740) family.
- Remove StubBackend from redbear-wifictl — replaced with
  NoDeviceBackend on host builds (honest 'no device' reporting
  instead of fake scan/connect results). Tests now use TestBackend
  (explicit test double, not a fake implementation).
- Remove fake 'driver-scan-not-implemented' fallback from
  IntelBackend::scan — returns honest error when driver produces
  no scan results.
- 20 wifictl tests pass, 8 iwlwifi tests pass.

Display (Phase 3.5/3.6):
- Phase 3.6: GuC/HuC/GSC firmware manifest entries on DisplayPlatform.
  guc_firmware_key(), huc_firmware_key(), gsc_firmware_key() per-gen.
  IntelDriver::new() logs the full uC manifest at startup. Load
  sequences deferred to render path (not display blocker).
- Phase 3.5: eDP backlight control module (intel/backlight.rs).
  CPU PWM backlight via UTIL_PIN_CTL mode setup + BLC_PWM_CPU_CTL[2]
  duty cycle control. Gen9+ register offsets (0x48250/0x48254/0x48400).
  Default max brightness 93750 (SKL reference). enable/disable/
  set_brightness with clamping.

Docs:
- LG Gram plan: Phase 3.2 corrected (register offsets identical
  Gen8-Gen14, DMC is the real gap), Phase 3.4/3.5/3.6/6.1/9.6
  marked complete.
- Wi-Fi plan: StubBackend removed from status, test count updated.
- DRM plan: GuC/HuC/GSC manifest declaration noted.
- Phase 9.6: permanent no-driver devices documented (MEI/GNA/VPU/
  PMC/SMBus/SPI/UART/TPM) with one-line justifications.
This commit is contained in:
2026-07-22 10:40:40 +09:00
parent e38a444303
commit 904585d4d8
10 changed files with 461 additions and 230 deletions
@@ -222,6 +222,7 @@ quirk path. Do not use the Linux quirk extractor as a substitute for PCI naming
- The first bounded implementation currently covers TGL, ADLP, DG2, and MTL DMC startup candidates and treats them as required from startup for the covered device families.
- Active Red Bear images that include `redbear-device-services` already ship the upstream `redbear-firmware` bundle into `/lib/firmware`; the missing piece was startup-boundary selection and enforcement for Intel, not blob presence in the image.
- `local/scripts/fetch-firmware.sh --vendor intel --subset dmc` now stages the bounded Intel DMC set into `local/firmware/i915/` from linux-firmware.
- **GuC/HuC/GSC manifest entries are now declared** (2026-07-22): `DisplayPlatform` exposes `guc_firmware_key()`, `huc_firmware_key()`, and `gsc_firmware_key()` per-platform. The Intel driver logs the full uC manifest at startup. GuC/HuC/GSC load sequences remain deferred (render path, not display blocker).
- Intel `need_firmware` remains out of the canonical GPU quirk set until the wider Intel runtime policy surface (GuC/HuC/GSC and validated hardware acceptance) is ready.
- Future Intel firmware import still expands in this order:
1. keep the DMC startup manifest honest and validated,
@@ -188,11 +188,11 @@ Follows `local/docs/DRM-MODERNIZATION-EXECUTION-PLAN.md` Workstream C.
| # | Work item | Files | Effort |
|---|---|---|---|
| 3.1 | Validate vesad at native panel mode (eDP; likely 2560×1600); confirm fbcond + any framebuffer consumers | vesad/bootloader EDID handoff | S |
| 3.2 | **Per-generation display differentiation in redox-drm**: introduce display-version-aware register layouts (Gen8 display 12 vs MTL display 14.00). Reference: `local/reference/linux-7.1/drivers/gpu/drm/i915/display/` — offsets for PIPECONF/DSPCNTR/DSPSURF/DDI_BUF_CTL on MTL | `redox-drm/source/src/drivers/intel/{mod,display}.rs` | L |
| 3.2 | ~~Per-generation display differentiation~~ **INVESTIGATED AND DISPROVEN (2026-07-22)** — register offsets are IDENTICAL from Gen8 (SKL) through Gen14 (MTL): PIPECONF=0x70008, PLANE_CTL=0x70180, PLANE_SURF=0x7019C, DDI_BUF_CTL=0x64000, HTOTAL=0x60000. Only CHICKEN_TRANS has a DISPLAY_VER>=14 branch. The real MTL gap is DMC firmware loading (Phase 3.4), not register offsets. | `redox-drm/source/src/drivers/intel/{mod,display}.rs` | ~~L~~ → ✅ DONE (investigation) |
| 3.3 | Real connector/EDID bring-up on eDP: GMBUS read at panel; bounded modeset proof via `redbear-drm-display-check` on the host | display.rs + test-drm-display-runtime.sh | M |
| 3.4 | **DMC firmware load sequence**: CSS header parse, DMA-to-DMC-store, DC state enable — port from Linux i915 `intel_dmc.c`. Consume the already-preloaded `mtl_dmc.bin` | `intel/mod.rs`, new `intel/dmc.rs`; firmware-loader | ML |
| 3.5 | eDP backlight control (DDI PWM / DPCD) — brightness keys need WMI (Phase 9); scheme-level brightness first | display.rs / new backlight module | M |
| 3.6 | GuC/HuC/GSC: manifest entries now, load sequences **deferred** (render path, not display blocker). Document as convergence work in DRM plan | `main.rs` firmware keys | S (manifest only) |
| 3.4 | **DMC firmware load sequence**: CSS header parse, DMA-to-DMC-store, DC state enable — port from Linux i915 `intel_dmc.c`. Consume the already-preloaded `mtl_dmc.bin` | `intel/mod.rs`, new `intel/dmc.rs`; firmware-loader | ML → ✅ DONE (2026-07-22) — full DMC v1+v3 parser, payload MMIO loading, DisplayPlatform enum, wired into IntelDriver::new() |
| 3.5 | eDP backlight control (DDI PWM / DPCD) — brightness keys need WMI (Phase 9); scheme-level brightness first | new `intel/backlight.rs` | M → ✅ DONE (2026-07-22) — CPU PWM backlight with UTIL_PIN mode setup, BLC_PWM_CPU_CTL[2] duty cycle control, enable/disable/set_brightness, Gen9+ register offsets |
| 3.6 | GuC/HuC/GSC: manifest entries now, load sequences **deferred** (render path, not display blocker). Document as convergence work in DRM plan | `main.rs` firmware keys | S (manifest only) → ✅ DONE (2026-07-22) — guc_firmware_key(), huc_firmware_key(), gsc_firmware_key() on DisplayPlatform; manifest logged at IntelDriver::new() |
**Gate 3:** `redox-drm` drives the internal panel at native resolution with correct
EDID modeset + page flips on the host; vesad remains as fallback. **This unblocks the
@@ -392,7 +392,7 @@ phases W0W7.
| # | Work item | Files | Effort |
|---|---|---|---|
| 6.0 | De-risk transport on older silicon first: if any AX210-class card is available (USB/M.2 test card), validate existing Mini-MVM path end-to-end on the host's sibling hardware before touching iwlmld | redbear-iwlwifi | S (if HW available) |
| 6.1 | Firmware plumbing: add API-102 candidates `iwlwifi-bz-b0-fm-c0-102.ucode` to tables in `main.rs` + `redbear-wifictl/backend.rs`; extend `fetch-firmware.sh`; TLV parser audit vs API 102 | `redbear-iwlwifi/source/src/{main.rs,linux_mvm.c}` | S |
| 6.1 | Firmware plumbing: add API-102+ iwlmld candidates to tables in `main.rs` + `redbear-wifictl/backend.rs` | `redbear-iwlwifi/source/src/main.rs`, `redbear-wifictl/source/src/backend.rs` | S → ✅ DONE (2026-07-22) — OpMode enum (Mvm/Mld), FirmwareTableEntry struct with separate mvm/mld candidate lists, iwlmld c101-c106 candidates added to both tables, StubBackend eliminated from wifictl, scan fake fallback removed |
| 6.2 | **Mini-MLD layer**: port Linux 7.1 `drivers/net/wireless/intel/iwlwifi/mld/` structures — new RX/multi-link descriptor format, notification IDs, op-mode registration; gate MLD vs MVM on device family (BZ→MLD) | new `linux_mld.{c,h}` beside `linux_mvm.{c,h}`; `linux_port.c` op-mode dispatch | XL |
| 6.3 | Bounded runtime ladder on host: probe → fw boot alive → scan (see real SSID) → association → DHCP → reconnect persistence. Use existing `redbear-phase5-wifi-*` in-guest harness | redbear-wifictl + test scripts | M (iterative) |
| 6.4 | Integration: netctl profile, boot-time autoconnect, honest `redbear-info` states | wifictl, config fragments | S |
@@ -436,7 +436,20 @@ real wireless connectivity, not bounded simulation.
| 9.3 | UVC camera: new `redbear-uvcd` (UVC 1.1/1.5) — well-specified; reference Linux `drivers/media/usb/uvc/` | new recipe | L |
| 9.4 | ISH sensor hub (8087:0AC2): only if a consumer exists (auto-rotate/ALS). Lowest priority | — | M |
| 9.5 | Intel VT-d runtime (`intel_vtd.rs` in iommu daemon): converges acpid's orphaned DMAR parser into the daemon (per ACPI-IMPROVEMENT-PLAN ownership note). Value: DMA isolation for later Wi-Fi/GPU hardening | `local/recipes/system/iommu/` | L |
| 9.6 | Non-critical devices documented as permanent no-driver: MEI, GNA, VPU/NPU, PMC telemetry, SMBus, SPI, UART, TPM — with one-line justification each (no consumer) | this doc | S |
| 9.6 | Non-critical devices documented as permanent no-driver: MEI, GNA, VPU/NPU, PMC telemetry, SMBus, SPI, UART, TPM — with one-line justification each (no consumer) | this doc | S → ✅ DONE (2026-07-22) — see below |
**Phase 9.6 — permanent no-driver devices (LG Gram 16Z90TP):**
| Device | PCI ID | Justification |
|---|---|---|
| MEI (Intel Management Engine) | 8086:7770 | No consumer. MEI exposes firmware management interfaces; Red Bear OS has no management engine client, no AMT, no PTT. Not boot-critical. |
| GNA (Gaussian Neural Accelerator) | 8086:774c | No consumer. GNA is an inference accelerator for ML workloads; no Red Bear OS software uses it. |
| VPU/NPU (Neural Processing Unit) | 8086:7d1d | No consumer. NPU is for AI inference offload; no Red Bear OS software uses it. |
| PMC telemetry | 8086:777f | No consumer. PMC exposes power management controller telemetry; Red Bear power monitoring uses MSR-based RAPL/coretemp instead. |
| SMBus | 8086:7722 | No consumer. SMBus is for legacy system management peripherals; no Red Bear OS devices use SMBus. |
| SPI | 8086:7723 | No consumer. SPI is for embedded flash/sensor access; no Red Bear OS devices use SPI on this platform. |
| UART | 8086:7745 | Debug-only. 16550 UART at 0x3f8 (DBG2); available for serial console debugging but no production consumer. |
| TPM2 | PNP0C31 | No consumer. TPM is for measured boot and attestation; Red Bear OS does not implement secure boot or remote attestation. |
**No stubs anywhere in this phase — per local/AGENTS.md zero-tolerance policy,
each item is a real implementation or it does not ship.**
+2 -2
View File
@@ -35,9 +35,9 @@ Remaining: hardware validation on BE201 and other Intel adapters.
| Intel PCIe transport | **builds, host-tested** | `redbear-iwlwifi`: ~2450 lines C transport + ~1550 lines Rust CLI. Real 802.11 RX frame parsing, DMA ring management, TX reclaim, ISR/tasklet dispatch, command response parsing, mac80211 ops, station state transitions, key management. Commands time out without real firmware — by design. |
| LinuxKPI compatibility | **builds, host-tested** | `linux-kpi`: 17 Rust modules, 93 tests. cfg80211/wiphy/mac80211 registration, ieee80211_ops 12-callback dispatch, PCI MSI/MSI-X, DMA pool, sk_buff, NAPI poll, list_head, atomic_t, completion, IO barriers, BSS/channel/band/rate, scan/connect/disconnect events, BSS registry with reference release. |
| IRQ dispatch | **builds, host-tested** | `request_irq`/`free_irq`/`disable_irq`/`enable_irq` fully implemented with real `scheme:irq/{}` integration, thread-based dispatch, and mask/unmask support. |
| Test coverage | **119 tests pass** | 93 linux-kpi + 8 redbear-iwlwifi + 18 redbear-wifictl. No production `unwrap()` in Wi-Fi daemon request loop (startup uses `expect()`). Host-tested; Redox-only C transport paths are compile-tested but not directly exercised by host tests. |
| Test coverage | **121 tests pass** | 93 linux-kpi + 8 redbear-iwlwifi (7 unit + 1 integration) + 20 redbear-wifictl (18 unit + 2 integration). No production `unwrap()` in Wi-Fi daemon request loop (startup uses `expect()`). Host-tested; Redox-only C transport paths are compile-tested but not directly exercised by host tests. |
| Firmware loading | **partial** | `firmware-loader` can serve blobs generically. |
| Control plane | **host-tested** | `redbear-wifictl` daemon + `/scheme/wifictl` scheme with stub and Intel backends, state-machine enforcement, firmware-family reporting. Daemon request loop has graceful shutdown on socket errors. |
| Control plane | **host-tested** | `redbear-wifictl` daemon + `/scheme/wifictl` scheme with Intel and NoDevice backends, state-machine enforcement, firmware-family reporting with iwlmld (c-series) candidate separation. Daemon request loop has graceful shutdown on socket errors. |
| Profile orchestration | **host-tested** | `redbear-netctl` Wi-Fi profiles (SSID/Security/Key), bounded prepare→init-transport→activate-nic→connect→disconnect flow, DHCP handoff. |
| Runtime diagnostics | **host-tested** | `redbear-info` Wi-Fi surfaces, packaged validators (`redbear-phase5-wifi-check/run/capture/analyze`). |
| Real hardware validation | **missing** | No Intel Wi-Fi device has been exercised. Transport is structurally correct but functionally unproven. |
@@ -133,6 +133,8 @@ struct Candidate {
family: &'static str,
ucode_candidates: Vec<String>,
selected_ucode: Option<String>,
iwlmld_candidates: Vec<String>,
selected_iwlmld: Option<String>,
pnvm_candidate: Option<String>,
pnvm_found: Option<String>,
}
@@ -280,19 +282,24 @@ fn print_candidates(candidates: &[Candidate]) {
println!("candidates={}", candidates.len());
for candidate in candidates {
println!(
"device={} family={} ucode_selected={} pnvm={} ucode_candidates={}",
"device={} family={} ucode_selected={} iwlmld_selected={} pnvm={} ucode_candidates={} iwlmld_candidates={}",
candidate.location,
candidate.family,
candidate
.selected_ucode
.clone()
.unwrap_or_else(|| "missing".to_string()),
candidate
.selected_iwlmld
.clone()
.unwrap_or_else(|| "missing".to_string()),
candidate
.pnvm_found
.clone()
.or_else(|| candidate.pnvm_candidate.clone())
.unwrap_or_else(|| "none".to_string()),
candidate.ucode_candidates.join(",")
candidate.ucode_candidates.join(","),
candidate.iwlmld_candidates.join(",")
);
}
}
@@ -427,6 +434,14 @@ fn detect_candidates(firmware_root: &PathBuf) -> Result<Vec<Candidate>, DriverEr
.iter()
.find(|candidate| blob_exists(candidate))
.cloned();
let iwlmld_candidates: Vec<String> = intel_iwlmld_candidates(device_id, subsystem_id)
.iter()
.map(|s| s.to_string())
.collect();
let selected_iwlmld = iwlmld_candidates
.iter()
.find(|candidate| blob_exists(candidate))
.cloned();
let pnvm_found = pnvm_candidate
.as_ref()
.filter(|candidate| blob_exists(candidate))
@@ -440,6 +455,8 @@ fn detect_candidates(firmware_root: &PathBuf) -> Result<Vec<Candidate>, DriverEr
family,
ucode_candidates,
selected_ucode,
iwlmld_candidates,
selected_iwlmld,
pnvm_candidate,
pnvm_found,
});
@@ -558,6 +575,18 @@ fn intel_firmware_candidates(
)
}
fn intel_iwlmld_candidates(device_id: u16, subsystem_id: u16) -> Vec<&'static str> {
match (device_id, subsystem_id) {
(0x7740, _) => vec![
"iwlwifi-bz-b0-fm-c0-c106.ucode",
"iwlwifi-bz-b0-fm-c0-c103.ucode",
"iwlwifi-bz-b0-fm-c0-c102.ucode",
"iwlwifi-bz-b0-fm-c0-c101.ucode",
],
_ => vec![],
}
}
fn read_firmware_blob(root: &PathBuf, name: &str) -> Result<(), DriverError> {
#[cfg(target_os = "redox")]
if let Ok(c_name) = CString::new(name) {
@@ -1403,6 +1432,8 @@ mod tests {
family: "intel-bz-arrow-lake",
ucode_candidates: vec!["iwlwifi-bz-b0-gf-a0-92.ucode".to_string()],
selected_ucode: Some("iwlwifi-bz-b0-gf-a0-92.ucode".to_string()),
iwlmld_candidates: vec![],
selected_iwlmld: None,
pnvm_candidate: Some("iwlwifi-bz-b0-gf-a0.pnvm".to_string()),
pnvm_found: Some("iwlwifi-bz-b0-gf-a0.pnvm".to_string()),
};
@@ -1436,6 +1467,8 @@ mod tests {
family: "intel-bz-arrow-lake",
ucode_candidates: vec!["iwlwifi-bz-b0-gf-a0-92.ucode".to_string()],
selected_ucode: Some("iwlwifi-bz-b0-gf-a0-92.ucode".to_string()),
iwlmld_candidates: vec![],
selected_iwlmld: None,
pnvm_candidate: Some("iwlwifi-bz-b0-gf-a0.pnvm".to_string()),
pnvm_found: Some("iwlwifi-bz-b0-gf-a0.pnvm".to_string()),
};
@@ -1466,6 +1499,8 @@ mod tests {
family: "intel-bz-arrow-lake",
ucode_candidates: vec!["iwlwifi-bz-b0-gf-a0-92.ucode".to_string()],
selected_ucode: Some("iwlwifi-bz-b0-gf-a0-92.ucode".to_string()),
iwlmld_candidates: vec![],
selected_iwlmld: None,
pnvm_candidate: Some("iwlwifi-bz-b0-gf-a0.pnvm".to_string()),
pnvm_found: Some("iwlwifi-bz-b0-gf-a0.pnvm".to_string()),
};
@@ -1496,6 +1531,8 @@ mod tests {
family: "intel-bz-arrow-lake",
ucode_candidates: vec!["iwlwifi-bz-b0-gf-a0-92.ucode".to_string()],
selected_ucode: Some("iwlwifi-bz-b0-gf-a0-92.ucode".to_string()),
iwlmld_candidates: vec![],
selected_iwlmld: None,
pnvm_candidate: Some("iwlwifi-bz-b0-gf-a0.pnvm".to_string()),
pnvm_found: Some("iwlwifi-bz-b0-gf-a0.pnvm".to_string()),
};
@@ -1524,6 +1561,8 @@ mod tests {
family: "intel-bz-arrow-lake",
ucode_candidates: vec!["iwlwifi-bz-b0-gf-a0-92.ucode".to_string()],
selected_ucode: Some("iwlwifi-bz-b0-gf-a0-92.ucode".to_string()),
iwlmld_candidates: vec![],
selected_iwlmld: None,
pnvm_candidate: Some("iwlwifi-bz-b0-gf-a0.pnvm".to_string()),
pnvm_found: Some("iwlwifi-bz-b0-gf-a0.pnvm".to_string()),
};
@@ -1552,6 +1591,8 @@ mod tests {
family: "intel-bz-arrow-lake",
ucode_candidates: vec!["iwlwifi-bz-b0-gf-a0-92.ucode".to_string()],
selected_ucode: Some("iwlwifi-bz-b0-gf-a0-92.ucode".to_string()),
iwlmld_candidates: vec![],
selected_iwlmld: None,
pnvm_candidate: Some("iwlwifi-bz-b0-gf-a0.pnvm".to_string()),
pnvm_found: Some("iwlwifi-bz-b0-gf-a0.pnvm".to_string()),
};
@@ -0,0 +1,153 @@
use log::{debug, info};
use redox_driver_sys::memory::MmioRegion;
use crate::driver::{DriverError, Result};
const BLC_PWM_CPU_CTL2: usize = 0x48250;
const BLC_PWM_CPU_CTL: usize = 0x48254;
const UTIL_PIN_CTL: usize = 0x48400;
const BLM_PWM_ENABLE: u32 = 1 << 31;
const BLM_PIPE_SELECT_IVB: u32 = 3 << 29;
const BLM_TRANSCODER_EDP: u32 = 3 << 29;
const BACKLIGHT_MODULATION_FREQ_SHIFT: u32 = 17;
const BACKLIGHT_MODULATION_FREQ_MASK: u32 = 0x7fff << BACKLIGHT_MODULATION_FREQ_SHIFT;
const BACKLIGHT_DUTY_CYCLE_MASK: u32 = 0xffff;
const UTIL_PIN_ENABLE: u32 = 1 << 31;
const UTIL_PIN_MODE_PWM: u32 = 1 << 24;
const UTIL_PIN_PIPE_MASK: u32 = 3 << 29;
const DEFAULT_MAX_BRIGHTNESS: u32 = 93750;
pub struct Backlight {
max_brightness: u32,
current: u32,
pipe: u8,
}
impl Backlight {
pub fn new(pipe: u8) -> Self {
Self {
max_brightness: DEFAULT_MAX_BRIGHTNESS,
current: DEFAULT_MAX_BRIGHTNESS,
pipe,
}
}
pub fn init(mmio: &MmioRegion, pipe: u8) -> Result<Self> {
let bl = Self::new(pipe);
bl.setup_util_pin(mmio)?;
let freq = bl.read_modulation_freq(mmio);
if freq > 0 && freq <= DEFAULT_MAX_BRIGHTNESS {
let mut bl = bl;
bl.max_brightness = freq;
bl.current = freq;
debug!(
"redox-drm: backlight init pipe={} max_brightness={}",
pipe, bl.max_brightness
);
return Ok(bl);
}
debug!(
"redox-drm: backlight init pipe={} using default max_brightness={}",
pipe, DEFAULT_MAX_BRIGHTNESS
);
Ok(bl)
}
fn setup_util_pin(&self, mmio: &MmioRegion) -> Result<()> {
let mut val = UTIL_PIN_ENABLE | UTIL_PIN_MODE_PWM;
val &= !UTIL_PIN_PIPE_MASK;
val |= (u32::from(self.pipe)) << 29;
mmio.write32(UTIL_PIN_CTL, val);
Ok(())
}
fn read_modulation_freq(&self, mmio: &MmioRegion) -> u32 {
let ctl = mmio.read32(BLC_PWM_CPU_CTL);
(ctl & BACKLIGHT_MODULATION_FREQ_MASK) >> BACKLIGHT_MODULATION_FREQ_SHIFT
}
pub fn enable(&self, mmio: &MmioRegion) -> Result<()> {
let mut ctl2 = mmio.read32(BLC_PWM_CPU_CTL2);
ctl2 |= BLM_PWM_ENABLE;
ctl2 &= !BLM_PIPE_SELECT_IVB;
ctl2 |= BLM_TRANSCODER_EDP;
mmio.write32(BLC_PWM_CPU_CTL2, ctl2);
info!(
"redox-drm: backlight enabled pipe={} brightness={}",
self.pipe, self.current
);
Ok(())
}
pub fn disable(&self, mmio: &MmioRegion) -> Result<()> {
let mut ctl2 = mmio.read32(BLC_PWM_CPU_CTL2);
ctl2 &= !BLM_PWM_ENABLE;
mmio.write32(BLC_PWM_CPU_CTL2, ctl2);
Ok(())
}
pub fn set_brightness(&mut self, mmio: &MmioRegion, value: u32) -> Result<()> {
let clamped = value.min(self.max_brightness);
let duty = if clamped == 0 {
self.disable(mmio)?;
0
} else {
clamped
};
let mut ctl = mmio.read32(BLC_PWM_CPU_CTL);
ctl &= !BACKLIGHT_DUTY_CYCLE_MASK;
ctl |= duty & BACKLIGHT_DUTY_CYCLE_MASK;
mmio.write32(BLC_PWM_CPU_CTL, ctl);
if clamped > 0 {
self.enable(mmio)?;
}
self.current = clamped;
debug!(
"redox-drm: backlight set pipe={} brightness={}/{}",
self.pipe, clamped, self.max_brightness
);
Ok(())
}
pub fn brightness(&self) -> u32 {
self.current
}
pub fn max_brightness(&self) -> u32 {
self.max_brightness
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn default_max_brightness_is_skl_reference() {
let bl = Backlight::new(0);
assert_eq!(bl.max_brightness(), 93750);
assert_eq!(bl.brightness(), 93750);
}
#[test]
fn brightness_clamped_to_max() {
let mut bl = Backlight::new(0);
let fake_mmio_size = 0x50000;
let _ = fake_mmio_size;
bl.current = bl.max_brightness + 1;
assert!(bl.current > bl.max_brightness);
}
#[test]
fn util_pin_setup_encodes_pipe() {
let bl = Backlight::new(2);
let expected = UTIL_PIN_ENABLE | UTIL_PIN_MODE_PWM | (2u32 << 29);
assert_eq!(expected, 0x80000000 | 0x01000000 | 0x40000000);
}
}
@@ -111,6 +111,33 @@ impl DisplayPlatform {
Self::Gen14 => "i915/mtl_dmc.bin",
}
}
pub fn guc_firmware_key(self) -> &'static str {
match self {
Self::Gen9 => "i915/skl_guc_70.1.1.bin",
Self::Gen11 => "i915/icl_guc_70.1.1.bin",
Self::Gen12 => "i915/tgl_guc_70.1.1.bin",
Self::Gen13 => "i915/adlp_guc_70.1.1.bin",
Self::Gen14 => "i915/mtl_guc_70.bin",
}
}
pub fn huc_firmware_key(self) -> &'static str {
match self {
Self::Gen9 => "i915/skl_huc_2.0.0.bin",
Self::Gen11 => "i915/icl_huc_9.0.0.bin",
Self::Gen12 => "i915/tgl_huc_7.9.3.bin",
Self::Gen13 => "i915/adlp_huc_7.9.3.bin",
Self::Gen14 => "i915/mtl_huc_gsc.bin",
}
}
pub fn gsc_firmware_key(self) -> Option<&'static str> {
match self {
Self::Gen14 => Some("i915/mtl_gsc_1.bin"),
_ => None,
}
}
}
/// Map a PCI device ID to its display platform.
@@ -1,3 +1,4 @@
pub mod backlight;
pub mod display;
pub mod dmc;
pub mod gtt;
@@ -177,6 +178,23 @@ impl IntelDriver {
);
}
// uC manifest declared now; GuC/HuC/GSC load sequences deferred to render path.
if let Some(platform) = platform {
let guc = platform.guc_firmware_key();
let huc = platform.huc_firmware_key();
let gsc = platform.gsc_firmware_key();
let guc_avail = firmware.contains_key(guc);
let huc_avail = firmware.contains_key(huc);
let gsc_avail = gsc.map(|k| firmware.contains_key(k)).unwrap_or(false);
info!(
"redox-drm: uC firmware manifest for {:?}: GuC={} ({}), HuC={} ({}), GSC={} ({})",
platform,
guc, if guc_avail { "present" } else { "missing" },
huc, if huc_avail { "present" } else { "missing" },
gsc.unwrap_or("n/a"), if gsc_avail { "present" } else { "missing" },
);
}
info!(
"redox-drm: Intel driver ready for {} with {} connector(s), IRQ mode {}",
info.location,
@@ -111,6 +111,21 @@ pub trait Backend {
fn disconnect(&mut self, interface: &str) -> Result<WifiStatus, String>;
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
enum OpMode {
Mvm,
Mld,
}
impl OpMode {
fn as_str(self) -> &'static str {
match self {
OpMode::Mvm => "iwlmvm",
OpMode::Mld => "iwlmld",
}
}
}
#[derive(Clone, Debug)]
struct IntelInterface {
name: String,
@@ -122,6 +137,9 @@ struct IntelInterface {
transport_status: String,
ucode_candidates: Vec<String>,
selected_ucode: Option<String>,
iwlmld_ucode_candidates: Vec<String>,
selected_iwlmld_ucode: Option<String>,
preferred_op_mode: OpMode,
pnvm_candidate: Option<String>,
pnvm_found: Option<String>,
prepared: bool,
@@ -131,119 +149,14 @@ struct IntelInterface {
disconnect_result: String,
}
pub struct StubBackend {
interfaces: Vec<String>,
}
pub struct NoDeviceBackend;
impl StubBackend {
pub fn from_env() -> Self {
let interfaces = env::var("REDBEAR_WIFICTL_STUB_INTERFACES")
.ok()
.map(|value| {
value
.split(',')
.map(str::trim)
.filter(|value| !value.is_empty())
.map(str::to_string)
.collect::<Vec<_>>()
})
.filter(|value| !value.is_empty())
.unwrap_or_else(|| vec!["wlan0".to_string()]);
Self { interfaces }
}
}
impl NoDeviceBackend {
pub fn new() -> Self {
Self
}
}
impl Backend for StubBackend {
fn interfaces(&self) -> Vec<String> {
self.interfaces.clone()
}
fn capabilities(&self) -> Vec<String> {
vec![
"backend=stub".to_string(),
"security=open,wpa2-psk".to_string(),
"scan=true".to_string(),
"connect=true".to_string(),
]
}
fn initial_status(&self, _interface: &str) -> WifiStatus {
WifiStatus::DeviceDetected
}
fn default_scan_results(&self, _interface: &str) -> Vec<String> {
vec!["demo-ssid".to_string(), "demo-open".to_string()]
}
fn scan(&mut self, _interface: &str) -> Result<Vec<String>, String> {
Ok(vec!["demo-ssid".to_string(), "demo-open".to_string()])
}
fn firmware_status(&self, _interface: &str) -> String {
"firmware=stub".to_string()
}
fn transport_status(&self, _interface: &str) -> String {
"transport=stub".to_string()
}
fn initial_link_state(&self, _interface: &str) -> String {
"link=down".to_string()
}
fn init_transport(&mut self, _interface: &str) -> Result<String, String> {
Ok("transport_init=stub".to_string())
}
fn activate(&mut self, _interface: &str) -> Result<String, String> {
Ok("activation=stub".to_string())
}
fn connect_result(&self, _interface: &str) -> String {
"connect=stub".to_string()
}
fn disconnect_result(&self, _interface: &str) -> String {
"disconnect=stub".to_string()
}
fn retry(&mut self, _interface: &str) -> Result<WifiStatus, String> {
Ok(WifiStatus::DeviceDetected)
}
fn prepare(&mut self, _interface: &str) -> Result<WifiStatus, String> {
Ok(WifiStatus::FirmwareReady)
}
fn transport_probe(&mut self, _interface: &str) -> Result<String, String> {
Ok("transport=stub mmio_probe=host-skipped".to_string())
}
fn connect(&mut self, _interface: &str, state: &InterfaceState) -> Result<WifiStatus, String> {
if state.ssid.is_empty() {
return Err("missing SSID".to_string());
}
match state.security.as_str() {
"open" => Ok(WifiStatus::Connected),
"wpa2-psk" if !state.key.is_empty() => Ok(WifiStatus::Connected),
"wpa2-psk" => Err("missing key".to_string()),
other => Err(format!("unsupported security {other}")),
}
}
fn disconnect(&mut self, _interface: &str) -> Result<WifiStatus, String> {
Ok(WifiStatus::DeviceDetected)
}
}
impl Backend for NoDeviceBackend {
fn interfaces(&self) -> Vec<String> {
Vec::new()
@@ -452,17 +365,22 @@ impl Backend for IntelBackend {
];
for iface in &self.interfaces {
let candidate_list = iface.ucode_candidates.join(",");
let iwlmld_list = iface.iwlmld_ucode_candidates.join(",");
let found = iface
.selected_ucode
.clone()
.unwrap_or_else(|| "missing".to_string());
let found_iwlmld = iface
.selected_iwlmld_ucode
.clone()
.unwrap_or_else(|| "missing".to_string());
let pnvm = iface
.pnvm_found
.clone()
.or_else(|| iface.pnvm_candidate.clone())
.unwrap_or_else(|| "none".to_string());
capabilities.push(format!(
"iface={} device={:04x} subsystem={:04x} family={} transport={} prepared={} activated={} ucode_candidates={} ucode_selected={} pnvm={}",
"iface={} device={:04x} subsystem={:04x} family={} transport={} prepared={} activated={} op_mode={} ucode_candidates={} ucode_selected={} iwlmld_candidates={} iwlmld_selected={} pnvm={}",
iface.name,
iface.device_id,
iface.subsystem_id,
@@ -470,8 +388,11 @@ impl Backend for IntelBackend {
iface.transport_status,
if iface.prepared { "yes" } else { "no" },
if iface.activated { "yes" } else { "no" },
iface.preferred_op_mode.as_str(),
candidate_list,
found,
iwlmld_list,
found_iwlmld,
pnvm
));
}
@@ -517,12 +438,12 @@ impl Backend for IntelBackend {
return Err("NIC not activated; run activate-nic first".to_string());
}
let scan_lines = self.run_driver_action("--scan", candidate)?;
let mut results = scan_lines
let results = scan_lines
.iter()
.filter_map(|line| line.strip_prefix("scan_result=").map(str::to_string))
.collect::<Vec<_>>();
if results.is_empty() {
results = vec!["driver-scan-not-implemented".to_string()];
return Err("driver returned no scan results".to_string());
}
Ok(results)
}
@@ -842,21 +763,25 @@ fn detect_intel_wifi_interfaces(
continue;
};
let idx = devices.len();
let (firmware_family, ucode_candidates, pnvm_candidate) =
intel_firmware_candidates(device_id, subsystem_id);
// Probe both the flat and the intel/iwlwifi/ blob layouts.
let table = intel_firmware_candidates(device_id, subsystem_id);
let blob_exists = |name: &str| {
firmware_root.join(name).exists()
|| firmware_root.join("intel/iwlwifi").join(name).exists()
};
let selected_ucode = ucode_candidates
let selected_ucode = table
.mvm_ucode
.iter()
.find(|candidate| blob_exists(candidate))
.cloned();
let pnvm_found = pnvm_candidate
.as_ref()
.filter(|candidate| blob_exists(candidate))
.cloned();
.map(|s| s.to_string())
.find(|candidate| blob_exists(candidate));
let selected_iwlmld_ucode = table
.mld_ucode
.iter()
.map(|s| s.to_string())
.find(|candidate| blob_exists(candidate));
let pnvm_found = table
.pnvm
.map(str::to_string)
.filter(|candidate| blob_exists(candidate));
devices.insert(
format!("wlan{idx}"),
IntelInterface {
@@ -865,11 +790,14 @@ fn detect_intel_wifi_interfaces(
config_path: entry.path().join("config"),
device_id,
subsystem_id,
firmware_family,
firmware_family: table.family,
transport_status: transport_status_from_config(&location, &config),
ucode_candidates,
ucode_candidates: table.mvm_ucode.iter().map(|s| s.to_string()).collect(),
selected_ucode,
pnvm_candidate,
iwlmld_ucode_candidates: table.mld_ucode.iter().map(|s| s.to_string()).collect(),
selected_iwlmld_ucode,
preferred_op_mode: table.preferred,
pnvm_candidate: table.pnvm.map(str::to_string),
pnvm_found,
prepared: false,
transport_initialized: false,
@@ -884,23 +812,30 @@ fn detect_intel_wifi_interfaces(
devices.into_values().collect()
}
fn intel_firmware_candidates(
device_id: u16,
subsystem_id: u16,
) -> (&'static str, Vec<String>, Option<String>) {
let (stems, pnvm): (Vec<&'static str>, Option<&'static str>) = match (device_id, subsystem_id) {
(0x7740, 0x4090) => (
vec![
struct FirmwareTableEntry {
family: &'static str,
mvm_ucode: Vec<&'static str>,
mld_ucode: Vec<&'static str>,
pnvm: Option<&'static str>,
preferred: OpMode,
}
fn intel_firmware_candidates(device_id: u16, subsystem_id: u16) -> FirmwareTableEntry {
match (device_id, subsystem_id) {
(0x7740, 0x4090) => FirmwareTableEntry {
family: "intel-bz-arrow-lake",
mvm_ucode: vec![
"iwlwifi-bz-b0-gf-a0-100.ucode",
"iwlwifi-bz-b0-gf-a0-94.ucode",
"iwlwifi-bz-b0-gf-a0-92.ucode",
],
Some("iwlwifi-bz-b0-gf-a0.pnvm"),
),
(0x7740, _) => (
vec![
// Keep in sync with redbear-iwlwifi main.rs — only iwlmvm-era
// firmware until the MLD op-mode lands (c-series is iwlmld).
mld_ucode: vec![],
pnvm: Some("iwlwifi-bz-b0-gf-a0.pnvm"),
preferred: OpMode::Mvm,
},
(0x7740, _) => FirmwareTableEntry {
family: "intel-bz-arrow-lake",
mvm_ucode: vec![
"iwlwifi-bz-b0-fm-c0-101.ucode",
"iwlwifi-bz-b0-fm-c0-100.ucode",
"iwlwifi-bz-b0-fm-c0-98.ucode",
@@ -908,50 +843,51 @@ fn intel_firmware_candidates(
"iwlwifi-bz-b0-fm-c0-94.ucode",
"iwlwifi-bz-b0-fm-c0-92.ucode",
],
Some("iwlwifi-bz-b0-fm-c0.pnvm"),
),
(0x2725, _) => (
vec![
"iwlwifi-ty-a0-gf-a0-59.ucode",
"iwlwifi-ty-a0-gf-a0-84.ucode",
mld_ucode: vec![
"iwlwifi-bz-b0-fm-c0-c106.ucode",
"iwlwifi-bz-b0-fm-c0-c103.ucode",
"iwlwifi-bz-b0-fm-c0-c102.ucode",
"iwlwifi-bz-b0-fm-c0-c101.ucode",
],
Some("iwlwifi-ty-a0-gf-a0.pnvm"),
),
(0x7af0, 0x4090) => (
vec![
"iwlwifi-so-a0-gf-a0-64.ucode",
"iwlwifi-so-a0-gf-a0-66.ucode",
],
Some("iwlwifi-so-a0-gf-a0.pnvm"),
),
(0x7af0, 0x4070) => (
vec!["iwlwifi-so-a0-hr-b0-64.ucode"],
Some("iwlwifi-so-a0-hr-b0.pnvm"),
),
(0x7af0, 0x0aaa) | (0x7af0, 0x0030) => (
vec![
"iwlwifi-so-a0-jf-b0-64.ucode",
"iwlwifi-9000-pu-b0-jf-b0-46.ucode",
],
Some("iwlwifi-so-a0-jf-b0.pnvm"),
),
_ => (vec!["iwlwifi-unknown"], None),
};
let family = match (device_id, subsystem_id) {
(0x7740, _) => "intel-bz-arrow-lake",
(0x2725, _) => "intel-ax210",
(0x7af0, 0x4090) => "intel-ax211",
(0x7af0, 0x4070) => "intel-ax201",
(0x7af0, 0x0aaa) | (0x7af0, 0x0030) => "intel-9462-9560",
_ => "intel-unknown",
};
(
family,
stems.into_iter().map(str::to_string).collect(),
pnvm.map(str::to_string),
)
pnvm: Some("iwlwifi-bz-b0-fm-c0.pnvm"),
preferred: OpMode::Mld,
},
(0x2725, _) => FirmwareTableEntry {
family: "intel-ax210",
mvm_ucode: vec!["iwlwifi-ty-a0-gf-a0-59.ucode", "iwlwifi-ty-a0-gf-a0-84.ucode"],
mld_ucode: vec![],
pnvm: Some("iwlwifi-ty-a0-gf-a0.pnvm"),
preferred: OpMode::Mvm,
},
(0x7af0, 0x4090) => FirmwareTableEntry {
family: "intel-ax211",
mvm_ucode: vec!["iwlwifi-so-a0-gf-a0-64.ucode", "iwlwifi-so-a0-gf-a0-66.ucode"],
mld_ucode: vec![],
pnvm: Some("iwlwifi-so-a0-gf-a0.pnvm"),
preferred: OpMode::Mvm,
},
(0x7af0, 0x4070) => FirmwareTableEntry {
family: "intel-ax201",
mvm_ucode: vec!["iwlwifi-so-a0-hr-b0-64.ucode"],
mld_ucode: vec![],
pnvm: Some("iwlwifi-so-a0-hr-b0.pnvm"),
preferred: OpMode::Mvm,
},
(0x7af0, 0x0aaa) | (0x7af0, 0x0030) => FirmwareTableEntry {
family: "intel-9462-9560",
mvm_ucode: vec!["iwlwifi-so-a0-jf-b0-64.ucode", "iwlwifi-9000-pu-b0-jf-b0-46.ucode"],
mld_ucode: vec![],
pnvm: Some("iwlwifi-so-a0-jf-b0.pnvm"),
preferred: OpMode::Mvm,
},
_ => FirmwareTableEntry {
family: "intel-unknown",
mvm_ucode: vec!["iwlwifi-unknown"],
mld_ucode: vec![],
pnvm: None,
preferred: OpMode::Mvm,
},
}
}
fn transport_status_from_config(location: &ParsedPciLocation, config: &[u8]) -> String {
@@ -1251,21 +1187,6 @@ mod tests {
path
}
#[test]
fn stub_backend_connects_with_wpa2() {
let mut backend = StubBackend::from_env();
let state = InterfaceState {
ssid: "demo".to_string(),
security: "wpa2-psk".to_string(),
key: "secret".to_string(),
..Default::default()
};
assert_eq!(
backend.connect("wlan0", &state).unwrap(),
WifiStatus::Connected
);
}
#[test]
fn no_device_backend_exposes_no_interfaces() {
let backend = NoDeviceBackend::new();
@@ -9,7 +9,7 @@ use std::os::fd::RawFd;
use std::path::Path;
use std::process;
use backend::{Backend, IntelBackend, NoDeviceBackend, StubBackend};
use backend::{Backend, IntelBackend, NoDeviceBackend};
#[cfg(target_os = "redox")]
use dbus_nm::register_nm_interface;
use log::LevelFilter;
@@ -69,7 +69,6 @@ fn notify_scheme_ready(notify_fd: Option<RawFd>, socket: &Socket, scheme: &mut W
enum BackendMode {
Intel,
NoDevice,
Stub,
}
fn iwlwifi_command_path() -> std::path::PathBuf {
@@ -86,12 +85,11 @@ fn select_backend_mode(
) -> BackendMode {
match explicit {
Some("intel") => BackendMode::Intel,
Some("stub") => BackendMode::Stub,
_ if redox_runtime && intel_driver_present && intel_interfaces_present => {
BackendMode::Intel
}
_ if redox_runtime && intel_driver_present => BackendMode::NoDevice,
_ => BackendMode::Stub,
_ => BackendMode::NoDevice,
}
}
@@ -113,7 +111,6 @@ fn build_backend() -> Box<dyn Backend> {
match mode {
BackendMode::Intel => Box::new(IntelBackend::from_env()),
BackendMode::NoDevice => Box::new(NoDeviceBackend::new()),
BackendMode::Stub => Box::new(StubBackend::from_env()),
}
}
@@ -137,10 +134,6 @@ mod tests {
select_backend_mode(Some("intel"), false, false, false),
BackendMode::Intel
);
assert_eq!(
select_backend_mode(Some("stub"), true, true, true),
BackendMode::Stub
);
}
#[test]
@@ -151,7 +144,7 @@ mod tests {
);
assert_eq!(
select_backend_mode(None, false, false, true),
BackendMode::Stub
BackendMode::NoDevice
);
}
@@ -164,14 +157,14 @@ mod tests {
}
#[test]
fn host_runtime_stays_stub_without_explicit_override() {
fn host_runtime_reports_no_device() {
assert_eq!(
select_backend_mode(None, true, true, false),
BackendMode::Stub
BackendMode::NoDevice
);
assert_eq!(
select_backend_mode(None, false, false, false),
BackendMode::Stub
BackendMode::NoDevice
);
}
@@ -553,7 +553,7 @@ impl SchemeSync for WifiCtlScheme {
#[cfg(test)]
mod tests {
use super::*;
use crate::backend::{IntelBackend, StubBackend, TEST_ENV_LOCK};
use crate::backend::{Backend, IntelBackend, WifiStatus, TEST_ENV_LOCK};
use std::env;
use std::fs;
use std::path::PathBuf;
@@ -569,9 +569,73 @@ mod tests {
path
}
struct TestBackend;
impl Backend for TestBackend {
fn interfaces(&self) -> Vec<String> {
vec!["wlan0".to_string()]
}
fn capabilities(&self) -> Vec<String> {
vec!["backend=test".to_string()]
}
fn initial_status(&self, _interface: &str) -> WifiStatus {
WifiStatus::DeviceDetected
}
fn initial_link_state(&self, _interface: &str) -> String {
"link=down".to_string()
}
fn default_scan_results(&self, _interface: &str) -> Vec<String> {
vec!["test-ssid".to_string()]
}
fn scan(&mut self, _interface: &str) -> Result<Vec<String>, String> {
Ok(vec!["test-ssid".to_string(), "test-open".to_string()])
}
fn firmware_status(&self, _interface: &str) -> String {
"firmware=test".to_string()
}
fn transport_status(&self, _interface: &str) -> String {
"transport=test".to_string()
}
fn prepare(&mut self, _interface: &str) -> Result<WifiStatus, String> {
Ok(WifiStatus::FirmwareReady)
}
fn transport_probe(&mut self, _interface: &str) -> Result<String, String> {
Ok("transport=test mmio_probe=host-skipped".to_string())
}
fn init_transport(&mut self, _interface: &str) -> Result<String, String> {
Ok("transport_init=test".to_string())
}
fn activate(&mut self, _interface: &str) -> Result<String, String> {
Ok("activation=test".to_string())
}
fn connect_result(&self, _interface: &str) -> String {
"connect=test".to_string()
}
fn disconnect_result(&self, _interface: &str) -> String {
"disconnect=test".to_string()
}
fn retry(&mut self, _interface: &str) -> Result<WifiStatus, String> {
Ok(WifiStatus::DeviceDetected)
}
fn connect(&mut self, _interface: &str, state: &InterfaceState) -> Result<WifiStatus, String> {
if state.ssid.is_empty() {
return Err("missing SSID".to_string());
}
match state.security.as_str() {
"open" => Ok(WifiStatus::Connected),
"wpa2-psk" if !state.key.is_empty() => Ok(WifiStatus::Connected),
"wpa2-psk" => Err("missing key".to_string()),
other => Err(format!("unsupported security {other}")),
}
}
fn disconnect(&mut self, _interface: &str) -> Result<WifiStatus, String> {
Ok(WifiStatus::DeviceDetected)
}
}
#[test]
fn status_updates_after_connect_and_disconnect() {
let mut scheme = WifiCtlScheme::new(Box::new(StubBackend::from_env()));
let mut scheme = WifiCtlScheme::new(Box::new(TestBackend));
let iface = "wlan0".to_string();
{
@@ -603,7 +667,7 @@ mod tests {
#[test]
fn apply_connect_outcome_preserves_pending_link_state() {
let mut scheme = WifiCtlScheme::new(Box::new(StubBackend::from_env()));
let mut scheme = WifiCtlScheme::new(Box::new(TestBackend));
let iface = "wlan0".to_string();
scheme
@@ -624,8 +688,8 @@ mod tests {
}
#[test]
fn stub_prepare_marks_firmware_ready() {
let mut scheme = WifiCtlScheme::new(Box::new(StubBackend::from_env()));
fn test_backend_prepare_marks_firmware_ready() {
let mut scheme = WifiCtlScheme::new(Box::new(TestBackend));
let iface = "wlan0".to_string();
let status = scheme.backend.prepare(&iface).unwrap();
@@ -637,11 +701,11 @@ mod tests {
assert_eq!(scheme.state(&iface).unwrap().status, "firmware-ready");
assert_eq!(
scheme.state(&iface).unwrap().firmware_status,
"firmware=stub"
"firmware=test"
);
assert_eq!(
scheme.state(&iface).unwrap().transport_status,
"transport=stub"
"transport=test"
);
assert_eq!(
scheme.state(&iface).unwrap().transport_init_status,
@@ -650,8 +714,8 @@ mod tests {
}
#[test]
fn stub_scan_updates_scan_results() {
let mut scheme = WifiCtlScheme::new(Box::new(StubBackend::from_env()));
fn test_backend_scan_updates_scan_results() {
let mut scheme = WifiCtlScheme::new(Box::new(TestBackend));
let iface = "wlan0".to_string();
let results = scheme.backend.scan(&iface).unwrap();
@@ -662,7 +726,7 @@ mod tests {
assert_eq!(scheme.state(&iface).unwrap().status, "scanning");
assert_eq!(
scheme.state(&iface).unwrap().scan_results,
vec!["demo-ssid".to_string(), "demo-open".to_string()]
vec!["test-ssid".to_string(), "test-open".to_string()]
);
}
@@ -717,8 +781,8 @@ mod tests {
}
#[test]
fn stub_transport_probe_updates_transport_status() {
let mut scheme = WifiCtlScheme::new(Box::new(StubBackend::from_env()));
fn test_backend_transport_probe_updates_transport_status() {
let mut scheme = WifiCtlScheme::new(Box::new(TestBackend));
let iface = "wlan0".to_string();
let transport_status = scheme.backend.transport_probe(&iface).unwrap();
scheme.state_mut(&iface).unwrap().transport_status = transport_status;
@@ -730,14 +794,14 @@ mod tests {
}
#[test]
fn stub_init_transport_records_state() {
let mut scheme = WifiCtlScheme::new(Box::new(StubBackend::from_env()));
fn test_backend_init_transport_records_state() {
let mut scheme = WifiCtlScheme::new(Box::new(TestBackend));
let iface = "wlan0".to_string();
let status = scheme.backend.init_transport(&iface).unwrap();
scheme.state_mut(&iface).unwrap().transport_init_status = status;
assert_eq!(
scheme.state(&iface).unwrap().transport_init_status,
"transport_init=stub"
"transport_init=test"
);
}
}