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.c94
1 files changed, 87 insertions, 7 deletions
diff --git a/drivers/serial/kgdboc.c b/drivers/serial/kgdboc.c
index eadc1ab6bbce..a9a94ae72349 100644
--- a/drivers/serial/kgdboc.c
+++ b/drivers/serial/kgdboc.c
@@ -14,7 +14,9 @@
14#include <linux/kernel.h> 14#include <linux/kernel.h>
15#include <linux/ctype.h> 15#include <linux/ctype.h>
16#include <linux/kgdb.h> 16#include <linux/kgdb.h>
17#include <linux/kdb.h>
17#include <linux/tty.h> 18#include <linux/tty.h>
19#include <linux/console.h>
18 20
19#define MAX_CONFIG_LEN 40 21#define MAX_CONFIG_LEN 40
20 22
@@ -32,6 +34,40 @@ static struct kparam_string kps = {
32static struct tty_driver *kgdb_tty_driver; 34static struct tty_driver *kgdb_tty_driver;
33static int kgdb_tty_line; 35static int kgdb_tty_line;
34 36
37#ifdef CONFIG_KDB_KEYBOARD
38static int kgdboc_register_kbd(char **cptr)
39{
40 if (strncmp(*cptr, "kbd", 3) == 0) {
41 if (kdb_poll_idx < KDB_POLL_FUNC_MAX) {
42 kdb_poll_funcs[kdb_poll_idx] = kdb_get_kbd_char;
43 kdb_poll_idx++;
44 if (cptr[0][3] == ',')
45 *cptr += 4;
46 else
47 return 1;
48 }
49 }
50 return 0;
51}
52
53static void kgdboc_unregister_kbd(void)
54{
55 int i;
56
57 for (i = 0; i < kdb_poll_idx; i++) {
58 if (kdb_poll_funcs[i] == kdb_get_kbd_char) {
59 kdb_poll_idx--;
60 kdb_poll_funcs[i] = kdb_poll_funcs[kdb_poll_idx];
61 kdb_poll_funcs[kdb_poll_idx] = NULL;
62 i--;
63 }
64 }
65}
66#else /* ! CONFIG_KDB_KEYBOARD */
67#define kgdboc_register_kbd(x) 0
68#define kgdboc_unregister_kbd()
69#endif /* ! CONFIG_KDB_KEYBOARD */
70
35static int kgdboc_option_setup(char *opt) 71static int kgdboc_option_setup(char *opt)
36{ 72{
37 if (strlen(opt) > MAX_CONFIG_LEN) { 73 if (strlen(opt) > MAX_CONFIG_LEN) {
@@ -45,25 +81,51 @@ static int kgdboc_option_setup(char *opt)
45 81
46__setup("kgdboc=", kgdboc_option_setup); 82__setup("kgdboc=", kgdboc_option_setup);
47 83
84static void cleanup_kgdboc(void)
85{
86 kgdboc_unregister_kbd();
87 if (configured == 1)
88 kgdb_unregister_io_module(&kgdboc_io_ops);
89}
90
48static int configure_kgdboc(void) 91static int configure_kgdboc(void)
49{ 92{
50 struct tty_driver *p; 93 struct tty_driver *p;
51 int tty_line = 0; 94 int tty_line = 0;
52 int err; 95 int err;
96 char *cptr = config;
97 struct console *cons;
53 98
54 err = kgdboc_option_setup(config); 99 err = kgdboc_option_setup(config);
55 if (err || !strlen(config) || isspace(config[0])) 100 if (err || !strlen(config) || isspace(config[0]))
56 goto noconfig; 101 goto noconfig;
57 102
58 err = -ENODEV; 103 err = -ENODEV;
104 kgdboc_io_ops.is_console = 0;
105 kgdb_tty_driver = NULL;
59 106
60 p = tty_find_polling_driver(config, &tty_line); 107 if (kgdboc_register_kbd(&cptr))
108 goto do_register;
109
110 p = tty_find_polling_driver(cptr, &tty_line);
61 if (!p) 111 if (!p)
62 goto noconfig; 112 goto noconfig;
63 113
114 cons = console_drivers;
115 while (cons) {
116 int idx;
117 if (cons->device && cons->device(cons, &idx) == p &&
118 idx == tty_line) {
119 kgdboc_io_ops.is_console = 1;
120 break;
121 }
122 cons = cons->next;
123 }
124
64 kgdb_tty_driver = p; 125 kgdb_tty_driver = p;
65 kgdb_tty_line = tty_line; 126 kgdb_tty_line = tty_line;
66 127
128do_register:
67 err = kgdb_register_io_module(&kgdboc_io_ops); 129 err = kgdb_register_io_module(&kgdboc_io_ops);
68 if (err) 130 if (err)
69 goto noconfig; 131 goto noconfig;
@@ -75,6 +137,7 @@ static int configure_kgdboc(void)
75noconfig: 137noconfig:
76 config[0] = 0; 138 config[0] = 0;
77 configured = 0; 139 configured = 0;
140 cleanup_kgdboc();
78 141
79 return err; 142 return err;
80} 143}
@@ -88,20 +151,18 @@ static int __init init_kgdboc(void)
88 return configure_kgdboc(); 151 return configure_kgdboc();
89} 152}
90 153
91static void cleanup_kgdboc(void)
92{
93 if (configured == 1)
94 kgdb_unregister_io_module(&kgdboc_io_ops);
95}
96
97static int kgdboc_get_char(void) 154static int kgdboc_get_char(void)
98{ 155{
156 if (!kgdb_tty_driver)
157 return -1;
99 return kgdb_tty_driver->ops->poll_get_char(kgdb_tty_driver, 158 return kgdb_tty_driver->ops->poll_get_char(kgdb_tty_driver,
100 kgdb_tty_line); 159 kgdb_tty_line);
101} 160}
102 161
103static void kgdboc_put_char(u8 chr) 162static void kgdboc_put_char(u8 chr)
104{ 163{
164 if (!kgdb_tty_driver)
165 return;
105 kgdb_tty_driver->ops->poll_put_char(kgdb_tty_driver, 166 kgdb_tty_driver->ops->poll_put_char(kgdb_tty_driver,
106 kgdb_tty_line, chr); 167 kgdb_tty_line, chr);
107} 168}
@@ -162,6 +223,25 @@ static struct kgdb_io kgdboc_io_ops = {
162 .post_exception = kgdboc_post_exp_handler, 223 .post_exception = kgdboc_post_exp_handler,
163}; 224};
164 225
226#ifdef CONFIG_KGDB_SERIAL_CONSOLE
227/* This is only available if kgdboc is a built in for early debugging */
228int __init kgdboc_early_init(char *opt)
229{
230 /* save the first character of the config string because the
231 * init routine can destroy it.
232 */
233 char save_ch;
234
235 kgdboc_option_setup(opt);
236 save_ch = config[0];
237 init_kgdboc();
238 config[0] = save_ch;
239 return 0;
240}
241
242early_param("ekgdboc", kgdboc_early_init);
243#endif /* CONFIG_KGDB_SERIAL_CONSOLE */
244
165module_init(init_kgdboc); 245module_init(init_kgdboc);
166module_exit(cleanup_kgdboc); 246module_exit(cleanup_kgdboc);
167module_param_call(kgdboc, param_set_kgdboc_var, param_get_string, &kps, 0644); 247module_param_call(kgdboc, param_set_kgdboc_var, param_get_string, &kps, 0644);