input: add hackish fn handling to twl4030_keypad
authorGrazvydas Ignotas <notasas@gmail.com>
Sat, 26 Jun 2010 20:03:59 +0000 (23:03 +0300)
committerGrazvydas Ignotas <notasas@gmail.com>
Fri, 3 Jun 2011 22:29:29 +0000 (01:29 +0300)
drivers/input/keyboard/twl4030_keypad.c

index 09bef79..fbaba2d 100644 (file)
@@ -56,7 +56,7 @@
  * row lines connected to the gnd (see twl4030_col_xlate()).
  */
 #define TWL4030_ROW_SHIFT      4
-#define TWL4030_KEYMAP_SIZE    (TWL4030_MAX_ROWS << TWL4030_ROW_SHIFT)
+#define TWL4030_KEYMAP_SIZE    ((TWL4030_MAX_ROWS << TWL4030_ROW_SHIFT) * 2)
 
 struct twl4030_keypad {
        unsigned short  keymap[TWL4030_KEYMAP_SIZE];
@@ -65,6 +65,9 @@ struct twl4030_keypad {
        unsigned        n_cols;
        unsigned        irq;
 
+       unsigned        fn_down:1;
+       unsigned        fn_sticked:1;
+
        struct device *dbg_dev;
        struct input_dev *input;
 };
@@ -231,7 +234,8 @@ static void twl4030_kp_scan(struct twl4030_keypad *kp, bool release_all)
 
                /* Extra column handles "all gnd" rows */
                for (col = 0; col < kp->n_cols + 1; col++) {
-                       int code;
+                       int code, kcode, is_down;
+                       int code2;
 
                        if (!(changed & (1 << col)))
                                continue;
@@ -241,9 +245,34 @@ static void twl4030_kp_scan(struct twl4030_keypad *kp, bool release_all)
                                "press" : "release");
 
                        code = MATRIX_SCAN_CODE(row, col, TWL4030_ROW_SHIFT);
+                       kcode = kp->keymap[code];
+                       is_down = (new_state[row] & (1 << col)) ? 1 : 0;
+
+                       dev_dbg(kp->dbg_dev, "code:     %d %d\n", code, kcode);
+                       /* Fn handling */
+                       if (kcode == KEY_FN) {
+                               kp->fn_down = is_down;
+                               kp->fn_sticked |= is_down;
+                       } else if (kp->fn_down || kp->fn_sticked) {
+                               /* make sure other function is up */
+                               input_event(input, EV_MSC, MSC_SCAN, code);
+                               input_report_key(input, kcode, 0);
+
+                               code = MATRIX_SCAN_CODE(row + TWL4030_MAX_ROWS,
+                                       col, TWL4030_ROW_SHIFT);
+                               kcode = kp->keymap[code];
+
+                               kp->fn_sticked = 0;
+                       } else {
+                               code2 = MATRIX_SCAN_CODE(row + TWL4030_MAX_ROWS,
+                                       col, TWL4030_ROW_SHIFT);
+                               input_event(input, EV_MSC, MSC_SCAN, code2);
+                               input_report_key(input, kp->keymap[code2], 0);
+                       }
+
+                       dev_dbg(kp->dbg_dev, "code(fn): %d %d\n", code, kcode);
                        input_event(input, EV_MSC, MSC_SCAN, code);
-                       input_report_key(input, kp->keymap[code],
-                                        new_state[row] & (1 << col));
+                       input_report_key(input, kcode, is_down);
                }
                kp->kp_state[row] = new_state[row];
        }
@@ -368,7 +397,7 @@ static int __devinit twl4030_kp_probe(struct platform_device *pdev)
 
        input_set_capability(input, EV_MSC, MSC_SCAN);
 
-       input->name             = "TWL4030 Keypad";
+       input->name             = "keypad";
        input->phys             = "twl4030_keypad/input0";
        input->dev.parent       = &pdev->dev;