xref: /haiku/src/add-ons/kernel/debugger/usb_keyboard/usb_keyboard.cpp (revision dbd527de10bf916febd63f3633aaf88ad9f568a9)
11c053f17SMichael Lotz /*
28bcc50c3SIngo Weinhold  * Copyright 2009-2011, Haiku, Inc. All rights reserved.
31c053f17SMichael Lotz  * Distributed under the terms of the MIT License.
41c053f17SMichael Lotz  *
51c053f17SMichael Lotz  * Authors:
61c053f17SMichael Lotz  *		Michael Lotz <mmlr@mlotz.ch>
71c053f17SMichael Lotz  */
81c053f17SMichael Lotz 
91c053f17SMichael Lotz #include <debug.h>
101c053f17SMichael Lotz #include <debugger_keymaps.h>
111c053f17SMichael Lotz 
121c053f17SMichael Lotz static bool sUseUSBKeyboard = false;
131c053f17SMichael Lotz static uint8 sUSBTransferData[64];
141c053f17SMichael Lotz static uint8 sLastTransferData[64];
151c053f17SMichael Lotz static size_t sUSBTransferLength = 0;
161c053f17SMichael Lotz static void *sUSBPipe = NULL;
171c053f17SMichael Lotz 
181c053f17SMichael Lotz // simple ring buffer
191c053f17SMichael Lotz static int sBufferedChars[32];
201c053f17SMichael Lotz static uint8 sBufferSize = sizeof(sBufferedChars) / sizeof(sBufferedChars[0]);
211c053f17SMichael Lotz static uint8 sBufferedCharCount = 0;
221c053f17SMichael Lotz static uint8 sBufferWriteIndex = 0;
231c053f17SMichael Lotz static uint8 sBufferReadIndex = 0;
241c053f17SMichael Lotz 
251c053f17SMichael Lotz #define MODIFIER_CONTROL	0x01
261c053f17SMichael Lotz #define MODIFIER_SHIFT		0x02
271c053f17SMichael Lotz #define MODIFIER_ALT		0x04
281c053f17SMichael Lotz 
291c053f17SMichael Lotz static uint32 sModifierTable[] = {
301c053f17SMichael Lotz 	MODIFIER_CONTROL,
311c053f17SMichael Lotz 	MODIFIER_SHIFT,
321c053f17SMichael Lotz 	MODIFIER_ALT,
331c053f17SMichael Lotz 	0,
341c053f17SMichael Lotz 	MODIFIER_CONTROL,
351c053f17SMichael Lotz 	MODIFIER_SHIFT,
361c053f17SMichael Lotz 	MODIFIER_ALT,
371c053f17SMichael Lotz 	0
381c053f17SMichael Lotz };
391c053f17SMichael Lotz 
401c053f17SMichael Lotz static uint8 sKeyTable[] = {
411c053f17SMichael Lotz 	0,	// ERROR
421c053f17SMichael Lotz 	0,	// ERROR
431c053f17SMichael Lotz 	0,	// ERROR
441c053f17SMichael Lotz 	0,	// ERROR
451c053f17SMichael Lotz 	30,	// A
461c053f17SMichael Lotz 	48,	// B
471c053f17SMichael Lotz 	46,	// C
481c053f17SMichael Lotz 	32,	// D
491c053f17SMichael Lotz 	18,	// E
501c053f17SMichael Lotz 	33,	// F
511c053f17SMichael Lotz 	34,	// G
521c053f17SMichael Lotz 	35,	// H
531c053f17SMichael Lotz 	23,	// I
541c053f17SMichael Lotz 	36,	// J
551c053f17SMichael Lotz 	37,	// K
561c053f17SMichael Lotz 	38,	// L
571c053f17SMichael Lotz 	50,	// M
581c053f17SMichael Lotz 	49,	// N
591c053f17SMichael Lotz 	24,	// O
601c053f17SMichael Lotz 	25,	// P
611c053f17SMichael Lotz 	16,	// Q
621c053f17SMichael Lotz 	19,	// R
631c053f17SMichael Lotz 	31,	// S
641c053f17SMichael Lotz 	20,	// T
651c053f17SMichael Lotz 	22,	// U
661c053f17SMichael Lotz 	47,	// V
671c053f17SMichael Lotz 	17,	// W
681c053f17SMichael Lotz 	45,	// X
691c053f17SMichael Lotz 	21,	// Y
701c053f17SMichael Lotz 	44,	// Z
711c053f17SMichael Lotz 	2,	// 1
721c053f17SMichael Lotz 	3,	// 2
731c053f17SMichael Lotz 	4,	// 3
741c053f17SMichael Lotz 	5,	// 4
751c053f17SMichael Lotz 	6,	// 5
761c053f17SMichael Lotz 	7,	// 6
771c053f17SMichael Lotz 	8,	// 7
781c053f17SMichael Lotz 	9,	// 8
791c053f17SMichael Lotz 	10,	// 9
801c053f17SMichael Lotz 	11,	// 0
811c053f17SMichael Lotz 	28,	// enter
821c053f17SMichael Lotz 	1,	// Esc
831c053f17SMichael Lotz 	14,	// Backspace
841c053f17SMichael Lotz 	15,	// Tab
851c053f17SMichael Lotz 	57,	// Space
861c053f17SMichael Lotz 	12,	// -
871c053f17SMichael Lotz 	13,	// =
881c053f17SMichael Lotz 	26,	// [
891c053f17SMichael Lotz 	27,	// ]
901c053f17SMichael Lotz 	43,	// backslash
911c053f17SMichael Lotz 	80,	// backslash
921c053f17SMichael Lotz 	39,	// ;
931c053f17SMichael Lotz 	40,	// '
941c053f17SMichael Lotz 	41,	// `
951c053f17SMichael Lotz 	51,	// ,
961c053f17SMichael Lotz 	52,	// .
971c053f17SMichael Lotz 	53,	// /
981c053f17SMichael Lotz 	0,	// Caps
991c053f17SMichael Lotz 	0,	// F1
1001c053f17SMichael Lotz 	0,	// F2
1011c053f17SMichael Lotz 	0,	// F3
1021c053f17SMichael Lotz 	0,	// F4
1031c053f17SMichael Lotz 	0,	// F5
1041c053f17SMichael Lotz 	0,	// F6
1051c053f17SMichael Lotz 	0,	// F7
1061c053f17SMichael Lotz 	0,	// F8
1071c053f17SMichael Lotz 	0,	// F9
1081c053f17SMichael Lotz 	0,	// F10
1091c053f17SMichael Lotz 	0,	// F11
1101c053f17SMichael Lotz 	0,	// F12
1111c053f17SMichael Lotz 	0,	// PrintScreen
1121c053f17SMichael Lotz 	0,	// Scroll Lock
1131c053f17SMichael Lotz 	0,	// Pause (0x7f with Ctrl)
1141c053f17SMichael Lotz 	0,	// Insert
1151c053f17SMichael Lotz 	0x80 | 'H',	// Home
1161c053f17SMichael Lotz 	0x80 | '5',	// Page up
1171c053f17SMichael Lotz 	0x80 | '3',	// Delete
1181c053f17SMichael Lotz 	0x80 | 'F',	// End
1191c053f17SMichael Lotz 	0x80 | '6',	// Page down
1201c053f17SMichael Lotz 	0x80 | 'C',	// Right arrow
1211c053f17SMichael Lotz 	0x80 | 'D',	// Left arrow
1221c053f17SMichael Lotz 	0x80 | 'B',	// Down arrow
1231c053f17SMichael Lotz 	0x80 | 'A',	// Up arrow
1241c053f17SMichael Lotz 	0,	// Num Lock
1251c053f17SMichael Lotz 	53,	// Pad /
1261c053f17SMichael Lotz 	55,	// Pad *
1271c053f17SMichael Lotz 	12,	// Pad -
1281c053f17SMichael Lotz 	54,	// Pad +
1291c053f17SMichael Lotz 	28,	// Pad Enter
1301c053f17SMichael Lotz 	2,	// Pad 1
1311c053f17SMichael Lotz 	3,	// Pad 2
1321c053f17SMichael Lotz 	4,	// Pad 3
1331c053f17SMichael Lotz 	5,	// Pad 4
1341c053f17SMichael Lotz 	6,	// Pad 5
1351c053f17SMichael Lotz 	7,	// Pad 6
1361c053f17SMichael Lotz 	8,	// Pad 7
1371c053f17SMichael Lotz 	9,	// Pad 8
1381c053f17SMichael Lotz 	10,	// Pad 9
1391c053f17SMichael Lotz 	11,	// Pad 0
1401c053f17SMichael Lotz 	52,	// Pad .
1411c053f17SMichael Lotz 	86,	// <
1421c053f17SMichael Lotz 	0,	// Menu
1431c053f17SMichael Lotz 	0,	// Power
1441c053f17SMichael Lotz 	13	// Pad =
1451c053f17SMichael Lotz };
1461c053f17SMichael Lotz 
1471c053f17SMichael Lotz static size_t sKeyTableSize = sizeof(sKeyTable) / sizeof(sKeyTable[0]);
1481c053f17SMichael Lotz 
1491c053f17SMichael Lotz 
1501c053f17SMichael Lotz static void
enter_debugger(void)1511c053f17SMichael Lotz enter_debugger(void)
1521c053f17SMichael Lotz {
1535b9d5a2eSMichael Lotz 	if (!has_debugger_command("get_usb_keyboard_config")
1545b9d5a2eSMichael Lotz 		|| !has_debugger_command("get_usb_pipe_for_id")
155326645d2SMichael Lotz 		|| !has_debugger_command("usb_process_transfer")) {
1565b9d5a2eSMichael Lotz 		return;
157dd89f967SMichael Lotz 	}
1585b9d5a2eSMichael Lotz 
1595a0bca36SMichael Lotz 	unset_debug_variable("_usbPipe");
1605a0bca36SMichael Lotz 	unset_debug_variable("_usbReportSize");
1615a0bca36SMichael Lotz 
1621c053f17SMichael Lotz 	evaluate_debug_command("get_usb_keyboard_config");
1631c053f17SMichael Lotz 	sUSBTransferLength = get_debug_variable("_usbReportSize", 0);
1641c053f17SMichael Lotz 	if (sUSBTransferLength == 0 || sUSBTransferLength > sizeof(sUSBTransferData))
1651c053f17SMichael Lotz 		return;
1661c053f17SMichael Lotz 
1671c053f17SMichael Lotz 	evaluate_debug_command("get_usb_pipe_for_id");
1681c053f17SMichael Lotz 	sUSBPipe = (void *)get_debug_variable("_usbPipe", 0);
1691c053f17SMichael Lotz 	if (sUSBPipe == NULL)
1701c053f17SMichael Lotz 		return;
1711c053f17SMichael Lotz 
1721c053f17SMichael Lotz 	sUseUSBKeyboard = true;
1731c053f17SMichael Lotz }
1741c053f17SMichael Lotz 
1751c053f17SMichael Lotz 
1761c053f17SMichael Lotz static void
exit_debugger(void)1771c053f17SMichael Lotz exit_debugger(void)
1781c053f17SMichael Lotz {
179ec5cc81fSIngo Weinhold 	if (sUseUSBKeyboard) {
1808bcc50c3SIngo Weinhold 		// make sure a possibly pending transfer is canceled
181ec5cc81fSIngo Weinhold 		set_debug_variable("_usbPipe", (uint64)sUSBPipe);
182326645d2SMichael Lotz 		evaluate_debug_command("usb_process_transfer cancel");
1831c053f17SMichael Lotz 		sUseUSBKeyboard = false;
1841c053f17SMichael Lotz 	}
185ec5cc81fSIngo Weinhold }
1861c053f17SMichael Lotz 
1871c053f17SMichael Lotz 
1881c053f17SMichael Lotz static void
write_key(int key)1891c053f17SMichael Lotz write_key(int key)
1901c053f17SMichael Lotz {
1911c053f17SMichael Lotz 	sBufferedChars[sBufferWriteIndex++] = key;
1921c053f17SMichael Lotz 	sBufferWriteIndex %= sBufferSize;
1931c053f17SMichael Lotz 	sBufferedCharCount++;
1941c053f17SMichael Lotz }
1951c053f17SMichael Lotz 
1961c053f17SMichael Lotz 
1971c053f17SMichael Lotz static int
debugger_getchar(void)1981c053f17SMichael Lotz debugger_getchar(void)
1991c053f17SMichael Lotz {
2001c053f17SMichael Lotz 	if (!sUseUSBKeyboard)
2011c053f17SMichael Lotz 		return -1;
2021c053f17SMichael Lotz 
2038bcc50c3SIngo Weinhold 	if (sBufferedCharCount == 0) {
2041c053f17SMichael Lotz 		set_debug_variable("_usbPipe", (uint64)sUSBPipe);
2051c053f17SMichael Lotz 		set_debug_variable("_usbTransferData", (uint64)sUSBTransferData);
2061c053f17SMichael Lotz 		set_debug_variable("_usbTransferLength", (uint64)sUSBTransferLength);
207326645d2SMichael Lotz 
208326645d2SMichael Lotz 		status_t status = evaluate_debug_command("usb_process_transfer");
209*dbd527deSMichael Lotz 		if (status == B_DEV_PENDING)
2108bcc50c3SIngo Weinhold 			return -1;
2111c053f17SMichael Lotz 
212*dbd527deSMichael Lotz 		if (status != B_OK) {
213*dbd527deSMichael Lotz 			// try clearing a possibly set halt due to toggle mismatches
214*dbd527deSMichael Lotz 			evaluate_debug_command("usb_clear_stall");
215*dbd527deSMichael Lotz 			return -1;
216*dbd527deSMichael Lotz 		}
217*dbd527deSMichael Lotz 
2181c053f17SMichael Lotz 		bool phantomState = true;
2191c053f17SMichael Lotz 		for (size_t i = 2; i < sUSBTransferLength; i++) {
2201c053f17SMichael Lotz 			if (sUSBTransferData[i] != 0x01) {
2211c053f17SMichael Lotz 				phantomState = false;
2221c053f17SMichael Lotz 				break;
2231c053f17SMichael Lotz 			}
2241c053f17SMichael Lotz 		}
2251c053f17SMichael Lotz 
2261c053f17SMichael Lotz 		if (phantomState)
2278bcc50c3SIngo Weinhold 			return -1;
2281c053f17SMichael Lotz 
2291c053f17SMichael Lotz 		uint8 modifiers = 0;
2301c053f17SMichael Lotz 		for (uint32 i = 0; i < 8; i++) {
2311c053f17SMichael Lotz 			if (sUSBTransferData[0] & (1 << i))
2321c053f17SMichael Lotz 				modifiers |= sModifierTable[i];
2331c053f17SMichael Lotz 		}
2341c053f17SMichael Lotz 
2351c053f17SMichael Lotz 		uint8 *current = sUSBTransferData;
2361c053f17SMichael Lotz 		uint8 *compare = sLastTransferData;
2371c053f17SMichael Lotz 		for (uint32 i = 2; i < sUSBTransferLength; i++) {
2381c053f17SMichael Lotz 			if (current[i] == 0x00 || current[i] == 0x01)
2391c053f17SMichael Lotz 				continue;
2401c053f17SMichael Lotz 
2411c053f17SMichael Lotz 			bool found = false;
2421c053f17SMichael Lotz 			for (uint32 j = 2; j < sUSBTransferLength; j++) {
2431c053f17SMichael Lotz 				if (compare[j] == current[i]) {
2441c053f17SMichael Lotz 					found = true;
2451c053f17SMichael Lotz 					break;
2461c053f17SMichael Lotz 				}
2471c053f17SMichael Lotz 			}
2481c053f17SMichael Lotz 
2491c053f17SMichael Lotz 			if (found)
2501c053f17SMichael Lotz 				continue;
2511c053f17SMichael Lotz 
2521c053f17SMichael Lotz 			if (current[i] >= sKeyTableSize)
2531c053f17SMichael Lotz 				continue;
2541c053f17SMichael Lotz 
2551c053f17SMichael Lotz 			int result = -1;
2561c053f17SMichael Lotz 			uint8 key = sKeyTable[current[i]];
2571c053f17SMichael Lotz 			if (key & 0x80) {
2581c053f17SMichael Lotz 				write_key(27);
2591c053f17SMichael Lotz 				write_key('[');
2601c053f17SMichael Lotz 
2611c053f17SMichael Lotz 				key &= ~0x80;
2621c053f17SMichael Lotz 				write_key(key);
2631c053f17SMichael Lotz 
2641c053f17SMichael Lotz 				if (key == '5' || key == '6' || key == '3')
2651c053f17SMichael Lotz 					write_key('~');
2661c053f17SMichael Lotz 
2671c053f17SMichael Lotz 				continue;
2681c053f17SMichael Lotz 			} else if (modifiers & MODIFIER_CONTROL) {
2691c053f17SMichael Lotz 				char c = kShiftedKeymap[key];
2701c053f17SMichael Lotz 				if (c >= 'A' && c <= 'Z')
2711c053f17SMichael Lotz 					result = 0x1f & c;
2721c053f17SMichael Lotz 			} else if (modifiers & MODIFIER_ALT)
2731c053f17SMichael Lotz 				result = kAltedKeymap[key];
2741c053f17SMichael Lotz 			else if (modifiers & MODIFIER_SHIFT)
2751c053f17SMichael Lotz 				result = kShiftedKeymap[key];
2761c053f17SMichael Lotz 			else
2771c053f17SMichael Lotz 				result = kUnshiftedKeymap[key];
2781c053f17SMichael Lotz 
2791c053f17SMichael Lotz 			if (result < 0)
2801c053f17SMichael Lotz 				continue;
2811c053f17SMichael Lotz 
2821c053f17SMichael Lotz 			write_key(result);
2831c053f17SMichael Lotz 		}
2841c053f17SMichael Lotz 
2851c053f17SMichael Lotz 		for (uint32 i = 0; i < sUSBTransferLength; i++)
2861c053f17SMichael Lotz 			sLastTransferData[i] = sUSBTransferData[i];
2871c053f17SMichael Lotz 	}
2881c053f17SMichael Lotz 
2898bcc50c3SIngo Weinhold 	if (sBufferedCharCount == 0)
2908bcc50c3SIngo Weinhold 		return -1;
2918bcc50c3SIngo Weinhold 
2921c053f17SMichael Lotz 	int result = sBufferedChars[sBufferReadIndex++];
2931c053f17SMichael Lotz 	sBufferReadIndex %= sBufferSize;
2941c053f17SMichael Lotz 	sBufferedCharCount--;
2951c053f17SMichael Lotz 	return result;
2961c053f17SMichael Lotz }
2971c053f17SMichael Lotz 
2981c053f17SMichael Lotz 
2991c053f17SMichael Lotz static status_t
std_ops(int32 op,...)3001c053f17SMichael Lotz std_ops(int32 op, ...)
3011c053f17SMichael Lotz {
3021c053f17SMichael Lotz 	if (op == B_MODULE_INIT || op == B_MODULE_UNINIT)
3031c053f17SMichael Lotz 		return B_OK;
3041c053f17SMichael Lotz 
3051c053f17SMichael Lotz 	return B_BAD_VALUE;
3061c053f17SMichael Lotz }
3071c053f17SMichael Lotz 
3081c053f17SMichael Lotz 
3091c053f17SMichael Lotz static struct debugger_module_info sModuleInfo = {
3101c053f17SMichael Lotz 	{
3111c053f17SMichael Lotz 		"debugger/usb_keyboard/v1",
3121c053f17SMichael Lotz 		0,
3131c053f17SMichael Lotz 		&std_ops
3141c053f17SMichael Lotz 	},
3151c053f17SMichael Lotz 
3161c053f17SMichael Lotz 	&enter_debugger,
3171c053f17SMichael Lotz 	&exit_debugger,
3181c053f17SMichael Lotz 	NULL,
3191c053f17SMichael Lotz 	&debugger_getchar
3201c053f17SMichael Lotz };
3211c053f17SMichael Lotz 
3221c053f17SMichael Lotz module_info *modules[] = {
3231c053f17SMichael Lotz 	(module_info *)&sModuleInfo,
3241c053f17SMichael Lotz 	NULL
3251c053f17SMichael Lotz };
3261c053f17SMichael Lotz 
327