xref: /openbmc/linux/kernel/debug/kdb/kdb_keyboard.c (revision 2612e3bbc0386368a850140a6c9b990cd496a5ec)
1ada64e4cSJason Wessel /*
2ada64e4cSJason Wessel  * Kernel Debugger Architecture Dependent Console I/O handler
3ada64e4cSJason Wessel  *
4ada64e4cSJason Wessel  * This file is subject to the terms and conditions of the GNU General Public
5ada64e4cSJason Wessel  * License.
6ada64e4cSJason Wessel  *
7ada64e4cSJason Wessel  * Copyright (c) 1999-2006 Silicon Graphics, Inc.  All Rights Reserved.
8ada64e4cSJason Wessel  * Copyright (c) 2009 Wind River Systems, Inc.  All Rights Reserved.
9ada64e4cSJason Wessel  */
10ada64e4cSJason Wessel 
11ada64e4cSJason Wessel #include <linux/kdb.h>
12ada64e4cSJason Wessel #include <linux/keyboard.h>
13ada64e4cSJason Wessel #include <linux/ctype.h>
14ada64e4cSJason Wessel #include <linux/io.h>
15ada64e4cSJason Wessel 
16*0914e4d3SArnd Bergmann #include "kdb_private.h"
17*0914e4d3SArnd Bergmann 
18ada64e4cSJason Wessel /* Keyboard Controller Registers on normal PCs. */
19ada64e4cSJason Wessel 
20ada64e4cSJason Wessel #define KBD_STATUS_REG		0x64	/* Status register (R) */
21ada64e4cSJason Wessel #define KBD_DATA_REG		0x60	/* Keyboard data register (R/W) */
22ada64e4cSJason Wessel 
23ada64e4cSJason Wessel /* Status Register Bits */
24ada64e4cSJason Wessel 
25ada64e4cSJason Wessel #define KBD_STAT_OBF 		0x01	/* Keyboard output buffer full */
26ada64e4cSJason Wessel #define KBD_STAT_MOUSE_OBF	0x20	/* Mouse output buffer full */
27ada64e4cSJason Wessel 
28ada64e4cSJason Wessel static int kbd_exists;
298f30d411SAndrei Warkentin static int kbd_last_ret;
30ada64e4cSJason Wessel 
31ada64e4cSJason Wessel /*
32ada64e4cSJason Wessel  * Check if the keyboard controller has a keypress for us.
33ada64e4cSJason Wessel  * Some parts (Enter Release, LED change) are still blocking polled here,
34ada64e4cSJason Wessel  * but hopefully they are all short.
35ada64e4cSJason Wessel  */
kdb_get_kbd_char(void)36ada64e4cSJason Wessel int kdb_get_kbd_char(void)
37ada64e4cSJason Wessel {
38ada64e4cSJason Wessel 	int scancode, scanstatus;
39ada64e4cSJason Wessel 	static int shift_lock;	/* CAPS LOCK state (0-off, 1-on) */
40ada64e4cSJason Wessel 	static int shift_key;	/* Shift next keypress */
41ada64e4cSJason Wessel 	static int ctrl_key;
42ada64e4cSJason Wessel 	u_short keychar;
43ada64e4cSJason Wessel 
44ada64e4cSJason Wessel 	if (KDB_FLAG(NO_I8042) || KDB_FLAG(NO_VT_CONSOLE) ||
45ada64e4cSJason Wessel 	    (inb(KBD_STATUS_REG) == 0xff && inb(KBD_DATA_REG) == 0xff)) {
46ada64e4cSJason Wessel 		kbd_exists = 0;
47ada64e4cSJason Wessel 		return -1;
48ada64e4cSJason Wessel 	}
49ada64e4cSJason Wessel 	kbd_exists = 1;
50ada64e4cSJason Wessel 
51ada64e4cSJason Wessel 	if ((inb(KBD_STATUS_REG) & KBD_STAT_OBF) == 0)
52ada64e4cSJason Wessel 		return -1;
53ada64e4cSJason Wessel 
54ada64e4cSJason Wessel 	/*
55ada64e4cSJason Wessel 	 * Fetch the scancode
56ada64e4cSJason Wessel 	 */
57ada64e4cSJason Wessel 	scancode = inb(KBD_DATA_REG);
58ada64e4cSJason Wessel 	scanstatus = inb(KBD_STATUS_REG);
59ada64e4cSJason Wessel 
60ada64e4cSJason Wessel 	/*
61ada64e4cSJason Wessel 	 * Ignore mouse events.
62ada64e4cSJason Wessel 	 */
63ada64e4cSJason Wessel 	if (scanstatus & KBD_STAT_MOUSE_OBF)
64ada64e4cSJason Wessel 		return -1;
65ada64e4cSJason Wessel 
66ada64e4cSJason Wessel 	/*
67ada64e4cSJason Wessel 	 * Ignore release, trigger on make
68ada64e4cSJason Wessel 	 * (except for shift keys, where we want to
69ada64e4cSJason Wessel 	 *  keep the shift state so long as the key is
70ada64e4cSJason Wessel 	 *  held down).
71ada64e4cSJason Wessel 	 */
72ada64e4cSJason Wessel 
73ada64e4cSJason Wessel 	if (((scancode&0x7f) == 0x2a) || ((scancode&0x7f) == 0x36)) {
74ada64e4cSJason Wessel 		/*
75ada64e4cSJason Wessel 		 * Next key may use shift table
76ada64e4cSJason Wessel 		 */
77ada64e4cSJason Wessel 		if ((scancode & 0x80) == 0)
78ada64e4cSJason Wessel 			shift_key = 1;
79ada64e4cSJason Wessel 		else
80ada64e4cSJason Wessel 			shift_key = 0;
81ada64e4cSJason Wessel 		return -1;
82ada64e4cSJason Wessel 	}
83ada64e4cSJason Wessel 
84ada64e4cSJason Wessel 	if ((scancode&0x7f) == 0x1d) {
85ada64e4cSJason Wessel 		/*
86ada64e4cSJason Wessel 		 * Left ctrl key
87ada64e4cSJason Wessel 		 */
88ada64e4cSJason Wessel 		if ((scancode & 0x80) == 0)
89ada64e4cSJason Wessel 			ctrl_key = 1;
90ada64e4cSJason Wessel 		else
91ada64e4cSJason Wessel 			ctrl_key = 0;
92ada64e4cSJason Wessel 		return -1;
93ada64e4cSJason Wessel 	}
94ada64e4cSJason Wessel 
958f30d411SAndrei Warkentin 	if ((scancode & 0x80) != 0) {
968f30d411SAndrei Warkentin 		if (scancode == 0x9c)
978f30d411SAndrei Warkentin 			kbd_last_ret = 0;
98ada64e4cSJason Wessel 		return -1;
998f30d411SAndrei Warkentin 	}
100ada64e4cSJason Wessel 
101ada64e4cSJason Wessel 	scancode &= 0x7f;
102ada64e4cSJason Wessel 
103ada64e4cSJason Wessel 	/*
104ada64e4cSJason Wessel 	 * Translate scancode
105ada64e4cSJason Wessel 	 */
106ada64e4cSJason Wessel 
107ada64e4cSJason Wessel 	if (scancode == 0x3a) {
108ada64e4cSJason Wessel 		/*
109ada64e4cSJason Wessel 		 * Toggle caps lock
110ada64e4cSJason Wessel 		 */
111ada64e4cSJason Wessel 		shift_lock ^= 1;
112ada64e4cSJason Wessel 
113ada64e4cSJason Wessel #ifdef	KDB_BLINK_LED
114ada64e4cSJason Wessel 		kdb_toggleled(0x4);
115ada64e4cSJason Wessel #endif
116ada64e4cSJason Wessel 		return -1;
117ada64e4cSJason Wessel 	}
118ada64e4cSJason Wessel 
119ada64e4cSJason Wessel 	if (scancode == 0x0e) {
120ada64e4cSJason Wessel 		/*
121ada64e4cSJason Wessel 		 * Backspace
122ada64e4cSJason Wessel 		 */
123ada64e4cSJason Wessel 		return 8;
124ada64e4cSJason Wessel 	}
125ada64e4cSJason Wessel 
126ada64e4cSJason Wessel 	/* Special Key */
127ada64e4cSJason Wessel 	switch (scancode) {
128ada64e4cSJason Wessel 	case 0xF: /* Tab */
129ada64e4cSJason Wessel 		return 9;
130ada64e4cSJason Wessel 	case 0x53: /* Del */
131ada64e4cSJason Wessel 		return 4;
132ada64e4cSJason Wessel 	case 0x47: /* Home */
133ada64e4cSJason Wessel 		return 1;
134ada64e4cSJason Wessel 	case 0x4F: /* End */
135ada64e4cSJason Wessel 		return 5;
136ada64e4cSJason Wessel 	case 0x4B: /* Left */
137ada64e4cSJason Wessel 		return 2;
138ada64e4cSJason Wessel 	case 0x48: /* Up */
139ada64e4cSJason Wessel 		return 16;
140ada64e4cSJason Wessel 	case 0x50: /* Down */
141ada64e4cSJason Wessel 		return 14;
142ada64e4cSJason Wessel 	case 0x4D: /* Right */
143ada64e4cSJason Wessel 		return 6;
144ada64e4cSJason Wessel 	}
145ada64e4cSJason Wessel 
146ada64e4cSJason Wessel 	if (scancode == 0xe0)
147ada64e4cSJason Wessel 		return -1;
148ada64e4cSJason Wessel 
149ada64e4cSJason Wessel 	/*
150ada64e4cSJason Wessel 	 * For Japanese 86/106 keyboards
151ada64e4cSJason Wessel 	 * 	See comment in drivers/char/pc_keyb.c.
152ada64e4cSJason Wessel 	 * 	- Masahiro Adegawa
153ada64e4cSJason Wessel 	 */
154ada64e4cSJason Wessel 	if (scancode == 0x73)
155ada64e4cSJason Wessel 		scancode = 0x59;
156ada64e4cSJason Wessel 	else if (scancode == 0x7d)
157ada64e4cSJason Wessel 		scancode = 0x7c;
158ada64e4cSJason Wessel 
159ada64e4cSJason Wessel 	if (!shift_lock && !shift_key && !ctrl_key) {
160ada64e4cSJason Wessel 		keychar = plain_map[scancode];
161ada64e4cSJason Wessel 	} else if ((shift_lock || shift_key) && key_maps[1]) {
162ada64e4cSJason Wessel 		keychar = key_maps[1][scancode];
163ada64e4cSJason Wessel 	} else if (ctrl_key && key_maps[4]) {
164ada64e4cSJason Wessel 		keychar = key_maps[4][scancode];
165ada64e4cSJason Wessel 	} else {
166ada64e4cSJason Wessel 		keychar = 0x0020;
167ada64e4cSJason Wessel 		kdb_printf("Unknown state/scancode (%d)\n", scancode);
168ada64e4cSJason Wessel 	}
169ada64e4cSJason Wessel 	keychar &= 0x0fff;
170ada64e4cSJason Wessel 	if (keychar == '\t')
171ada64e4cSJason Wessel 		keychar = ' ';
172ada64e4cSJason Wessel 	switch (KTYP(keychar)) {
173ada64e4cSJason Wessel 	case KT_LETTER:
174ada64e4cSJason Wessel 	case KT_LATIN:
175ada64e4cSJason Wessel 		if (isprint(keychar))
176ada64e4cSJason Wessel 			break;		/* printable characters */
177df561f66SGustavo A. R. Silva 		fallthrough;
178ada64e4cSJason Wessel 	case KT_SPEC:
179ada64e4cSJason Wessel 		if (keychar == K_ENTER)
180ada64e4cSJason Wessel 			break;
181df561f66SGustavo A. R. Silva 		fallthrough;
182ada64e4cSJason Wessel 	default:
183ada64e4cSJason Wessel 		return -1;	/* ignore unprintables */
184ada64e4cSJason Wessel 	}
185ada64e4cSJason Wessel 
1868f30d411SAndrei Warkentin 	if (scancode == 0x1c) {
1878f30d411SAndrei Warkentin 		kbd_last_ret = 1;
188ada64e4cSJason Wessel 		return 13;
189ada64e4cSJason Wessel 	}
190ada64e4cSJason Wessel 
191ada64e4cSJason Wessel 	return keychar & 0xff;
192ada64e4cSJason Wessel }
193ada64e4cSJason Wessel EXPORT_SYMBOL_GPL(kdb_get_kbd_char);
1948f30d411SAndrei Warkentin 
1958f30d411SAndrei Warkentin /*
1968f30d411SAndrei Warkentin  * Best effort cleanup of ENTER break codes on leaving KDB. Called on
1978f30d411SAndrei Warkentin  * exiting KDB, when we know we processed an ENTER or KP ENTER scan
1988f30d411SAndrei Warkentin  * code.
1998f30d411SAndrei Warkentin  */
kdb_kbd_cleanup_state(void)2008f30d411SAndrei Warkentin void kdb_kbd_cleanup_state(void)
2018f30d411SAndrei Warkentin {
2028f30d411SAndrei Warkentin 	int scancode, scanstatus;
2038f30d411SAndrei Warkentin 
2048f30d411SAndrei Warkentin 	/*
2058f30d411SAndrei Warkentin 	 * Nothing to clean up, since either
2068f30d411SAndrei Warkentin 	 * ENTER was never pressed, or has already
2078f30d411SAndrei Warkentin 	 * gotten cleaned up.
2088f30d411SAndrei Warkentin 	 */
2098f30d411SAndrei Warkentin 	if (!kbd_last_ret)
2108f30d411SAndrei Warkentin 		return;
2118f30d411SAndrei Warkentin 
2128f30d411SAndrei Warkentin 	kbd_last_ret = 0;
2138f30d411SAndrei Warkentin 	/*
2148f30d411SAndrei Warkentin 	 * Enter key. Need to absorb the break code here, lest it gets
2158f30d411SAndrei Warkentin 	 * leaked out if we exit KDB as the result of processing 'g'.
2168f30d411SAndrei Warkentin 	 *
2178f30d411SAndrei Warkentin 	 * This has several interesting implications:
2188f30d411SAndrei Warkentin 	 * + Need to handle KP ENTER, which has break code 0xe0 0x9c.
2198f30d411SAndrei Warkentin 	 * + Need to handle repeat ENTER and repeat KP ENTER. Repeats
2208f30d411SAndrei Warkentin 	 *   only get a break code at the end of the repeated
2218f30d411SAndrei Warkentin 	 *   sequence. This means we can't propagate the repeated key
2228f30d411SAndrei Warkentin 	 *   press, and must swallow it away.
2238f30d411SAndrei Warkentin 	 * + Need to handle possible PS/2 mouse input.
2248f30d411SAndrei Warkentin 	 * + Need to handle mashed keys.
2258f30d411SAndrei Warkentin 	 */
2268f30d411SAndrei Warkentin 
2278f30d411SAndrei Warkentin 	while (1) {
2288f30d411SAndrei Warkentin 		while ((inb(KBD_STATUS_REG) & KBD_STAT_OBF) == 0)
2298f30d411SAndrei Warkentin 			cpu_relax();
2308f30d411SAndrei Warkentin 
2318f30d411SAndrei Warkentin 		/*
2328f30d411SAndrei Warkentin 		 * Fetch the scancode.
2338f30d411SAndrei Warkentin 		 */
2348f30d411SAndrei Warkentin 		scancode = inb(KBD_DATA_REG);
2358f30d411SAndrei Warkentin 		scanstatus = inb(KBD_STATUS_REG);
2368f30d411SAndrei Warkentin 
2378f30d411SAndrei Warkentin 		/*
2388f30d411SAndrei Warkentin 		 * Skip mouse input.
2398f30d411SAndrei Warkentin 		 */
2408f30d411SAndrei Warkentin 		if (scanstatus & KBD_STAT_MOUSE_OBF)
2418f30d411SAndrei Warkentin 			continue;
2428f30d411SAndrei Warkentin 
2438f30d411SAndrei Warkentin 		/*
2448f30d411SAndrei Warkentin 		 * If we see 0xe0, this is either a break code for KP
2458f30d411SAndrei Warkentin 		 * ENTER, or a repeat make for KP ENTER. Either way,
2468f30d411SAndrei Warkentin 		 * since the second byte is equivalent to an ENTER,
2478f30d411SAndrei Warkentin 		 * skip the 0xe0 and try again.
2488f30d411SAndrei Warkentin 		 *
2498f30d411SAndrei Warkentin 		 * If we see 0x1c, this must be a repeat ENTER or KP
2508f30d411SAndrei Warkentin 		 * ENTER (and we swallowed 0xe0 before). Try again.
2518f30d411SAndrei Warkentin 		 *
2528f30d411SAndrei Warkentin 		 * We can also see make and break codes for other keys
2538f30d411SAndrei Warkentin 		 * mashed before or after pressing ENTER. Thus, if we
2548f30d411SAndrei Warkentin 		 * see anything other than 0x9c, we have to try again.
2558f30d411SAndrei Warkentin 		 *
2568f30d411SAndrei Warkentin 		 * Note, if you held some key as ENTER was depressed,
2578f30d411SAndrei Warkentin 		 * that break code would get leaked out.
2588f30d411SAndrei Warkentin 		 */
2598f30d411SAndrei Warkentin 		if (scancode != 0x9c)
2608f30d411SAndrei Warkentin 			continue;
2618f30d411SAndrei Warkentin 
2628f30d411SAndrei Warkentin 		return;
2638f30d411SAndrei Warkentin 	}
2648f30d411SAndrei Warkentin }
265