Re: Buffer overrun in the TWL4030 keypad driver with Nokia RX51

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi Laurent.

On Fri, Jul 16, 2010 at 05:28:43PM +0200, Laurent Pinchart wrote:
> Hi everybody,
> 
> I've spent the day debugging a kernel crash in the USB networking code to find 
> out the problem was caused by a buffer overrun in the TWL4030 keypad driver. 
> 
> The Nokia RX51 board code (arch/arm/mach-omap2/board-rx51-peripherals.c) 
> defines a key map for the matrix keypad keyboard. The hardware seems to use 
> all of the 8 rows and 8 columns of the keypad, although not all possible 
> locations are used.
> 
> The TWL4030 supports keypads with at most 8 rows and 8 columns. Most keys are 
> defined with a row and column number between 0 and 7, except
> 
>         KEY(0xff, 2, KEY_F9),
>         KEY(0xff, 4, KEY_F10),
>         KEY(0xff, 5, KEY_F11),
> 
> The row number is set to 0xff. As the generic matrix keypad support 
> (include/linux/input/matrix_keypad.h) supports at most 16 rows and 16 columns, 
> it masks all but the lower 4 bits of the row and column numbers in the KEY 
> macro.

[..snipped..]

Thanks for the report. Could yo uplease try the patch below and let me
know if it works.

I have some concerns with the keymap assignments, I see that Amit
changed them during KEY(col, row) -> KEY(row, col) conversion. I marked
the entries I am concerned with with XXX.

Thanks.

-- 
Dmitry

Input: twl40300-keypad - fix handling of "all ground" rows

From: Dmitry Torokhov <dmitry.torokhov@xxxxxxxxx>

The Nokia RX51 board code (arch/arm/mach-omap2/board-rx51-peripherals.c)
defines a key map for the matrix keypad keyboard. The hardware seems to
use all of the 8 rows and 8 columns of the keypad, although not all
possible locations are used.

The TWL4030 supports keypads with at most 8 rows and 8 columns. Most keys
are defined with a row and column number between 0 and 7, except

        KEY(0xff, 2, KEY_F9),
        KEY(0xff, 4, KEY_F10),
        KEY(0xff, 5, KEY_F11),

which represent keycodes that should be emitted when entire row is
connected to the ground. The driver handles this case as if we had an
extra column in the key matrix. Unfortunately we do not allocate enough
space and end up owerwriting some random memory.

Reported-by: Laurent Pinchart <laurent.pinchart@xxxxxxxxxxxxxxxx>
Signed-off-by: Dmitry Torokhov <dtor@xxxxxxx>
---

 arch/arm/mach-omap2/board-rx51-peripherals.c |   28 ++++++++++++++++++++------
 drivers/input/keyboard/twl4030_keypad.c      |   17 ++++++++++------
 2 files changed, 32 insertions(+), 13 deletions(-)


