diff --git a/kernel/Makefile b/kernel/Makefile index cece315c..2f9b482c 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -36,6 +36,7 @@ kernel/Keyboard.o \ kernel/kmalloc.o \ kernel/PIC.o \ kernel/PIT.o \ +kernel/RTC.o \ kernel/Serial.o \ kernel/SSP.o \ icxxabi.o \ diff --git a/kernel/include/kernel/Keyboard.h b/kernel/include/kernel/Keyboard.h index 984404b7..729f5874 100644 --- a/kernel/include/kernel/Keyboard.h +++ b/kernel/include/kernel/Keyboard.h @@ -18,18 +18,30 @@ namespace Keyboard Dollar, Pound, Euro, Currency, Enter, Space, Tab, Backspace, LessThan, MoreThan, Tick, BackTick, Section, Half, At, Pipe, End, Home, Insert, Delete, Super, PageUp, PageDown, PrintScreen, Left, Right, Up, Down, - LeftShift, RightShift, CapsLock, Ctrl, Alt, NumLock, Escape, + LeftShift, RightShift, CapsLock, LeftCtrl, RightCtrl, LeftAlt, RightAlt, NumLock, ScrollLock, Escape, Numpad0, Numpad1, Numpad2, Numpad3, Numpad4, Numpad5, Numpad6, Numpad7, Numpad8, Numpad9, - NumpadComma, NumpadPlus, NumpadMult, NumpadDiv, NumpadMinus, + NumpadSep, NumpadPlus, NumpadMult, NumpadDiv, NumpadMinus, NumpadEnter, + + Mute, VolumeDown, VolumeUp, Calculator, PlayPause, Stop, PreviousTrack, NextTrack, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, Count }; - void initialize(void (*callback)(Key, uint8_t, bool)); + struct KeyEvent + { + Key key; + uint8_t modifiers; + bool pressed; + }; - char key_to_ascii(Key, uint8_t); + bool initialize(void (*callback)(KeyEvent)); + void update_keyboard(); + + char key_event_to_ascii(KeyEvent); + + void led_disco(); } \ No newline at end of file diff --git a/kernel/include/kernel/KeyboardLayout/FI.h b/kernel/include/kernel/KeyboardLayout/FI.h index 368e2b0e..935221d4 100644 --- a/kernel/include/kernel/KeyboardLayout/FI.h +++ b/kernel/include/kernel/KeyboardLayout/FI.h @@ -5,412 +5,519 @@ namespace Keyboard { - static Key scs2_to_key_altgr[0xFF] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + constexpr Key scan_code_to_key_extended[0xFF] { Key::INVALID, - Key::F9, - Key::INVALID, - Key::F5, - Key::F3, - Key::F1, - Key::F2, - Key::F12, - Key::INVALID, - Key::F10, - Key::F8, - Key::F6, - Key::F4, - Key::Tab, - Key::None, - Key::INVALID, - Key::INVALID, - Key::Alt, - Key::LeftShift, - Key::INVALID, - Key::Ctrl, - Key::Q, - Key::None, Key::INVALID, Key::INVALID, Key::INVALID, - Key::None, - Key::None, - Key::None, + Key::INVALID, + Key::INVALID, + Key::INVALID, + Key::INVALID, + Key::INVALID, + Key::INVALID, + Key::INVALID, + Key::INVALID, + Key::INVALID, + Key::INVALID, + Key::INVALID, + Key::INVALID, + Key::PreviousTrack, + Key::INVALID, + Key::INVALID, + Key::INVALID, + Key::INVALID, + Key::INVALID, + Key::INVALID, + Key::INVALID, + Key::INVALID, + Key::NextTrack, + Key::INVALID, + Key::INVALID, + Key::NumpadEnter, + Key::RightCtrl, + Key::INVALID, + Key::INVALID, + Key::Mute, + Key::Calculator, + Key::PlayPause, + Key::INVALID, + Key::Stop, + Key::INVALID, + Key::INVALID, + Key::INVALID, + Key::INVALID, + Key::INVALID, + Key::INVALID, + Key::INVALID, + Key::INVALID, + Key::INVALID, + Key::VolumeDown, + Key::INVALID, + Key::VolumeUp, + Key::INVALID, + Key::INVALID, + Key::INVALID, + Key::INVALID, + Key::NumpadDiv, + Key::INVALID, + Key::INVALID, + Key::RightAlt, + Key::INVALID, + Key::INVALID, + Key::INVALID, + Key::INVALID, + Key::INVALID, + Key::INVALID, + Key::INVALID, + Key::INVALID, + Key::INVALID, + Key::INVALID, + Key::INVALID, + Key::INVALID, + Key::INVALID, + Key::INVALID, + Key::Home, + Key::Up, + Key::PageUp, + Key::INVALID, + Key::Left, + Key::INVALID, + Key::Right, + Key::INVALID, + Key::End, + Key::Down, + Key::PageDown, + Key::Insert, + Key::Delete, + Key::INVALID, + Key::INVALID, + Key::INVALID, + Key::INVALID, + Key::INVALID, + Key::INVALID, + Key::INVALID, + Key::Super, + Key::INVALID, + Key::INVALID, + Key::INVALID, + Key::INVALID, + Key::INVALID, + Key::INVALID, + Key::INVALID, + Key::INVALID, + Key::INVALID, + Key::INVALID, + Key::INVALID, + Key::INVALID, + Key::INVALID, + Key::INVALID, + Key::INVALID, + Key::INVALID, + Key::INVALID, + Key::INVALID, + Key::INVALID, + Key::INVALID, + Key::INVALID, + Key::INVALID, + Key::INVALID, + Key::INVALID, + Key::INVALID, + Key::INVALID, + Key::INVALID, + Key::INVALID, + Key::INVALID, + Key::INVALID, + Key::INVALID, + Key::INVALID, + Key::INVALID, + Key::INVALID, + Key::INVALID, + Key::INVALID, + Key::INVALID, + Key::INVALID, + Key::INVALID, + Key::INVALID, + Key::INVALID, + Key::INVALID, + Key::INVALID, + Key::INVALID, + Key::INVALID, + Key::INVALID, + Key::INVALID, + Key::INVALID, + Key::INVALID, + Key::INVALID, + }; + + constexpr Key scan_code_to_key_altgr[0xFF] + { + Key::INVALID, + Key::Escape, Key::None, Key::At, - Key::INVALID, - Key::INVALID, + Key::Pound, + Key::Dollar, Key::None, Key::None, + Key::OpenBracket, + Key::OpenBrace, + Key::CloseBrace, + Key::CloseBracket, + Key::BackSlash, + Key::BackTick, + Key::Backspace, + Key::Tab, + Key::None, Key::None, Key::Euro, - Key::Dollar, - Key::Pound, - Key::INVALID, - Key::INVALID, - Key::Space, - Key::None, - Key::None, - Key::None, - Key::None, - Key::None, - Key::INVALID, - Key::INVALID, Key::None, Key::None, Key::None, Key::None, Key::None, Key::None, - Key::INVALID, - Key::INVALID, - Key::INVALID, Key::None, Key::None, - Key::None, - Key::OpenBrace, - Key::OpenBracket, - Key::INVALID, - Key::INVALID, - Key::None, - Key::None, - Key::None, - Key::None, - Key::CloseBrace, - Key::CloseBracket, - Key::INVALID, - Key::INVALID, - Key::None, - Key::None, - Key::None, - Key::None, - Key::None, - Key::BackSlash, - Key::INVALID, - Key::INVALID, - Key::INVALID, - Key::None, - Key::INVALID, - Key::None, - Key::None, - Key::INVALID, - Key::INVALID, - Key::CapsLock, - Key::RightShift, - Key::Enter, Key::Tilde, - Key::INVALID, + Key::Enter, + Key::LeftCtrl, Key::None, - Key::INVALID, + Key::None, + Key::None, + Key::None, + Key::None, + Key::None, + Key::None, + Key::None, + Key::None, + Key::None, + Key::None, + Key::None, + Key::LeftShift, + Key::None, + Key::None, + Key::None, + Key::None, + Key::None, + Key::None, + Key::None, + Key::None, + Key::None, + Key::None, + Key::None, + Key::RightShift, + Key::NumpadMult, + Key::LeftAlt, + Key::Space, + Key::CapsLock, + Key::F1, + Key::F2, + Key::F3, + Key::F4, + Key::F5, + Key::F6, + Key::F7, + Key::F8, + Key::F9, + Key::F10, + Key::NumLock, + Key::ScrollLock, + Key::Numpad7, + Key::Numpad8, + Key::Numpad9, + Key::NumpadMinus, + Key::Numpad4, + Key::Numpad5, + Key::Numpad6, + Key::NumpadPlus, + Key::Numpad1, + Key::Numpad2, + Key::Numpad3, + Key::Numpad0, + Key::NumpadSep, Key::INVALID, Key::INVALID, Key::Pipe, - Key::INVALID, - Key::INVALID, - Key::INVALID, - Key::INVALID, - Key::Backspace, - Key::INVALID, - Key::INVALID, - Key::Numpad1, - Key::INVALID, - Key::Numpad4, - Key::Numpad7, - Key::INVALID, - Key::INVALID, - Key::INVALID, - Key::Numpad0, - Key::NumpadComma, - Key::Numpad2, - Key::Numpad5, - Key::Numpad6, - Key::Numpad8, - Key::Escape, - Key::NumLock, Key::F11, - Key::NumpadPlus, - Key::Numpad3, - Key::NumpadMinus, - Key::NumpadMult, - Key::Numpad9, - Key::INVALID, - Key::INVALID, - Key::INVALID, - Key::INVALID, - Key::INVALID, - Key::F7, + Key::F12, }; - static Key scs2_to_key_shift[0xFF] + constexpr Key scan_code_to_key_shift[0xFF] { Key::INVALID, - Key::F9, - Key::INVALID, - Key::F5, - Key::F3, - Key::F1, - Key::F2, - Key::F12, - Key::INVALID, - Key::F10, - Key::F8, - Key::F6, - Key::F4, - Key::Tab, - Key::Half, - Key::INVALID, - Key::INVALID, - Key::Alt, - Key::LeftShift, - Key::INVALID, - Key::Ctrl, - Key::Q, + Key::Escape, Key::ExclamationMark, - Key::INVALID, - Key::INVALID, - Key::INVALID, - Key::Z, - Key::S, - Key::A, - Key::W, Key::DoubleQuote, - Key::INVALID, - Key::INVALID, - Key::C, - Key::X, - Key::D, - Key::E, - Key::Currency, Key::Hashtag, - Key::INVALID, - Key::INVALID, - Key::Space, - Key::V, - Key::F, - Key::T, - Key::R, + Key::Currency, Key::Percent, - Key::INVALID, - Key::INVALID, - Key::N, - Key::B, - Key::H, - Key::G, - Key::Y, Key::Ampersand, - Key::INVALID, - Key::INVALID, - Key::INVALID, - Key::M, - Key::J, - Key::U, Key::Slash, Key::OpenParen, - Key::INVALID, - Key::INVALID, - Key::Semicolon, - Key::K, + Key::CloseParen, + Key::Equals, + Key::QuestionMark, + Key::BackTick, + Key::Backspace, + Key::Tab, + Key::Q, + Key::W, + Key::E, + Key::R, + Key::T, + Key::Y, + Key::U, Key::I, Key::O, - Key::Equals, - Key::CloseParen, - Key::INVALID, - Key::INVALID, - Key::Colon, - Key::Underscore, + Key::P, + Key::A_Dot, + Key::Caret, + Key::Enter, + Key::LeftCtrl, + Key::A, + Key::S, + Key::D, + Key::F, + Key::G, + Key::H, + Key::J, + Key::K, Key::L, Key::O_Dots, - Key::P, - Key::QuestionMark, - Key::INVALID, - Key::INVALID, - Key::INVALID, Key::A_Dots, - Key::INVALID, - Key::A_Dot, - Key::BackTick, - Key::INVALID, - Key::INVALID, - Key::CapsLock, - Key::RightShift, - Key::Enter, - Key::Caret, - Key::INVALID, + Key::Half, + Key::LeftShift, Key::Asterix, - Key::INVALID, + Key::Z, + Key::X, + Key::C, + Key::V, + Key::B, + Key::N, + Key::M, + Key::Semicolon, + Key::Colon, + Key::Underscore, + Key::RightShift, + Key::NumpadMult, + Key::LeftAlt, + Key::Space, + Key::CapsLock, + Key::None, + Key::None, + Key::None, + Key::None, + Key::None, + Key::None, + Key::None, + Key::None, + Key::None, + Key::None, + Key::NumLock, + Key::ScrollLock, + Key::Home, + Key::Up, + Key::PageUp, + Key::NumpadMinus, + Key::Left, + Key::None, + Key::Right, + Key::NumpadPlus, + Key::End, + Key::Down, + Key::PageDown, + Key::Insert, + Key::Delete, Key::INVALID, Key::INVALID, Key::MoreThan, - Key::INVALID, - Key::INVALID, - Key::INVALID, - Key::INVALID, - Key::Backspace, - Key::INVALID, - Key::INVALID, - Key::End, - Key::INVALID, - Key::Left, - Key::Right, - Key::INVALID, - Key::INVALID, - Key::INVALID, - Key::Insert, - Key::Delete, - Key::Down, Key::None, - Key::Right, - Key::Up, - Key::Escape, - Key::NumLock, - Key::F11, - Key::NumpadPlus, - Key::PageDown, - Key::NumpadMinus, - Key::NumpadMult, - Key::PageUp, - Key::INVALID, - Key::INVALID, - Key::INVALID, - Key::INVALID, - Key::INVALID, - Key::F7, + Key::None, }; - static Key scs2_to_key[0xFF] + constexpr Key scan_code_to_key_normal[0xFF] { Key::INVALID, - Key::F9, - Key::INVALID, - Key::F5, - Key::F3, - Key::F1, - Key::F2, - Key::F12, - Key::INVALID, - Key::F10, - Key::F8, - Key::F6, - Key::F4, - Key::Tab, - Key::Section, - Key::INVALID, - Key::INVALID, - Key::Alt, - Key::LeftShift, - Key::INVALID, - Key::Ctrl, - Key::Q, + Key::Escape, Key::_1, - Key::INVALID, - Key::INVALID, - Key::INVALID, - Key::Z, - Key::S, - Key::A, - Key::W, Key::_2, - Key::INVALID, - Key::INVALID, - Key::C, - Key::X, - Key::D, - Key::E, - Key::_4, Key::_3, - Key::INVALID, - Key::INVALID, - Key::Space, - Key::V, - Key::F, - Key::T, - Key::R, + Key::_4, Key::_5, - Key::INVALID, - Key::INVALID, - Key::N, - Key::B, - Key::H, - Key::G, - Key::Y, Key::_6, - Key::INVALID, - Key::INVALID, - Key::INVALID, - Key::M, - Key::J, - Key::U, Key::_7, Key::_8, - Key::INVALID, - Key::INVALID, - Key::Comma, - Key::K, + Key::_9, + Key::_0, + Key::Plus, + Key::Tick, + Key::Backspace, + Key::Tab, + Key::Q, + Key::W, + Key::E, + Key::R, + Key::T, + Key::Y, + Key::U, Key::I, Key::O, - Key::_0, - Key::_9, - Key::INVALID, - Key::INVALID, - Key::Period, - Key::Hyphen, + Key::P, + Key::A_Dot, + Key::Caret, + Key::Enter, + Key::LeftCtrl, + Key::A, + Key::S, + Key::D, + Key::F, + Key::G, + Key::H, + Key::J, + Key::K, Key::L, Key::O_Dots, - Key::P, - Key::Plus, - Key::INVALID, - Key::INVALID, - Key::INVALID, Key::A_Dots, - Key::INVALID, - Key::A_Dot, - Key::Tick, - Key::INVALID, - Key::INVALID, - Key::CapsLock, - Key::RightShift, - Key::Enter, - Key::Caret, - Key::INVALID, + Key::Section, + Key::LeftShift, Key::SingleQuote, - Key::INVALID, + Key::Z, + Key::X, + Key::C, + Key::V, + Key::B, + Key::N, + Key::M, + Key::Comma, + Key::Period, + Key::Hyphen, + Key::RightShift, + Key::NumpadMult, + Key::LeftAlt, + Key::Space, + Key::CapsLock, + Key::F1, + Key::F2, + Key::F3, + Key::F4, + Key::F5, + Key::F6, + Key::F7, + Key::F8, + Key::F9, + Key::F10, + Key::NumLock, + Key::ScrollLock, + Key::Numpad7, + Key::Numpad8, + Key::Numpad9, + Key::NumpadMinus, + Key::Numpad4, + Key::Numpad5, + Key::Numpad6, + Key::NumpadPlus, + Key::Numpad1, + Key::Numpad2, + Key::Numpad3, + Key::Numpad0, + Key::NumpadSep, Key::INVALID, Key::INVALID, Key::LessThan, - Key::INVALID, - Key::INVALID, - Key::INVALID, - Key::INVALID, - Key::Backspace, - Key::INVALID, - Key::INVALID, - Key::Numpad1, - Key::INVALID, - Key::Numpad4, - Key::Numpad7, - Key::INVALID, - Key::INVALID, - Key::INVALID, - Key::Numpad0, - Key::NumpadComma, - Key::Numpad2, - Key::Numpad5, - Key::Numpad6, - Key::Numpad8, - Key::Escape, - Key::NumLock, Key::F11, - Key::NumpadPlus, - Key::Numpad3, - Key::NumpadMinus, - Key::NumpadMult, - Key::Numpad9, - Key::INVALID, - Key::INVALID, - Key::INVALID, - Key::INVALID, - Key::INVALID, - Key::F7, + Key::F12, }; } \ No newline at end of file diff --git a/kernel/kernel/Keyboard.cpp b/kernel/kernel/Keyboard.cpp index ebd0f6b2..23c06285 100644 --- a/kernel/kernel/Keyboard.cpp +++ b/kernel/kernel/Keyboard.cpp @@ -1,50 +1,89 @@ #include #include #include -#include #include +#include +#include +#include +#include #include -#define I8042_DATA_PORT 0x60 -#define I8042_STATUS_REGISTER 0x64 -#define I8042_COMMAND_REGISTER 0x64 +#define KB_DEBUG_PRINT 1 -#define I8042_READ_BYTE0 0x20 -#define I8042_WRITE_BYTE0 0x60 +#define I8042_DATA_PORT 0x60 +#define I8042_STATUS_REGISTER 0x64 +#define I8042_COMMAND_REGISTER 0x64 -#define I8042_ENABLE_FIRST 0xAE -#define I8042_ENABLE_SECOND 0xA8 -#define I8042_DISABLE_FIRST 0xAD -#define I8042_DISABLE_SECOND 0xA7 +#define I8042_STATUS_OUT_FULL (1 << 0) +#define I8042_STATUS_IN_FULL (1 << 1) -#define I8042_TEST_CONTROLLER 0xAA -#define I8042_CONTROLLER_TEST_PASS 0x55 +#define I8042_READ_CONFIG 0x20 +#define I8042_WRITE_CONFIG 0x60 -#define I8042_TEST_FIRST_PORT 0xAB -#define I8042_FIRST_PORT_TEST_PASS 0x00 +#define I8042_CONFING_IRQ_FIRST (1 << 0) +#define I8042_CONFING_IRQ_SECOND (1 << 1) +#define I8042_CONFING_TRANSLATION (1 << 6) -#define I8042_TEST_SECOND 0xA9 -#define I8042_SECOND_PORT_TEST_PASS 0x00 +#define I8042_ENABLE_FIRST 0xAE +#define I8042_ENABLE_SECOND 0xA8 +#define I8042_DISABLE_FIRST 0xAD +#define I8042_DISABLE_SECOND 0xA7 -#define I8042_ACK 0xfa +#define I8042_TEST_CONTROLLER 0xAA +#define I8042_TEST_CONTROLLER_PASS 0x55 -#define KEYBOARD_IRQ 0x01 +#define I8042_TEST_FIRST_PORT 0xAB +#define I8042_TEST_FIRST_PORT_PASS 0x00 -#define MOD_ALT 0b0001 -#define MOD_CTRL 0b0010 -#define MOD_SHIFT 0b0100 -#define MOD_ALTGR 0b1000 +#define I8042_TEST_SECOND_PORT 0xA9 +#define I8042_TEST_SECOND_PORT_PASS 0x00 -#define KEYBOARD_FI +#define I8042_KB_ACK 0xFA +#define I8042_KB_RESEND 0xFE +#define I8042_KB_RESET 0xFF +#define I8042_KB_SELF_TEST_PASS 0xAA +#define I8042_KB_SET_SCAN_CODE_SET 0xF0 +#define I8042_KB_SET_LEDS 0xED +#define I8042_KB_TIMEOUT_MS 1000 +#define I8042_KB_LED_SCROLL_LOCK (1 << 0) +#define I8042_KB_LED_NUM_LOCK (1 << 1) +#define I8042_KB_LED_CAPS_LOCK (1 << 2) + +#define KEYBOARD_IRQ 0x01 + +#define MOD_ALT (1 << 0) +#define MOD_CTRL (1 << 1) +#define MOD_SHIFT (1 << 2) +#define MOD_ALTGR (1 << 3) +#define MOD_CAPS (1 << 4) namespace Keyboard { static bool s_keyboard_state[0xFF] = {}; - static uint8_t s_modifiers = 0; - static void (*s_key_callback)(Key, uint8_t, bool) = nullptr; + struct Command + { + uint8_t command = 0; + uint8_t data = 0; + bool has_data = false; + bool extra = false; + uint8_t _sent = 0; + uint8_t _ack = 0; + bool _done = false; + }; + static Queue s_keyboard_command_queue; + static uint8_t s_keyboard_command_extra = 0x00; + + static Queue s_key_event_queue; + static uint8_t s_keyboard_key_buffer[10] = {}; + static uint8_t s_keyboard_key_buffer_size = 0; + + static uint8_t s_led_states = 0b000; + static uint8_t s_modifiers = 0x00; + + static void (*s_key_callback)(KeyEvent) = nullptr; static char s_key_to_char[] { @@ -59,110 +98,263 @@ namespace Keyboard '$', '\0', '\0', '\0', '\n', ' ', '\t', '\b', '<', '>', '\0', '`', '\0', '\0', '@', '|', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', - '\0', '\0', '\0', '\0', '\0', '\0', '\0', + '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', - ',', '+', '*', '/', '-', + ',', '+', '*', '/', '-', '\n', + + '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', + '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', }; static_assert(sizeof(s_key_to_char) == static_cast(Key::Count)); - static uint8_t kb_read() + static uint8_t wait_and_read() { - while (!(IO::inb(I8042_STATUS_REGISTER) & 0x01)) + while ((IO::inb(I8042_STATUS_REGISTER) & I8042_STATUS_OUT_FULL) == 0) continue; return IO::inb(I8042_DATA_PORT); } - static bool kb_try_read(uint8_t& out) + static void i8042_controller_command(uint8_t command) { - if (IO::inb(I8042_STATUS_REGISTER) & 0x01) - { - out = IO::inb(I8042_DATA_PORT); - return true; - } - return false; - } - - static void kb_command(uint8_t command) - { - IO::io_wait(); IO::outb(I8042_COMMAND_REGISTER, command); } - static void kb_command(uint8_t command, uint8_t data) + static void i8042_controller_command(uint8_t command, uint8_t data) { - IO::io_wait(); IO::outb(I8042_COMMAND_REGISTER, command); - IO::io_wait(); + while ((IO::inb(I8042_STATUS_REGISTER) & I8042_STATUS_IN_FULL) != 0) + continue; IO::outb(I8042_DATA_PORT, data); } - void irq_handler() + static bool i8042_keyboard_command(uint8_t command) { - uint8_t ch; - while (kb_try_read(ch)) + auto timeout = PIT::ms_since_boot() + I8042_KB_TIMEOUT_MS; + + while (PIT::ms_since_boot() < timeout) { - bool multimedia = false, pressed = true; - - if (ch == 0xE0) + if ((IO::inb(I8042_STATUS_REGISTER) & I8042_STATUS_IN_FULL) == 0) { - multimedia = true; - ch = kb_read(); + IO::outb(I8042_DATA_PORT, command); + return true; + } + } + + return false; + } + + void update_keyboard() + { + if (!s_keyboard_command_queue.Empty()) + { + auto& command = s_keyboard_command_queue.Front(); + + if (command._sent == 0 && command._ack == 0) + { + if (!i8042_keyboard_command(command.command)) + Kernel::panic("oof 1"); + command._sent++; } - if (ch == 0xF0) + if (command._sent == 1 && command._ack == 1 && command.has_data) { - pressed = false; - ch = kb_read(); - } - - // TODO: Handle multimedia keys - if (multimedia) - { - if (ch == 17) - pressed ? (s_modifiers |= MOD_ALTGR) : (s_modifiers &= ~MOD_ALTGR); - if (pressed && false) - kprint("", ch); - continue; + if (!i8042_keyboard_command(command.data)) + Kernel::panic("oof 2"); + command._sent++; } - s_keyboard_state[ch] = pressed; - - switch (ch) + if (command._done) { - case 17: - pressed ? (s_modifiers |= MOD_ALT) : (s_modifiers &= ~MOD_ALT); - break; - case 18: - case 89: - pressed ? (s_modifiers |= MOD_SHIFT) : (s_modifiers &= ~MOD_SHIFT); - break; - case 20: - pressed ? (s_modifiers |= MOD_CTRL) : (s_modifiers &= ~MOD_CTRL); - break; - default: - break; + switch (command.command) + { + case I8042_KB_RESET: + if (s_keyboard_command_extra != I8042_KB_SELF_TEST_PASS) + Kernel::panic("PS/2 Keyboard self test failed"); + break; + case I8042_KB_SET_SCAN_CODE_SET: + break; + case I8042_KB_SET_LEDS: + break; + } + s_keyboard_command_queue.Pop(); } + } - Key key; - if (s_modifiers & MOD_ALTGR) - key = scs2_to_key_altgr[ch]; - else if (s_modifiers & MOD_SHIFT) - key = scs2_to_key_shift[ch]; - else - key = scs2_to_key[ch]; - - // Debug print for unregistered keys - if (key == Key::INVALID && pressed) - kprint("<{}>", ch); - - s_key_callback(key, s_modifiers, pressed); + while (!s_key_event_queue.Empty()) + { + s_key_callback(s_key_event_queue.Front()); + s_key_event_queue.Pop(); } } - void initialize(void (*callback)(Key, uint8_t, bool)) + static void keyboard_new_key() + { + uint8_t index = 0; + bool extended = (s_keyboard_key_buffer[index] == 0xE0); + if (extended) + index++; + + bool pressed = (s_keyboard_key_buffer[index] & 0x80) == 0; + uint8_t ch = s_keyboard_key_buffer[index] & ~0x80; + + Key key = Key::INVALID; + + if (extended) + { + key = scan_code_to_key_extended[ch]; + } + else + { + if (s_modifiers & MOD_SHIFT) + key = scan_code_to_key_shift[ch]; + else if (s_modifiers & MOD_ALTGR) + key = scan_code_to_key_altgr[ch]; + else + key = scan_code_to_key_normal[ch]; + } + + if ((s_led_states & I8042_KB_LED_NUM_LOCK)) + { + switch (key) + { + case Key::Numpad0: key = Key::Insert; break; + case Key::Numpad1: key = Key::End; break; + case Key::Numpad2: key = Key::Down; break; + case Key::Numpad3: key = Key::PageDown; break; + case Key::Numpad4: key = Key::Left; break; + case Key::Numpad5: key = Key::None; break; + case Key::Numpad6: key = Key::Right; break; + case Key::Numpad7: key = Key::Home; break; + case Key::Numpad8: key = Key::Up; break; + case Key::Numpad9: key = Key::PageUp; break; + case Key::NumpadSep: key = Key::Delete; break; + default: break; + } + } + + +#if KB_DEBUG_PRINT + if (key == Key::INVALID) + kprintln("{} {}", ch, extended ? 'E' : ' '); +#endif + + s_keyboard_state[static_cast(key)] = pressed; + + bool update_leds = false; + switch (key) + { + case Key::ScrollLock: + update_leds = pressed; + if (update_leds) + s_led_states ^= I8042_KB_LED_SCROLL_LOCK; + break; + case Key::NumLock: + update_leds = pressed; + if (update_leds) + s_led_states ^= I8042_KB_LED_NUM_LOCK; + break; + case Key::CapsLock: + update_leds = pressed; + if (update_leds) + s_led_states ^= I8042_KB_LED_CAPS_LOCK; + break; + default: + break; + } + + if (update_leds) + { + s_keyboard_command_queue.Push({ + .command = I8042_KB_SET_LEDS, + .data = s_led_states, + .has_data = true, + }); + } + + uint8_t modifiers = 0; + if (s_keyboard_state[(int)Key::LeftShift] || s_keyboard_state[(int)Key::RightShift]) + modifiers |= MOD_SHIFT; + if (s_keyboard_state[(int)Key::LeftCtrl] || s_keyboard_state[(int)Key::RightCtrl]) + modifiers |= MOD_CTRL; + if (s_keyboard_state[(int)Key::LeftAlt]) + modifiers |= MOD_ALT; + if (s_keyboard_state[(int)Key::RightAlt]) + modifiers |= MOD_ALTGR; + if (s_led_states & I8042_KB_LED_CAPS_LOCK) + modifiers |= MOD_CAPS; + s_modifiers = modifiers; + + if (key != Key::INVALID) + { + auto error_or = s_key_event_queue.Push({ .key = key, .modifiers = modifiers, .pressed = pressed }); + if (error_or.HasError()) + dprintln("PS/2 Keyboard: {}", error_or.GetError().message); + } + s_keyboard_key_buffer_size -= index + 1; + memmove(s_keyboard_key_buffer, s_keyboard_key_buffer + index, s_keyboard_key_buffer_size); + } + + void keyboard_irq_handler() + { + uint8_t raw = IO::inb(I8042_DATA_PORT); + + bool command_waiting = false; + if (!s_keyboard_command_queue.Empty()) + { + auto& command = s_keyboard_command_queue.Front(); + command_waiting = (command._sent > 0 && !command._done); + } + + if (command_waiting) + { + auto& command = s_keyboard_command_queue.Front(); + if (raw == I8042_KB_RESEND) + { + dprintln("PS/2 Keyboard: Resend 0x{H}", command._sent == 2 ? command.data : command.command); + command._sent--; + return; + } + + if (raw == I8042_KB_ACK) + { + command._ack++; + if (command.extra > 0) + return; + command._done = command.has_data ? (command._ack == 2) : true; + return; + } + + if (raw == 0x00) + { + dprintln("\e[33mKey detection error or internal buffer overrun\e[m"); + command._sent = 0; + command._ack = 0; + command._done = false; + return; + } + + if (raw == 0xEE && command.command == 0xEE) + { + s_keyboard_command_queue.Pop(); + return; + } + + s_keyboard_command_extra = raw; + command._done = true; + return; + } + else + { + s_keyboard_key_buffer[s_keyboard_key_buffer_size++] = raw; + if (raw != 0xE0) + keyboard_new_key(); + } + } + + bool initialize(void (*callback)(KeyEvent)) { // https://wiki.osdev.org/%228042%22_PS/2_Controller @@ -175,74 +367,102 @@ namespace Keyboard // TODO // Step 3: Disable Devices - kb_command(I8042_DISABLE_FIRST); - kb_command(I8042_DISABLE_SECOND); + i8042_controller_command(I8042_DISABLE_FIRST); + i8042_controller_command(I8042_DISABLE_SECOND); // Step 4: Flush The Ouput Buffer - uint8_t tmp; - while(kb_try_read(tmp)) - continue; + while ((IO::inb(I8042_STATUS_REGISTER) & I8042_STATUS_OUT_FULL) != 0) + IO::inb(I8042_DATA_PORT); // Step 5: Set the Controller Configuration Byte - kb_command(I8042_READ_BYTE0); - uint8_t conf = kb_read(); - conf &= 0b10111100; - kb_command(I8042_WRITE_BYTE0, conf); + i8042_controller_command(I8042_READ_CONFIG); + uint8_t config = wait_and_read(); + config &= ~(I8042_CONFING_IRQ_FIRST | I8042_CONFING_IRQ_SECOND); + i8042_controller_command(I8042_WRITE_CONFIG, config); // Step 6: Perform Controller Self Test - kb_command(I8042_TEST_CONTROLLER); - uint8_t resp = kb_read(); - if (resp != I8042_CONTROLLER_TEST_PASS) + i8042_controller_command(I8042_TEST_CONTROLLER); + if (wait_and_read() != I8042_TEST_CONTROLLER_PASS) { - kprint("ERROR: PS/2 self test failed\n"); - return; + kprintln("\e[33mERROR: PS/2 controller self test failed\e[m"); + return false; } // Step 7: Determine If There Are 2 Channels // Step 8: Perform Interface Tests - kb_command(I8042_TEST_FIRST_PORT); - resp = kb_read(); - if (resp != I8042_FIRST_PORT_TEST_PASS) + i8042_controller_command(I8042_TEST_FIRST_PORT); + if (wait_and_read() != I8042_TEST_FIRST_PORT_PASS) { - kprint("ERROR: PS/2 interface test failed\n"); - return; + kprintln("\e[33mERROR: PS/2 first port test failed\e[m"); + return false; } // Step 9: Enable Devices - kb_command(I8042_WRITE_BYTE0, conf | 0x01); // enable IRQs - kb_command(I8042_ENABLE_FIRST); + config |= I8042_CONFING_IRQ_FIRST; + i8042_controller_command(I8042_WRITE_CONFIG, config); + i8042_controller_command(I8042_ENABLE_FIRST); // Step 10: Reset Devices - /* TODO: doesnt seem to respond - kb_command(0xFF); - resp = kb_read(); - if (resp != PS2_ACK) - { - kprint("ERROR: PS/2 could not restart devices\n"); - return; - } - */ + MUST(s_keyboard_command_queue.Push({ + .command = I8042_KB_RESET, + .extra = true, + })); + + // Set scan code set 2 + MUST(s_keyboard_command_queue.Push({ + .command = I8042_KB_SET_SCAN_CODE_SET, + .data = 0x02, + .has_data = true, + })); + + // Turn LEDs off + MUST(s_keyboard_command_queue.Push({ + .command = I8042_KB_SET_LEDS, + .data = s_led_states, + .has_data = true, + })); // Register callback and IRQ s_key_callback = callback; - IDT::register_irq_handler(KEYBOARD_IRQ, irq_handler); + IDT::register_irq_handler(KEYBOARD_IRQ, keyboard_irq_handler); PIC::unmask(KEYBOARD_IRQ); - kb_command(0xED, 0b111); - IO::io_wait(); - while (kb_try_read(tmp)); + return true; } - char key_to_ascii(Key key, uint8_t modifiers) + char key_event_to_ascii(KeyEvent event) { - char res = s_key_to_char[static_cast(key)]; + char res = s_key_to_char[static_cast(event.key)]; - if (!(modifiers & MOD_SHIFT)) + if (!(event.modifiers & (MOD_SHIFT | MOD_CAPS))) if (res >= 'A' && res <= 'Z') res = res - 'A' + 'a'; return res; } + void led_disco() + { + uint64_t time = PIT::ms_since_boot(); + uint64_t freq = 100; + bool state = false; + for(;;) + { + if (PIT::ms_since_boot() > time + freq) + { + time += freq; + state = !state; + + MUST(s_keyboard_command_queue.Push({ + .command = I8042_KB_SET_LEDS, + .data = (uint8_t)(state ? 0b111 : 0b000), + .has_data = true, + })); + } + + update_keyboard(); + } + } + } \ No newline at end of file diff --git a/kernel/kernel/kernel.cpp b/kernel/kernel/kernel.cpp index bd969a0a..e757ad12 100644 --- a/kernel/kernel/kernel.cpp +++ b/kernel/kernel/kernel.cpp @@ -62,7 +62,8 @@ void kernel_main(multiboot_info_t* mbi, uint32_t magic) IDT::initialize(); PIT::initialize(); - Keyboard::initialize(on_key_press); + if (!Keyboard::initialize(on_key_press)) + return; auto time = RTC::GetCurrentTime(); kprintln("Today is {2}:{2}:{2} {2}.{2}.{4}", time.hour, time.minute, time.second, time.day, time.month, time.year); @@ -71,8 +72,9 @@ void kernel_main(multiboot_info_t* mbi, uint32_t magic) ENABLE_INTERRUPTS(); + for (;;) { - asm("hlt"); + Keyboard::update_keyboard(); } } \ No newline at end of file