This is a read-only archive. Find the latest Linux articles, documentation, and answers at the new Linux.com!

Linux.com

Feature

Improved ways to suspend and hibernate a laptop under Linux

By Manolis Tzanidakis on February 16, 2007 (8:00:00 AM)

Share    Print    Comments   

Last June I wrote about suspending and hibernating laptops under Linux. Since then a few things have changed -- thankfully, for the better -- so it's time to revisit the subject. Also, a few readers have responded offering suggestions for improving the suspend shell script I wrote back then, and I've incorporated these suggestions in a new version; unfortunately most of the comments are anonymous, so I can't give proper credit to their authors.

The most important change since the last article is that laptops with multi-core CPUs are now the de facto standard. Intel Core Duo and Core2 Duo processors not only offer Symmetric Multiprocessing (SMP) functionality to mobile users but also consume less power, and thus produce less heat, than their predecessors.

These new multi-core CPUs are supported by the Linux kernel, but you need a fairly recent version to fully utilize them in SMP mode. Suspend-to-RAM with SMP enabled works in kernel versions 2.6.18 onwards, but it's not 100% stable with occasional crashes on resume. Another problem I faced on a Core Duo system is the occasional miscalculation of the remaining battery life; the battery level might be at 70% one minute and then at 40% the next, and then back to 70%. However, things are greatly improved in kernel version 2.6.20 -- marked as release candidate now -- and if you own a multi-core laptop you should upgrade your kernel.

In the last article I mentioned the three available solutions for hibernating your system: swsusp (part of the kernel), uswsusp (an implementation of swsusp running in user space mode), and suspend2. I used the latter since it was the most stable and reliable method at the time. Suspend2 is a great piece of software, but it's not part of the Linux kernel, so it requires manual patching and kernel compilation.

The good news is that uswsusp is now stable, well integrated with kernel versions 2.6.17 onwards, and supported by most major Linux distributions. Debian (Etch and Sid) and Ubuntu (Edgy Eft and Feisty Fawn) users can install the uswusp package, enter their swap space partition when asked by the package manager, and then run s2disk to hibernate their laptop, as long as they run the stock kernel provided by their distribution.

Suspend script revisited and automation

Some readers suggested that the script I wrote for the previous article should store the system time to the hardware clock during suspend and then restore it from the hardware on resume to avoid clock skew problems. Actually, I use OpenNTPD on my systems to synchronize the clock over the network, so I've never faced such problems. Nevertheless it's a nice suggestion. Another reader with better knowledge of sed than me offered a way to discover the PCI ID of the video card using a single sed command instead of the combination of grep, awk, and sed I used; writing elegant shell scripts is a form of art, so this goes in the new version of the suspend script too.

I've also added the option to suspend or hibernate based on a given argument; you can now run suspend.sh suspend for suspend-to-RAM and suspend.sh hibernate for hibernation.

Here is the new and improved suspend script. Paste it as /usr/local/sbin/suspend.sh and make it executable with chmod +x /usr/local/sbin/suspend.sh.

#!/bin/sh

# discover video card's ID
ID=`lspci | sed -e '/VGA/!d' -e 's/ .*//' -e 's@0000:@@' -e 's@:@/@' -eq`

# securely create a temporary file
TMP_FILE=`mktemp /var/tmp/video_state.XXXXXX`
trap 'rm -f $TMP_FILE' 0 1 15

# switch to virtual terminal 1 to avoid graphics
# corruption in X
chvt 1

# synchronize system clock with hardware
hwclock --directisa --localtime --systohc

# write all unwritten data (just in case)
sync

# dump current data from the video card to the
# temporary file
cat /proc/bus/pci/$ID > $TMP_FILE

# suspend or hibernate
case "$1" in
  suspend)   echo -n mem > /sys/power/state ;;
  hibernate) s2disk  ;;
esac

# restore video card data from the temporary file
# on resume
cat $TMP_FILE > /proc/bus/pci/$ID

# synchronize hardware clock with system
hwclock --directisa --localtime --hctosys