diff --git a/arch/arm/mach-omap2/board-rx51-peripherals.c b/arch/arm/mach-omap2/board-rx51-peripherals.c
index abdf321..ea32143 100644
--- a/arch/arm/mach-omap2/board-rx51-peripherals.c
+++ b/arch/arm/mach-omap2/board-rx51-peripherals.c
@@ -175,6 +175,10 @@ static void __init rx51_add_gpio_keys(void)
 #endif /* CONFIG_KEYBOARD_GPIO || CONFIG_KEYBOARD_GPIO_MODULE */
 
 static int board_keymap[] = {
+	/*
+	 * Note that KEY(x, 8, KEY_XXX) entries represent "entire row
+	 * connected to the ground" matrix state.
+	 */
 	KEY(0, 0, KEY_Q),
 	KEY(0, 1, KEY_O),
 	KEY(0, 2, KEY_P),
@@ -182,6 +186,8 @@ static int board_keymap[] = {
 	KEY(0, 4, KEY_BACKSPACE),
 	KEY(0, 6, KEY_A),
 	KEY(0, 7, KEY_S),
+//	KEY(0, 8, KEY_F6),	// XXX was removed
+
 	KEY(1, 0, KEY_W),
 	KEY(1, 1, KEY_D),
 	KEY(1, 2, KEY_F),
@@ -190,6 +196,8 @@ static int board_keymap[] = {
 	KEY(1, 5, KEY_J),
 	KEY(1, 6, KEY_K),
 	KEY(1, 7, KEY_L),
+//	KEY(1, 8, KEY_F7),	// XXX was moved to (7, 1)
+
 	KEY(2, 0, KEY_E),
 	KEY(2, 1, KEY_DOT),
 	KEY(2, 2, KEY_UP),
@@ -197,6 +205,8 @@ static int board_keymap[] = {
 	KEY(2, 5, KEY_Z),
 	KEY(2, 6, KEY_X),
 	KEY(2, 7, KEY_C),
+	KEY(2, 8, KEY_F9),	// XXX was F8 and moved to (7, 2), F9 was (4, 8)
+
 	KEY(3, 0, KEY_R),
 	KEY(3, 1, KEY_V),
 	KEY(3, 2, KEY_B),
@@ -205,20 +215,24 @@ static int board_keymap[] = {
 	KEY(3, 5, KEY_SPACE),
 	KEY(3, 6, KEY_SPACE),
 	KEY(3, 7, KEY_LEFT),
+
 	KEY(4, 0, KEY_T),
 	KEY(4, 1, KEY_DOWN),
 	KEY(4, 2, KEY_RIGHT),
 	KEY(4, 4, KEY_LEFTCTRL),
-	KEY(4, 5, KEY_RIGHTALT),
-	KEY(4, 6, KEY_LEFTSHIFT),
+	KEY(4, 5, KEY_RIGHTALT),	// XXX was LEFTSHIFT
+	KEY(4, 6, KEY_LEFTSHIFT),	// XXX was FN which is now removed
+	KEY(4, 8, KEY_10),		// XXX was F9 and moved to (2, 8), F10 was (5, 8)
+
+
 	KEY(5, 0, KEY_Y),
+	KEY(5, 8, KEY_11),		// XXX was F10 and moved to (4, 8), F11 is new
+
 	KEY(6, 0, KEY_U),
+
 	KEY(7, 0, KEY_I),
-	KEY(7, 1, KEY_F7),
-	KEY(7, 2, KEY_F8),
-	KEY(0xff, 2, KEY_F9),
-	KEY(0xff, 4, KEY_F10),
-	KEY(0xff, 5, KEY_F11),
+	KEY(7, 1, KEY_F7),		// XXX was undefined
+	KEY(7, 2, KEY_F8),		// XXX was undefined
 };
 
 static struct matrix_keymap_data board_map_data = {
diff --git a/drivers/input/keyboard/twl4030_keypad.c b/drivers/input/keyboard/twl4030_keypad.c
index 7aa59e0..fb16b5e 100644
--- a/drivers/input/keyboard/twl4030_keypad.c
+++ b/drivers/input/keyboard/twl4030_keypad.c
@@ -51,8 +51,12 @@
  */
 #define TWL4030_MAX_ROWS	8	/* TWL4030 hard limit */
 #define TWL4030_MAX_COLS	8
-#define TWL4030_ROW_SHIFT	3
-#define TWL4030_KEYMAP_SIZE	(TWL4030_MAX_ROWS * TWL4030_MAX_COLS)
+/*
+ * Note that we add space for an extra column so that we can handle
+ * 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)
 
 struct twl4030_keypad {
 	unsigned short	keymap[TWL4030_KEYMAP_SIZE];
@@ -182,7 +186,7 @@ static int twl4030_read_kp_matrix_state(struct twl4030_keypad *kp, u16 *state)
 	return ret;
 }
 
-static int twl4030_is_in_ghost_state(struct twl4030_keypad *kp, u16 *key_state)
+static bool twl4030_is_in_ghost_state(struct twl4030_keypad *kp, u16 *key_state)
 {
 	int i;
 	u16 check = 0;
@@ -191,12 +195,12 @@ static int twl4030_is_in_ghost_state(struct twl4030_keypad *kp, u16 *key_state)
 		u16 col = key_state[i];
 
 		if ((col & check) && hweight16(col) > 1)
-			return 1;
+			return true;
 
 		check |= col;
 	}
 
-	return 0;
+	return false;
 }
 
 static void twl4030_kp_scan(struct twl4030_keypad *kp, bool release_all)
@@ -225,7 +229,8 @@ static void twl4030_kp_scan(struct twl4030_keypad *kp, bool release_all)
 		if (!changed)
 			continue;
 
-		for (col = 0; col < kp->n_cols; col++) {
+		/* Extra column handles "all gnd" rows */
+		for (col = 0; col < kp->n_cols + 1; col++) {
 			int code;
 
 			if (!(changed & (1 << col)))
--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux Arm (vger)]     [ARM Kernel]     [ARM MSM]     [Linux Tegra]     [Linux WPAN Networking]     [Linux Wireless Networking]     [Maemo Users]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite Trails]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux