[RESPONDED] Waking from suspend w/ lid closed

It has been quite some time since I last reported my experience in this thread.
Good news: since I applied “the two noticeable changes in my habits” (cf my previous message), my Framework 16 laptop successfully wakes up from s2idle sleep every time.
Of course, it is also possible that something was fixed by a kernel update (the laptop runs Debian Sid).

Bad news: I experienced the lid-hitting-the-keyboard-or-touchpad issue multiple times, both at home when the cat walks on the laptop (cat-proofing is the next step after dog-fooding) and when traveling. Regarding the latter, system logs confirm the laptop typically wakes up when I start walking. Depending on how long I walk and what is running on my laptop, it may or may not be burning hot when I finally take it out of my bagpack.
I intend to investigate whether I can configure the exact kind of events that wake up my system so as to work around that issue, but a firmware update that ignores all Framework input modules when the lid is closed would make sense.

2 Likes

Modifying my cheesy little script to account for lid state and multiple keyboards is left as an exercise for the reader

The script below targets USB and i2c devices so as to disable wakeup only for devices known to sit under the lid – the regex can probably be further adjusted to account for devices I do not own.

#!/usr/bin/env bash

state='disabled'

# Framework keyboard and numpad should not wake the laptop:
grep -l 'Framework' /sys/bus/usb/devices/*/manufacturer |\
	sed 's/manufacturer$/product/' |\
	xargs grep -lP 'Laptop 16 (Keyboard|Numpad) Module' |\
	sed 's/product$//' |\
	while read -r framework_keyboard_device;
do
	echo "${state}" > "${framework_keyboard_device}/power/wakeup"
done

# The PixArt touchpad should not wake the laptop:
for pixart_device in /sys/bus/i2c/devices/i2c-PIXA*; do
	echo "${state}" > "${pixart_device}/power/wakeup"
done
1 Like

Here’s a systemd unit to run that script on boot for those wanting to quickly add it to their system:

[Unit]
Description=Prevents keyboard and trackpad from waking machine while lid is closed by calling /etc/disable-wakeup.sh

[Service]
Type=oneshot
ExecStart=/etc/disable-wakeup.sh

[Install]
WantedBy=multi-user.target

To add it, copy the above unit file and run:

sudoedit /etc/systemd/system/disable-wakeup.service

Paste the text. Save and exit your editor.

Copy Xavier’s script and run:

sudoedit /etc/disable-wakeup.sh

Paste the text. Save and exit your editor.

Then run these commands to “install” the new service:

sudo chmod a+x /etc/disable-wakeup.sh
sudo systemctl daemon-reload
sudo systemctl enable --now disable-wakeup.service

@Peter_J_Stewart: nice – although, on my side, I simply dropped my script in /usr/lib/systemd/system-sleep/20-disable-wakeup.sh, as hinted by @Victor_Lowther. It seems there is no documented /etc counterpart to that /usr directory.

Additionally, since we are discussing scripts and workaround, here is my cat-proof script for Linux+X.org: it runs unprivileged but requires the DISPLAY environment to be set. Otherly put, it must be launched as part of the X session (possibly via XDG autostart). It polls the lid state and enables/disables all input devices underneath accordingly. That way, my cat can walk on the laptop without inputting anything.

#!/usr/bin/env bash

DEVICES=(
'Framework Laptop 16 Keyboard Module - ANSI Keyboard'
'Framework Laptop 16 Numpad Module Keyboard'
'keyboard:Framework Laptop 16 Numpad Module Consumer Control'
'PIXA3854:00 093A:0274 Mouse'
'PIXA3854:00 093A:0274 Touchpad'
)

script_name=$(basename "$0")
device_id_file="/tmp/${script_name}.ids"
if [ ! -f "${device_id_file}" ]; then
	for device in "${DEVICES[@]}"; do
		xinput list --id-only "${device}"
	done > "${device_id_file}"
fi

current_state=''
known_state=''

function get_state {
	[[ "$(</proc/acpi/button/lid/LID0/state)" =~ open ]] && current_state='open' || current_state='closed'
}

function state_changed {
	[ "${known_state}" == 'open' ] && action='enable' || action='disable'
	adjust_devices "${action}"
}

function adjust_devices {
	local action="$1"
	xargs -n 1 xinput "${action}" < "${device_id_file}"
}

function update_state {
	get_state
	if [ "${current_state}" != "${known_state}" ]; then
		known_state="${current_state}"
		state_changed
	fi
}

function watch_state {
	while sleep 5; do
		update_state
	done
}

if [ "$1" ]; then
	adjust_devices "${1}"
	exit
fi
watch_state