# switch back to virtual terminal 7 (running X)
chvt 7

# remove temporary file
rm -f $TMP_FILE

I've tested this script on Debian Sid and Ubuntu Edgy Eft. Uswsusp offers the s2ram for suspending to RAM, but it didn't work correctly during my tests, so I stuck to the trusted ACPI method.

If your laptop has a GeForce video card and you use the proprietary Nvidia drivers, you don't need to store the video card data in a temporary file and restore it on resume, so remove those lines from the script. You need to follow some extra steps however. First of all, make sure to install the latest version of the 9xxx series of the Nvidia drivers (8xxx drivers don't suspend correctly) and load the nvidia kernel module with the NVreg_Mobile=1 option. Also, in the device section in /etc/X11/xorg.conf, add this line: Option "NvAGP" "1".

At this point I need to apologize to owners of ATI Radeon-based laptops; since I don't own one myself I can't help you any further.

Now, let's automate suspending or hibernating when closing the lid based on whether the AC adapter is present or not using acpid; i.e. suspend when the AC adapter is connected and hibernate when not. First create the /etc/acpi/events/lid file based on the instruction on the previous article, then paste the following as /etc/acpi/actions/lid.sh and make that file executable.

#!/bin/sh
if grep -q off-line /proc/acpi/ac_adapter/AC/state; then
  /usr/local/sbin/suspend.sh hibernate
else
  /usr/local/sbin/suspend.sh suspend
fi

Note that on your laptop the AC adapter might be called something different in the /proc file system, so adjust the script accordingly.

To automate things even further we'll have acpid hibernate the laptop automatically when the battery percentage level reaches 4%. Create the following files for handling battery events and actions:

/etc/acpi/events/battery

event=battery.*
action=/etc/acpi/actions/battery.sh

/etc/acpi/actions/battery.sh

#!/bin/sh
if grep -q on-line /proc/acpi/ac_adapter/AC/state; then
  exit 0
fi

BAT_DIR=/proc/acpi/battery/BAT0
FULL_BAT=`grep 'last full capacity' ${BAT_DIR}/info | awk '{ print $4 }'`
CUR_BAT=`grep 'remaining capacity' ${BAT_DIR}/state | awk '{ print $3 }'`
AVG=`expr $(expr ${CUR_BAT} \* 100) / ${FULL_BAT}`

if [ "$AVG" -le "4" ]; then
  /usr/local/sbin/suspend.sh hibernate
fi

Again, adjust the value of BAT_DIR to match your setup and make the second file executable with chmod +x /etc/acpi/actions/battery.sh. Start the acpid daemon and you're done.

Conclusion

Some readers might argue that this article is useless, since the last version of their favorite distribution does all these things automatically on their laptop. Sure, things have improved, but still they're not perfect; for example, Ubuntu Edgy Eft still doesn't resume my IBM ThinkPad R50e and Sony VAIO VGN-FE21M out of the box. However, distribution and kernel developers are not the ones to blame; the ACPI specification is largely misused by manufacturers. This article along, with sites such as TuxMobil and Linux on Laptops, could be useful for successfully running Linux on your laptop.

Share    Print    Comments   

Comments

on Improved ways to suspend and hibernate a laptop under Linux

Note: Comments are owned by the poster. We are not responsible for their content.

lock the screen after waking up

Posted by: Anonymous Coward on February 16, 2007 10:14 PM
You might want to add
su $USERNAME -c "/usr/bin/gnome-screensaver-command --lock"

(or xscreensaver-command) to the top of the script to lock the screen for better security.

#

kernel 2.6.20 is released

Posted by: Anonymous Coward on February 17, 2007 01:50 AM
2.6.20 was released on 4th of February.

#

ACPI sucks?

Posted by: Anonymous Coward on February 17, 2007 05:21 AM
I heard that the ACPI specification is over 500 pages long.

