>From beedbe850eacedbee25e39ff68cf59e42402ba4e Mon Sep 17 00:00:00 2001
From: Jekyll Lai <[email protected]>
Date: Tue, 4 Jan 2011 14:15:11 +0800
Subject: [PATCH 3/3] mid_keypad: support multiple keypad matrixes

Add DMI scan to distinguish which keypad will be used.

Signed-off-by: Jekyll Lai <[email protected]>
---
 drivers/input/keyboard/intel_mid_keypad.c |  170
++++++++++++++++++++++++-----
 1 files changed, 142 insertions(+), 28 deletions(-)

diff --git a/drivers/input/keyboard/intel_mid_keypad.c
b/drivers/input/keyboard/intel_mid_keypad.c
index 8886158..48e0755 100644
--- a/drivers/input/keyboard/intel_mid_keypad.c
+++ b/drivers/input/keyboard/intel_mid_keypad.c
@@ -6,6 +6,7 @@
  * Copyright (c) 2009 Intel Corporation.
  * Created:    Sep 18, 2008
  * Updated:    May 14, 2010
+ * Copyright (C) 2010 Jekyll Lai, Wistron <[email protected]>
  *
  * Based on pxa27x_keypad.c by Rodolfo Giometti <[email protected]>
  * pxa27x_keypad.c is based on a previous implementation by Kevin
O'Connor
@@ -28,7 +29,7 @@
  */
 
 #define DRV_NAME       "mrst_keypad"
-#define DRV_VERSION    "0.0.1"
+#define DRV_VERSION    "1.2"
 #define MRST_KEYPAD_DRIVER_NAME   DRV_NAME " " DRV_VERSION
 
 #include <linux/kernel.h>
@@ -38,6 +39,7 @@
 #include <linux/interrupt.h>
 #include <linux/input.h>
 #include <linux/device.h>
+#include <linux/dmi.h>
 #include <linux/err.h>
 #include <linux/gpio.h>
 
@@ -118,6 +120,51 @@
 #define KEY_HALFSHUTTER                KEY_PROG1
 #define KEY_FULLSHUTTER                KEY_CAMERA
 
