aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJason Wessel <jason.wessel@windriver.com>2010-05-20 22:04:24 -0400
committerJason Wessel <jason.wessel@windriver.com>2010-05-20 22:04:24 -0400
commitada64e4c98eb5f04a9ca223c5ff9e7ac22ce6404 (patch)
tree48e284cf69157cf54302dcceb01ad7a07b889206
parenta0de055cf61338549b13079a5677ef2e1b6472ef (diff)
kgdboc,keyboard: Keyboard driver for kdb with kgdb
This patch adds in the kdb PS/2 keyboard driver. This was mostly a direct port from the original kdb where I cleaned up the code against checkpatch.pl and added the glue to stitch it into kgdb. This patch also enables early kdb debug via kgdbwait and the keyboard. All the access to configure kdb using either a serial console or the keyboard is done via kgdboc. If you want to use only the keyboard and want to break in early you would add to your kernel command arguments: kgdboc=kbd kgdbwait If you wanted serial and or the keyboard access you could use: kgdboc=kbd,ttyS0 You can also configure kgdboc as a kernel module or at run time with the sysfs where you can activate and deactivate kgdb. Turn it on: echo kbd,ttyS0 > /sys/module/kgdboc/parameters/kgdboc Turn it off: echo "" > /sys/module/kgdboc/parameters/kgdboc Signed-off-by: Jason Wessel <jason.wessel@windriver.com> Reviewed-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
-rw-r--r--Documentation/kernel-parameters.txt8
-rw-r--r--drivers/serial/kgdboc.c61
-rw-r--r--kernel/debug/kdb/Makefile1
-rw-r--r--kernel/debug/kdb/kdb_keyboard.c212
-rw-r--r--lib/Kconfig.kgdb7
5 files changed, 279 insertions, 10 deletions
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index b12bacd252fc..3845e3a84a52 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -1121,9 +1121,11 @@ and is between 256 and 4096 characters. It is defined in the file
1121 zone if it does not. 1121 zone if it does not.
1122 1122
1123 kgdboc= [HW] kgdb over consoles. 1123 kgdboc= [HW] kgdb over consoles.
1124 Requires a tty driver that supports console polling. 1124 Requires a tty driver that supports console polling,
1125 (only serial supported for now) 1125 or a supported polling keyboard driver (non-usb).
1126 Format: <serial_device>[,baud] 1126 Serial only format: <serial_device>[,baud]
1127 keyboard only format: kbd
1128 keyboard and serial format: kbd,<serial_device>[,baud]
1127 1129
1128 kmac= [MIPS] korina ethernet MAC address. 1130 kmac= [MIPS] korina ethernet MAC address.
1129 Configure the RouterBoard 532 series on-chip 1131 Configure the RouterBoard 532 series on-chip
diff --git a/drivers/serial/kgdboc.c b/drivers/serial/kgdboc.c
index eadc1ab6bbce..ecef6e1a599a 100644
--- a/drivers/serial/kgdboc.c
+++ b/drivers/serial/kgdboc.c
@@ -14,6 +14,7 @@
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>
18 19
19#define MAX_CONFIG_LEN 40 20#define MAX_CONFIG_LEN 40
@@ -32,6 +33,40 @@ static struct kparam_string kps = {
32static struct tty_driver *kgdb_tty_driver; 33static struct tty_driver *kgdb_tty_driver;
33static int kgdb_tty_line; 34static int kgdb_tty_line;
34 35
36#ifdef CONFIG_KDB_KEYBOARD
37static int kgdboc_register_kbd(char **cptr)
38{
39 if (strncmp(*cptr, "kbd", 3) == 0) {
40 if (kdb_poll_idx < KDB_POLL_FUNC_MAX) {
41 kdb_poll_funcs[kdb_poll_idx] = kdb_get_kbd_char;
42 kdb_poll_idx++;
43 if (cptr[0][3] == ',')
44 *cptr += 4;
45 else
46 return 1;
47 }
48 }
49 return 0;
50}
51
52static void kgdboc_unregister_kbd(void)
53{
54 int i;
55
56 for (i = 0; i < kdb_poll_idx; i++) {
57 if (kdb_poll_funcs[i] == kdb_get_kbd_char) {
58 kdb_poll_idx--;
59 kdb_poll_funcs[i] = kdb_poll_funcs[kdb_poll_idx];
60 kdb_poll_funcs[kdb_poll_idx] = NULL;
61 i--;
62 }
63 }
64}
65#else /* ! CONFIG_KDB_KEYBOARD */
66#define kgdboc_register_kbd(x) 0
67#define kgdboc_unregister_kbd()
68#endif /* ! CONFIG_KDB_KEYBOARD */
69
35static int kgdboc_option_setup(char *opt) 70static int kgdboc_option_setup(char *opt)
36{ 71{
37 if (strlen(opt) > MAX_CONFIG_LEN) { 72 if (strlen(opt) > MAX_CONFIG_LEN) {
@@ -45,25 +80,38 @@ static int kgdboc_option_setup(char *opt)
45 80
46__setup("kgdboc=", kgdboc_option_setup); 81__setup("kgdboc=", kgdboc_option_setup);
47 82
83static void cleanup_kgdboc(void)
84{
85 kgdboc_unregister_kbd();
86 if (configured == 1)
87 kgdb_unregister_io_module(&kgdboc_io_ops);
88}
89
48static int configure_kgdboc(void) 90static int configure_kgdboc(void)
49{ 91{
50 struct tty_driver *p; 92 struct tty_driver *p;
51 int tty_line = 0; 93 int tty_line = 0;
52 int err; 94 int err;
95 char *cptr = config;
53 96
54 err = kgdboc_option_setup(config); 97 err = kgdboc_option_setup(config);
55 if (err || !strlen(config) || isspace(config[0])) 98 if (err || !strlen(config) || isspace(config[0]))
56 goto noconfig; 99 goto noconfig;
57 100
58 err = -ENODEV; 101 err = -ENODEV;
102 kgdb_tty_driver = NULL;
103
104 if (kgdboc_register_kbd(&cptr))
105 goto do_register;
59 106
60 p = tty_find_polling_driver(config, &tty_line); 107 p = tty_find_polling_driver(cptr, &tty_line);
61 if (!p) 108 if (!p)
62 goto noconfig; 109 goto noconfig;
63 110
64 kgdb_tty_driver = p; 111 kgdb_tty_driver = p;
65 kgdb_tty_line = tty_line; 112 kgdb_tty_line = tty_line;
66 113
114do_register:
67 err = kgdb_register_io_module(&kgdboc_io_ops); 115 err = kgdb_register_io_module(&kgdboc_io_ops);
68 if (err) 116 if (err)
69 goto noconfig; 117 goto noconfig;
@@ -75,6 +123,7 @@ static int configure_kgdboc(void)
75noconfig: 123noconfig:
76 config[0] = 0; 124 config[0] = 0;
77 configured = 0; 125 configured = 0;
126 cleanup_kgdboc();
78 127
79 return err; 128 return err;
80} 129}
@@ -88,20 +137,18 @@ static int __init init_kgdboc(void)
88 return configure_kgdboc(); 137 return configure_kgdboc();
89} 138}
90 139
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) 140static int kgdboc_get_char(void)
98{ 141{
142 if (!kgdb_tty_driver)
143 return -1;
99 return kgdb_tty_driver->ops->poll_get_char(kgdb_tty_driver, 144 return kgdb_tty_driver->ops->poll_get_char(kgdb_tty_driver,
100 kgdb_tty_line); 145 kgdb_tty_line);
101} 146}
102 147
103static void kgdboc_put_char(u8 chr) 148static void kgdboc_put_char(u8 chr)
104{ 149{
150 if (!kgdb_tty_driver)
151 return;
105 kgdb_tty_driver->ops->poll_put_char(kgdb_tty_driver, 152 kgdb_tty_driver->ops->poll_put_char(kgdb_tty_driver,
106 kgdb_tty_line, chr); 153 kgdb_tty_line, chr);
107} 154}
diff --git a/kernel/debug/kdb/Makefile b/kernel/debug/kdb/Makefile
index d1e925eddbcd..d4fc58f4b88d 100644
--- a/kernel/debug/kdb/Makefile
+++ b/kernel/debug/kdb/Makefile
@@ -8,6 +8,7 @@
8 8
9CCVERSION := $(shell $(CC) -v 2>&1 | sed -ne '$$p') 9CCVERSION := $(shell $(CC) -v 2>&1 | sed -ne '$$p')
10obj-y := kdb_io.o kdb_main.o kdb_support.o kdb_bt.o gen-kdb_cmds.o kdb_bp.o kdb_debugger.o 10obj-y := kdb_io.o kdb_main.o kdb_support.o kdb_bt.o gen-kdb_cmds.o kdb_bp.o kdb_debugger.o
11obj-$(CONFIG_KDB_KEYBOARD) += kdb_keyboard.o
11 12
12clean-files := gen-kdb_cmds.c 13clean-files := gen-kdb_cmds.c
13 14
diff --git a/kernel/debug/kdb/kdb_keyboard.c b/kernel/debug/kdb/kdb_keyboard.c
new file mode 100644
index 000000000000..4bca634975c0
--- /dev/null
+++ b/kernel/debug/kdb/kdb_keyboard.c
@@ -0,0 +1,212 @@
1/*
2 * Kernel Debugger Architecture Dependent Console I/O handler
3 *
4 * This file is subject to the terms and conditions of the GNU General Public
5 * License.
6 *
7 * Copyright (c) 1999-2006 Silicon Graphics, Inc. All Rights Reserved.
8 * Copyright (c) 2009 Wind River Systems, Inc. All Rights Reserved.
9 */
10
11#include <linux/kdb.h>
12#include <linux/keyboard.h>
13#include <linux/ctype.h>
14#include <linux/module.h>
15#include <linux/io.h>
16
17/* Keyboard Controller Registers on normal PCs. */
18
19#define KBD_STATUS_REG 0x64 /* Status register (R) */
20#define KBD_DATA_REG 0x60 /* Keyboard data register (R/W) */
21
22/* Status Register Bits */
23
24#define KBD_STAT_OBF 0x01 /* Keyboard output buffer full */
25#define KBD_STAT_MOUSE_OBF 0x20 /* Mouse output buffer full */
26
27static int kbd_exists;
28
29/*
30 * Check if the keyboard controller has a keypress for us.
31 * Some parts (Enter Release, LED change) are still blocking polled here,
32 * but hopefully they are all short.
33 */
34int kdb_get_kbd_char(void)
35{
36 int scancode, scanstatus;
37 static int shift_lock; /* CAPS LOCK state (0-off, 1-on) */
38 static int shift_key; /* Shift next keypress */
39 static int ctrl_key;
40 u_short keychar;
41
42 if (KDB_FLAG(NO_I8042) || KDB_FLAG(NO_VT_CONSOLE) ||
43 (inb(KBD_STATUS_REG) == 0xff && inb(KBD_DATA_REG) == 0xff)) {
44 kbd_exists = 0;
45 return -1;
46 }
47 kbd_exists = 1;
48
49 if ((inb(KBD_STATUS_REG) & KBD_STAT_OBF) == 0)
50 return -1;
51
52 /*
53 * Fetch the scancode
54 */
55 scancode = inb(KBD_DATA_REG);
56 scanstatus = inb(KBD_STATUS_REG);
57
58 /*
59 * Ignore mouse events.
60 */
61 if (scanstatus & KBD_STAT_MOUSE_OBF)
62 return -1;
63
64 /*
65 * Ignore release, trigger on make
66 * (except for shift keys, where we want to
67 * keep the shift state so long as the key is
68 * held down).
69 */
70
71 if (((scancode&0x7f) == 0x2a) || ((scancode&0x7f) == 0x36)) {
72 /*
73 * Next key may use shift table
74 */
75 if ((scancode & 0x80) == 0)
76 shift_key = 1;
77 else
78 shift_key = 0;
79 return -1;
80 }
81
82 if ((scancode&0x7f) == 0x1d) {
83 /*
84 * Left ctrl key
85 */
86 if ((scancode & 0x80) == 0)
87 ctrl_key = 1;
88 else
89 ctrl_key = 0;
90 return -1;
91 }
92
93 if ((scancode & 0x80) != 0)
94 return -1;
95
96 scancode &= 0x7f;
97
98 /*
99 * Translate scancode
100 */
101
102 if (scancode == 0x3a) {
103 /*
104 * Toggle caps lock
105 */
106 shift_lock ^= 1;
107
108#ifdef KDB_BLINK_LED
109 kdb_toggleled(0x4);
110#endif
111 return -1;
112 }
113
114 if (scancode == 0x0e) {
115 /*
116 * Backspace
117 */
118 return 8;
119 }
120
121 /* Special Key */
122 switch (scancode) {
123 case 0xF: /* Tab */
124 return 9;
125 case 0x53: /* Del */
126 return 4;
127 case 0x47: /* Home */
128 return 1;
129 case 0x4F: /* End */
130 return 5;
131 case 0x4B: /* Left */
132 return 2;
133 case 0x48: /* Up */
134 return 16;
135 case 0x50: /* Down */
136 return 14;
137 case 0x4D: /* Right */
138 return 6;
139 }
140
141 if (scancode == 0xe0)
142 return -1;
143
144 /*
145 * For Japanese 86/106 keyboards
146 * See comment in drivers/char/pc_keyb.c.
147 * - Masahiro Adegawa
148 */
149 if (scancode == 0x73)
150 scancode = 0x59;
151 else if (scancode == 0x7d)
152 scancode = 0x7c;
153
154 if (!shift_lock && !shift_key && !ctrl_key) {
155 keychar = plain_map[scancode];
156 } else if ((shift_lock || shift_key) && key_maps[1]) {
157 keychar = key_maps[1][scancode];
158 } else if (ctrl_key && key_maps[4]) {
159 keychar = key_maps[4][scancode];
160 } else {
161 keychar = 0x0020;
162 kdb_printf("Unknown state/scancode (%d)\n", scancode);
163 }
164 keychar &= 0x0fff;
165 if (keychar == '\t')
166 keychar = ' ';
167 switch (KTYP(keychar)) {
168 case KT_LETTER:
169 case KT_LATIN:
170 if (isprint(keychar))
171 break; /* printable characters */
172 /* drop through */
173 case KT_SPEC:
174 if (keychar == K_ENTER)
175 break;
176 /* drop through */
177 default:
178 return -1; /* ignore unprintables */
179 }
180
181 if ((scancode & 0x7f) == 0x1c) {
182 /*
183 * enter key. All done. Absorb the release scancode.
184 */
185 while ((inb(KBD_STATUS_REG) & KBD_STAT_OBF) == 0)
186 ;
187
188 /*
189 * Fetch the scancode
190 */
191 scancode = inb(KBD_DATA_REG);
192 scanstatus = inb(KBD_STATUS_REG);
193
194 while (scanstatus & KBD_STAT_MOUSE_OBF) {
195 scancode = inb(KBD_DATA_REG);
196 scanstatus = inb(KBD_STATUS_REG);
197 }
198
199 if (scancode != 0x9c) {
200 /*
201 * Wasn't an enter-release, why not?
202 */
203 kdb_printf("kdb: expected enter got 0x%x status 0x%x\n",
204 scancode, scanstatus);
205 }
206
207 return 13;
208 }
209
210 return keychar & 0xff;
211}
212EXPORT_SYMBOL_GPL(kdb_get_kbd_char);
diff --git a/lib/Kconfig.kgdb b/lib/Kconfig.kgdb
index 78de43a5e902..ee8ae7132f20 100644
--- a/lib/Kconfig.kgdb
+++ b/lib/Kconfig.kgdb
@@ -63,4 +63,11 @@ config KGDB_KDB
63 help 63 help
64 KDB frontend for kernel 64 KDB frontend for kernel
65 65
66config KDB_KEYBOARD
67 bool "KGDB_KDB: keyboard as input device"
68 depends on VT && KGDB_KDB
69 default n
70 help
71 KDB can use a PS/2 type keyboard for an input device
72
66endif # KGDB 73endif # KGDB