<a href="http://en.wikipedia.org/wiki/Advanced_Configuration_and_Power_Interface" title="wikipedia.org">http://en.wikipedia.org/wiki/Advanced_Configurati<nobr>o<wbr></nobr> n_and_Power_Interface</a wikipedia.org>

ACPI sucks?

#

Re:ACPI sucks?

Posted by: Anonymous Coward on February 17, 2007 06:30 AM
There are two ways of looking at the value of ACPI. The first is that bad OEMs can't implement it properly. The other is that you can disassemble the ACPI bytecode and possibly fix whatever the OEM screwed up on, without too much wizardry. That doesn't mean that hacking a DSDT is any fun, though.

#

hibernate package?

Posted by: Anonymous Coward on February 17, 2007 10:03 AM
Debian sarge, etch and sid have the 'hibernate' package (and I'd assume Ubuntu does as well). Simply run 'hibernate' as root, and the lill' script turns my laptop fast asleep.

Truly a gem.

#

Suspend2 patched kernels on Ubuntu

Posted by: Anonymous Coward on February 25, 2007 02:04 AM
There are patched kernels with suspend2 for ubuntu ready to be installed: <a href="http://3v1n0.tuxfamily.org/dists/edgy/suspend2/" title="tuxfamily.org">http://3v1n0.tuxfamily.org/dists/edgy/suspend2/</a tuxfamily.org>

Bye ^_^

#

Improve the AVG calc

Posted by: Administrator on February 17, 2007 12:22 PM
awk "/remaining/ {a=\"`awk '/last full/ {print $4}'<nobr> <wbr></nobr>/proc/acpi/battery/C171/info`\"; avg=\$3*100/a; print avg}"<nobr> <wbr></nobr>/proc/acpi/battery/C171/state

This makes the calculation of the AVG fater with less commands involved.

#

Re:Improve the AVG calc

Posted by: Administrator on February 17, 2007 12:24 PM
Sorry, the path to the files should be:
$BAT_DIR/info and $BAT_DIR/state

#

Re:Improve the AVG calc

Posted by: Administrator on February 17, 2007 12:35 PM
If you have two batteries like me you can modify the script like this:

count=0
for batery in `ls -1A<nobr> <wbr></nobr>/proc/acpi/battery/`; do

                bat_dir="/proc/acpi/battery/$batery/"

                AVG[$count]=awk "/remaining/ {a=\"`awk '/last full/ {print $4}' $bat_dir/info`\"; avg=\$3*100/a; print avg}" $bat_dir/state

                let count++
done
if [ "${AVG[0]}" -lt '4' ] && [ "${AVG[1]}" -lt '4' ]; then

This way you will prevent the hibernation when the first battery runs out.

#

suspend.sh not working on edgy

Posted by: Administrator on February 17, 2007 12:32 PM
I installed the package and tried these steps
and when testing the script i got this error :<nobr> <wbr></nobr>/etc/acpi$<nobr> <wbr></nobr>./lid.sh
Couldnt get a file descriptor referring to the console
Sorry, only the superuser can change the Hardware Clock.<nobr> <wbr></nobr>/usr/local/sbin/suspend.sh: 28: cannot create<nobr> <wbr></nobr>/sys/power/state: Permission denied<nobr> <wbr></nobr>/usr/local/sbin/suspend.sh: 32: cannot create<nobr> <wbr></nobr>/proc/bus/pci/01/00.0: Permission denied
Sorry, only the superuser can change the Hardware Clock.
Couldnt get a file descriptor referring to the console

Closed the lid, nothing happened.

Was able to execute the script as root and my laptop went into suspend mode, but got a blank screen when tried to resume by pressing the power button.
Any ideas...

Thanks

#

What if I also see "disk" is /sys/power/state

Posted by: Anonymous [ip: 77.125.110.172] on February 21, 2008 02:23 PM
Hi. I see "disk" and "mem" when I cat /sys/power/state. Does that mean i can just echo disk > that file and it'll suspend straight to disk?

#

This story has been archived. Comments can no longer be posted.



 
Tableless layout Validate XHTML 1.0 Strict Validate CSS Powered by Xaraya