aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/serial/kgdboc.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/serial/kgdboc.c')
-rw-r--r--drivers/serial/kgdboc.c60
1 files changed, 60 insertions, 0 deletions
diff --git a/drivers/serial/kgdboc.c b/drivers/serial/kgdboc.c
index d4b711c9a416..25a8bc565f40 100644
--- a/drivers/serial/kgdboc.c
+++ b/drivers/serial/kgdboc.c
@@ -18,6 +18,7 @@
18#include <linux/tty.h> 18#include <linux/tty.h>
19#include <linux/console.h> 19#include <linux/console.h>
20#include <linux/vt_kern.h> 20#include <linux/vt_kern.h>
21#include <linux/input.h>
21 22
22#define MAX_CONFIG_LEN 40 23#define MAX_CONFIG_LEN 40
23 24
@@ -37,6 +38,62 @@ static struct tty_driver *kgdb_tty_driver;
37static int kgdb_tty_line; 38static int kgdb_tty_line;
38 39
39#ifdef CONFIG_KDB_KEYBOARD 40#ifdef CONFIG_KDB_KEYBOARD
41static int kgdboc_reset_connect(struct input_handler *handler,
42 struct input_dev *dev,
43 const struct input_device_id *id)
44{
45 input_reset_device(dev);
46
47 /* Retrun an error - we do not want to bind, just to reset */
48 return -ENODEV;
49}
50
51static void kgdboc_reset_disconnect(struct input_handle *handle)
52{
53 /* We do not expect anyone to actually bind to us */
54 BUG();
55}
56
57static const struct input_device_id kgdboc_reset_ids[] = {
58 {
59 .flags = INPUT_DEVICE_ID_MATCH_EVBIT,
60 .evbit = { BIT_MASK(EV_KEY) },
61 },
62 { }
63};
64
65static struct input_handler kgdboc_reset_handler = {
66 .connect = kgdboc_reset_connect,
67 .disconnect = kgdboc_reset_disconnect,
68 .name = "kgdboc_reset",
69 .id_table = kgdboc_reset_ids,
70};
71
72static DEFINE_MUTEX(kgdboc_reset_mutex);
73
74static void kgdboc_restore_input_helper(struct work_struct *dummy)
75{
76 /*
77 * We need to take a mutex to prevent several instances of
78 * this work running on different CPUs so they don't try
79 * to register again already registered handler.
80 */
81 mutex_lock(&kgdboc_reset_mutex);
82
83 if (input_register_handler(&kgdboc_reset_handler) == 0)
84 input_unregister_handler(&kgdboc_reset_handler);
85
86 mutex_unlock(&kgdboc_reset_mutex);
87}
88
89static DECLARE_WORK(kgdboc_restore_input_work, kgdboc_restore_input_helper);
90
91static void kgdboc_restore_input(void)
92{
93 if (likely(system_state == SYSTEM_RUNNING))
94 schedule_work(&kgdboc_restore_input_work);
95}
96
40static int kgdboc_register_kbd(char **cptr) 97static int kgdboc_register_kbd(char **cptr)
41{ 98{
42 if (strncmp(*cptr, "kbd", 3) == 0) { 99 if (strncmp(*cptr, "kbd", 3) == 0) {
@@ -64,10 +121,12 @@ static void kgdboc_unregister_kbd(void)
64 i--; 121 i--;
65 } 122 }
66 } 123 }
124 flush_work_sync(&kgdboc_restore_input_work);
67} 125}
68#else /* ! CONFIG_KDB_KEYBOARD */ 126#else /* ! CONFIG_KDB_KEYBOARD */
69#define kgdboc_register_kbd(x) 0 127#define kgdboc_register_kbd(x) 0
70#define kgdboc_unregister_kbd() 128#define kgdboc_unregister_kbd()
129#define kgdboc_restore_input()
71#endif /* ! CONFIG_KDB_KEYBOARD */ 130#endif /* ! CONFIG_KDB_KEYBOARD */
72 131
73static int kgdboc_option_setup(char *opt) 132static int kgdboc_option_setup(char *opt)
@@ -231,6 +290,7 @@ static void kgdboc_post_exp_handler(void)
231 dbg_restore_graphics = 0; 290 dbg_restore_graphics = 0;
232 con_debug_leave(); 291 con_debug_leave();
233 } 292 }
293 kgdboc_restore_input();
234} 294}
235 295
236static struct kgdb_io kgdboc_io_ops = { 296static struct kgdb_io kgdboc_io_ops = {