Architecture

Differences between revisions 19 and 20
Revision 19 as of 2009-02-02 06:27:04
Size: 8009
Editor: port-213-160-23-154
Comment:
Revision 20 as of 2009-02-02 06:39:47
Size: 8204
Editor: port-213-160-23-154
Comment: clarify the status of /dev/nvram on ThinkPads (to the extent possible)
Deletions are marked like this. Additions are marked like this.
Line 89: Line 89:
On IBM/Lenovo laptops, some keys are only accessible via {{{/dev/nvram}}}. On IBM/Lenovo laptops, some keys are only accessible via {{{/dev/nvram}}}. This '''should''' be superseded by the `thinkpad_acpi` kernel module, but it's unconfirmed if this is the case for all older Think``Pad models. (It is definitely superseded for the T60 model.)


NOTE: This document is a work in progress. ACPI is a complex subsystem and impossible for any one person to fully understand. Please take a few minutes to improve this document with the bits you know!


Current architecture

hotkeys.png

Target architecture

hotkeys-sb.png

Here is the bird's-eye view of how key mapping works: The kernel recognizes the key and establishes a raw scancode and maps it to an arbitrary kernel keycode (e.g. e06d -> 120). Xorg reads the kernel's keycode table, and generates it's own list of X keycodes (e.g. 120 -> 136). X then maps each X keycode to a keysym (e.g. 136 -> XF86AudioMedia). Finally, the window manager maps the keysym to a desired window manager shortcut action or an application command (e.g. XF86AudioMedia -> rhythmbox).

Part A: Kernel keyboard mapping

All acpi events associated with keys are intended to be translated to keycodes in the kernel. MatthewGarrett is actively pursuing this in kernel upstream:

If a key's scancode is unknown to the kernel's keyboard mapping layer, this will typically result in a kernel log message when pressed. For instance, hitting the 'Media' key on a Dell Inspiron, we might see in dmesg output:

        atkbd.c: Unknown key pressed (translated set 2, code ... on isa0060/serio0).
        atkbd.c: Use 'setkeycodes e06d <keycode>' to make it known.

In the above, e06d is what we're looking for.

Generally, the keys will already be mapped but may be mapped to an incorrect keycode. In this case, use showkey -s from the console to see the raw scancodes, or showkey -k to see the keycodes. This will give output for Media on a Dell Inspiron 1505N like:

0x9c
0x00 0x80 0xe2
0x80 0x81 0xe2

Once the correct keymapping has been determined, this is configured either by setting a default in the per-platform hotkey kernel driver, or by overriding the kernel keymap using an fdi file in the hal-info package. You should not add any keymappings to the obsolete hotkey-setup package.

hal-info key maps

If the steps above revealed that the kernel does not know the key symbol for a particular key (or assigns the wrong symbol), the key can be added/changed in hal-info's keymaps (/usr/share/hal/fdi/information/10freedesktop/30-keymap-*). These have model-specific (system.hardware.vendor and system.hardware.product) scan code → key symbol mappings.

hal reads those FDI files and pokes them into the kernel with the EVIOCSKEYCODE ioctl.

Key codes

input-events outputs a "code/value" pair, which needs to be changed into a hex number which hal/the kernel understand. The meaning of "code" is unknown as of now (it is usually "4"). Values below 128 are put into hal-info as they are (just converted to hex), values above 128 must be converted:

  • hal_value = hex(value - 128 + 0xE0000)

Examples:

  • value

    hal-info representation

    1

    0x01

    16

    0x10

    127

    0x7f

    128

    0xe0000

    129

    0xe0001

FIXME: this doesn't seem to work for keys already known to input-events, how do we find the code/value pair in this case in order to be able to remap it?

Key symbol names

The file /usr/include/linux/input.h defines available key names. To convert this into a list of symbols which are valid to put into hal-info, use:

  •    awk '/^#define.*KEY_/ { if ($2 != "KEY_MAX") { print substr($2, 5) } }' /usr/include/linux/input.h

Case is ignored in hal-info's key names, but by convention you should use lower-case names.

ACPI-only keys

In some cases, your keys may be generating ACPI events instead of standard keycodes. To check this, stop acpid (if necessary), run cat /proc/acpi/event and then hit the key. You should see something like:

