@@ -379,6 +379,32 @@ static void to_utf8(struct vc_data *vc,
}
}
+static int kbd_dbg_clear_keys_helper(struct input_handle *handle, void *data)
+{
+ unsigned int *keycode = data;
+ input_inject_event(handle, EV_KEY, *keycode, 0);
+ return 0;
+}
+
+/* Called to clear the any key presses after resuming the kernel. */
+void kbd_dbg_clear_keys(void) {
+ unsigned int i, j, k;
+
+ for (i = 0; i < ARRAY_SIZE(key_down); i++) {
+ if (!key_down[i])
+ continue;
+
+ k = i * BITS_PER_LONG;
+
+ for (j = 0; j < BITS_PER_LONG; j++, k++) {
+ if (!test_bit(k, key_down))
+ continue;
+ input_handler_for_each_handle(&kbd_handler, &k,
+ kbd_dbg_clear_keys_helper);
+ }
+ }
+}
+
/*
* Called after returning from RAW mode or when changing consoles - recompute
* shift_down[] and shift_state from key_down[] maybe called when keymap is
@@ -1206,6 +1232,7 @@ static void kbd_keycode(unsigned int key
if (sysrq_down && !down && keycode == sysrq_alt_use)
sysrq_down = 0;
if (sysrq_down && down && !rep) {
+ set_bit(keycode, key_down);
handle_sysrq(kbd_sysrq_xlate[keycode], tty);
return;
}
@@ -17,6 +17,7 @@
#include <linux/kdb.h>
#include <linux/tty.h>
#include <linux/console.h>
+#include <linux/kbd_kern.h>
#define MAX_CONFIG_LEN 40
@@ -35,12 +36,16 @@ static struct tty_driver *kgdb_tty_drive
static int kgdb_tty_line;
#ifdef CONFIG_KDB_KEYBOARD
+static bool kgdboc_use_kbd;
+
static int kgdboc_register_kbd(char **cptr)
{
+ kgdboc_use_kbd = false;
if (strncmp(*cptr, "kbd", 3) == 0) {
if (kdb_poll_idx < KDB_POLL_FUNC_MAX) {
kdb_poll_funcs[kdb_poll_idx] = kdb_get_kbd_char;
kdb_poll_idx++;
+ kgdboc_use_kbd = true;
if (cptr[0][3] == ',')
*cptr += 4;
else
@@ -63,9 +68,16 @@ static void kgdboc_unregister_kbd(void)
}
}
}
+
+static inline void kgdboc_clear_kbd(void)
+{
+ if (kgdboc_use_kbd)
+ kdb_clear_keys(); /* Release all pressed keys */
+}
#else /* ! CONFIG_KDB_KEYBOARD */
#define kgdboc_register_kbd(x) 0
#define kgdboc_unregister_kbd()
+#define kgdboc_clear_kbd()
#endif /* ! CONFIG_KDB_KEYBOARD */
static int kgdboc_option_setup(char *opt)
@@ -213,6 +225,7 @@ static void kgdboc_post_exp_handler(void
/* decrement the module count when the debugger detaches */
if (!kgdb_connected)
module_put(THIS_MODULE);
+ kgdboc_clear_kbd();
}
static struct kgdb_io kgdboc_io_ops = {
@@ -144,6 +144,7 @@ struct console;
int getkeycode(unsigned int scancode);
int setkeycode(unsigned int scancode, unsigned int keycode);
void compute_shiftstate(void);
+void kbd_dbg_clear_keys(void);
/* defkeymap.c */
@@ -93,6 +93,9 @@ typedef int (*get_char_func)(void);
extern get_char_func kdb_poll_funcs[];
extern int kdb_get_kbd_char(void);
+/* KDB keyboard hooks */
+extern void kdb_clear_keys(void);
+
static inline
int kdb_process_cpu(const struct task_struct *p)
{
@@ -13,6 +13,7 @@
#include <linux/ctype.h>
#include <linux/module.h>
#include <linux/io.h>
+#include <linux/kbd_kern.h>
/* Keyboard Controller Registers on normal PCs. */
@@ -210,3 +211,27 @@ int kdb_get_kbd_char(void)
return keychar & 0xff;
}
EXPORT_SYMBOL_GPL(kdb_get_kbd_char);
+
+static bool dbg_keys_cleared;
+/*
+ * input_dbg_clear_keys - Clear any keyboards if they have a call back,
+ * after returning from the kernel debugger
+ */
+static void kdb_keys_task(unsigned long not_used)
+{
+ if (!dbg_keys_cleared)
+ return;
+ kbd_dbg_clear_keys();
+ dbg_keys_cleared = false;
+}
+
+static DECLARE_TASKLET(kdb_keys_tasklet, kdb_keys_task, 0);
+
+void kdb_clear_keys(void)
+{
+ if (dbg_keys_cleared)
+ return;
+ dbg_keys_cleared = true;
+ tasklet_schedule(&kdb_keys_tasklet);
+}
+EXPORT_SYMBOL_GPL(kdb_clear_keys);