On this laptop, the internal keyboard, lid, and power button fail to wake the machine from s2idle because of two bugs in the ACPI firmware — and both can be repaired from Linux without flashing the BIOS. Override the FACP table to fix the power button, and inject a small SSDT that supplies the wake object the lid is missing. Once the patched tables load from an early initrd, all three built-in wake sources work again.
Why the wake sources go dead during s2idle
While the system sits in s2idle, the kernel only arms the wake events it knows about. ACPI devices declare their wake capability with a _PRW object, which names the general-purpose event (GPE) that signals "this device wants to wake the system." On this model, the embedded controller reports internal key presses and lid transitions through GPE 0x02, but the DSDT never attaches a _PRW to the lid device at \_SB.PC00.LPCB.LID0. Because nothing claims GPE 0x02, the kernel masks it at sleep, so key presses and lid openings never become wake events.
The power button fails for a different reason. In the FACP table, the Control Method Power Button flag is set to 1, which tells the OS to expect the button to signal through an ACPI control method rather than fixed hardware event logic. This firmware never delivers that event the way Linux expects, and clearing the flag restores wake-on-power-button.
USB devices keep working because they wake through the PCI/PCIe power-management path, which neither bug touches. That is why an external mouse or keyboard reliably wakes the machine while nothing built-in does.
Confirm the diagnosis before patching
grep LID0 /proc/acpi/wakeupreturns nothing — the lid device is absent entirely, meaning no wake path was ever declared for it.- Decompiled tables (below) show
Device (LID0)with no_PRWunderneath it, plus theControl Method Power Button (V1)flag set infacp.dsl.
Install the tooling and dump both tables:
sudo apt install acpica-tools cpio
mkdir -p ~/acpi-fix/kernel/firmware/acpi
cd ~/acpi-fix
sudo cat /sys/firmware/acpi/tables/FACP > facp.dat
iasl -d facp.dat
sudo cat /sys/firmware/acpi/tables/DSDT > dsdt.dat
iasl -d dsdt.dat
The odd-looking directory layout matters: the kernel only reads overrides from kernel/firmware/acpi inside the early initrd, so create that path now.
Patching the tables
Fix the power button in FACP
Open facp.dsl and make two edits:
- Raise
Oem Revisionby one (e.g.01072009→0107200A). The kernel loads an override only when its revision is at least as high as the shipped table's. - Change
Control Method Power Button (V1)from1to0.
Compile and place the result in the override directory:
iasl -tc facp.dsl
cp facp.aml kernel/firmware/acpi/
Give the lid a wake path via SSDT
First confirm the exact scope name in your DSDT — recent platforms use PC00, older ones PCI0:
grep -B 2 -A 6 "Device (LID0)" dsdt.dsl
Then write a small SSDT that adds the missing _PRW: GPE 0x02, wakeable from S0 (the second package element, Zero, matches how s2idle operates):
cat > ssdt-lidwake.asl <<'EOF'
DefinitionBlock ("", "SSDT", 2, "FIXUP", "LIDWAKE", 0x00000001)
{
External (\_SB.PC00.LPCB.LID0, DeviceObj)
Scope (\_SB.PC00.LPCB.LID0)
{
Name (_PRW, Package (0x02)
{
0x02,
Zero
})
}
}
EOF
iasl -tc ssdt-lidwake.asl
cp ssdt-lidwake.aml kernel/firmware/acpi/
If your LID0 lives under PCI0, adjust both the External and Scope lines; a mismatched path makes the SSDT a silent no-op.
Loading the override at boot
Pack the kernel/ directory into an uncompressed newc cpio archive and place it in /boot:
find kernel -print0 | cpio --null -o --format=newc > acpi_override
sudo cp acpi_override /boot/acpi_override
Register it as an extra early initrd by adding this line to /etc/default/grub, then run sudo update-grub and reboot:
GRUB_EARLY_INITRD_LINUX_CUSTOM="acpi_override"
Keeping the override in its own file — instead of baking it into the distribution initramfs — means kernel upgrades and initramfs regeneration scripts never touch it. After rebooting, verify:
grep LID0 /proc/acpi/wakeup
LID0 S0 *enabled platform:PNP0C0D:01
Suspend the machine and test the internal keyboard, the lid, and the power button. All three should now wake it.
Keeping the fix working
- Kernel updates: the override survives package upgrades because it is a separate early initrd, but re-test suspend after major kernel changes in case wake handling shifts.
- BIOS updates: if ASUS ships firmware that fixes these tables, remove the override (delete
/boot/acpi_overrideand the GRUB line, thensudo update-grub) instead of layering old patches onto new firmware. - Keep the sources: retain the
.dslfiles. If a future BIOS changes the GPE number or device path, you must re-dump and re-edit rather than reuse compiled blobs. - Safety net: a bad table loads very early and can prevent booting. Keep a live USB handy so you can delete
/boot/acpi_overrideif the machine ever refuses to start.
Frequently Asked Questions
Why doesn't writing to /proc/acpi/wakeup fix this?
That interface only toggles wake for devices that already declared a wake path. With no _PRW on the lid and no driver claiming GPE 0x02, there is nothing to enable — the missing object must come from the tables themselves.
Why do USB devices wake the laptop fine?
USB controllers signal wake through the PCI/PCIe power-management mechanism, not through the embedded controller's GPE. Both firmware bugs affect only the ACPI/fixed-event path the built-in devices use.
Is overriding ACPI tables risky?
The mechanism is kernel-supported and validates each override, but a malformed table loads very early. Compile cleanly, change as little as possible, and know how to remove the file from a live environment.
My DSDT shows PCI0 instead of PC00 — now what?
Device paths differ across firmware generations. Always grep the decompiled DSDT for the lid's actual parent scope and use that name in the SSDT.
Will a BIOS update fix it permanently?
Possibly. Check ASUS release notes for sleep or wake fixes; if the new firmware declares the wake paths correctly, delete the override and confirm behavior before discarding your working setup.