received event "ibm/hotkey HKEY 00000080 00001010"

The interesting bits here is the part between the quotes.

If a key generates an ACPI event but not a keypress, there are two possible ways to communicate this event to applications:

  • implement a platform-specific kernel ACPI driver that translates these ACPI events to keypress events on a dedicated input device (e.g., thinkpad_acpi); or

  • handle these events in hald-addon-acpi, which will relay these events over dbus.

The latter is the simpler option; however, not all ACPI events should be shown to all sessions, in which case the first solution is the only viable option.

On IBM/Lenovo laptops, some keys are only accessible via /dev/nvram. This should be superseded by the thinkpad_acpi kernel module, but it's unconfirmed if this is the case for all older ThinkPad models. (It is definitely superseded for the T60 model.)

Identify the kernel keycode to use by referring to /usr/share/hotkey-setup/key-constants. For example, browsing through the file we find KEY_MEDIA:

...
KEY_BRIGHTNESSDOWN=224
KEY_BRIGHTNESSUP=225
KEY_MEDIA=226
KEY_SWITCHVIDEOMODE=227
KEY_KBDILLUMTOGGLE=228
...

These codes are defined in /usr/include/linux/input.h.

Part B: Hal

Set up the kernel keycode mapping for the keyboard layout. These can be set up via HAL quirks. See Keymap Quirk Debugger for details. Essentially, you need to add or update a section in the appropriate FDI file in /usr/share/hal/fdi/information/10freedesktop/, such as 30-keymap-dell.fdi for a Dell Inspiron 1505N:

...
        <!-- Dell Inspiron 9400, 640m, E1505/6400 -->
        <match key="/org/freedesktop/Hal/devices/computer:system.hardware.product" prefix_outof="MP061;MXC061;MM061"> 
          <append key="input.keymap.data" type="strlist">e005:brightnessdown</append> <!-- Fn+Down arrow Brightness Down -->
          <append key="input.keymap.data" type="strlist">e006:brightnessup</append> <!-- Fn+Up arrow Brightness Up -->
          <append key="input.keymap.data" type="strlist">e007:battery</append> <!-- Fn+F3 battery icon -->
          <append key="input.keymap.data" type="strlist">e008:wlan</append> <!-- Fn+F2 Toggle WiFi -->
          <append key="input.keymap.data" type="strlist">e008:bluetooth</append> <!-- FIXME Bluetooth switch (same as wireless) -->
          <append key="input.keymap.data" type="strlist">e009:ejectclosecd</append> <!-- Fn+F10 Eject CD -->
          <append key="input.keymap.data" type="strlist">e00a:suspend</append> <!-- Fn+F1 hibernate -->
          <append key="input.keymap.data" type="strlist">e00b:switchvideomode</append> <!-- Fn+F8 CRT/LCD -->
          <append key="input.keymap.data" type="strlist">e012:media</append> <!-- MediaDirect button (house icon) -->
          <append key="info.capabilities" type="strlist">input.keymap</append>
        </match>
...

So for instance, to support the e06d code we found before, we'd create a new section like the above, substituting in e06d for e012 (and any other codes that need remapping), into a new product section.

Use lshal | grep system.hardware.product and lshal | grep system.hardware.vendor to determine the product name and vendor of your laptop.

To see if hal has picked up your keymaps, restart the hal daemon and use lshal | grep keymap, which gives output like:

  info.callouts.add = {'hal-setup-keymap'} (string list)
  info.capabilities = {'input', 'input.keyboard', 'input.keypad', 'input.keys', 'input.keymap', 'button'} (string list)
  input.keymap.data = {'e005:brightnessdown', 'e006:brightnessup', 'e007:battery', 'e008:wlan', 'e008:bluetooth', 'e009:ejectclosecd', 'e00a:suspend', 'e00b:switchvideomode', 'e012:media'} (string list)

Part C: Gnome/KDE hotkey mapping

At this point, gnome-keybinding-properties should now be able to detect your key. Check this by setting it for "Launch help browser" for example.

Hotkeys/Architecture (last edited 2009-07-08 14:28:19 by pD9EB7542)