红联Linux门户
Linux帮助

A Thinkpad X61 Hotkeys Solution on Debian Linux

发布时间:2007-11-06 00:18:38来源:红联作者:bitrated
On my old Thinkpad X31, there is a nice little program called tpb that makes all Thinkpad hotkeys work on Linux. However, that project hasn't been updated for two years, and tpb does not work with the newer Thinkpad models. On my new X61, notably, the sound volume controls are broken: volume UP and volume Down keys produce the same effect - bring the volume to the half level. It seems that piece of hardware called nvram, on which tpb relies, now produces different values than older models. So, I have to ditch tpb. After some trial and errors, I worked out a mixed solution that made all keys work as expected.

What's needed

* Newer kernel. At least 2.6.16 or above (not sure exact version number).

* acpid. Newer laptops all support ACPI, so acpid should be used. I believe all linux distribution has it.

* thinkpad_acpi. This kernel module deals with Thinkpad hardware and generate ACPI events, such as temperature change, function key press, docking, etc. This module is included in the mainline kernel since 2.6.10. The version included in kernel 2.6.22 is thinkpad_acpi 0.14. The latest version is 0.18. I find 0.14 works fine. Maybe 0.18 is better, I don't know. If this module is loaded, cat /proc/acpi/ibm/driver should show its version number. If not, load the module with modprobe thinkpad_acpi. If you want it autoloaded on boot, put a line thinkpad_acpi in /etc/modules. If your kernel doesn't has this module (unlikely), you will have to download the source and build the module yourself.

* powersaved This daemon is what actually handles ACPI events. In the past, people put ACPI events handling scripts in /etc/acpi directory. Now this is not recommended. So you should not install similar packages such as acpi-support, hibernate scripts, etc. Instead, user space program such as powersaved should handle ACPI events. Therefore, all your ACPI customizations should be done under either /usr/lib/powersave/scripts or /etc/powersave

* uswsusp This user space software suspend package is called by powersaved to actually do sleeping (i.e. saving state in RAM, so sleep and resume are quick) and hibernation (i.e. save state on disk, so it lasts).

All these are already packaged in Debian. Just use apt-get to install them.

What's worked: without configuration

Without any software, sound Mute key and Thinklight key always work, they are hardware controlled I think.

With the above package installed, "Fn+F12 hibernate" worked without any problem. "Fn+F4 sleep" may or may not work. Please follow the suggestions in this s2ram documentation, and test the command options in order, until sleep works. My X61 worked with s2ram -f -a 1, so I stopped testing other options. Once found a successful combination, edit /usr/lib/powersave/sleep, so that these two options reads

SUSPEND2RAM_FORCE="yes"
SUSPEND2RAM_ACPI_SLEEP="1" #use your successful -a number here, mine is 1
"Fn+F5 toggle bluetooth" seems to work, as I can turn the bluetooth LED on and off with it and get corresponding KPowersave notification (I am on KDE).

I do not have a dock, so I can't test "Fn+F9 docking".

"Fn+F2 lock screen", "Fn+F7 toggle display", "Fn+Home brightness up", "Fn+End brightness down", "Fn+space zoom" , and "ThinkVantage", did not work out of box. But ACPI sees them, so I configured powersaved to make them work. See below.

"Volume Up/Down", "Fn+up stop", "Fn+down play", "Fn+left rewind", "Fn+right forward", "Page Left/Right", "Windows", and "Menu" did not work out of box, but X sees them, so I configured Xmodmap and KDE shortcuts to make them work. See below.

There's a battery icon on "Fn+F3", pressing it turned screen blank, but the backlight was still on, so it's useless. I used powersaved to make it a switch to go into power save mode - low LCD brightness and low power level. See below.

From the icon on it, "Fn+F8" seems to be a touchpad/touchpoint switch, and pressing it had no effect, since X61 doesn't have a touchpad. I made it a switch to presentation mode - no screensaver, no auto sleep, etc. See below.

Configure ACPI hotkeys with powersaved

Most of the Thinkpad function keys can be dealt with by editing /usr/lib/powersaved/scripts/thinkpad_acpi_events. Mine is below:

