diff --git a/drivers/acpid/src/main.rs b/drivers/acpid/src/main.rs index 0e97d13649..6c362d8512 100644 --- a/drivers/acpid/src/main.rs +++ b/drivers/acpid/src/main.rs @@ -295,6 +295,40 @@ fn daemon(daemon: daemon::Daemon) -> ! { } power_events::PowerEvent::LidChanged(open) => { log::info!("acpid: lid {}", if open { "opened" } else { "closed" }); + // Symmetric lid-switch → s2idle wiring. Mirrors + // Linux logind's `HandleLidSwitch=suspend` default + // for laptops. + // + // Lid-closed runs `enter_s2idle()` — the AML + // preparation sequence (_TTS/_PTS/_SST + wake-device + // arming via _DSW/_PSW) so the system is in the + // correct state when the kernel MWAIT loop (Phase + // 9.1, not yet landed) actually idles the CPU. + // + // Lid-open runs `exit_s2idle()` — the AML wake + // sequence (_SST(2) → _WAK(0) → _SST(1) + wake-device + // disarming). This is the userspace-driven wake path + // for the case where the kernel MWAIT loop hasn't + // engaged yet (e.g. a brief lid-close/open during + // active workload). When MWAIT IS engaged, the + // kernel-side MWAIT-return path fires kstop + // reason=2 which ALSO calls exit_s2idle() — the + // double-call is safe because the AML _WAK/_SST + // methods are spec-required to be idempotent in + // the working state (ACPI 6.5 §3.5.3). + // + // External-display detection (Linux's + // HandleLidSwitchDocked=ignore) is not wired yet — + // every lid-close triggers s2idle. Documented as a + // follow-up in local/docs/evidence/lg-gram/ + // ASSESSMENT-2026-07-26.md. + if open { + log::info!("acpid: lid opened — running s2idle wake sequence"); + acpi_context.exit_s2idle(); + } else { + log::info!("acpid: lid closed — entering s2idle preparation"); + acpi_context.enter_s2idle(); + } } power_events::PowerEvent::Notify { device, value } => { log::debug!("acpid: device notification {} = {:#x}", device, value);