+#define SHIFT_NEEDED    (0x1000)
+#define ALTGR_NEEDED    (0x2000)
+
+#define KEY_EXCLAM      (KEY_1 + SHIFT_NEEDED)  /* '!' -> shift+1 */
+#define KEY_AT          (KEY_2 + SHIFT_NEEDED)  /* '@' -> shift+2 */
+#define KEY_NUMBER_SIGN (KEY_3 + SHIFT_NEEDED)  /* '#' -> shift+3 */
+#define KEY_DOLLAR_SIGN (KEY_4 + SHIFT_NEEDED)  /* '$' -> shift+4 */
+#define KEY_PERCENT     (KEY_5 + SHIFT_NEEDED)  /* '%' -> shift+5 */
+#define KEY_NOR         (KEY_6 + SHIFT_NEEDED)  /* '^' -> shift+6 */
+#define KEY_AMPERSAND   (KEY_7 + SHIFT_NEEDED)  /* '&' -> shift+7 */
+#define KEY_PPARENL     (KEY_9 + SHIFT_NEEDED)  /* '(' -> shift+9 */
+#define KEY_PPARENR     (KEY_0 + SHIFT_NEEDED)  /* ')' -> shift+0 */
+
+#define KEY_UNDERSCORE  (KEY_MINUS + SHIFT_NEEDED) /* '_' -> shift+- */
+#define KEY_COLON       (KEY_SEMICOLON + SHIFT_NEEDED) /* ':' ->
shift+; */
+#define KEY_QUOTE_DBL   (KEY_APOSTROPHE + SHIFT_NEEDED) /* '"' ->
shift+' */
+#define KEY_TILDE       (KEY_GRAVE + SHIFT_NEEDED) /* '~' -> shift+` */
+#define KEY_QUEST_SIGN  (KEY_SLASH + SHIFT_NEEDED) /* '?' -> shift+/ */
+
+#define KEY_EURO_SIGN   (KEY_2 + ALTGR_NEEDED) /* AltGr+2 */
+#define KEY_POUND_SIGN  (KEY_3 + ALTGR_NEEDED) /* AltGr+3 */
+
+static unsigned int mrst_mm_keycode[MAX_MATRIX_KEY_NUM] = {
+       KEY_1, KEY_8, KEY_T, KEY_S, KEY_L, KEY_N, 0, KEY_MINUS,
+       KEY_2, KEY_9, KEY_Y, KEY_D, KEY_BACKSPACE, KEY_M, 0,
KEY_RIGHTALT,
+       KEY_3, KEY_0, KEY_U, KEY_F, KEY_Z, KEY_AT, 0, KEY_RIGHTSHIFT,
+       KEY_4, KEY_Q, KEY_I, KEY_G, KEY_X, KEY_UNDERSCORE, 0, 0,
+       KEY_5, KEY_W, KEY_O, KEY_H, KEY_C, KEY_COMMA, 0, 0,
+       KEY_6, KEY_E, KEY_P, KEY_J, KEY_V, KEY_DOT, 0, 0,
+       KEY_7, KEY_R, KEY_A, KEY_K, KEY_B, KEY_SPACE, 0, 0,
+       KEY_LEFTSHIFT, KEY_FN, KEY_ENTER, 0, 0, 0, 0, 0
+};
+
+/* Fn key mapping */
+static unsigned int mrst_mm_keycode_fn[MAX_MATRIX_KEY_NUM] = {
+       KEY_NUMBER_SIGN, KEY_KPASTERISK, 0, 0, KEY_GRAVE, KEY_SEMICOLON,
0, 0,
+       KEY_EURO_SIGN, KEY_KPPLUS, 0, 0, 0, KEY_COLON, 0, 0,
+       KEY_POUND_SIGN, KEY_EQUAL, KEY_PPARENL, 0, 0, 0, 0, 0,
+       KEY_DOLLAR_SIGN, 0, KEY_PPARENR, 0, 0, KEY_KPMINUS, 0, 0,
+       KEY_PERCENT, 0, KEY_TILDE, 0, 0, KEY_EXCLAM, 0, 0,
+       KEY_NOR, 0, KEY_SLASH, KEY_APOSTROPHE, 0, KEY_QUEST_SIGN, 0, 0,
+       KEY_AMPERSAND, 0, 0, KEY_QUOTE_DBL, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+};
+
 static unsigned int mrst_keycode[MAX_MATRIX_KEY_NUM] = {
        KEY_F, KEY_D, KEY_E, KEY_GRAVE, KEY_C, KEY_R, KEY_4, KEY_V,
        KEY_NUMLOCK, KEY_LEFTCTRL, KEY_Z, KEY_W, KEY_2, KEY_X, KEY_S,
KEY_3,
@@ -218,6 +265,31 @@ struct mrst_keypad {
        int count;
 };
 
+enum keymap_type {
+       DEFAULT_KEYMAP,
+       MM_KEYMAP,
+};
+
+/* To determine different keypad matrix */
+static int keymap_mode;
+
+static int __init dmi_matched(const struct dmi_system_id *dmi)
+{
+       keymap_mode = (int)dmi->driver_data;
+       return 1;
+}
+
+static const struct dmi_system_id __initconst dmi_ids[] = {
+       {
+               .callback = dmi_matched,
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VERSION,
"MM-A2.0-07-1G-4pcs"),
+               },
+               .driver_data = (void *)MM_KEYMAP
+       },
+       { NULL, }
+};
+
 static void mrst_keypad_build_keycode(struct mrst_keypad *keypad)
 {
        struct input_dev *input_dev = keypad->input_dev;
@@ -226,23 +298,40 @@ static void mrst_keypad_build_keycode(struct
mrst_keypad *keypad)
 
        keypad->matrix_key_rows = MAX_MATRIX_KEY_ROWS;
        keypad->matrix_key_cols = MAX_MATRIX_KEY_COLS;
-       keypad->direct_key_num = MAX_DIRECT_KEY_NUM;
        keypad->matrix_key_map_size = MAX_MATRIX_KEY_NUM;
        keypad->debounce_interval = DEBOUNCE_INTERVAL;
 
-       /* three sets of keycode here */
-       if (keypad->fn)
-               memcpy(keypad->matrix_keycodes, mrst_keycode_fn,
-                      sizeof(keypad->matrix_keycodes));
-       else if (keypad->numlck)
-               memcpy(keypad->matrix_keycodes, mrst_keycode_numlck,
-                      sizeof(keypad->matrix_keycodes));
-       else
-               memcpy(keypad->matrix_keycodes, mrst_keycode,
-                      sizeof(keypad->matrix_keycodes));
-
-       memcpy(keypad->direct_key_map, mrst_direct_keycode,
-              sizeof(keypad->direct_key_map));
+       if (keymap_mode == MM_KEYMAP) {
+               keypad->direct_key_num = 0;
+               /* three sets of keycode here */
+               if (keypad->fn)
+                       memcpy(keypad->matrix_keycodes,
mrst_mm_keycode_fn,
+                               sizeof(keypad->matrix_keycodes));
+               else
+                       memcpy(keypad->matrix_keycodes, mrst_mm_keycode,
+                               sizeof(keypad->matrix_keycodes));
+       } else {
+               keypad->direct_key_num = MAX_DIRECT_KEY_NUM;
+               /* three sets of keycode here */
+               if (keypad->fn)
+                       memcpy(keypad->matrix_keycodes, mrst_keycode_fn,
+                               sizeof(keypad->matrix_keycodes));
+               else if (keypad->numlck)
+                       memcpy(keypad->matrix_keycodes,
mrst_keycode_numlck,
+                               sizeof(keypad->matrix_keycodes));
+               else
+                       memcpy(keypad->matrix_keycodes, mrst_keycode,
+                               sizeof(keypad->matrix_keycodes));
+
+               memcpy(keypad->direct_key_map, mrst_direct_keycode,
+
sizeof(keypad->direct_key_map));
+
+               key = &keypad->direct_key_map[0];
+               for (i = 0; i < keypad->direct_key_num; i++, key++) {
+                       code = (*key) & 0xffffff;
+                       set_bit(code, input_dev->keybit);
+               }
+       }
 
        key = &keypad->matrix_keycodes[0];
        for (i = 0; i < MAX_MATRIX_KEY_NUM; i++, key++) {
@@ -250,12 +339,6 @@ static void mrst_keypad_build_keycode(struct
mrst_keypad *keypad)
                set_bit(code, input_dev->keybit);
        }
 
-       key = &keypad->direct_key_map[0];
-       for (i = 0; i < keypad->direct_key_num; i++, key++) {
-               code = (*key) & 0xffffff;
-               set_bit(code, input_dev->keybit);
-       }
-
        keypad->enable_rotary0 = 0;
        keypad->enable_rotary1 = 0;
 }
