xref: /linux-6.15/kernel/debug/kdb/kdb_keyboard.c (revision 24b2455f)
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 
160914e4d3SArnd Bergmann #include "kdb_private.h"
170914e4d3SArnd 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 
28*24b2455fSNir Lichtman #define CTRL(c) ((c) - 64)
29*24b2455fSNir Lichtman 
30ada64e4cSJason Wessel static int kbd_exists;
318f30d411SAndrei Warkentin static int kbd_last_ret;
32ada64e4cSJason Wessel 
33ada64e4cSJason Wessel /*
34ada64e4cSJason Wessel  * Check if the keyboard controller has a keypress for us.
35ada64e4cSJason Wessel  * Some parts (Enter Release, LED change) are still blocking polled here,
36ada64e4cSJason Wessel  * but hopefully they are all short.
37ada64e4cSJason Wessel  */
kdb_get_kbd_char(void)38ada64e4cSJason Wessel int kdb_get_kbd_char(void)
39ada64e4cSJason Wessel {
40ada64e4cSJason Wessel 	int scancode, scanstatus;
41ada64e4cSJason Wessel 	static int shift_lock;	/* CAPS LOCK state (0-off, 1-on) */
42ada64e4cSJason Wessel 	static int shift_key;	/* Shift next keypress */
43ada64e4cSJason Wessel 	static int ctrl_key;
44ada64e4cSJason Wessel 	u_short keychar;
45ada64e4cSJason Wessel 
46ada64e4cSJason Wessel 	if (KDB_FLAG(NO_I8042) || KDB_FLAG(NO_VT_CONSOLE) ||
47ada64e4cSJason Wessel 	    (inb(KBD_STATUS_REG) == 0xff && inb(KBD_DATA_REG) == 0xff)) {
48ada64e4cSJason Wessel 		kbd_exists = 0;
49ada64e4cSJason Wessel 		return -1;
50ada64e4cSJason Wessel 	}
51ada64e4cSJason Wessel 	kbd_exists = 1;
52ada64e4cSJason Wessel 
53ada64e4cSJason Wessel 	if ((inb(KBD_STATUS_REG) & KBD_STAT_OBF) == 0)
54ada64e4cSJason Wessel 		return -1;
55ada64e4cSJason Wessel 
56ada64e4cSJason Wessel 	/*
57ada64e4cSJason Wessel 	 * Fetch the scancode
58ada64e4cSJason Wessel 	 */
59ada64e4cSJason Wessel 	scancode = inb(KBD_DATA_REG);
60ada64e4cSJason Wessel 	scanstatus = inb(KBD_STATUS_REG);
61ada64e4cSJason Wessel 
62ada64e4cSJason Wessel 	/*
63ada64e4cSJason Wessel 	 * Ignore mouse events.
64ada64e4cSJason Wessel 	 */
65ada64e4cSJason Wessel 	if (scanstatus & KBD_STAT_MOUSE_OBF)
66ada64e4cSJason Wessel 		return -1;
67ada64e4cSJason Wessel 
68ada64e4cSJason Wessel 	/*
69ada64e4cSJason Wessel 	 * Ignore release, trigger on make
70ada64e4cSJason Wessel 	 * (except for shift keys, where we want to
71ada64e4cSJason Wessel 	 *  keep the shift state so long as the key is
72ada64e4cSJason Wessel 	 *  held down).
73ada64e4cSJason Wessel 	 */
74ada64e4cSJason Wessel 
75ada64e4cSJason Wessel 	if (((scancode&0x7f) == 0x2a) || ((scancode&0x7f) == 0x36)) {
76ada64e4cSJason Wessel 		/*
77ada64e4cSJason Wessel 		 * Next key may use shift table
78ada64e4cSJason Wessel 		 */
79ada64e4cSJason Wessel 		if ((scancode & 0x80) == 0)
80ada64e4cSJason Wessel 			shift_key = 1;
81ada64e4cSJason Wessel 		else
82ada64e4cSJason Wessel 			shift_key = 0;
83ada64e4cSJason Wessel 		return -1;
84ada64e4cSJason Wessel 	}
85ada64e4cSJason Wessel 
86ada64e4cSJason Wessel 	if ((scancode&0x7f) == 0x1d) {
87ada64e4cSJason Wessel 		/*
88ada64e4cSJason Wessel 		 * Left ctrl key
89ada64e4cSJason Wessel 		 */
90ada64e4cSJason Wessel 		if ((scancode & 0x80) == 0)
91ada64e4cSJason Wessel 			ctrl_key = 1;
92ada64e4cSJason Wessel 		else
93ada64e4cSJason Wessel 			ctrl_key = 0;
94ada64e4cSJason Wessel 		return -1;
95ada64e4cSJason Wessel 	}
96ada64e4cSJason Wessel 
978f30d411SAndrei Warkentin 	if ((scancode & 0x80) != 0) {
988f30d411SAndrei Warkentin 		if (scancode == 0x9c)
998f30d411SAndrei Warkentin 			kbd_last_ret = 0;
100ada64e4cSJason Wessel 		return -1;
1018f30d411SAndrei Warkentin 	}
102ada64e4cSJason Wessel 
103ada64e4cSJason Wessel 	scancode &= 0x7f;
104ada64e4cSJason Wessel 
105ada64e4cSJason Wessel 	/*
106ada64e4cSJason Wessel 	 * Translate scancode
107ada64e4cSJason Wessel 	 */
108ada64e4cSJason Wessel 
109ada64e4cSJason Wessel 	if (scancode == 0x3a) {
110ada64e4cSJason Wessel 		/*
111ada64e4cSJason Wessel 		 * Toggle caps lock
112ada64e4cSJason Wessel 		 */
113ada64e4cSJason Wessel 		shift_lock ^= 1;
114ada64e4cSJason Wessel 
115ada64e4cSJason Wessel #ifdef	KDB_BLINK_LED
116ada64e4cSJason Wessel 		kdb_toggleled(0x4);
117ada64e4cSJason Wessel #endif
118ada64e4cSJason Wessel 		return -1;
119ada64e4cSJason Wessel 	}
120ada64e4cSJason Wessel 
121ada64e4cSJason Wessel 	if (scancode == 0x0e) {
122ada64e4cSJason Wessel 		/*
123ada64e4cSJason Wessel 		 * Backspace
124ada64e4cSJason Wessel 		 */
125ada64e4cSJason Wessel 		return 8;
126ada64e4cSJason Wessel 	}
127ada64e4cSJason Wessel 
128*24b2455fSNir Lichtman 	/* Translate special keys to equivalent CTRL control characters */
129ada64e4cSJason Wessel 	switch (scancode) {
130ada64e4cSJason Wessel 	case 0xF: /* Tab */
131*24b2455fSNir Lichtman 		return CTRL('I');
132ada64e4cSJason Wessel 	case 0x53: /* Del */
133*24b2455fSNir Lichtman 		return CTRL('D');
134ada64e4cSJason Wessel 	case 0x47: /* Home */
135*24b2455fSNir Lichtman 		return CTRL('A');
136ada64e4cSJason Wessel 	case 0x4F: /* End */
137*24b2455fSNir Lichtman 		return CTRL('E');
138ada64e4cSJason Wessel 	case 0x4B: /* Left */
139*24b2455fSNir Lichtman 		return CTRL('B');
140ada64e4cSJason Wessel 	case 0x48: /* Up */
141*24b2455fSNir Lichtman 		return CTRL('P');
142ada64e4cSJason Wessel 	case 0x50: /* Down */
143*24b2455fSNir Lichtman 		return CTRL('N');
144ada64e4cSJason Wessel 	case 0x4D: /* Right */
145*24b2455fSNir Lichtman 		return CTRL('F');
146ada64e4cSJason Wessel 	}
147ada64e4cSJason Wessel 
148ada64e4cSJason Wessel 	if (scancode == 0xe0)
149ada64e4cSJason Wessel 		return -1;
150ada64e4cSJason Wessel 
151ada64e4cSJason Wessel 	/*
152ada64e4cSJason Wessel 	 * For Japanese 86/106 keyboards
153ada64e4cSJason Wessel 	 * 	See comment in drivers/char/pc_keyb.c.
154ada64e4cSJason Wessel 	 * 	- Masahiro Adegawa
155ada64e4cSJason Wessel 	 */
156ada64e4cSJason Wessel 	if (scancode == 0x73)
157ada64e4cSJason Wessel 		scancode = 0x59;
158ada64e4cSJason Wessel 	else if (scancode == 0x7d)
159ada64e4cSJason Wessel 		scancode = 0x7c;
160ada64e4cSJason Wessel 
161ada64e4cSJason Wessel 	if (!shift_lock && !shift_key && !ctrl_key) {
162ada64e4cSJason Wessel 		keychar = plain_map[scancode];
163ada64e4cSJason Wessel 	} else if ((shift_lock || shift_key) && key_maps[1]) {
164ada64e4cSJason Wessel 		keychar = key_maps[1][scancode];
165ada64e4cSJason Wessel 	} else if (ctrl_key && key_maps[4]) {
166ada64e4cSJason Wessel 		keychar = key_maps[4][scancode];
167ada64e4cSJason Wessel 	} else {
168ada64e4cSJason Wessel 		keychar = 0x0020;
169ada64e4cSJason Wessel 		kdb_printf("Unknown state/scancode (%d)\n", scancode);
170ada64e4cSJason Wessel 	}
171ada64e4cSJason Wessel 	keychar &= 0x0fff;
172ada64e4cSJason Wessel 	if (keychar == '\t')
173ada64e4cSJason Wessel 		keychar = ' ';
174ada64e4cSJason Wessel 	switch (KTYP(keychar)) {
175ada64e4cSJason Wessel 	case KT_LETTER:
176ada64e4cSJason Wessel 	case KT_LATIN:
177*24b2455fSNir Lichtman 		switch (keychar) {
178*24b2455fSNir Lichtman 		/* non-printable supported control characters */
179*24b2455fSNir Lichtman 		case CTRL('A'): /* Home */
180*24b2455fSNir Lichtman 		case CTRL('B'): /* Left */
181*24b2455fSNir Lichtman 		case CTRL('D'): /* Del */
182*24b2455fSNir Lichtman 		case CTRL('E'): /* End */
183*24b2455fSNir Lichtman 		case CTRL('F'): /* Right */
184*24b2455fSNir Lichtman 		case CTRL('I'): /* Tab */
185*24b2455fSNir Lichtman 		case CTRL('N'): /* Down */
186*24b2455fSNir Lichtman 		case CTRL('P'): /* Up */
187*24b2455fSNir Lichtman 			return keychar;
188*24b2455fSNir Lichtman 		}
189*24b2455fSNir Lichtman 
190ada64e4cSJason Wessel 		if (isprint(keychar))
191ada64e4cSJason Wessel 			break;		/* printable characters */
192df561f66SGustavo A. R. Silva 		fallthrough;
193ada64e4cSJason Wessel 	case KT_SPEC:
194ada64e4cSJason Wessel 		if (keychar == K_ENTER)
195ada64e4cSJason Wessel 			break;
196df561f66SGustavo A. R. Silva 		fallthrough;
197ada64e4cSJason Wessel 	default:
198ada64e4cSJason Wessel 		return -1;	/* ignore unprintables */
199ada64e4cSJason Wessel 	}
200ada64e4cSJason Wessel 
2018f30d411SAndrei Warkentin 	if (scancode == 0x1c) {
2028f30d411SAndrei Warkentin 		kbd_last_ret = 1;
203ada64e4cSJason Wessel 		return 13;
204ada64e4cSJason Wessel 	}
205ada64e4cSJason Wessel 
206ada64e4cSJason Wessel 	return keychar & 0xff;
207ada64e4cSJason Wessel }
208ada64e4cSJason Wessel EXPORT_SYMBOL_GPL(kdb_get_kbd_char);
2098f30d411SAndrei Warkentin 
2108f30d411SAndrei Warkentin /*
2118f30d411SAndrei Warkentin  * Best effort cleanup of ENTER break codes on leaving KDB. Called on
2128f30d411SAndrei Warkentin  * exiting KDB, when we know we processed an ENTER or KP ENTER scan
2138f30d411SAndrei Warkentin  * code.
2148f30d411SAndrei Warkentin  */
kdb_kbd_cleanup_state(void)2158f30d411SAndrei Warkentin void kdb_kbd_cleanup_state(void)
2168f30d411SAndrei Warkentin {
2178f30d411SAndrei Warkentin 	int scancode, scanstatus;
2188f30d411SAndrei Warkentin 
2198f30d411SAndrei Warkentin 	/*
2208f30d411SAndrei Warkentin 	 * Nothing to clean up, since either
2218f30d411SAndrei Warkentin 	 * ENTER was never pressed, or has already
2228f30d411SAndrei Warkentin 	 * gotten cleaned up.
2238f30d411SAndrei Warkentin 	 */
2248f30d411SAndrei Warkentin 	if (!kbd_last_ret)
2258f30d411SAndrei Warkentin 		return;
2268f30d411SAndrei Warkentin 
2278f30d411SAndrei Warkentin 	kbd_last_ret = 0;
2288f30d411SAndrei Warkentin 	/*
2298f30d411SAndrei Warkentin 	 * Enter key. Need to absorb the break code here, lest it gets
2308f30d411SAndrei Warkentin 	 * leaked out if we exit KDB as the result of processing 'g'.
2318f30d411SAndrei Warkentin 	 *
2328f30d411SAndrei Warkentin 	 * This has several interesting implications:
2338f30d411SAndrei Warkentin 	 * + Need to handle KP ENTER, which has break code 0xe0 0x9c.
2348f30d411SAndrei Warkentin 	 * + Need to handle repeat ENTER and repeat KP ENTER. Repeats
2358f30d411SAndrei Warkentin 	 *   only get a break code at the end of the repeated
2368f30d411SAndrei Warkentin 	 *   sequence. This means we can't propagate the repeated key
2378f30d411SAndrei Warkentin 	 *   press, and must swallow it away.
2388f30d411SAndrei Warkentin 	 * + Need to handle possible PS/2 mouse input.
2398f30d411SAndrei Warkentin 	 * + Need to handle mashed keys.
2408f30d411SAndrei Warkentin 	 */
2418f30d411SAndrei Warkentin 
2428f30d411SAndrei Warkentin 	while (1) {
2438f30d411SAndrei Warkentin 		while ((inb(KBD_STATUS_REG) & KBD_STAT_OBF) == 0)
2448f30d411SAndrei Warkentin 			cpu_relax();
2458f30d411SAndrei Warkentin 
2468f30d411SAndrei Warkentin 		/*
2478f30d411SAndrei Warkentin 		 * Fetch the scancode.
2488f30d411SAndrei Warkentin 		 */
2498f30d411SAndrei Warkentin 		scancode = inb(KBD_DATA_REG);
2508f30d411SAndrei Warkentin 		scanstatus = inb(KBD_STATUS_REG);
2518f30d411SAndrei Warkentin 
2528f30d411SAndrei Warkentin 		/*
2538f30d411SAndrei Warkentin 		 * Skip mouse input.
2548f30d411SAndrei Warkentin 		 */
2558f30d411SAndrei Warkentin 		if (scanstatus & KBD_STAT_MOUSE_OBF)
2568f30d411SAndrei Warkentin 			continue;
2578f30d411SAndrei Warkentin 
2588f30d411SAndrei Warkentin 		/*
2598f30d411SAndrei Warkentin 		 * If we see 0xe0, this is either a break code for KP
2608f30d411SAndrei Warkentin 		 * ENTER, or a repeat make for KP ENTER. Either way,
2618f30d411SAndrei Warkentin 		 * since the second byte is equivalent to an ENTER,
2628f30d411SAndrei Warkentin 		 * skip the 0xe0 and try again.
2638f30d411SAndrei Warkentin 		 *
2648f30d411SAndrei Warkentin 		 * If we see 0x1c, this must be a repeat ENTER or KP
2658f30d411SAndrei Warkentin 		 * ENTER (and we swallowed 0xe0 before). Try again.
2668f30d411SAndrei Warkentin 		 *
2678f30d411SAndrei Warkentin 		 * We can also see make and break codes for other keys
2688f30d411SAndrei Warkentin 		 * mashed before or after pressing ENTER. Thus, if we
2698f30d411SAndrei Warkentin 		 * see anything other than 0x9c, we have to try again.
2708f30d411SAndrei Warkentin 		 *
2718f30d411SAndrei Warkentin 		 * Note, if you held some key as ENTER was depressed,
2728f30d411SAndrei Warkentin 		 * that break code would get leaked out.
2738f30d411SAndrei Warkentin 		 */
2748f30d411SAndrei Warkentin 		if (scancode != 0x9c)
2758f30d411SAndrei Warkentin 			continue;
2768f30d411SAndrei Warkentin 
2778f30d411SAndrei Warkentin 		return;
2788f30d411SAndrei Warkentin 	}
2798f30d411SAndrei Warkentin }
280