Waking The Framework Up (And Not)

A notebook computer with a rectangular piece of cloth over the keyboard.

The piece of cloth in the photo above made all the difference between key prints and a nice, homogeneous display in my old Thinkpad X240. Perhaps my new Framework's metal case is sturdy enough to keep the screen print-free even without extra precautions, but for now I don't want to try.

However, the cloth sometimes presses keys when the lid is closed, which would wake the machine up. That suggests to me, incidentally, that protecting the screen probably is a smart thing even on the Framework. Anyway: the Framework's firmware makes it wake up both when I open the lid and when (almost) any key is pressed on the built-in keyboard. And that does not fit my interactions with the computer. Hence, I want to configure it to only wake up when I press the power button; lid and keyboard events should be ignored when the machine is in suspend.

ACPI is a Four-Letter Word

“No problem”, I thought, “done that before”. The conventional way to select what wakes a machine up from suspend is to echo sometimes slightly intransparent ACPI identifiers into /proc/acpi/wakeup. Each echo toggles whether or not the machine will wake up when some activity occurs on that source; this could be USB or network ports, but also buttons and switches.

On the Framework, that's not so simple. First off, most of the ACPI identifiers are positively opaque even by ACPI standards:

$ cat /proc/acpi/wakeup
  Device      S-state   Status   Sysfs node
  AWAC          S4    *disabled
  XDCI          S4    *disabled
  XHCI          S4    *disabled  pci:0000:00:14.0
  HDAS          S4    *disabled  pci:0000:00:1f.3
  I3C0          S4    *disabled
  RP01          S4    *disabled  pci:0000:00:1c.0
  PXSX          S4    *disabled  pci:0000:a9:00.0
  RP02          S4    *disabled
  PXSX          S4    *disabled
  RP03          S4    *disabled
  PXSX          S4    *disabled
  RP04          S4    *disabled
  PXSX          S4    *disabled
  RP05          S4    *disabled
  PXSX          S4    *disabled
  RP06          S4    *disabled  pci:0000:00:1c.5
  PXSX          S4    *disabled  pci:0000:aa:00.0
  RP07          S4    *disabled
  PXSX          S4    *disabled
  RP08          S4    *disabled
  PXSX          S4    *disabled
  RP09          S4    *disabled
  PXSX          S4    *disabled
  RP10          S4    *disabled
  PXSX          S4    *disabled
  RP11          S4    *disabled
  PXSX          S4    *disabled
  RP12          S4    *disabled
  PXSX          S4    *disabled
  TXHC          S4    *disabled  pci:0000:00:0d.0
  TDM0          S4    *disabled  pci:0000:00:0d.2
  TDM1          S4    *disabled  pci:0000:00:0d.3
  TRP0          S4    *disabled  pci:0000:00:07.0
  PXSX          S4    *disabled
  TRP1          S4    *disabled  pci:0000:00:07.1
  PXSX          S4    *disabled
  TRP2          S4    *disabled  pci:0000:00:07.2
  PXSX          S4    *disabled
  TRP3          S4    *disabled  pci:0000:00:07.3
  PXSX          S4    *disabled

(originally, not all of them were disabled). I had hoped for something containing the letters “LID”; I would then have said something like:

echo LID > /proc/acpi/wakeup

and the machine would have slept on.

Alas: No LID, nothing I could recognise at all (if you can decode the four-letter words in the Framework's /proc/acpi other than XHCI, please enlighten me). And worse: even when I disabled all sources (which is normally unwise because you can't get the machine to wake up then), the Framework would still wake up on key presses and lid opens.

Well: ACPI. Four letters that are clearly a botched acronym for “vendors never get it right“.[1] Even the number of characters doesn't match.

Finding Wakeup Sources in sysfs

But then there is a second API to communicate wakeup preferences; this is via wakeup files in sysfs, which probably maps directly to hardware rather than through usually broken firmware like ACPI. Here, I am interested in wakeup sources from input devices.

You might plan on finding them like this:

find /sys/class/input -name wakeup

But that does not work because find does not follow symlinks, and /sys is full of symlinks. The reason find ignores symlinks by default becomes evident if your override that default:

$ find /sys/class/input -name wakeup -follow |& head -5
find: File system loop detected; ‘/sys/class/input/input9/event7/device’ is part of the same file system loop as ‘/sys/class/input/input9’.
find: File system loop detected; ‘/sys/class/input/input9/event7/subsystem’ is part of the same file system loop as ‘/sys/class/input’.
find: File system loop detected; ‘/sys/class/input/input9/device/driver/module/drivers/platform:pcspkr’ is part of the same file system loop as ‘/sys/class/input/input9/device/driver’.
find: File system loop detected; ‘/sys/class/input/input9/device/driver/pcspkr’ is part of the same file system loop as ‘/sys/class/input/input9/device’.
/sys/class/input/input9/device/subsystem/devices/i2c_designware.1/firmware_node/wakeup
[... and so on ad infinitum ...]

Fortunately, the locations of the wakeup files are predictable, and thus a plain shell pattern will work:

$ ls /sys/class/input/*/device/power/wakeup
/sys/class/input/input0/device/power/wakeup
/sys/class/input/input1/device/power/wakeup
/sys/class/input/input2/device/power/wakeup

So, we have three input devices that can raise the machine from the half-dead. Originally, all of them were enabled; on my box, I now have:

$ cat /sys/class/input/*/device/power/wakeu
disabled
enabled
disabled

Power Button Only, Please

How did I find out what input is what? Well, I had a look at the names of the devices:

$ cat /sys/class/input/input0/name
Lid Switch

This technique furthermore shows that input 1 is the power switch, and input 2 is the keyboard. I have no idea how stable these numbers are over time, models, and kernel and firmware versions; for now, I assume they will not change on reboots and have put the following into my /etc/rc.local:

echo disabled > /sys/class/input/input0/device/power/wakeup
echo disabled > /sys/class/input/input2/device/power/wakeup

If the paths turn out to be unstable, I think I'd do some grepping in that script to find, for instance, the path segment for the lid switch:

grep -i "Lid Switch" /sys/class/inputs/*/name | cut -f4 -d/

would give the lid switch's input path. But let's see if I will need that.

[1]

There are, by the way, strong indications that ACPI's brokenness is no accident. In the 2000 Iowa class action suit Comes v Microsoft (eventually won by the plaintiffs), an e-mail by Bill Gates was presented as evidence in which he, in 1999, wondered:

Maybe we could define the APIs so that they work well with NT and not with the others even if they are open.

On the positive side: They didn't even work well with Windows NT.

Kategorie: edv

Letzte Ergänzungen