diff --git a/src/add-ons/kernel/debugger/usb_keyboard/Jamfile b/src/add-ons/kernel/debugger/usb_keyboard/Jamfile new file mode 100644 index 0000000000..c8e5b62751 --- /dev/null +++ b/src/add-ons/kernel/debugger/usb_keyboard/Jamfile @@ -0,0 +1,7 @@ +SubDir HAIKU_TOP src add-ons kernel debugger usb_keyboard ; + +UsePrivateHeaders kernel ; + +KernelAddon usb_keyboard : + usb_keyboard.cpp + ; diff --git a/src/add-ons/kernel/debugger/usb_keyboard/usb_keyboard.cpp b/src/add-ons/kernel/debugger/usb_keyboard/usb_keyboard.cpp new file mode 100644 index 0000000000..8f6089c5c0 --- /dev/null +++ b/src/add-ons/kernel/debugger/usb_keyboard/usb_keyboard.cpp @@ -0,0 +1,300 @@ +/* + * Copyright 2009, 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) +{ + 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) +{ + sUseUSBKeyboard = false; +} + + +static void +write_key(int key) +{ + sBufferedChars[sBufferWriteIndex++] = key; + sBufferWriteIndex %= sBufferSize; + sBufferedCharCount++; +} + + +static int +debugger_getchar(void) +{ + if (!sUseUSBKeyboard) + return -1; + + while (sBufferedCharCount == 0) { + set_debug_variable("_usbPipe", (uint64)sUSBPipe); + set_debug_variable("_usbTransferData", (uint64)sUSBTransferData); + set_debug_variable("_usbTransferLength", (uint64)sUSBTransferLength); + evaluate_debug_command("uhci_process_transfer"); + + bool phantomState = true; + for (size_t i = 2; i < sUSBTransferLength; i++) { + if (sUSBTransferData[i] != 0x01) { + phantomState = false; + break; + } + } + + if (phantomState) + continue; + + 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]; + } + + 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 +}; +