#!/bin/bash
###########################################################################
# #
# Powersave Daemon #
# #
# Copyright (C) 2005,2006 SUSE Linux Products GmbH #
# #
# Author(s): Based on code by Stefan Seyfried #
# Hotkey support by Alex Solovey, solovey@us.ibm.com #
# Enhancements (docking station support) by Holger Macht #
# #
# This program is free software; you can redistribute it and/or modify it #
# under the terms of the GNU General Public License as published by the #
# Free Software Foundation; either version 2 of the License, or (at you #
# option) any later version. #
# #
# This program is distributed in the hope that it will be useful, but #
# WITHOUT ANY WARRANTY; without even the implied warranty of #
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU #
# General Public License for more details. #
# #
# You should have received a copy of the GNU General Public License along #
# with this program; if not, write to the Free Software Foundation, Inc., #
# 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #
# #
###########################################################################
#
# thinkpad_acpi_events - process ThinkPad specific ACPI events generated by
# ibm_acpi driver and log them to syslog
#
# Configuration changes required for the script to work with powersave package:
# 1) Set EVENT_OTHER="thinkpad_acpi_events" in /etc/sysconfig/powersave/events
# 2) Place this script into /usr/lib/powersave/scripts directory
#
#########################################################################
#
# Customized by Huahai Yang to support Thinkpad X61 ACPI keys on KDE.
# Added on screen visual feedback for key press, the following keys are
# supported on top of existing powersaved supported keys:
# - Fn+F1 to start wireless connection
# - Fn+F2 to lock desktop
# - Fn+F3, F6, F8 to switch among Powersave, Performance and Presentation
# mode
# - Fn+F7 to toggle external display
# - Fn+F11 to start LAN connection
# - Fn+Home, Fn+End to increase, decrease LCD brightness
# - Fn+Space to toggle screen resolution
# - ThinkVantage to open konsole
#
#########################################################################
PATH=/bin:/usr/bin:/usr/X11R6/bin:/sbin:/usr/sbin # be paranoid, we're running as root.

# First, we pull in the helper functions.
. ${0%/*}/helper_functions # `dirname $0`/helper_functions
# get_x_user comes from here...
. ${0%/*}/x_helper_functions # `dirname $0`/x_helper_functions
export PATH

ME=${0##*/} # basename $0

# argument $4 is set to $EV_ID in helper_functions which is included above
if [ -z "$EV_ID" ]; then
DEBUG "$ME 'Sorry, not enough arguments: $4 is empty.'" WARN
$SCRIPT_RETURN $EV_ID 1 "$ME finished unsuccessful."
exit 1
fi

# this script run as root, so we need to pretend we are the user, or
# X functionalities won't work.
run_on_xserver() {
get_x_user
DEBUG "User $X_USER display $DISP $1 " INFO
su - $X_USER -c "DISPLAY=$DISP $1"
}

HOTKEY=$3

TYPE=$1

DEBUG "Custom event script for ThinkPad ibm_acpi driver" INFO

# we discard $2 which is the name of the current scheme.
set $HOTKEY # powersaved gives us "other '' ''"
# so we must split $3 to get the contents of /proc/acpi/event.
EVENT=$1 # "ibm/hotkey"
ACPI=$2 # "HOTK"
WHAT=$3 # "00000080"
SERIAL=$4 # "0000100c" Fn+F12

# it is easier to deal with numerical values (for me :-)
declare -i VAL
VAL=0x$WHAT # hex -> decimal
declare -i SER
SER=0x$SERIAL # hex -> decimal

# on screen display, it's always good to have visual feedback
OSD="DISPLAY=:0.0 osd_cat -p bottom -o 80 -A center -c green -l 1 -f -*-lucidatypewriter-*-r-*-*-*-240-*-*-*-*-*-*"

