diff options
Diffstat (limited to 'drivers/serial/kgdboc.c')
-rw-r--r-- | drivers/serial/kgdboc.c | 94 |
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 = { | |||
32 | static struct tty_driver *kgdb_tty_driver; | 34 | static struct tty_driver *kgdb_tty_driver; |
33 | static int kgdb_tty_line; | 35 | static int kgdb_tty_line; |
34 | 36 | ||
37 | #ifdef CONFIG_KDB_KEYBOARD | ||
38 | static 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 | |||
53 | static 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 | |||
35 | static int kgdboc_option_setup(char *opt) | 71 | static 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 | ||
84 | static void cleanup_kgdboc(void) | ||
85 | { | ||
86 | kgdboc_unregister_kbd(); | ||
87 | if (configured == 1) | ||
88 | kgdb_unregister_io_module(&kgdboc_io_ops); | ||
89 | } | ||
90 | |||
48 | static int configure_kgdboc(void) | 91 | static 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 | ||
128 | do_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) | |||
75 | noconfig: | 137 | noconfig: |
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 | ||
91 | static void cleanup_kgdboc(void) | ||
92 | { | ||
93 | if (configured == 1) | ||
94 | kgdb_unregister_io_module(&kgdboc_io_ops); | ||
95 | } | ||
96 | |||
97 | static int kgdboc_get_char(void) | 154 | static 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 | ||
103 | static void kgdboc_put_char(u8 chr) | 162 | static 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 */ | ||
228 | int __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 | |||
242 | early_param("ekgdboc", kgdboc_early_init); | ||
243 | #endif /* CONFIG_KGDB_SERIAL_CONSOLE */ | ||
244 | |||
165 | module_init(init_kgdboc); | 245 | module_init(init_kgdboc); |
166 | module_exit(cleanup_kgdboc); | 246 | module_exit(cleanup_kgdboc); |
167 | module_param_call(kgdboc, param_set_kgdboc_var, param_get_string, &kps, 0644); | 247 | module_param_call(kgdboc, param_set_kgdboc_var, param_get_string, &kps, 0644); |