thinkpad-acpi: add support for model-specific keymaps
Henrique de Moraes Holschuh [Tue, 10 Aug 2010 02:48:21 +0000 (23:48 -0300)]
Use the quirks engine to select model-specific keymaps, which makes
it much easier to extend should we need it.

Keycodes are based on the tables at
http://www.thinkwiki.org/wiki/Default_meanings_of_special_keys.

Signed-off-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
Signed-off-by: Matthew Garrett <mjg@redhat.com>

drivers/platform/x86/thinkpad_acpi.c

index b0b66fb..9ebe4f7 100644 (file)
@@ -3093,6 +3093,8 @@ static const struct tpacpi_quirk tpacpi_hotkey_qtable[] __initconst = {
        TPACPI_Q_IBM('1', 'D', TPACPI_HK_Q_INIMASK), /* X22, X23, X24 */
 };
 
+typedef u16 tpacpi_keymap_t[TPACPI_HOTKEY_MAP_LEN];
+
 static int __init hotkey_init(struct ibm_init_struct *iibm)
 {
        /* Requirements for changing the default keymaps:
@@ -3124,9 +3126,17 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
         * If the above is too much to ask, don't change the keymap.
         * Ask the thinkpad-acpi maintainer to do it, instead.
         */
-       static u16 ibm_keycode_map[TPACPI_HOTKEY_MAP_LEN] __initdata = {
+
+       enum keymap_index {
+               TPACPI_KEYMAP_IBM_GENERIC = 0,
+               TPACPI_KEYMAP_LENOVO_GENERIC,
+       };
+
+       static const tpacpi_keymap_t tpacpi_keymaps[] __initconst = {
+       /* Generic keymap for IBM ThinkPads */
+       [TPACPI_KEYMAP_IBM_GENERIC] = {
                /* Scan Codes 0x00 to 0x0B: ACPI HKEY FN+F1..F12 */
-               KEY_FN_F1,      KEY_FN_F2,      KEY_COFFEE,     KEY_SLEEP,
+               KEY_FN_F1,      KEY_BATTERY,    KEY_COFFEE,     KEY_SLEEP,
                KEY_WLAN,       KEY_FN_F6, KEY_SWITCHVIDEOMODE, KEY_FN_F8,
                KEY_FN_F9,      KEY_FN_F10,     KEY_FN_F11,     KEY_SUSPEND,
 
@@ -3157,8 +3167,10 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
                /* (assignments unknown, please report if found) */
                KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN,
                KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN,
-       };
-       static u16 lenovo_keycode_map[TPACPI_HOTKEY_MAP_LEN] __initdata = {
+               },
+
+       /* Generic keymap for Lenovo ThinkPads */
+       [TPACPI_KEYMAP_LENOVO_GENERIC] = {
                /* Scan Codes 0x00 to 0x0B: ACPI HKEY FN+F1..F12 */
                KEY_FN_F1,      KEY_COFFEE,     KEY_BATTERY,    KEY_SLEEP,
                KEY_WLAN,       KEY_FN_F6, KEY_SWITCHVIDEOMODE, KEY_FN_F8,
@@ -3200,10 +3212,25 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
                /* (assignments unknown, please report if found) */
                KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN,
                KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN,
+               },
        };
 
-#define TPACPI_HOTKEY_MAP_SIZE         sizeof(ibm_keycode_map)
-#define TPACPI_HOTKEY_MAP_TYPESIZE     sizeof(ibm_keycode_map[0])
+       static const struct tpacpi_quirk tpacpi_keymap_qtable[] __initconst = {
+               /* Generic maps (fallback) */
+               {
+                 .vendor = PCI_VENDOR_ID_IBM,
+                 .bios = TPACPI_MATCH_ANY, .ec = TPACPI_MATCH_ANY,
+                 .quirks = TPACPI_KEYMAP_IBM_GENERIC,
+               },
+               {
+                 .vendor = PCI_VENDOR_ID_LENOVO,
+                 .bios = TPACPI_MATCH_ANY, .ec = TPACPI_MATCH_ANY,
+                 .quirks = TPACPI_KEYMAP_LENOVO_GENERIC,
+               },
+       };
+
+#define TPACPI_HOTKEY_MAP_SIZE         sizeof(tpacpi_keymap_t)
+#define TPACPI_HOTKEY_MAP_TYPESIZE     sizeof(tpacpi_keymap_t[0])
 
        int res, i;
        int status;
@@ -3212,6 +3239,7 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
        bool tabletsw_state = false;
 
        unsigned long quirks;
+       unsigned long keymap_id;
 
        vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_HKEY,
                        "initializing hotkey subdriver\n");
@@ -3352,7 +3380,6 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
                goto err_exit;
 
        /* Set up key map */
-
        hotkey_keycode_map = kmalloc(TPACPI_HOTKEY_MAP_SIZE,
                                        GFP_KERNEL);
        if (!hotkey_keycode_map) {
@@ -3362,17 +3389,14 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
                goto err_exit;
        }
 
-       if (tpacpi_is_lenovo()) {
-               dbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_HKEY,
-                          "using Lenovo default hot key map\n");
-               memcpy(hotkey_keycode_map, &lenovo_keycode_map,
-                       TPACPI_HOTKEY_MAP_SIZE);
-       } else {
-               dbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_HKEY,
-                          "using IBM default hot key map\n");
-               memcpy(hotkey_keycode_map, &ibm_keycode_map,
-                       TPACPI_HOTKEY_MAP_SIZE);
-       }
+       keymap_id = tpacpi_check_quirks(tpacpi_keymap_qtable,
+                                       ARRAY_SIZE(tpacpi_keymap_qtable));
+       BUG_ON(keymap_id >= ARRAY_SIZE(tpacpi_keymaps));
+       dbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_HKEY,
+                  "using keymap number %lu\n", keymap_id);
+
+       memcpy(hotkey_keycode_map, &tpacpi_keymaps[keymap_id],
+               TPACPI_HOTKEY_MAP_SIZE);
 
        input_set_capability(tpacpi_inputdev, EV_MSC, MSC_SCAN);
        tpacpi_inputdev->keycodesize = TPACPI_HOTKEY_MAP_TYPESIZE;