if [ "$EVENT" = "ibm/hotkey" ]; then
ACTION="log event"
if [ "$VAL" -eq 128 ]; then
case $SER in
4097) HOTKEY="Fn+F1"
/home/directory/bin/wireless.sh &
ACTION="make wireless connection"
;;
4098) HOTKEY="Fn+F2"
#run_on_xserver "dcop kdesktop KScreensaverIface lock"
run_on_xserver "xscreensaver-command -lock"
ACTION="lock screen"
;;
4099) HOTKEY="Fn+F3"
powersave -e Powersave
run_on_xserver "echo 'Power Save Mode' | $OSD" &
ACTION="enter powersave mode"
;;
4100) HOTKEY="Fn+F4"
ACTION="suspend-to-ram"
run_on_xserver "xscreensaver-command -lock" &
run_on_xserver "xset dpms force suspend"
. $SYSCONF_DIR/sleep
[ "$DISABLE_USER_SUSPEND2RAM" != "yes" ] && powersave "--$ACTION"
;;
4101) HOTKEY="Fn+F5"
if [ -x /opt/thinkpad/ac/onscreen_ac.sh ] ; then
run_on_xserver "/opt/thinkpad/ac/onscreen_ac.sh start" &
ACTION="start onscreen_ac applet"
elif grep -q "status.*disabled" /proc/acpi/ibm/bluetooth ; then
echo enable > /proc/acpi/ibm/bluetooth
ACTION="enable blooetooth"
else
echo disable > /proc/acpi/ibm/bluetooth
ACTION="disable blooetooth"
fi
;;
4102) HOTKEY="Fn+F6"
powersave -e Performance
run_on_xserver "echo 'Full Performance Mode' | $OSD" &
ACTION="enter full performance mode"
;;
4103) HOTKEY="Fn+F7"
ACTION="toggle external display"
if run_on_xserver "xrandr -q" | grep "VGA connected"; then
if run_on_xserver "xrandr -q" | grep "VGA connected [0-9]\+"; then
run_on_xserver "echo 'Turn OFF External VGA Display' | $OSD" &
run_on_xserver "xrandr --output VGA --off"
else
run_on_xserver "echo 'Turn ON External VGA Display' | $OSD" &
run_on_xserver "xrandr --output VGA --auto"
fi
else
run_on_xserver "echo 'External VGA Display is DISCONNECTED' | $OSD" &
fi
;;
4104) HOTKEY="Fn+F8"
powersave -e Presentation
run_on_xserver "echo 'Presentation Mode' | $OSD" &
ACTION="enter presentation mode"
;;
4105) HOTKEY="Fn+F9"
ACTION="undock"
echo undock > /proc/acpi/ibm/dock
;;
4106) HOTKEY="Fn+F10" ;;
4107) HOTKEY="Fn+F11"
ACTION="make NIC connection"
run_on_xserver "echo 'Connecting LAN...' | $OSD" &
/home/directory/bin/nic.sh &
;;
4108) HOTKEY="Fn+F12"
ACTION="suspend-to-disk"
run_on_xserver "xscreensaver-command -lock" &
. $SYSCONF_DIR/sleep
[ "$DISABLE_USER_SUSPEND2DISK" != "yes" ] && powersave "--$ACTION"
;;
4109) HOTKEY="Fn+Backspace" ;;
4110) HOTKEY="Fn+Insert" ;;
4111) HOTKEY="Fn+Delete" ;;
4112) HOTKEY="Fn+Home"
powersave -ku
ACTION="brighter display"
;;
4113) HOTKEY="Fn+End"
powersave -kd
ACTION="dimmer display"
;;
4116) HOTKEY="Fn+Zoom"
ACTION="toggle screen resolution"
run_on_xserver "/home/directory/bin/toggle-zoom.sh"
;;
4120) HOTKEY="Thinkpad"
run_on_xserver "konsole" &
ACTION="launch konsole"
;;
*) HOTKEY="Unidentified" ;;
esac
else
HOTKEY="Unidentified"
fi
elif [ "$EVENT" = "ibm/bay" ]; then
case $VAL in
1) HOTKEY="Eject lever inserted" ;;
3) HOTKEY="Eject Request" ;;
*) HOTKEY="Unidentified" ;;
esac
elif [ "$EVENT" = "ibm/dock" ]; then
case $VAL in
0) if [ $SER -eq 3 ]; then # X32 has strange dock code
HOTKEY="Dock requested"
ACTION="Docking"
echo dock > /proc/acpi/ibm/dock 2>&1
fi
;;
1) HOTKEY="Dock requested"
ACTION="Docking"
echo dock > /proc/acpi/ibm/dock 2>&1
;;
3) HOTKEY="Undock requested"
ACTION="Undocking"
echo undock > /proc/acpi/ibm/dock 2>&1
;;
esac
DEBUG "$HOTKEY: keycode $VAL serial $SER. action: $ACTION " INFO
else
DEBUG "Unidentified event: $EVENT $ACPI $WHAT $SERIAL" INFO
fi