@@ -266,6 +349,21 @@ static inline unsigned int lookup_matrix_keycode(
        return keypad->matrix_keycodes[(row << 3) + col];
 }
 
+/* translate the non-exist keycode keys */
+static void translate_keycode(struct mrst_keypad *keypad,
+                               unsigned int keycode, int isdown)
+{
+       if (keycode & SHIFT_NEEDED) {
+               keycode = keycode & ~(SHIFT_NEEDED);
+               input_report_key(keypad->input_dev, KEY_RIGHTSHIFT,
isdown);
+       } else if (keycode & ALTGR_NEEDED) {
+               keycode = keycode & ~(ALTGR_NEEDED);
+               input_report_key(keypad->input_dev, KEY_RIGHTALT,
isdown);
+       }
+
+       input_report_key(keypad->input_dev, keycode, isdown);
+}
+
 static void handle_constant_keypress(struct mrst_keypad *keypad,
                                     int num, int col, int row,
                                     int state)
@@ -294,6 +392,10 @@ static void handle_constant_keypress(struct
mrst_keypad *keypad,
 
        case 1:
                /* if Fn pressed */
+               if (keymap_mode == MM_KEYMAP) {
+                       if (col == 1 && row == 7)
+                               keypad->fn = 1;
+               } else {
                if (col == 6 && row == 6)
                        keypad->fn = 1;
                /* key '[' */
@@ -320,6 +422,7 @@ static void handle_constant_keypress(struct
mrst_keypad *keypad,
                        set_bit(KEY_DOT, dev->key);
                        dev->repeat_key = KEY_DOT;
                }
+               }
 
                return;
        default:
@@ -332,7 +435,8 @@ static void mrst_keypad_scan_matrix(struct
mrst_keypad *keypad)
        int row, col, num_keys_pressed = 0;
        uint32_t new_state[MAX_MATRIX_KEY_COLS];
        uint32_t kpas = keypad_readl(KPAS);
-       int status;
+       int status, isdown;
+       unsigned int keycode;
 
        num_keys_pressed = KPAS_MUKP(kpas);
 
@@ -382,6 +486,10 @@ static void mrst_keypad_scan_matrix(struct
mrst_keypad *keypad)
                new_state[6] = kpasmkp3 & KPASMKP_MKC_MASK;
                new_state[7] = (kpasmkp3 >> 16) & KPASMKP_MKC_MASK;
 
+               if (keymap_mode == MM_KEYMAP) {
+                       if (new_state[1] & 0x80)
+                               keypad->fn = 1;
+               } else {
                /* if Fn is pressed, all SHIFT is ignored, except when {
                 * or } is pressed */
                if (new_state[6] & 0x40) {
@@ -404,8 +512,7 @@ static void mrst_keypad_scan_matrix(struct
mrst_keypad *keypad)
                                new_state[6] &= ~0x40;
                }
        }
-
-
+       }
 scan:
        /* re-build keycode */
        mrst_keypad_build_keycode(keypad);
