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