If you use FreeBSD 11 on the good ol’ ThinkPad X201, you’ve probably noticed now that suspend and resume work perfectly flawlessly with the latest FreeBSD release.
You probably wish to take advantage of this and suspend your laptop automatically when the lid is closed. Nothing could be easier:
sysctl hw.acpi.lid_switch_state=S3
Save this option /etc/sysctl.conf
for it to be permanent.
Close the lid, the laptop goes to sleep, you’re done!
It’s that simple.
But, with this method it will go to sleep each time the lid is closed, completely ignoring whether the laptop is on battery or not. And if you’re like me you probably don’t want this. Instead you want it to suspend itself when the lid is closed and the laptop is on battery. Easy enough! We just have to invoke the mighty power of devd along with a very little shell script.
First we need to tell devd how to react when the lid is closed. Put this in /etc/devd/lid.conf
, then restart (service devd restart
):
# Notify lid close/open events. notify 10 { match "system" "ACPI"; match "subsystem" "Lid"; action "/etc/acpi/lid.sh $notify"; };
Now we will make a script that checks the lid and AC line states and chooses to suspend the laptop when both the lid is closed and AC line is disconnected. This goes in /etc/acpi/lid.sh
:
#!/bin/sh lid="$1" # 0x00 is closed, 0x01 is open (see devd.conf) acline=$(sysctl -n hw.acpi.acline) # 0 is battery, 1 is online (man acpi) if [ \( "$lid" = "0x00" \) -a \( "$acline" -eq 0 \) ] then logger "Lid closed on battery. Going to sleep." acpiconf -s3 fi
Try it out! Disconnect the AC line, close the lid, it should go to sleep within seconds. However if it doesn’t work you might want to modify the script above a little to check whether lid events are received correctly or not.
Now you may use a modified version of this script to lock xscreensaver when the lid is closed and before the actual suspend. Well OK, I’ve done that for you:
#!/bin/sh # XScreensaver should be called BEFORE going to sleep to avoid the desktop to be # shown for a few seconds when the system resumes from sleep. PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin lid="$1" # 0x00 is closed, 0x01 is open (see devd.conf) acline=$(sysctl -n hw.acpi.acline) # 0 is battery, 1 is online (man acpi) lock_display() ( socket="$1" display=$(echo "$socket" | tr "X" ":") # Temporary pid file for the watching command tpid=$(mktemp) # Wait until the display is actually locked. (timeout 2s xscreensaver-command -display "$display" -watch & echo $! > $tpid) | ( # Issue the lock command only when we know that # the watching pipe is ready. xscreensaver-command -display "$display" -lock while read line do line=$(echo $line | cut -d' ' -f 1) if [ "$line" = LOCK ] then # We have to kill the watching command manually before breaking. kill -TERM $(cat $tpid) break fi done ) rm $tpid ) # The X server may not be running if [ ! -d /tmp/.X11-unix ] then exit 0 fi # Lock each available display for socket in $(ls /tmp/.X11-unix) do # Lock the display logger "Locking xscreensaver on $socket" lock_display $socket & done # Wait until every displays are locked wait # Now we can suspend if needed if [ \( "$lid" = "0x00" \) -a \( "$acline" -eq 0 \) ] then logger "Lid closed on battery. Going to sleep." acpiconf -s3 fi