@@ -421,9 +528,14 @@ scan:
                        if ((bits_changed & (1 << row)) == 0)
                                continue;
 
-                       input_report_key(keypad->input_dev,
-                               lookup_matrix_keycode(keypad, row, col),
-                               new_state[col] & (1 << row));
+                       keycode = lookup_matrix_keycode(keypad, row,
col);
+                       isdown = new_state[col] & (1 << row);
+
+                       if (keymap_mode == MM_KEYMAP)
+                               translate_keycode(keypad, keycode,
isdown);
+                       else
+                               input_report_key(keypad->input_dev,
keycode,
+                                       isdown);
                }
        }
        input_sync(keypad->input_dev);
@@ -546,7 +658,6 @@ static void mrst_keypad_set_alt_func(void)
        iounmap(mem);
 }
 
-
 static int mrst_keypad_gpio_init(struct mrst_keypad *keypad)
 {
        int i, err, cnt = 0;
@@ -695,6 +806,9 @@ static int __devinit mrst_keypad_probe(struct
pci_dev *pdev,
                goto failed_free_io;
        }
 
+       keymap_mode = DEFAULT_KEYMAP;
+       dmi_check_system(dmi_ids);
+
        input_dev->name = pci_name(pdev);
        input_dev->id.bustype = BUS_PCI;
        input_dev->open = mrst_keypad_open;
-- 
1.7.0.4

_______________________________________________
MeeGo-kernel mailing list
[email protected]
http://lists.meego.com/listinfo/meego-kernel

Reply via email to