diff --git a/chip/lm4/mock_keyboard_scan_stub.c b/chip/lm4/mock_keyboard_scan_stub.c
new file mode 100644
index 0000000000..743c20aef4
--- /dev/null
+++ b/chip/lm4/mock_keyboard_scan_stub.c
@@ -0,0 +1,113 @@
+/* Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+/* Mock functions for keyboard scanner module for Chrome EC */
+
+#include "board.h"
+#include "console.h"
+#include "keyboard_scan.h"
+#include "keyboard_scan_stub.h"
+#include "task.h"
+#include "uart.h"
+#include "util.h"
+
+#define MOCK_COLUMN_COUNT 13
+
+static int enable_scanning = 1;
+static int selected_column = -1;
+static int interrupt_enabled = 0;
+static uint8_t matrix_status[MOCK_COLUMN_COUNT];
+
+
+void lm4_set_scanning_enabled(int enabled)
+{
+ enable_scanning = enabled;
+ uart_printf("%s keyboard scanning\n", enabled ? "Enable" : "Disable");
+}
+
+
+int lm4_get_scanning_enabled(void)
+{
+ return enable_scanning;
+}
+
+
+void lm4_select_column(int col)
+{
+ selected_column = col;
+}
+
+
+uint32_t lm4_clear_matrix_interrupt_status(void)
+{
+ /* Not implemented */
+ return 0;
+}
+
+
+void lm4_enable_matrix_interrupt(void)
+{
+ interrupt_enabled = 1;
+}
+
+
+void lm4_disable_matrix_interrupt(void)
+{
+ interrupt_enabled = 0;
+}
+
+
+int lm4_read_raw_row_state(void)
+{
+ if (selected_column >= 0)
+ return matrix_status[selected_column];
+ else
+ return 0;
+}
+
+
+void lm4_configure_keyboard_gpio(void)
+{
+ /* Init matrix status to release all */
+ int i;
+ for (i = 0; i < MOCK_COLUMN_COUNT; ++i)
+ matrix_status[i] = 0xff;
+}
+
+
+static int command_mock_matrix(int argc, char **argv)
+{
+ int r, c, p;
+ char *e;
+
+ if (argc < 4)
+ return EC_ERROR_PARAM_COUNT;
+
+ c = strtoi(argv[1], &e, 0);
+ if (*e || c < 0 || c >= MOCK_COLUMN_COUNT)
+ return EC_ERROR_PARAM1;
+
+ r = strtoi(argv[2], &e, 0);
+ if (*e || r < 0 || r >= 8)
+ return EC_ERROR_PARAM2;
+
+ p = strtoi(argv[3], &e, 0);
+ if (*e)
+ return EC_ERROR_PARAM3;
+
+ if (p)
+ matrix_status[c] &= ~(1 << r);
+ else
+ matrix_status[c] |= (1 << r);
+
+ if (interrupt_enabled)
+ task_wake(TASK_ID_KEYSCAN);
+
+ return EC_SUCCESS;
+}
+DECLARE_CONSOLE_COMMAND(mockmatrix, command_mock_matrix,
+ "
<0 | 1>",
+ "Mock keyboard matrix",
+ NULL);
diff --git a/test/build.mk b/test/build.mk
index e4ca8341c2..87a8a11d39 100644
--- a/test/build.mk
+++ b/test/build.mk
@@ -7,7 +7,7 @@
#
test-list=hello pingpong timer_calib timer_dos timer_jump mutex thermal
-test-list+=power_button
+test-list+=power_button kb_deghost
#disable: powerdemo
pingpong-y=pingpong.o
@@ -27,3 +27,7 @@ chip-mock-power_button-gpio.o=mock_gpio.o
chip-mock-power_button-pwm.o=mock_pwm.o
common-mock-power_button-x86_power.o=mock_x86_power.o
common-mock-power_button-i8042.o=mock_i8042.o
+
+# Mock modules for 'kb_deghost'
+chip-mock-kb_deghost-keyboard_scan_stub.o=mock_keyboard_scan_stub.o
+common-mock-kb_deghost-i8042.o=mock_i8042.o
diff --git a/test/kb_deghost.py b/test/kb_deghost.py
new file mode 100644
index 0000000000..c9241e063e
--- /dev/null
+++ b/test/kb_deghost.py
@@ -0,0 +1,63 @@
+# Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+#
+# Keyboard deghost test
+#
+
+import time
+
+def check_no_output(helper, reg_ex):
+ success = False
+ try:
+ helper.wait_output(reg_ex, use_re=True, timeout=1)
+ except:
+ success = True
+ return success
+
+def test(helper):
+ # Wait for EC initialized
+ helper.wait_output("--- UART initialized")
+
+ # Enable keyboard scanning and disable typematic
+ helper.ec_command("kbd enable")
+ helper.ec_command("typematic 1000000 1000000")
+
+ # Press (1, 1) and (2, 2)
+ helper.ec_command("mockmatrix 1 1 1")
+ helper.wait_output("KB raw")
+ helper.ec_command("mockmatrix 2 2 1")
+ helper.wait_output("KB raw")
+
+ # Now press (1, 2) which should cause (2, 1) to be pressed also
+ # Expect this is ignored
+ helper.ec_command("mockmatrix 2 1 1")
+ helper.ec_command("mockmatrix 1 2 1")
+ if not check_no_output(helper, "KB raw"):
+ return False
+ # Now release (1, 2) which should cause (2, 1) to be released also
+ # Expect this is ignored
+ helper.ec_command("mockmatrix 2 1 0")
+ helper.ec_command("mockmatrix 1 2 0")
+ if not check_no_output(helper, "KB raw"):
+ return False
+
+ # Done testing with (1, 1) and (2, 2). Release them.
+ helper.ec_command("mockmatrix 1 1 0")
+ helper.wait_output("KB raw")
+ helper.ec_command("mockmatrix 2 2 0")
+ helper.wait_output("KB raw")
+
+ # Press (0, 2) and (1, 1)
+ helper.ec_command("mockmatrix 0 2 1")
+ helper.wait_output("KB raw")
+ helper.ec_command("mockmatrix 1 1 1")
+ helper.wait_output("KB raw")
+
+ # (0, 1) maps to no key. Pressing (1, 2) and (0, 1) should not be
+ # deghosted.
+ helper.ec_command("mockmatrix 1 2 1")
+ helper.ec_command("mockmatrix 0 1 1")
+ helper.wait_output("KB raw")
+
+ return True # PASS !
diff --git a/test/kb_deghost.tasklist b/test/kb_deghost.tasklist
new file mode 100644
index 0000000000..b5dfe5163c
--- /dev/null
+++ b/test/kb_deghost.tasklist
@@ -0,0 +1,24 @@
+/* Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+/**
+ * List of enabled tasks in the priority order
+ *
+ * The first one has the lowest priority.
+ *
+ * For each task, use the macro TASK(n, r, d) where :
+ * 'n' in the name of the task
+ * 'r' in the main routine of the task
+ * 'd' in an opaque parameter passed to the routine at startup
+ */
+#define CONFIG_TASK_LIST \
+ TASK(WATCHDOG, watchdog_task, NULL) \
+ TASK(PWM, pwm_task, NULL) \
+ TASK(TYPEMATIC, keyboard_typematic_task, NULL) \
+ TASK(X86POWER, x86_power_task, NULL) \
+ TASK(I8042CMD, i8042_command_task, NULL) \
+ TASK(KEYSCAN, keyboard_scan_task, NULL) \
+ TASK(POWERBTN, power_button_task, NULL) \
+ TASK(CONSOLE, console_task, NULL)