/* * Copyright 2009-2011, Haiku, Inc. All rights reserved. * Distributed under the terms of the MIT License. * * Authors: * Michael Lotz */ #include #include static bool sUseUSBKeyboard = false; static uint8 sUSBTransferData[64]; static uint8 sLastTransferData[64]; static size_t sUSBTransferLength = 0; static void *sUSBPipe = NULL; // simple ring buffer static int sBufferedChars[32]; static uint8 sBufferSize = sizeof(sBufferedChars) / sizeof(sBufferedChars[0]); static uint8 sBufferedCharCount = 0; static uint8 sBufferWriteIndex = 0; static uint8 sBufferReadIndex = 0; #define MODIFIER_CONTROL 0x01 #define MODIFIER_SHIFT 0x02 #define MODIFIER_ALT 0x04 static uint32 sModifierTable[] = { MODIFIER_CONTROL, MODIFIER_SHIFT, MODIFIER_ALT, 0, MODIFIER_CONTROL, MODIFIER_SHIFT, MODIFIER_ALT, 0 }; static uint8 sKeyTable[] = { 0, // ERROR 0, // ERROR 0, // ERROR 0, // ERROR 30, // A 48, // B 46, // C 32, // D 18, // E 33, // F 34, // G 35, // H 23, // I 36, // J 37, // K 38, // L 50, // M 49, // N 24, // O 25, // P 16, // Q 19, // R 31, // S 20, // T 22, // U 47, // V 17, // W 45, // X 21, // Y 44, // Z 2, // 1 3, // 2 4, // 3 5, // 4 6, // 5 7, // 6 8, // 7 9, // 8 10, // 9 11, // 0 28, // enter 1, // Esc 14, // Backspace 15, // Tab 57, // Space 12, // - 13, // = 26, // [ 27, // ] 43, // backslash 80, // backslash 39, // ; 40, // ' 41, // ` 51, // , 52, // . 53, // / 0, // Caps 0, // F1 0, // F2 0, // F3 0, // F4 0, // F5 0, // F6 0, // F7 0, // F8 0, // F9 0, // F10 0, // F11 0, // F12 0, // PrintScreen 0, // Scroll Lock 0, // Pause (0x7f with Ctrl) 0, // Insert 0x80 | 'H', // Home 0x80 | '5', // Page up 0x80 | '3', // Delete 0x80 | 'F', // End 0x80 | '6', // Page down 0x80 | 'C', // Right arrow 0x80 | 'D', // Left arrow 0x80 | 'B', // Down arrow 0x80 | 'A', // Up arrow 0, // Num Lock 53, // Pad / 55, // Pad * 12, // Pad - 54, // Pad + 28, // Pad Enter 2, // Pad 1 3, // Pad 2 4, // Pad 3 5, // Pad 4 6, // Pad 5 7, // Pad 6 8, // Pad 7 9, // Pad 8 10, // Pad 9 11, // Pad 0 52, // Pad . 86, // < 0, // Menu 0, // Power 13 // Pad = }; static size_t sKeyTableSize = sizeof(sKeyTable) / sizeof(sKeyTable[0]); static void enter_debugger(void) { if (!has_debugger_command("get_usb_keyboard_config") || !has_debugger_command("get_usb_pipe_for_id") || !has_debugger_command("usb_process_transfer")) { return; } unset_debug_variable("_usbPipe"); unset_debug_variable("_usbReportSize"); evaluate_debug_command("get_usb_keyboard_config"); sUSBTransferLength = get_debug_variable("_usbReportSize", 0); if (sUSBTransferLength == 0 || sUSBTransferLength > sizeof(sUSBTransferData)) return; evaluate_debug_command("get_usb_pipe_for_id"); sUSBPipe = (void *)get_debug_variable("_usbPipe", 0); if (sUSBPipe == NULL) return; sUseUSBKeyboard = true; } static void exit_debugger(void) { if (sUseUSBKeyboard) { // make sure a possibly pending transfer is canceled set_debug_variable("_usbPipe", (uint64)sUSBPipe); evaluate_debug_command("usb_process_transfer cancel"); sUseUSBKeyboard = false; } } static void write_key(int key) { sBufferedChars[sBufferWriteIndex++] = key; sBufferWriteIndex %= sBufferSize; sBufferedCharCount++; } static int debugger_getchar(void) { if (!sUseUSBKeyboard) return -1; if (sBufferedCharCount == 0) { set_debug_variable("_usbPipe", (uint64)sUSBPipe); set_debug_variable("_usbTransferData", (uint64)sUSBTransferData); set_debug_variable("_usbTransferLength", (uint64)sUSBTransferLength); status_t status = evaluate_debug_command("usb_process_transfer"); if (status == B_DEV_PENDING) return -1; if (status != B_OK) { // try clearing a possibly set halt due to toggle mismatches evaluate_debug_command("usb_clear_stall"); return -1; } bool phantomState = true; for (size_t i = 2; i < sUSBTransferLength; i++) { if (sUSBTransferData[i] != 0x01) { phantomState = false; break; } } if (phantomState) return -1; uint8 modifiers = 0; for (uint32 i = 0; i < 8; i++) { if (sUSBTransferData[0] & (1 << i)) modifiers |= sModifierTable[i]; } uint8 *current = sUSBTransferData; uint8 *compare = sLastTransferData; for (uint32 i = 2; i < sUSBTransferLength; i++) { if (current[i] == 0x00 || current[i] == 0x01) continue; bool found = false; for (uint32 j = 2; j < sUSBTransferLength; j++) { if (compare[j] == current[i]) { found = true; break; } } if (found) continue; if (current[i] >= sKeyTableSize) continue; int result = -1; uint8 key = sKeyTable[current[i]]; if (key & 0x80) { write_key(27); write_key('['); key &= ~0x80; write_key(key); if (key == '5' || key == '6' || key == '3') write_key('~'); continue; } else if (modifiers & MODIFIER_CONTROL) { char c = kShiftedKeymap[key]; if (c >= 'A' && c <= 'Z') result = 0x1f & c; } else if (modifiers & MODIFIER_ALT) result = kAltedKeymap[key]; else if (modifiers & MODIFIER_SHIFT) result = kShiftedKeymap[key]; else result = kUnshiftedKeymap[key]; if (result < 0) continue; write_key(result); } for (uint32 i = 0; i < sUSBTransferLength; i++) sLastTransferData[i] = sUSBTransferData[i]; } if (sBufferedCharCount == 0) return -1; int result = sBufferedChars[sBufferReadIndex++]; sBufferReadIndex %= sBufferSize; sBufferedCharCount--; return result; } static status_t std_ops(int32 op, ...) { if (op == B_MODULE_INIT || op == B_MODULE_UNINIT) return B_OK; return B_BAD_VALUE; } static struct debugger_module_info sModuleInfo = { { "debugger/usb_keyboard/v1", 0, &std_ops }, &enter_debugger, &exit_debugger, NULL, &debugger_getchar }; module_info *modules[] = { (module_info *)&sModuleInfo, NULL };