![]() ![]() |
![]()
|
My Configuration for
|
||||||||||||||||||||||
| power button | lid button | |
| on AC power | shut down if power button was pressed the second time within 4 seconds, else ignored | suspend if power button was pressed at most 4 seconds before, else ignored |
| on battery | shut down | suspend |
| shutting down | ignore | ignore |
Here you will find the main shell script that performs the steps for the above operations. The action is taken either from the name that was used to call the script or from the first parameter.
We use variables to set up the locations of lock files and the ACPI files.
#!/bin/sh -e
# /etc/acpi/lidbtn.sh
# Initiates a sleep S1 if the display lid is closed.
# Wake up by pressing on/off button.
LOCKDIR=/var/lock
SUSPEND_LOCK=$LOCKDIR/suspend
POWER_LOCK=$LOCKDIR/power
LID_STATE_FILE="/proc/acpi/button/lid/LID/state"
AC_STATE_FILE="/proc/acpi/ac_adapter/AC/state"
Here are the functions we use to access the states of the lid, the AC adapter and the current runlevel.
get_lid_state() {
local TEMP STATE
# there shoud only be one directory in /proc/acpi/button/lid/
read TEMP STATE < $LID_STATE_FILE
case $STATE in
clo*|CLO*) echo CLOSE ;;
*) echo OPEN ;;
esac
}
get_ac_adapter_state() {
local TEMP STATE
read TEMP STATE < $AC_STATE_FILE
case $STATE in
off*|OFF*) echo OFF ;;
*) echo ON ;;
esac
}
get_runlevel() {
local STATE
STATE=`/sbin/runlevel | cut -c3`
case $STATE in
0|6) echo OFF ;;
1|2|3|4|5) echo ON ;;
esac
}
Perhaps some care must be taken for suspend. E.g., my notebook will not wake up correctly if USB was still running, so I will shut down the hotplug system before suspend and restart it after the system wakes up from suspend. And saving the system clock to the hardware clock is always a good idea. ;o)
enter_standby() {
# create lock file
touch $SUSPEND_LOCK
echo enter_standby
# work around bug in USB re-initialization after sleep
/etc/init.d/hotplug stop
# reset the hardware clock to the system clock
hwclock --systohc
# put the notebook to sleep
echo -n 1 > /proc/acpi/sleep
}
leave_standby() {
echo leave_standby
# work around bug in USB re-initialization after sleep
/etc/init.d/hotplug start
# reset the system clock to the hardware clock
hwclock --hctosys
# rm lock files
rm -f $SUSPEND_LOCK $POWER_LOCK
}
if [ "`get_runlevel`" == "OFF" ]; then
# shutting down: ignore any action
exit 0
fi
# get the action
if [ -z $1 ]; then
ACTION=$0
else
ACTION=$1
fi
echo "action=$ACTION"
case $ACTION in
*lidbtn.sh)
if [ ! -e $SUSPEND_LOCK -a "`get_lid_state`" == "CLOSE" ]; then
# we are not suspending...
if [ -e $POWER_LOCK -o "`get_ac_adapter_state`" == "OFF" ];
then
# ...and the power button was pressed before or we run
# on battery
enter_standby
fi
fi
;;
*powerbtn.sh)
if [ -e $SUSPEND_LOCK ]; then
# we were suspended, so this is the wake up event
leave_standby
elif [ -e $POWER_LOCK -o "`get_ac_adapter_state`" == "OFF" ];
then
# the power button was pressed before or we run on battery
# so we will shut down the system
echo shutting down
rm -f $SUSPEND_LOCK $POWER_LOCK
/sbin/init 0
else
# the power button is pressed the first time and we are
# not running on battery. We will remember the power
# button event by creating the lock file and removing it
# (in a new shell) after 4 seconds.
echo prepare shut down or standby
touch $POWER_LOCK
( sleep 4 ; rm $POWER_LOCK ) &
fi
;;
*ac_adapter.sh)
if [ ! -e $SUSPEND_LOCK -a "`get_ac_adapter_state`" == "OFF" ];
then
if [ "`get_lid_state`" == "CLOSE" ]; then
# we switch to from AC power to battery. Therfore if
# the lid is closed we will suspend the machine.
enter_standby
else
echo ac ignore
fi
fi
;;
*standby)
if [ ! -e $SUSPEND_LOCK ]; then
enter_standby
fi
;;
esac
acpid Event Triggers
Store the above script in e.g. /etc/acpi/lidbtn.sh and create /etc/acpi/ac_adapter.sh and /etc/acpi/powerbtn.sh as (symbolic or hard) links to the file.
Now we have to disable the default events. The simple way to do so is to rename the /etc/acpi/events directory and create a new one.
/etc/acpi/events/ac_adapter
event=ac_adapter
action=/etc/acpi/ac_adapter.sh
/etc/acpi/events/lidbtn
event=button/lid
action=/etc/acpi/lidbtn.sh
/etc/acpi/events/powerbtn
event=button[ /]power
action=/etc/acpi/powerbtn.sh
You can download this configuration as a tar file. Please let me know if it was useful for you and if you could improve the script.
You can also download my new configuration for SuSE 9.2/kernel 2.6.8 (see below for a description of changes). Please let me know if it works for you.
With SuSE 9.1 it was no longer possible to use my script(s) if you were also using the powersaved - and since that tool provides some nice features I recommend to use it. But powersaved read the /proc/acpi/events, so that it was impossible to start acpid.
In SuSE 9.2 the powersaved was changed to get its events from acpid and thus using my scripts with acpid is possible, again.
Along with this change the new Linux kernel that comes with SuSE 9.2 (kernel 2.6.8) provides software suspend to disk that works with my notebook (the first time). Sleep and suspend-to-disk seem to work without shutting down hotplug.
So what actually changed? The acpid that is started from the powersaved init script uses the configuration in /etc/acpi/events.ignore. So the trigger there (events.ignore) has to be moved (or removed) and my own triggers go there.
Next there is a change in ACPI event handling: any ACPI event seems to wake
up the notebook from sleep and that event is not reported (any more). So
deleting the suspend lock triggered by the power button will not work (well).
Instead I added a sleep 1 and a call to leave_standby in
enter_standby, to get the lock removed.
Instead of shutting down the system (on power button pressed twice) I now
perform a suspend to disk. To do so I copied the code from enter_standby
and replaced the sleep-command (echo -n 1 > /proc/acpi/sleep)
with the suspend-to-disk command (echo -n disk > /sys/power/state)
There seem to be a problem with button events dissapearing
in the 2.6.x series of the kernel (Thanks to Andrew Waldram for reporting
this). Reloading the kernel module "button"
will prevent the events from disappearing.
You can also download my new configuration for SuSE 9.2/kernel 2.6.8.
No warranty! All information I'm giving here is provided without any guarantee. I hope it is useful (please let me know if so), but I will not be responsible for any harm happening to someone or something due to this description.