$SCRIPT_RETURN $EV_ID 0 "$ME finished"
EXIT 0
Notice that you need to install osd_cat package to get on-screen display, or you can comments out them. Also, I used xscreensaver to lock screen, because KDE screen saver and locker do not support ThinkFinger. I like the coolness of login and unlocking screen with a finger swipe :) Finally, I use my own simple scripts to make network connections. Here is nic.sh:

#!/bin/sh
# This script brings up wired network connection (plug in cable first!). With
# augument "stop", it turns off wired network interface. Root privilige
# is required to run
#
if [ "$1" = "stop" ];
then
ifdown eth0
else
ifup eth0

# restart some services that depends on networking
/etc/init.d/samba restart
/etc/init.d/spamassassin restart
fi
And here is wireless.sh

#!/bin/sh
# This script use Matthew Brett's wlan-ui.pl to select a wireless AP to
# connect to. With augument "stop", it turns off wireless network interface.
# Root privilige is required to run
#
if [ "$1" = "stop" ];
then
ifconfig eth1 down #my wireless interface is mapped to eth1, yours may be different
else
DISPLAY=:0.0 wlan-ui.pl

# restart some services that depends on networking
/etc/init.d/samba restart
/etc/init.d/spamassassin restart
fi
wlan-ui.pl is a GTK-2 based little GUI program that scans the available wireless access points, and allows you to connect to one of them. The only configuration needed is to put the name of your wireless card kernel module name in /etc/wlan-uirc, mine has a line:$MODULE='ipw3945'

Configure the rest of hotkeys
ACPI does not deal with the rest of the hotkeys. But most of these can be seen by X, so it's possible to map them to any functions you like.

First, need to get their keycodes. Use xev to do that and write down the keycodes.

Second, edit your ~/.Xmodmap, put these keycodes in, assign them reasonable XF86 names, and mine is here:

! Page Left, Right
keycode 234 = F19
keycode 233 = F20

! multimedia
keycode 162 = XF86AudioPlay
keycode 164 = XF86AudioStop
keycode 153 = XF86AudioNext
keycode 144 = XF86AudioPrev

! volume up, down
keycode 174 = XF86AudioLowerVolume
keycode 176 = XF86AudioRaiseVolume

! Windows keys
keycode 117 = XF86MenuKB
keycode 115 = XF86Start

! No Caps Lock
clear lock
! Caps Lock as Win key
add mod4 = Caps_Lock
Now try xmodmap ~/.Xmodmap, then go to KDE Control Center > Regional and Accessibility > Input Actions, and associate these keys with whatever actions you like.

To autoload your Xmodmap setting, create a file in ~/.kde/Autostart, and put the xmodmap command in. Mine is:

#!/bin/sh
# map keys
xmodmap ~/.Xmodmap
xprop -root -f _XKB_RULES_NAMES 8s -set _XKB_RULES_NAMES xorg
setxkbmap -model pc105 -layout us -variant nodeadkeys

# allow X access by root
xhost +

# Start xscreensaver
xscreensaver -no-splash &
To properly handle volume up and down keys, I associated these keys with this script:

#!/bin/sh
#########################################################################
# Bring up or down sound volume with amixer, with on screen display
# the volume range is 0-58.5dB, so we change 4.5dB each run, it takes
# 13 run to go from 0 to 58.5dB
#
# Usage: audio-volume.sh [up|down]
#
########################################################################
if [ "$1" = "up" ]
then
PERCENT=$(amixer set PCM 4.5dB+ | \
sed -n -e 's/[^\[]*\[\([0-9]*\)\%\][^\%]*/\1/p' -e 'n')
elif [ "$1" = "down" ]
then
PERCENT=$(amixer set PCM 4.5dB- | \
sed -n -e 's/[^\[]*\[\([0-9]*\)\%\][^\%]*/\1/p' -e 'n')
else
PERCENT=$(amixer get PCM | \
sed -n -e 's/[^\[]*\[\([0-9]*\)\%\][^\%]*/\1/p' -e 'n')
fi

osd_cat -b percentage -P $PERCENT -d 1 -p bottom -o 80 -i 100 -A left -c green -T "Sound Volume" &
That's all there is to it. Now all hotkeys work as intended, and with nice on-screen user feedback. Please let me know if I missed anything.
文章评论

共有 0 条评论