diff options
Diffstat (limited to 'drivers/serial/kgdboc.c')
-rw-r--r-- | drivers/serial/kgdboc.c | 328 |
1 files changed, 0 insertions, 328 deletions
diff --git a/drivers/serial/kgdboc.c b/drivers/serial/kgdboc.c deleted file mode 100644 index 25a8bc565f40..000000000000 --- a/drivers/serial/kgdboc.c +++ /dev/null @@ -1,328 +0,0 @@ -/* - * Based on the same principle as kgdboe using the NETPOLL api, this - * driver uses a console polling api to implement a gdb serial inteface - * which is multiplexed on a console port. - * - * Maintainer: Jason Wessel <jason.wessel@windriver.com> - * - * 2007-2008 (c) Jason Wessel - Wind River Systems, Inc. - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. - */ -#include <linux/kernel.h> -#include <linux/ctype.h> -#include <linux/kgdb.h> -#include <linux/kdb.h> -#include <linux/tty.h> -#include <linux/console.h> -#include <linux/vt_kern.h> -#include <linux/input.h> - -#define MAX_CONFIG_LEN 40 - -static struct kgdb_io kgdboc_io_ops; - -/* -1 = init not run yet, 0 = unconfigured, 1 = configured. */ -static int configured = -1; - -static char config[MAX_CONFIG_LEN]; -static struct kparam_string kps = { - .string = config, - .maxlen = MAX_CONFIG_LEN, -}; - -static int kgdboc_use_kms; /* 1 if we use kernel mode switching */ -static struct tty_driver *kgdb_tty_driver; -static int kgdb_tty_line; - -#ifdef CONFIG_KDB_KEYBOARD -static int kgdboc_reset_connect(struct input_handler *handler, - struct input_dev *dev, - const struct input_device_id *id) -{ - input_reset_device(dev); - - /* Retrun an error - we do not want to bind, just to reset */ - return -ENODEV; -} - -static void kgdboc_reset_disconnect(struct input_handle *handle) -{ - /* We do not expect anyone to actually bind to us */ - BUG(); -} - -static const struct input_device_id kgdboc_reset_ids[] = { - { - .flags = INPUT_DEVICE_ID_MATCH_EVBIT, - .evbit = { BIT_MASK(EV_KEY) }, - }, - { } -}; - -static struct input_handler kgdboc_reset_handler = { - .connect = kgdboc_reset_connect, - .disconnect = kgdboc_reset_disconnect, - .name = "kgdboc_reset", - .id_table = kgdboc_reset_ids, -}; - -static DEFINE_MUTEX(kgdboc_reset_mutex); - -static void kgdboc_restore_input_helper(struct work_struct *dummy) -{ - /* - * We need to take a mutex to prevent several instances of - * this work running on different CPUs so they don't try - * to register again already registered handler. - */ - mutex_lock(&kgdboc_reset_mutex); - - if (input_register_handler(&kgdboc_reset_handler) == 0) - input_unregister_handler(&kgdboc_reset_handler); - - mutex_unlock(&kgdboc_reset_mutex); -} - -static DECLARE_WORK(kgdboc_restore_input_work, kgdboc_restore_input_helper); - -static void kgdboc_restore_input(void) -{ - if (likely(system_state == SYSTEM_RUNNING)) - schedule_work(&kgdboc_restore_input_work); -} - -static int kgdboc_register_kbd(char **cptr) -{ - 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++; - if (cptr[0][3] == ',') - *cptr += 4; - else - return 1; - } - } - return 0; -} - -static void kgdboc_unregister_kbd(void) -{ - int i; - - for (i = 0; i < kdb_poll_idx; i++) { - if (kdb_poll_funcs[i] == kdb_get_kbd_char) { - kdb_poll_idx--; - kdb_poll_funcs[i] = kdb_poll_funcs[kdb_poll_idx]; - kdb_poll_funcs[kdb_poll_idx] = NULL; - i--; - } - } - flush_work_sync(&kgdboc_restore_input_work); -} -#else /* ! CONFIG_KDB_KEYBOARD */ -#define kgdboc_register_kbd(x) 0 -#define kgdboc_unregister_kbd() -#define kgdboc_restore_input() -#endif /* ! CONFIG_KDB_KEYBOARD */ - -static int kgdboc_option_setup(char *opt) -{ - if (strlen(opt) > MAX_CONFIG_LEN) { - printk(KERN_ERR "kgdboc: config string too long\n"); - return -ENOSPC; - } - strcpy(config, opt); - - return 0; -} - -__setup("kgdboc=", kgdboc_option_setup); - -static void cleanup_kgdboc(void) -{ - kgdboc_unregister_kbd(); - if (configured == 1) - kgdb_unregister_io_module(&kgdboc_io_ops); -} - -static int configure_kgdboc(void) -{ - struct tty_driver *p; - int tty_line = 0; - int err; - char *cptr = config; - struct console *cons; - - err = kgdboc_option_setup(config); - if (err || !strlen(config) || isspace(config[0])) - goto noconfig; - - err = -ENODEV; - kgdboc_io_ops.is_console = 0; - kgdb_tty_driver = NULL; - - kgdboc_use_kms = 0; - if (strncmp(cptr, "kms,", 4) == 0) { - cptr += 4; - kgdboc_use_kms = 1; - } - - if (kgdboc_register_kbd(&cptr)) - goto do_register; - - p = tty_find_polling_driver(cptr, &tty_line); - if (!p) - goto noconfig; - - cons = console_drivers; - while (cons) { - int idx; - if (cons->device && cons->device(cons, &idx) == p && - idx == tty_line) { - kgdboc_io_ops.is_console = 1; - break; - } - cons = cons->next; - } - - kgdb_tty_driver = p; - kgdb_tty_line = tty_line; - -do_register: - err = kgdb_register_io_module(&kgdboc_io_ops); - if (err) - goto noconfig; - - configured = 1; - - return 0; - -noconfig: - config[0] = 0; - configured = 0; - cleanup_kgdboc(); - - return err; -} - -static int __init init_kgdboc(void) -{ - /* Already configured? */ - if (configured == 1) - return 0; - - return configure_kgdboc(); -} - -static int kgdboc_get_char(void) -{ - if (!kgdb_tty_driver) - return -1; - return kgdb_tty_driver->ops->poll_get_char(kgdb_tty_driver, - kgdb_tty_line); -} - -static void kgdboc_put_char(u8 chr) -{ - if (!kgdb_tty_driver) - return; - kgdb_tty_driver->ops->poll_put_char(kgdb_tty_driver, - kgdb_tty_line, chr); -} - -static int param_set_kgdboc_var(const char *kmessage, struct kernel_param *kp) -{ - int len = strlen(kmessage); - - if (len >= MAX_CONFIG_LEN) { - printk(KERN_ERR "kgdboc: config string too long\n"); - return -ENOSPC; - } - - /* Only copy in the string if the init function has not run yet */ - if (configured < 0) { - strcpy(config, kmessage); - return 0; - } - - if (kgdb_connected) { - printk(KERN_ERR - "kgdboc: Cannot reconfigure while KGDB is connected.\n"); - - return -EBUSY; - } - - strcpy(config, kmessage); - /* Chop out \n char as a result of echo */ - if (config[len - 1] == '\n') - config[len - 1] = '\0'; - - if (configured == 1) - cleanup_kgdboc(); - - /* Go and configure with the new params. */ - return configure_kgdboc(); -} - -static int dbg_restore_graphics; - -static void kgdboc_pre_exp_handler(void) -{ - if (!dbg_restore_graphics && kgdboc_use_kms) { - dbg_restore_graphics = 1; - con_debug_enter(vc_cons[fg_console].d); - } - /* Increment the module count when the debugger is active */ - if (!kgdb_connected) - try_module_get(THIS_MODULE); -} - -static void kgdboc_post_exp_handler(void) -{ - /* decrement the module count when the debugger detaches */ - if (!kgdb_connected) - module_put(THIS_MODULE); - if (kgdboc_use_kms && dbg_restore_graphics) { - dbg_restore_graphics = 0; - con_debug_leave(); - } - kgdboc_restore_input(); -} - -static struct kgdb_io kgdboc_io_ops = { - .name = "kgdboc", - .read_char = kgdboc_get_char, - .write_char = kgdboc_put_char, - .pre_exception = kgdboc_pre_exp_handler, - .post_exception = kgdboc_post_exp_handler, -}; - -#ifdef CONFIG_KGDB_SERIAL_CONSOLE -/* This is only available if kgdboc is a built in for early debugging */ -static int __init kgdboc_early_init(char *opt) -{ - /* save the first character of the config string because the - * init routine can destroy it. - */ - char save_ch; - - kgdboc_option_setup(opt); - save_ch = config[0]; - init_kgdboc(); - config[0] = save_ch; - return 0; -} - -early_param("ekgdboc", kgdboc_early_init); -#endif /* CONFIG_KGDB_SERIAL_CONSOLE */ - -module_init(init_kgdboc); -module_exit(cleanup_kgdboc); -module_param_call(kgdboc, param_set_kgdboc_var, param_get_string, &kps, 0644); -MODULE_PARM_DESC(kgdboc, "<serial_device>[,baud]"); -MODULE_DESCRIPTION("KGDB Console TTY Driver"); -MODULE_LICENSE("GPL"); |