1f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel/*
2f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel * Based on the same principle as kgdboe using the NETPOLL api, this
3f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel * driver uses a console polling api to implement a gdb serial inteface
4f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel * which is multiplexed on a console port.
5f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel *
6f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel * Maintainer: Jason Wessel <jason.wessel@windriver.com>
7f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel *
8f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel * 2007-2008 (c) Jason Wessel - Wind River Systems, Inc.
9f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel *
10f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel * This file is licensed under the terms of the GNU General Public
11f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel * License version 2. This program is licensed "as is" without any
12f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel * warranty of any kind, whether express or implied.
13f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel */
14f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel#include <linux/kernel.h>
15f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel#include <linux/ctype.h>
16f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel#include <linux/kgdb.h>
17ada64e4c98eb5f04a9ca223c5ff9e7ac22ce6404Jason Wessel#include <linux/kdb.h>
18f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel#include <linux/tty.h>
19efe2f29e324fd20e0449bcd6dc6dbe4734c2ba94Jason Wessel#include <linux/console.h>
20408a4be1f8cbee511895ee07da2a007a5a24303fJason Wessel#include <linux/vt_kern.h>
21111c182340cd22e238ab1cc6564df336c6ebd7cbDmitry Torokhov#include <linux/input.h>
22578b9ce0095ff3dd2c3b94508407c3be8fcce68dPaul Gortmaker#include <linux/module.h>
23f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel
24f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel#define MAX_CONFIG_LEN		40
25f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel
26f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wesselstatic struct kgdb_io		kgdboc_io_ops;
27f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel
28f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel/* -1 = init not run yet, 0 = unconfigured, 1 = configured. */
29f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wesselstatic int configured		= -1;
30f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel
31f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wesselstatic char config[MAX_CONFIG_LEN];
32f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wesselstatic struct kparam_string kps = {
33f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel	.string			= config,
34f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel	.maxlen			= MAX_CONFIG_LEN,
35f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel};
36f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel
37408a4be1f8cbee511895ee07da2a007a5a24303fJason Wesselstatic int kgdboc_use_kms;  /* 1 if we use kernel mode switching */
38f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wesselstatic struct tty_driver	*kgdb_tty_driver;
39f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wesselstatic int			kgdb_tty_line;
40f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel
41ada64e4c98eb5f04a9ca223c5ff9e7ac22ce6404Jason Wessel#ifdef CONFIG_KDB_KEYBOARD
42111c182340cd22e238ab1cc6564df336c6ebd7cbDmitry Torokhovstatic int kgdboc_reset_connect(struct input_handler *handler,
43111c182340cd22e238ab1cc6564df336c6ebd7cbDmitry Torokhov				struct input_dev *dev,
44111c182340cd22e238ab1cc6564df336c6ebd7cbDmitry Torokhov				const struct input_device_id *id)
45111c182340cd22e238ab1cc6564df336c6ebd7cbDmitry Torokhov{
46111c182340cd22e238ab1cc6564df336c6ebd7cbDmitry Torokhov	input_reset_device(dev);
47111c182340cd22e238ab1cc6564df336c6ebd7cbDmitry Torokhov
48111c182340cd22e238ab1cc6564df336c6ebd7cbDmitry Torokhov	/* Retrun an error - we do not want to bind, just to reset */
49111c182340cd22e238ab1cc6564df336c6ebd7cbDmitry Torokhov	return -ENODEV;
50111c182340cd22e238ab1cc6564df336c6ebd7cbDmitry Torokhov}
51111c182340cd22e238ab1cc6564df336c6ebd7cbDmitry Torokhov
52111c182340cd22e238ab1cc6564df336c6ebd7cbDmitry Torokhovstatic void kgdboc_reset_disconnect(struct input_handle *handle)
53111c182340cd22e238ab1cc6564df336c6ebd7cbDmitry Torokhov{
54111c182340cd22e238ab1cc6564df336c6ebd7cbDmitry Torokhov	/* We do not expect anyone to actually bind to us */
55111c182340cd22e238ab1cc6564df336c6ebd7cbDmitry Torokhov	BUG();
56111c182340cd22e238ab1cc6564df336c6ebd7cbDmitry Torokhov}
57111c182340cd22e238ab1cc6564df336c6ebd7cbDmitry Torokhov
58111c182340cd22e238ab1cc6564df336c6ebd7cbDmitry Torokhovstatic const struct input_device_id kgdboc_reset_ids[] = {
59111c182340cd22e238ab1cc6564df336c6ebd7cbDmitry Torokhov	{
60111c182340cd22e238ab1cc6564df336c6ebd7cbDmitry Torokhov		.flags = INPUT_DEVICE_ID_MATCH_EVBIT,
61111c182340cd22e238ab1cc6564df336c6ebd7cbDmitry Torokhov		.evbit = { BIT_MASK(EV_KEY) },
62111c182340cd22e238ab1cc6564df336c6ebd7cbDmitry Torokhov	},
63111c182340cd22e238ab1cc6564df336c6ebd7cbDmitry Torokhov	{ }
64111c182340cd22e238ab1cc6564df336c6ebd7cbDmitry Torokhov};
65111c182340cd22e238ab1cc6564df336c6ebd7cbDmitry Torokhov
66111c182340cd22e238ab1cc6564df336c6ebd7cbDmitry Torokhovstatic struct input_handler kgdboc_reset_handler = {
67111c182340cd22e238ab1cc6564df336c6ebd7cbDmitry Torokhov	.connect	= kgdboc_reset_connect,
68111c182340cd22e238ab1cc6564df336c6ebd7cbDmitry Torokhov	.disconnect	= kgdboc_reset_disconnect,
69111c182340cd22e238ab1cc6564df336c6ebd7cbDmitry Torokhov	.name		= "kgdboc_reset",
70111c182340cd22e238ab1cc6564df336c6ebd7cbDmitry Torokhov	.id_table	= kgdboc_reset_ids,
71111c182340cd22e238ab1cc6564df336c6ebd7cbDmitry Torokhov};
72111c182340cd22e238ab1cc6564df336c6ebd7cbDmitry Torokhov
73111c182340cd22e238ab1cc6564df336c6ebd7cbDmitry Torokhovstatic DEFINE_MUTEX(kgdboc_reset_mutex);
74111c182340cd22e238ab1cc6564df336c6ebd7cbDmitry Torokhov
75111c182340cd22e238ab1cc6564df336c6ebd7cbDmitry Torokhovstatic void kgdboc_restore_input_helper(struct work_struct *dummy)
76111c182340cd22e238ab1cc6564df336c6ebd7cbDmitry Torokhov{
77111c182340cd22e238ab1cc6564df336c6ebd7cbDmitry Torokhov	/*
78111c182340cd22e238ab1cc6564df336c6ebd7cbDmitry Torokhov	 * We need to take a mutex to prevent several instances of
79111c182340cd22e238ab1cc6564df336c6ebd7cbDmitry Torokhov	 * this work running on different CPUs so they don't try
80111c182340cd22e238ab1cc6564df336c6ebd7cbDmitry Torokhov	 * to register again already registered handler.
81111c182340cd22e238ab1cc6564df336c6ebd7cbDmitry Torokhov	 */
82111c182340cd22e238ab1cc6564df336c6ebd7cbDmitry Torokhov	mutex_lock(&kgdboc_reset_mutex);
83111c182340cd22e238ab1cc6564df336c6ebd7cbDmitry Torokhov
84111c182340cd22e238ab1cc6564df336c6ebd7cbDmitry Torokhov	if (input_register_handler(&kgdboc_reset_handler) == 0)
85111c182340cd22e238ab1cc6564df336c6ebd7cbDmitry Torokhov		input_unregister_handler(&kgdboc_reset_handler);
86111c182340cd22e238ab1cc6564df336c6ebd7cbDmitry Torokhov
87111c182340cd22e238ab1cc6564df336c6ebd7cbDmitry Torokhov	mutex_unlock(&kgdboc_reset_mutex);
88111c182340cd22e238ab1cc6564df336c6ebd7cbDmitry Torokhov}
89111c182340cd22e238ab1cc6564df336c6ebd7cbDmitry Torokhov
90111c182340cd22e238ab1cc6564df336c6ebd7cbDmitry Torokhovstatic DECLARE_WORK(kgdboc_restore_input_work, kgdboc_restore_input_helper);
91111c182340cd22e238ab1cc6564df336c6ebd7cbDmitry Torokhov
92111c182340cd22e238ab1cc6564df336c6ebd7cbDmitry Torokhovstatic void kgdboc_restore_input(void)
93111c182340cd22e238ab1cc6564df336c6ebd7cbDmitry Torokhov{
948863ada9c47503bb93eba5e3a9ba88e6311db31fJason Wessel	if (likely(system_state == SYSTEM_RUNNING))
958863ada9c47503bb93eba5e3a9ba88e6311db31fJason Wessel		schedule_work(&kgdboc_restore_input_work);
96111c182340cd22e238ab1cc6564df336c6ebd7cbDmitry Torokhov}
97111c182340cd22e238ab1cc6564df336c6ebd7cbDmitry Torokhov
98ada64e4c98eb5f04a9ca223c5ff9e7ac22ce6404Jason Wesselstatic int kgdboc_register_kbd(char **cptr)
99ada64e4c98eb5f04a9ca223c5ff9e7ac22ce6404Jason Wessel{
100ada64e4c98eb5f04a9ca223c5ff9e7ac22ce6404Jason Wessel	if (strncmp(*cptr, "kbd", 3) == 0) {
101ada64e4c98eb5f04a9ca223c5ff9e7ac22ce6404Jason Wessel		if (kdb_poll_idx < KDB_POLL_FUNC_MAX) {
102ada64e4c98eb5f04a9ca223c5ff9e7ac22ce6404Jason Wessel			kdb_poll_funcs[kdb_poll_idx] = kdb_get_kbd_char;
103ada64e4c98eb5f04a9ca223c5ff9e7ac22ce6404Jason Wessel			kdb_poll_idx++;
104ada64e4c98eb5f04a9ca223c5ff9e7ac22ce6404Jason Wessel			if (cptr[0][3] == ',')
105ada64e4c98eb5f04a9ca223c5ff9e7ac22ce6404Jason Wessel				*cptr += 4;
106ada64e4c98eb5f04a9ca223c5ff9e7ac22ce6404Jason Wessel			else
107ada64e4c98eb5f04a9ca223c5ff9e7ac22ce6404Jason Wessel				return 1;
108ada64e4c98eb5f04a9ca223c5ff9e7ac22ce6404Jason Wessel		}
109ada64e4c98eb5f04a9ca223c5ff9e7ac22ce6404Jason Wessel	}
110ada64e4c98eb5f04a9ca223c5ff9e7ac22ce6404Jason Wessel	return 0;
111ada64e4c98eb5f04a9ca223c5ff9e7ac22ce6404Jason Wessel}
112ada64e4c98eb5f04a9ca223c5ff9e7ac22ce6404Jason Wessel
113ada64e4c98eb5f04a9ca223c5ff9e7ac22ce6404Jason Wesselstatic void kgdboc_unregister_kbd(void)
114ada64e4c98eb5f04a9ca223c5ff9e7ac22ce6404Jason Wessel{
115ada64e4c98eb5f04a9ca223c5ff9e7ac22ce6404Jason Wessel	int i;
116ada64e4c98eb5f04a9ca223c5ff9e7ac22ce6404Jason Wessel
117ada64e4c98eb5f04a9ca223c5ff9e7ac22ce6404Jason Wessel	for (i = 0; i < kdb_poll_idx; i++) {
118ada64e4c98eb5f04a9ca223c5ff9e7ac22ce6404Jason Wessel		if (kdb_poll_funcs[i] == kdb_get_kbd_char) {
119ada64e4c98eb5f04a9ca223c5ff9e7ac22ce6404Jason Wessel			kdb_poll_idx--;
120ada64e4c98eb5f04a9ca223c5ff9e7ac22ce6404Jason Wessel			kdb_poll_funcs[i] = kdb_poll_funcs[kdb_poll_idx];
121ada64e4c98eb5f04a9ca223c5ff9e7ac22ce6404Jason Wessel			kdb_poll_funcs[kdb_poll_idx] = NULL;
122ada64e4c98eb5f04a9ca223c5ff9e7ac22ce6404Jason Wessel			i--;
123ada64e4c98eb5f04a9ca223c5ff9e7ac22ce6404Jason Wessel		}
124ada64e4c98eb5f04a9ca223c5ff9e7ac22ce6404Jason Wessel	}
125111c182340cd22e238ab1cc6564df336c6ebd7cbDmitry Torokhov	flush_work_sync(&kgdboc_restore_input_work);
126ada64e4c98eb5f04a9ca223c5ff9e7ac22ce6404Jason Wessel}
127ada64e4c98eb5f04a9ca223c5ff9e7ac22ce6404Jason Wessel#else /* ! CONFIG_KDB_KEYBOARD */
128ada64e4c98eb5f04a9ca223c5ff9e7ac22ce6404Jason Wessel#define kgdboc_register_kbd(x) 0
129ada64e4c98eb5f04a9ca223c5ff9e7ac22ce6404Jason Wessel#define kgdboc_unregister_kbd()
130111c182340cd22e238ab1cc6564df336c6ebd7cbDmitry Torokhov#define kgdboc_restore_input()
131ada64e4c98eb5f04a9ca223c5ff9e7ac22ce6404Jason Wessel#endif /* ! CONFIG_KDB_KEYBOARD */
132ada64e4c98eb5f04a9ca223c5ff9e7ac22ce6404Jason Wessel
133f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wesselstatic int kgdboc_option_setup(char *opt)
134f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel{
135adb4b83c12f9d966ea3478aa14c60511467c9916Dan Carpenter	if (strlen(opt) >= MAX_CONFIG_LEN) {
136f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel		printk(KERN_ERR "kgdboc: config string too long\n");
137f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel		return -ENOSPC;
138f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel	}
139f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel	strcpy(config, opt);
140f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel
141f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel	return 0;
142f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel}
143f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel
144f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel__setup("kgdboc=", kgdboc_option_setup);
145f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel
146ada64e4c98eb5f04a9ca223c5ff9e7ac22ce6404Jason Wesselstatic void cleanup_kgdboc(void)
147ada64e4c98eb5f04a9ca223c5ff9e7ac22ce6404Jason Wessel{
148ada64e4c98eb5f04a9ca223c5ff9e7ac22ce6404Jason Wessel	kgdboc_unregister_kbd();
149ada64e4c98eb5f04a9ca223c5ff9e7ac22ce6404Jason Wessel	if (configured == 1)
150ada64e4c98eb5f04a9ca223c5ff9e7ac22ce6404Jason Wessel		kgdb_unregister_io_module(&kgdboc_io_ops);
151ada64e4c98eb5f04a9ca223c5ff9e7ac22ce6404Jason Wessel}
152ada64e4c98eb5f04a9ca223c5ff9e7ac22ce6404Jason Wessel
153f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wesselstatic int configure_kgdboc(void)
154f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel{
155f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel	struct tty_driver *p;
156f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel	int tty_line = 0;
157f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel	int err;
158ada64e4c98eb5f04a9ca223c5ff9e7ac22ce6404Jason Wessel	char *cptr = config;
159efe2f29e324fd20e0449bcd6dc6dbe4734c2ba94Jason Wessel	struct console *cons;
160f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel
161f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel	err = kgdboc_option_setup(config);
162f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel	if (err || !strlen(config) || isspace(config[0]))
163f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel		goto noconfig;
164f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel
165f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel	err = -ENODEV;
166efe2f29e324fd20e0449bcd6dc6dbe4734c2ba94Jason Wessel	kgdboc_io_ops.is_console = 0;
167ada64e4c98eb5f04a9ca223c5ff9e7ac22ce6404Jason Wessel	kgdb_tty_driver = NULL;
168ada64e4c98eb5f04a9ca223c5ff9e7ac22ce6404Jason Wessel
169408a4be1f8cbee511895ee07da2a007a5a24303fJason Wessel	kgdboc_use_kms = 0;
170408a4be1f8cbee511895ee07da2a007a5a24303fJason Wessel	if (strncmp(cptr, "kms,", 4) == 0) {
171408a4be1f8cbee511895ee07da2a007a5a24303fJason Wessel		cptr += 4;
172408a4be1f8cbee511895ee07da2a007a5a24303fJason Wessel		kgdboc_use_kms = 1;
173408a4be1f8cbee511895ee07da2a007a5a24303fJason Wessel	}
174408a4be1f8cbee511895ee07da2a007a5a24303fJason Wessel
175ada64e4c98eb5f04a9ca223c5ff9e7ac22ce6404Jason Wessel	if (kgdboc_register_kbd(&cptr))
176ada64e4c98eb5f04a9ca223c5ff9e7ac22ce6404Jason Wessel		goto do_register;
177f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel
178ada64e4c98eb5f04a9ca223c5ff9e7ac22ce6404Jason Wessel	p = tty_find_polling_driver(cptr, &tty_line);
179f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel	if (!p)
180f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel		goto noconfig;
181f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel
182efe2f29e324fd20e0449bcd6dc6dbe4734c2ba94Jason Wessel	cons = console_drivers;
183efe2f29e324fd20e0449bcd6dc6dbe4734c2ba94Jason Wessel	while (cons) {
184efe2f29e324fd20e0449bcd6dc6dbe4734c2ba94Jason Wessel		int idx;
185efe2f29e324fd20e0449bcd6dc6dbe4734c2ba94Jason Wessel		if (cons->device && cons->device(cons, &idx) == p &&
186efe2f29e324fd20e0449bcd6dc6dbe4734c2ba94Jason Wessel		    idx == tty_line) {
187efe2f29e324fd20e0449bcd6dc6dbe4734c2ba94Jason Wessel			kgdboc_io_ops.is_console = 1;
188efe2f29e324fd20e0449bcd6dc6dbe4734c2ba94Jason Wessel			break;
189efe2f29e324fd20e0449bcd6dc6dbe4734c2ba94Jason Wessel		}
190efe2f29e324fd20e0449bcd6dc6dbe4734c2ba94Jason Wessel		cons = cons->next;
191efe2f29e324fd20e0449bcd6dc6dbe4734c2ba94Jason Wessel	}
192efe2f29e324fd20e0449bcd6dc6dbe4734c2ba94Jason Wessel
193f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel	kgdb_tty_driver = p;
194f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel	kgdb_tty_line = tty_line;
195f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel
196ada64e4c98eb5f04a9ca223c5ff9e7ac22ce6404Jason Wesseldo_register:
197f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel	err = kgdb_register_io_module(&kgdboc_io_ops);
198f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel	if (err)
199f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel		goto noconfig;
200f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel
201f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel	configured = 1;
202f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel
203f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel	return 0;
204f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel
205f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wesselnoconfig:
206f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel	config[0] = 0;
207f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel	configured = 0;
208ada64e4c98eb5f04a9ca223c5ff9e7ac22ce6404Jason Wessel	cleanup_kgdboc();
209f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel
210f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel	return err;
211f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel}
212f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel
213f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wesselstatic int __init init_kgdboc(void)
214f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel{
215f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel	/* Already configured? */
216f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel	if (configured == 1)
217f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel		return 0;
218f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel
219f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel	return configure_kgdboc();
220f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel}
221f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel
222f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wesselstatic int kgdboc_get_char(void)
223f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel{
224ada64e4c98eb5f04a9ca223c5ff9e7ac22ce6404Jason Wessel	if (!kgdb_tty_driver)
225ada64e4c98eb5f04a9ca223c5ff9e7ac22ce6404Jason Wessel		return -1;
226f34d7a5b7010b82fe97da95496b9971435530062Alan Cox	return kgdb_tty_driver->ops->poll_get_char(kgdb_tty_driver,
227f34d7a5b7010b82fe97da95496b9971435530062Alan Cox						kgdb_tty_line);
228f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel}
229f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel
230f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wesselstatic void kgdboc_put_char(u8 chr)
231f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel{
232ada64e4c98eb5f04a9ca223c5ff9e7ac22ce6404Jason Wessel	if (!kgdb_tty_driver)
233ada64e4c98eb5f04a9ca223c5ff9e7ac22ce6404Jason Wessel		return;
234f34d7a5b7010b82fe97da95496b9971435530062Alan Cox	kgdb_tty_driver->ops->poll_put_char(kgdb_tty_driver,
235f34d7a5b7010b82fe97da95496b9971435530062Alan Cox					kgdb_tty_line, chr);
236f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel}
237f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel
238f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wesselstatic int param_set_kgdboc_var(const char *kmessage, struct kernel_param *kp)
239f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel{
240c191e5ad6b3fd8cc84b2b6d62c02fcd6837c8a8fJason Wessel	int len = strlen(kmessage);
241c191e5ad6b3fd8cc84b2b6d62c02fcd6837c8a8fJason Wessel
242c191e5ad6b3fd8cc84b2b6d62c02fcd6837c8a8fJason Wessel	if (len >= MAX_CONFIG_LEN) {
243f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel		printk(KERN_ERR "kgdboc: config string too long\n");
244f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel		return -ENOSPC;
245f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel	}
246f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel
247f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel	/* Only copy in the string if the init function has not run yet */
248f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel	if (configured < 0) {
249f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel		strcpy(config, kmessage);
250f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel		return 0;
251f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel	}
252f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel
253f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel	if (kgdb_connected) {
254f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel		printk(KERN_ERR
255f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel		       "kgdboc: Cannot reconfigure while KGDB is connected.\n");
256f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel
257f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel		return -EBUSY;
258f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel	}
259f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel
260f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel	strcpy(config, kmessage);
261c191e5ad6b3fd8cc84b2b6d62c02fcd6837c8a8fJason Wessel	/* Chop out \n char as a result of echo */
262c191e5ad6b3fd8cc84b2b6d62c02fcd6837c8a8fJason Wessel	if (config[len - 1] == '\n')
263c191e5ad6b3fd8cc84b2b6d62c02fcd6837c8a8fJason Wessel		config[len - 1] = '\0';
264f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel
265f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel	if (configured == 1)
266f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel		cleanup_kgdboc();
267f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel
268f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel	/* Go and configure with the new params. */
269f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel	return configure_kgdboc();
270f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel}
271f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel
272408a4be1f8cbee511895ee07da2a007a5a24303fJason Wesselstatic int dbg_restore_graphics;
273408a4be1f8cbee511895ee07da2a007a5a24303fJason Wessel
274f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wesselstatic void kgdboc_pre_exp_handler(void)
275f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel{
276408a4be1f8cbee511895ee07da2a007a5a24303fJason Wessel	if (!dbg_restore_graphics && kgdboc_use_kms) {
277408a4be1f8cbee511895ee07da2a007a5a24303fJason Wessel		dbg_restore_graphics = 1;
278408a4be1f8cbee511895ee07da2a007a5a24303fJason Wessel		con_debug_enter(vc_cons[fg_console].d);
279408a4be1f8cbee511895ee07da2a007a5a24303fJason Wessel	}
280f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel	/* Increment the module count when the debugger is active */
281f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel	if (!kgdb_connected)
282f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel		try_module_get(THIS_MODULE);
283f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel}
284f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel
285f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wesselstatic void kgdboc_post_exp_handler(void)
286f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel{
287f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel	/* decrement the module count when the debugger detaches */
288f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel	if (!kgdb_connected)
289f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel		module_put(THIS_MODULE);
290408a4be1f8cbee511895ee07da2a007a5a24303fJason Wessel	if (kgdboc_use_kms && dbg_restore_graphics) {
291408a4be1f8cbee511895ee07da2a007a5a24303fJason Wessel		dbg_restore_graphics = 0;
292408a4be1f8cbee511895ee07da2a007a5a24303fJason Wessel		con_debug_leave();
293408a4be1f8cbee511895ee07da2a007a5a24303fJason Wessel	}
294111c182340cd22e238ab1cc6564df336c6ebd7cbDmitry Torokhov	kgdboc_restore_input();
295f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel}
296f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel
297f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wesselstatic struct kgdb_io kgdboc_io_ops = {
298f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel	.name			= "kgdboc",
299f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel	.read_char		= kgdboc_get_char,
300f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel	.write_char		= kgdboc_put_char,
301f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel	.pre_exception		= kgdboc_pre_exp_handler,
302f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel	.post_exception		= kgdboc_post_exp_handler,
303f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel};
304f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel
3059731191f75a54c4fa17e9b9b88f3144cf4b47836Jason Wessel#ifdef CONFIG_KGDB_SERIAL_CONSOLE
3069731191f75a54c4fa17e9b9b88f3144cf4b47836Jason Wessel/* This is only available if kgdboc is a built in for early debugging */
30791b152aa85bbcf076e269565394c31964f940371Jason Wesselstatic int __init kgdboc_early_init(char *opt)
3089731191f75a54c4fa17e9b9b88f3144cf4b47836Jason Wessel{
3099731191f75a54c4fa17e9b9b88f3144cf4b47836Jason Wessel	/* save the first character of the config string because the
3109731191f75a54c4fa17e9b9b88f3144cf4b47836Jason Wessel	 * init routine can destroy it.
3119731191f75a54c4fa17e9b9b88f3144cf4b47836Jason Wessel	 */
3129731191f75a54c4fa17e9b9b88f3144cf4b47836Jason Wessel	char save_ch;
3139731191f75a54c4fa17e9b9b88f3144cf4b47836Jason Wessel
3149731191f75a54c4fa17e9b9b88f3144cf4b47836Jason Wessel	kgdboc_option_setup(opt);
3159731191f75a54c4fa17e9b9b88f3144cf4b47836Jason Wessel	save_ch = config[0];
3169731191f75a54c4fa17e9b9b88f3144cf4b47836Jason Wessel	init_kgdboc();
3179731191f75a54c4fa17e9b9b88f3144cf4b47836Jason Wessel	config[0] = save_ch;
3189731191f75a54c4fa17e9b9b88f3144cf4b47836Jason Wessel	return 0;
3199731191f75a54c4fa17e9b9b88f3144cf4b47836Jason Wessel}
3209731191f75a54c4fa17e9b9b88f3144cf4b47836Jason Wessel
3219731191f75a54c4fa17e9b9b88f3144cf4b47836Jason Wesselearly_param("ekgdboc", kgdboc_early_init);
3229731191f75a54c4fa17e9b9b88f3144cf4b47836Jason Wessel#endif /* CONFIG_KGDB_SERIAL_CONSOLE */
3239731191f75a54c4fa17e9b9b88f3144cf4b47836Jason Wessel
324f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wesselmodule_init(init_kgdboc);
325f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wesselmodule_exit(cleanup_kgdboc);
326f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wesselmodule_param_call(kgdboc, param_set_kgdboc_var, param_get_string, &kps, 0644);
327f2d937f3bf00665ccf048b3b6616ef95859b0945Jason WesselMODULE_PARM_DESC(kgdboc, "<serial_device>[,baud]");
328f2d937f3bf00665ccf048b3b6616ef95859b0945Jason WesselMODULE_DESCRIPTION("KGDB Console TTY Driver");
329f2d937f3bf00665ccf048b3b6616ef95859b0945Jason WesselMODULE_LICENSE("GPL");
330