Enabling acpi handling of Thinkpad keys

From Nearline Storage
Jump to: navigation, search

The ibm_acpi kernel module provides the facilities that allow ACPI to intercept some of the ThinkPad hotkey events on some ThinkPads. For details on what is and is not supported, see the ibm-acpi README. Using Fedore Core 4 as I am, this module is included and automatically loaded.

I wanted to get more control over the Fn-F7 display switching on my ThinkPad Z60t and I wanted to enable the Fn-F9 docking station eject button. I wanted the Fn-F7 hotkey to toggle between LCD-only and LCD/CRT modes, skipping the CRT-only mode that's part of the default rotation. I also wanted the screen resolution to automatically change to suit the display and to toggle HV expansion when I switched screens.

When my system boots the CRT port is enabled by default. Since that wastes power I disable it during the X server startup using these two scripts:

/etc/X11/xinit/xinitrc.d/disableCRT.sh:

#/bin/sh
sudo /home/dlk/bin/disableCRT.sh

/home/dlk/bin/disableCRT.sh:

#/bin/sh
echo crt_disable >/proc/acpi/ibm/video

To enable the ACPI functionality I wanted I added the following to /etc/rc.local:

### Enable ACPI handling of the Fn-F7 and Fn-F9 hotkey events
# See http://ibm-acpi.sourceforge.net/README for hotkey bit masks
# The base mask, with nothing set, is 0x080c
echo enable >/proc/acpi/ibm/hotkey
echo 0x094c >/proc/acpi/ibm/hotkey

To handle the hotkey events the way I wanted I created:

/etc/acpi/events/ibm_hotkey.conf:

event=ibm/hotkey HKEY 00000080 00001007
action=/etc/acpi/actions/fn-f7.sh
event=ibm/hotkey HKEY 00000080 00001009
action=/etc/acpi/actions/dock.sh eject

The quickest way to obtain the event codes is to enable all the hotkeys with "echo 0Xffff >/proc/acpi/ibm/hotkey" and then watch the log with "tail -f /var/log/acpid" while pressing the keys you're interested in. Here's a list of some of them:

Key Event Line
Fn-F3 event=ibm/hotkey HKEY 00000080 00001003
Fn-F4 event=ibm/hotkey HKEY 00000080 00001004
Fn-F5 event=ibm/hotkey HKEY 00000080 00001005
Fn-F7 event=ibm/hotkey HKEY 00000080 00001007
Fn-F9 event=ibm/hotkey HKEY 00000080 00001009
Fn-F12 event=ibm/hotkey HKEY 00000080 0000100c

Keep in mind what it says in the README, not all keys work on all ThinkPads. On some, no keys work at all.

With that configuration, when Fn-F7 is pressed /etc/acpi/actions/fn-f7.sh is called:

#!/bin/sh

CRT_STATUS=`grep crt: /proc/acpi/ibm/video | awk '{print $2}'`

## Get the information we need to talk to the X display.  This code was
## stolen from the FindXServer funtion in the Sleep2 hibernate script

[ -z "$DISPLAY" ] && DISPLAY=:0
export DISPLAY

# See if we need to authenticate to this X server.
PATH=$PATH:/usr/bin/X11:/usr/X11R6/bin
export PATH
xhost=`command -v xhost 2>/dev/null`
if [ $? -ne 0 ] ; then
    echo "Could not find xhost program."
fi

# Find a useful XAUTHORITY and ideally a username too if we can!
for xpid in `pidof kwrapper ksmserver kdeinit gnome-session fvwm fvwm2 pwm blackbox fluxbox X XFree86 Xorg` ; do
    # Ensure the process still exists, and we aren't hallucinating.
    [ -d "/proc/$xpid/" ] || continue

    xauth=`awk 'BEGIN{RS="\\000";FS="="}($1 == "XAUTHORITY"){print $2}' < /proc/$xpid/environ`
    xhome=`awk 'BEGIN{RS="\\000";FS="="}($1 == "HOME"){print $2}' < /proc/$xpid/environ`
    xuser=`/bin/ls -ld /proc/$xpid/ | awk '{print $3}'`
    [ -z $xauth ] && [ -n $xhome ] && [ -f $xhome/.Xauthority ] && xauth=$xhome/.Xauthority

    XAUTHORITY=$xauth su $xuser -c "$xhost" > /dev/null 2>&1 && break

    xauth=
    xuser=
done
if [ -n $xuser ] ; then
    XUSER=$xuser
    if [ -n "$xauth" ] ; then
        XAUTHORITY=$xauth
        export XAUTHORITY
    fi
else
    echo "Could not attach to X server on $DISPLAY."
    exit
fi

## End of FindXServer code

if [ "${CRT_STATUS}" = "disabled" ]; then
  echo video_switch >/proc/acpi/ibm/video
  sleep 1
  echo video_switch >/proc/acpi/ibm/video
  su "${XUSER}" -c "/usr/X11R6/bin/xrandr -d ${DISPLAY} -s 1"
  echo expand_toggle >/proc/acpi/ibm/video
else
  echo expand_toggle >/proc/acpi/ibm/video
  echo video_switch >/proc/acpi/ibm/video
  su "${XUSER}" -c "/usr/X11R6/bin/xrandr -d ${DISPLAY} -s 0"
fi

The resolutions associated with the xrandr size (-s) numbers vary depending on your X configuration. Do an "xrandr -q" to see what yours are and adjust the commands above appropriately.

/etc/acpi/actions/dock.sh is called with the "eject" option when Fn-F9 is pressed:

#!/bin/sh

#  Handle ACPI docking events

case "${1}" in
  eject)
    echo undock >/proc/acpi/ibm/dock
    ;;
  docked)
    echo dock >/proc/acpi/ibm/dock
    ;;
  *)
    echo $"Unknown event: ${*}"
    exit 1
esac

exit $?

The dock.sh script is also called by another ACPI event I set up to handle ACPI dock and undock events. Undock events are generated by the eject button on the docking station and docking events are generated by putting the ThinkPad into the dock whikle powered on. Live docking doesn't actually work, but it's in here anyway. Ejecting the ThinkPad live does work, sort of. I haven't worked out all the kinks as I rarely, if ever, undock live.

/etc/acpi/events/docking.conf:

event=ibm/dock GDCK 00000003 00000001
action=/etc/acpi/actions/dock.sh eject
event=ibm/dock GDCK 00000003 00000003
action=/etc/acpi/actions/dock.sh docked