Release 4.7 drivers/tty/serial/kgdboc.c
  
  
/*
 * 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>
#include <linux/module.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);
	/* Return an error - we do not want to bind, just to reset */
	return -ENODEV;
}
Contributors
 | Person | Tokens | Prop | Commits | CommitProp | 
| dmitry torokhov | dmitry torokhov | 31 | 96.88% | 1 | 50.00% | 
| joe perches | joe perches | 1 | 3.12% | 1 | 50.00% | 
 | Total | 32 | 100.00% | 2 | 100.00% | 
static void kgdboc_reset_disconnect(struct input_handle *handle)
{
	/* We do not expect anyone to actually bind to us */
	BUG();
}
Contributors
 | Person | Tokens | Prop | Commits | CommitProp | 
| dmitry torokhov | dmitry torokhov | 15 | 100.00% | 1 | 100.00% | 
 | Total | 15 | 100.00% | 1 | 100.00% | 
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);
}
Contributors
 | Person | Tokens | Prop | Commits | CommitProp | 
| dmitry torokhov | dmitry torokhov | 40 | 100.00% | 1 | 100.00% | 
 | Total | 40 | 100.00% | 1 | 100.00% | 
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);
}
Contributors
 | Person | Tokens | Prop | Commits | CommitProp | 
| dmitry torokhov | dmitry torokhov | 14 | 60.87% | 1 | 50.00% | 
| jason wessel | jason wessel | 9 | 39.13% | 1 | 50.00% | 
 | Total | 23 | 100.00% | 2 | 100.00% | 
static int kgdboc_register_kbd(char **cptr)
{
	if (strncmp(*cptr, "kbd", 3) == 0 ||
		strncmp(*cptr, "kdb", 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;
}
Contributors
 | Person | Tokens | Prop | Commits | CommitProp | 
| jason wessel | jason wessel | 81 | 100.00% | 2 | 100.00% | 
 | Total | 81 | 100.00% | 2 | 100.00% | 
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(&kgdboc_restore_input_work);
}
Contributors
 | Person | Tokens | Prop | Commits | CommitProp | 
| jason wessel | jason wessel | 60 | 90.91% | 1 | 33.33% | 
| dmitry torokhov | dmitry torokhov | 5 | 7.58% | 1 | 33.33% | 
| tejun heo | tejun heo | 1 | 1.52% | 1 | 33.33% | 
 | Total | 66 | 100.00% | 3 | 100.00% | 
#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;
}
Contributors
 | Person | Tokens | Prop | Commits | CommitProp | 
| jason wessel | jason wessel | 40 | 97.56% | 1 | 50.00% | 
| dan carpenter | dan carpenter | 1 | 2.44% | 1 | 50.00% | 
 | Total | 41 | 100.00% | 2 | 100.00% | 
__setup("kgdboc=", kgdboc_option_setup);
static void cleanup_kgdboc(void)
{
	if (kgdb_unregister_nmi_console())
		return;
	kgdboc_unregister_kbd();
	if (configured == 1)
		kgdb_unregister_io_module(&kgdboc_io_ops);
}
Contributors
 | Person | Tokens | Prop | Commits | CommitProp | 
| jason wessel | jason wessel | 23 | 79.31% | 1 | 50.00% | 
| anton vorontsov | anton vorontsov | 6 | 20.69% | 1 | 50.00% | 
 | Total | 29 | 100.00% | 2 | 100.00% | 
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;
	err = kgdb_register_nmi_console();
	if (err)
		goto nmi_con_failed;
	configured = 1;
	return 0;
nmi_con_failed:
	kgdb_unregister_io_module(&kgdboc_io_ops);
noconfig:
	kgdboc_unregister_kbd();
	config[0] = 0;
	configured = 0;
	cleanup_kgdboc();
	return err;
}
Contributors
 | Person | Tokens | Prop | Commits | CommitProp | 
| jason wessel | jason wessel | 232 | 90.98% | 4 | 80.00% | 
| anton vorontsov | anton vorontsov | 23 | 9.02% | 1 | 20.00% | 
 | Total | 255 | 100.00% | 5 | 100.00% | 
static int __init init_kgdboc(void)
{
	/* Already configured? */
	if (configured == 1)
		return 0;
	return configure_kgdboc();
}
Contributors
 | Person | Tokens | Prop | Commits | CommitProp | 
| jason wessel | jason wessel | 23 | 100.00% | 1 | 100.00% | 
 | Total | 23 | 100.00% | 1 | 100.00% | 
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);
}
Contributors
 | Person | Tokens | Prop | Commits | CommitProp | 
| jason wessel | jason wessel | 27 | 93.10% | 2 | 66.67% | 
| alan cox | alan cox | 2 | 6.90% | 1 | 33.33% | 
 | Total | 29 | 100.00% | 3 | 100.00% | 
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);
}
Contributors
 | Person | Tokens | Prop | Commits | CommitProp | 
| jason wessel | jason wessel | 26 | 92.86% | 2 | 66.67% | 
| alan cox | alan cox | 2 | 7.14% | 1 | 33.33% | 
 | Total | 28 | 100.00% | 3 | 100.00% | 
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();
}
Contributors
 | Person | Tokens | Prop | Commits | CommitProp | 
| jason wessel | jason wessel | 119 | 100.00% | 2 | 100.00% | 
 | Total | 119 | 100.00% | 2 | 100.00% | 
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);
}
Contributors
 | Person | Tokens | Prop | Commits | CommitProp | 
| jason wessel | jason wessel | 42 | 100.00% | 2 | 100.00% | 
 | Total | 42 | 100.00% | 2 | 100.00% | 
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();
}
Contributors
 | Person | Tokens | Prop | Commits | CommitProp | 
| jason wessel | jason wessel | 34 | 91.89% | 2 | 66.67% | 
| dmitry torokhov | dmitry torokhov | 3 | 8.11% | 1 | 33.33% | 
 | Total | 37 | 100.00% | 3 | 100.00% | 
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;
}
Contributors
 | Person | Tokens | Prop | Commits | CommitProp | 
| jason wessel | jason wessel | 40 | 100.00% | 2 | 100.00% | 
 | Total | 40 | 100.00% | 2 | 100.00% | 
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");
Overall Contributors
 | Person | Tokens | Prop | Commits | CommitProp | 
| jason wessel | jason wessel | 952 | 81.02% | 9 | 56.25% | 
| dmitry torokhov | dmitry torokhov | 184 | 15.66% | 1 | 6.25% | 
| anton vorontsov | anton vorontsov | 29 | 2.47% | 1 | 6.25% | 
| alan cox | alan cox | 4 | 0.34% | 1 | 6.25% | 
| paul gortmaker | paul gortmaker | 3 | 0.26% | 1 | 6.25% | 
| dan carpenter | dan carpenter | 1 | 0.09% | 1 | 6.25% | 
| joe perches | joe perches | 1 | 0.09% | 1 | 6.25% | 
| tejun heo | tejun heo | 1 | 0.09% | 1 | 6.25% | 
 | Total | 1175 | 100.00% | 16 | 100.00% | 
  
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.