/* This file is part of Fennix Kernel. Fennix Kernel is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Fennix Kernel is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Fennix Kernel. If not, see . */ #include "../crashhandler.hpp" #include "chfcts.hpp" #include #include #include #include #include #include #include #if defined(a64) #include "../../arch/amd64/cpu/gdt.hpp" #elif defined(a32) #elif defined(aa64) #endif #include "../../kernel.h" const char sc_ascii_low[] = {'?', '?', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', '?', '?', 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', '?', '?', 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', '\'', '`', '?', '\\', 'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/', '?', '?', '?', ' '}; const char sc_ascii_high[] = {'?', '?', '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '+', '?', '?', 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '{', '}', '?', '?', 'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', ';', '\"', '~', '?', '|', 'Z', 'X', 'C', 'V', 'B', 'N', 'M', '<', '>', '?', '?', '?', '?', ' '}; static int LowerCase = true; static inline int GetLetterFromScanCode(uint8_t ScanCode) { if (ScanCode & 0x80) { switch (ScanCode) { case KEY_U_LSHIFT: LowerCase = true; return KEY_INVALID; case KEY_U_RSHIFT: LowerCase = true; return KEY_INVALID; default: return KEY_INVALID; } } else { switch (ScanCode) { case KEY_D_RETURN: return '\n'; case KEY_D_LSHIFT: LowerCase = false; return KEY_INVALID; case KEY_D_RSHIFT: LowerCase = false; return KEY_INVALID; case KEY_D_BACKSPACE: return ScanCode; default: { if (ScanCode > 0x39) break; if (LowerCase) return sc_ascii_low[ScanCode]; else return sc_ascii_high[ScanCode]; } } } return KEY_INVALID; } namespace CrashHandler { void CrashKeyboardDriver::PS2Wait(bool Read) { int Timeout = 100000; uint8_t Status = 0; while (Timeout--) { Status = inb(0x64); if (Read) { if ((Status & 1) == 1) return; } else { if ((Status & 2) == 0) return; } } } CrashKeyboardDriver::CrashKeyboardDriver() : Interrupts::Handler(1) /* IRQ1 */ { #define WaitRead PS2Wait(true) #define WaitWrite PS2Wait(false) CPU::Interrupts(CPU::Disable); #if defined(a86) // Disable devices WaitWrite; outb(0x64, 0xAD); WaitWrite; outb(0x64, 0xA7); // Flush buffer WaitRead; inb(0x60); // outb(0x64, 0xAE); // Configure devices WaitWrite; outb(0x64, 0x20); WaitRead; uint8_t cfg = inb(0x60); bool DualChannel = cfg & 0b00100000; if (DualChannel) trace("Dual channel PS/2 controller detected."); cfg |= 0b01000011; WaitWrite; outb(0x64, 0x60); WaitWrite; outb(0x60, cfg); WaitWrite; outb(0x64, 0xAA); WaitRead; uint8_t test = inb(0x60); if (test != 0x55) { error("PS/2 controller self test failed! (%#x)", test); printf("PS/2 controller self test failed! (%#x)\n", test); CPU::Stop(); } WaitWrite; outb(0x64, 0x60); WaitWrite; outb(0x60, cfg); bool DCExists = false; if (DualChannel) { WaitWrite; outb(0x64, 0xAE); WaitWrite; outb(0x64, 0x20); WaitRead; cfg = inb(0x60); DCExists = !(cfg & 0b00100000); WaitWrite; outb(0x64, 0xAD); debug("DCExists: %d", DCExists); } WaitWrite; outb(0x64, 0xAB); WaitRead; test = inb(0x60); if (test != 0x00) { error("PS/2 keyboard self test failed! (%#x)", test); printf("PS/2 keyboard self test failed! (%#x)\n", test); CPU::Stop(); } if (DCExists) { WaitWrite; outb(0x64, 0xA9); WaitRead; test = inb(0x60); if (test != 0x00) { error("PS/2 mouse self test failed! (%#x)", test); printf("PS/2 mouse self test failed! (%#x)\n", test); CPU::Stop(); } } WaitWrite; outb(0x64, 0xAE); if (DCExists) { WaitWrite; outb(0x64, 0xA8); } WaitWrite; outb(0x60, 0xFF); WaitRead; test = inb(0x60); if (test == 0xFC) { error("PS/2 keyboard reset failed! (%#x)", test); printf("PS/2 keyboard reset failed! (%#x)\n", test); CPU::Stop(); } WaitWrite; outb(0x60, 0xD4); WaitWrite; outb(0x60, 0xFF); WaitRead; test = inb(0x60); if (test == 0xFC) { error("PS/2 mouse reset failed! (%#x)", test); printf("PS/2 mouse reset failed! (%#x)\n", test); CPU::Stop(); } // outb(0x60, 0xF4); // outb(0x21, 0xFD); // outb(0xA1, 0xFF); #endif // defined(a86) CPU::Interrupts(CPU::Enable); } CrashKeyboardDriver::~CrashKeyboardDriver() { error("CrashKeyboardDriver::~CrashKeyboardDriver() called!"); } int BackSpaceLimit = 0; static char UserInputBuffer[1024]; #if defined(a64) SafeFunction void CrashKeyboardDriver::OnInterruptReceived(CPU::x64::TrapFrame *Frame) #elif defined(a32) SafeFunction void CrashKeyboardDriver::OnInterruptReceived(CPU::x32::TrapFrame *Frame) #elif defined(aa64) SafeFunction void CrashKeyboardDriver::OnInterruptReceived(CPU::aarch64::TrapFrame *Frame) #endif { #if defined(a86) UNUSED(Frame); uint8_t scanCode = inb(0x60); if (scanCode == KEY_D_TAB || scanCode == KEY_D_LCTRL || scanCode == KEY_D_LALT || scanCode == KEY_U_LCTRL || scanCode == KEY_U_LALT) return; switch (scanCode) { case KEY_D_UP: case KEY_D_LEFT: case KEY_D_RIGHT: case KEY_D_DOWN: ArrowInput(scanCode); break; default: break; } int key = GetLetterFromScanCode(scanCode); if (key != KEY_INVALID) { if (key == KEY_D_BACKSPACE) { if (BackSpaceLimit > 0) { Display->Print('\b', SBIdx); backspace(UserInputBuffer); BackSpaceLimit--; } } else if (key == '\n') { UserInput(UserInputBuffer); BackSpaceLimit = 0; UserInputBuffer[0] = '\0'; } else { append(UserInputBuffer, s_cst(char, key)); Display->Print((char)key, SBIdx); BackSpaceLimit++; } Display->SetBuffer(SBIdx); /* Update as we type. */ } #endif // a64 || a32 } }