From ac094a48d6a03dfa6dd35866e05bc46cbb4851d7 Mon Sep 17 00:00:00 2001 From: Bananymous Date: Wed, 29 Mar 2023 03:05:16 +0300 Subject: [PATCH] Kernel: Rework the whole input system We now use Device abstraction that will allow us to provide devices to userspace through /dev. Currently Shell reads from first and only device (it being PS/2 Keyboard). --- kernel/Makefile | 6 +- kernel/include/kernel/ACPI.h | 59 ++ kernel/include/kernel/Device.h | 59 ++ kernel/include/kernel/Input.h | 67 -- kernel/include/kernel/Input/KeyEvent.h | 99 +++ kernel/include/kernel/Input/PS2Controller.h | 38 ++ kernel/include/kernel/Input/PS2Keyboard.h | 64 ++ kernel/include/kernel/Input/PS2Keymap.h | 23 + kernel/include/kernel/Shell.h | 2 +- kernel/kernel/Device.cpp | 26 + kernel/kernel/Input.cpp | 690 -------------------- kernel/kernel/Input/PS2Controller.cpp | 334 ++++++++++ kernel/kernel/Input/PS2Keyboard.cpp | 244 +++++++ kernel/kernel/Input/PS2Keymap.cpp | 360 ++++++++++ kernel/kernel/Shell.cpp | 20 +- kernel/kernel/kernel.cpp | 23 +- 16 files changed, 1339 insertions(+), 775 deletions(-) create mode 100644 kernel/include/kernel/Device.h delete mode 100644 kernel/include/kernel/Input.h create mode 100644 kernel/include/kernel/Input/KeyEvent.h create mode 100644 kernel/include/kernel/Input/PS2Controller.h create mode 100644 kernel/include/kernel/Input/PS2Keyboard.h create mode 100644 kernel/include/kernel/Input/PS2Keymap.h create mode 100644 kernel/kernel/Device.cpp delete mode 100644 kernel/kernel/Input.cpp create mode 100644 kernel/kernel/Input/PS2Controller.cpp create mode 100644 kernel/kernel/Input/PS2Keyboard.cpp create mode 100644 kernel/kernel/Input/PS2Keymap.cpp diff --git a/kernel/Makefile b/kernel/Makefile index 041e23642..a34a5f745 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -41,11 +41,14 @@ kernel/APIC.o \ kernel/build_libc.o \ kernel/CPUID.o \ kernel/Debug.o \ +kernel/Device.o \ kernel/Font.o \ kernel/FS/Ext2.o \ kernel/FS/Inode.o \ kernel/FS/VirtualFileSystem.o \ -kernel/Input.o \ +kernel/Input/PS2Controller.o \ +kernel/Input/PS2Keyboard.o \ +kernel/Input/PS2Keymap.o \ kernel/InterruptController.o \ kernel/kernel.o \ kernel/kmalloc.o \ @@ -113,6 +116,7 @@ always: mkdir -p $(BUILDDIR)/$(ARCHDIR) mkdir -p $(BUILDDIR)/kernel mkdir -p $(BUILDDIR)/kernel/FS + mkdir -p $(BUILDDIR)/kernel/Input mkdir -p $(BUILDDIR)/kernel/Storage mkdir -p $(BUILDDIR)/userspace mkdir -p $(BUILDDIR)/font diff --git a/kernel/include/kernel/ACPI.h b/kernel/include/kernel/ACPI.h index 00bc05eef..293436300 100644 --- a/kernel/include/kernel/ACPI.h +++ b/kernel/include/kernel/ACPI.h @@ -21,6 +21,65 @@ namespace Kernel uint32_t creator_revision; } __attribute__((packed)); + struct FADT : public SDTHeader + { + uint32_t firmware_ctrl; + uint32_t dsdt; + uint8_t __reserved; + uint8_t preferred_pm_profile; + uint16_t sci_int; + uint32_t smi_cmd; + uint8_t acpi_enable; + uint8_t acpi_disable; + uint8_t s4bios_req; + uint8_t pstate_cnt; + uint32_t pm1a_evt_blk; + uint32_t pm1b_evt_blk; + uint32_t pm1a_cnt_blk; + uint32_t pm1b_cnt_blk; + uint32_t pm2_cnt_blk; + uint32_t pm_tmr_blk; + uint32_t gpe0_blk; + uint32_t gpe1_blk; + uint8_t pm1_evt_len; + uint8_t pm1_cnt_len; + uint8_t pm2_cnt_len; + uint8_t pm_tmr_len; + uint8_t gpe0_blk_len; + uint8_t gpe1_blk_len; + uint8_t gpe1_base; + uint8_t cst_cnt; + uint16_t p_lvl2_lat; + uint16_t p_lvl3_lat; + uint16_t flush_size; + uint16_t flush_stride; + uint8_t duty_offset; + uint8_t duty_width; + uint8_t day_alrm; + uint8_t mon_alrm; + uint8_t century; + uint16_t iapc_boot_arch; + uint8_t __reserved2; + uint32_t flags; + uint8_t reset_reg[12]; + uint8_t reset_value; + uint16_t arm_boot_arch; + uint8_t fadt_minor_version; + uint64_t x_firmware_version; + uint64_t x_dsdt; + uint8_t x_pm1a_evt_blk[12]; + uint8_t x_pm1b_evt_blk[12]; + uint8_t x_pm1a_cnt_blk[12]; + uint8_t x_pm1b_cnt_blk[12]; + uint8_t x_pm2_cnt_blk[12]; + uint8_t x_pm_tmr_blk[12]; + uint8_t x_gpe0_blk[12]; + uint8_t x_gpe1_blk[12]; + uint8_t sleep_control_reg[12]; + uint8_t sleep_status_reg[12]; + uint64_t hypervison_vendor_identity; + } __attribute__((packed)); + public: static BAN::ErrorOr initialize(); static ACPI& get(); diff --git a/kernel/include/kernel/Device.h b/kernel/include/kernel/Device.h new file mode 100644 index 000000000..c5ca6b84f --- /dev/null +++ b/kernel/include/kernel/Device.h @@ -0,0 +1,59 @@ +#pragma once + +#include +#include + +namespace Kernel +{ + + class Device + { + public: + enum class Type + { + BlockDevice, + CharacterDevice, + DeviceController + }; + + virtual ~Device() {} + virtual Type type() const = 0; + virtual void update() {} + }; + + class BlockDevice : public Device + { + public: + virtual Type type() const override { return Type::BlockDevice; } + }; + + class CharacterDevice : public Device + { + public: + virtual Type type() const override { return Type::CharacterDevice; } + + virtual BAN::ErrorOr read(BAN::Span); + }; + + class DeviceManager + { + BAN_NON_COPYABLE(DeviceManager); + BAN_NON_MOVABLE(DeviceManager); + + public: + static DeviceManager& get(); + + void update(); + void add_device(Device*); + + BAN::Vector devices() { return m_devices; } + + private: + DeviceManager() = default; + + private: + SpinLock m_lock; + BAN::Vector m_devices; + }; + +} \ No newline at end of file diff --git a/kernel/include/kernel/Input.h b/kernel/include/kernel/Input.h deleted file mode 100644 index 38e66786b..000000000 --- a/kernel/include/kernel/Input.h +++ /dev/null @@ -1,67 +0,0 @@ -#pragma once - -#include -#include - -namespace Input -{ - - enum class Key : uint8_t - { - INVALID, None, - _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, - A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z, - A_Dot, A_Dots, O_Dots, - - Comma, Colon, Period, Semicolon, Hyphen, Underscore, SingleQuote, Asterix, Caret, Tilde, - ExclamationMark, QuestionMark, DoubleQuote, Hashtag, Percent, Ampersand, Slash, BackSlash, Plus, Equals, - OpenParen, CloseParen, OpenBracket, CloseBracket, OpenBrace, CloseBrace, - 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, LeftCtrl, RightCtrl, LeftAlt, RightAlt, NumLock, ScrollLock, Escape, - - Numpad0, Numpad1, Numpad2, Numpad3, Numpad4, Numpad5, Numpad6, Numpad7, Numpad8, Numpad9, - 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 - }; - - struct KeyEvent - { - Key key; - uint8_t modifiers; - bool pressed; - }; - - enum class MouseButton - { - Left, Right, Middle, - }; - struct MouseButtonEvent - { - MouseButton button; - }; - - struct MouseMoveEvent - { - int16_t dx; - int16_t dy; - }; - - - bool initialize(); - void update(); - bool is_key_down(Key); - - void register_key_event_callback(const BAN::Function&); - void register_mouse_button_event_callback(const BAN::Function&); - void register_mouse_move_event_callback(const BAN::Function&); - - const char* key_event_to_utf8(KeyEvent); - -} \ No newline at end of file diff --git a/kernel/include/kernel/Input/KeyEvent.h b/kernel/include/kernel/Input/KeyEvent.h new file mode 100644 index 000000000..74b298f87 --- /dev/null +++ b/kernel/include/kernel/Input/KeyEvent.h @@ -0,0 +1,99 @@ +#pragma once + +#include + +namespace Kernel::Input +{ + + enum class Key + { + Invalid, None, + A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z, + A_Ring, A_Umlaut, O_Umlaut, + _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, + F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, + Insert, PrintScreen, Delete, Home, End, PageUp, PageDown, Enter, Space, + ExclamationMark, DoubleQuote, Hashtag, Currency, Percent, Ampersand, Slash, Section, Half, + OpenBracet, CloseBracet, OpenBrace, CloseBrace, OpenCurlyBrace, CloseCurlyBrace, + Equals, QuestionMark, Plus, BackSlash, Acute, BackTick, TwoDots, Backspace, AtSign, Pound, Dollar, Euro, + Escape, Tab, CapsLock, LeftShift, LeftCtrl, Super, Alt, AltGr, RightCtrl, RightShift, + SingleQuote, Asterix, Caret, Tilde, ArrowUp, ArrowDown, ArrowLeft, ArrowRight, + Comma, Semicolon, Period, Colon, Hyphen, Underscore, NumLock, ScrollLock, LessThan, GreaterThan, Pipe, + Numpad0, Numpad1, Numpad2, Numpad3, Numpad4, Numpad5, Numpad6, Numpad7, Numpad8, Numpad9, + NumpadPlus, NumpadMinus, NumpadMultiply, NumpadDivide, NumpadEnter, NumpadDecimal, + VolumeMute, VolumeUp, VolumeDown, Calculator, MediaPlayPause, MediaStop, MediaPrevious, MediaNext, + Count, + }; + + struct KeyEvent + { + enum class Modifier : uint8_t + { + Shift = (1 << 0), + Ctrl = (1 << 1), + Alt = (1 << 2), + AltGr = (1 << 3), + CapsLock = (1 << 4), + NumLock = (1 << 5), + ScrollLock = (1 << 6), + Released = (1 << 7), + }; + + bool shift() const { return modifier & (uint8_t)Modifier::Shift; } + bool ctrl() const { return modifier & (uint8_t)Modifier::Ctrl; } + bool alt() const { return modifier & (uint8_t)Modifier::Alt; } + bool altgr() const { return modifier & (uint8_t)Modifier::AltGr; } + bool caps_lock() const { return modifier & (uint8_t)Modifier::CapsLock; } + bool num_lock() const { return modifier & (uint8_t)Modifier::NumLock; } + bool scroll_lock() const { return modifier & (uint8_t)Modifier::ScrollLock; } + bool released() const { return modifier & (uint8_t)Modifier::Released; } + bool pressed() const { return !released(); } + + uint8_t modifier; + Key key; + }; + + inline const char* key_event_to_utf8(KeyEvent event) + { + static constexpr const char* utf8_lower[] = { + nullptr, nullptr, + "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", + "å", "ä", "ö", + "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, " ", + "!", "\"", "#", "¤", "%", "&", "/", "§", "½", + "(", ")", "[", "]", "{", "}", + "=", "?", "+", "\\", "´", "`", "¨", nullptr, "@", "£", "$", "€", + nullptr, "\t", nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + "'", "*", "^", "~", nullptr, nullptr, nullptr, nullptr, + ",", ";", ".", ":", "-", "_", nullptr, nullptr, "<", ">", "|", + "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", + "+", "-", "*", "/", nullptr, ",", + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + }; + static_assert((size_t)Key::Count == sizeof(utf8_lower) / sizeof(*utf8_lower)); + + static constexpr const char* utf8_upper[] = { + nullptr, nullptr, + "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", + "Å", "Ä", "Ö", + "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, " ", + "!", "\"", "#", "¤", "%", "&", "/", "§", "½", + "(", ")", "[", "]", "{", "}", + "=", "?", "+", "\\", "´", "`", "¨", nullptr, "@", "£", "$", "€", + nullptr, "\t", nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + "'", "*", "^", "~", nullptr, nullptr, nullptr, nullptr, + ",", ";", ".", ":", "-", "_", nullptr, nullptr, "<", ">", "|", + "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", + "+", "-", "*", "/", nullptr, ",", + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + }; + static_assert((size_t)Key::Count == sizeof(utf8_upper) / sizeof(*utf8_lower)); + + return (event.shift() ^ event.caps_lock()) ? utf8_upper[(uint8_t)event.key] : utf8_lower[(uint8_t)event.key]; + } + +} \ No newline at end of file diff --git a/kernel/include/kernel/Input/PS2Controller.h b/kernel/include/kernel/Input/PS2Controller.h new file mode 100644 index 000000000..571f83169 --- /dev/null +++ b/kernel/include/kernel/Input/PS2Controller.h @@ -0,0 +1,38 @@ +#pragma once + +#include + +namespace Kernel::Input +{ + + class PS2Device : public CharacterDevice + { + public: + virtual ~PS2Device() {} + virtual void on_byte(uint8_t) = 0; + }; + + class PS2Controller + { + public: + static BAN::ErrorOr initialize(); + static PS2Controller& get(); + + void send_byte(const PS2Device*, uint8_t); + + private: + PS2Controller() = default; + BAN::ErrorOr initialize_impl(); + BAN::ErrorOr initialize_device(uint8_t); + + BAN::ErrorOr reset_device(uint8_t); + BAN::ErrorOr set_scanning(uint8_t, bool); + + static void device0_irq(); + static void device1_irq(); + + private: + PS2Device* m_devices[2] { nullptr, nullptr }; + }; + +} \ No newline at end of file diff --git a/kernel/include/kernel/Input/PS2Keyboard.h b/kernel/include/kernel/Input/PS2Keyboard.h new file mode 100644 index 000000000..f6ae8f106 --- /dev/null +++ b/kernel/include/kernel/Input/PS2Keyboard.h @@ -0,0 +1,64 @@ +#pragma once + +#include +#include +#include +#include + +namespace Kernel::Input +{ + + class PS2Keyboard final : public PS2Device + { + private: + enum Command : uint8_t + { + SET_LEDS = 0xED, + SCANCODE = 0xF0, + ENABLE_SCANNING = 0xF4, + DISABLE_SCANNING = 0xF5, + }; + + enum class State + { + Normal, + WaitingAck, + }; + + public: + static BAN::ErrorOr create(PS2Controller&); + + virtual void on_byte(uint8_t) override; + virtual void update() override; + + virtual BAN::ErrorOr read(BAN::Span) override; + + private: + PS2Keyboard(PS2Controller& controller) + : m_controller(controller) + {} + BAN::ErrorOr initialize(); + + void append_command_queue(uint8_t); + void append_command_queue(uint8_t, uint8_t); + + void buffer_has_key(); + + void update_leds(); + + private: + PS2Controller& m_controller; + uint8_t m_byte_buffer[10]; + uint8_t m_byte_index { 0 }; + + uint8_t m_modifiers { 0 }; + + BAN::CircularQueue m_event_queue; + BAN::CircularQueue m_command_queue; + + PS2Keymap m_keymap; + + State m_state { State::Normal }; + }; + +} \ No newline at end of file diff --git a/kernel/include/kernel/Input/PS2Keymap.h b/kernel/include/kernel/Input/PS2Keymap.h new file mode 100644 index 000000000..aab0c86fb --- /dev/null +++ b/kernel/include/kernel/Input/PS2Keymap.h @@ -0,0 +1,23 @@ +#pragma once + +#include +#include + +namespace Kernel::Input +{ + + class PS2Keymap + { + public: + PS2Keymap(); + + Key key_for_scancode_and_modifiers(uint32_t, uint8_t); + + private: + BAN::Vector m_normal_keymap; + BAN::Vector m_shift_keymap; + BAN::Vector m_altgr_keymap; + BAN::Vector m_extended_keymap; + }; + +} \ No newline at end of file diff --git a/kernel/include/kernel/Shell.h b/kernel/include/kernel/Shell.h index 2e81680dd..b7741f6cc 100644 --- a/kernel/include/kernel/Shell.h +++ b/kernel/include/kernel/Shell.h @@ -2,7 +2,7 @@ #include #include -#include +#include #include namespace Kernel diff --git a/kernel/kernel/Device.cpp b/kernel/kernel/Device.cpp new file mode 100644 index 000000000..11c330159 --- /dev/null +++ b/kernel/kernel/Device.cpp @@ -0,0 +1,26 @@ +#include +#include + +namespace Kernel +{ + + DeviceManager& DeviceManager::get() + { + static DeviceManager instance; + return instance; + } + + void DeviceManager::update() + { + LockGuard _(m_lock); + for (Device* device : m_devices) + device->update(); + } + + void DeviceManager::add_device(Device* device) + { + LockGuard _(m_lock); + MUST(m_devices.push_back(device)); + } + +} \ No newline at end of file diff --git a/kernel/kernel/Input.cpp b/kernel/kernel/Input.cpp deleted file mode 100644 index fee4fa91c..000000000 --- a/kernel/kernel/Input.cpp +++ /dev/null @@ -1,690 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#define DEBUG_ALL_IRQ 0 -#define KEYBOARD_SHOW_UNKNOWN 1 - -#define MOUSE_ENABLED 0 - -#define I8042_DATA_PORT 0x60 -#define I8042_STATUS_REGISTER 0x64 -#define I8042_COMMAND_REGISTER 0x64 - -#define I8042_STATUS_OUT_FULL (1 << 0) -#define I8042_STATUS_IN_FULL (1 << 1) - -#define I8042_READ_CONFIG 0x20 -#define I8042_WRITE_CONFIG 0x60 - -#define I8042_CONFING_IRQ_FIRST (1 << 0) -#define I8042_CONFING_IRQ_SECOND (1 << 1) -#define I8042_CONFING_DUAL_CHANNEL (1 << 5) -#define I8042_CONFING_TRANSLATION (1 << 6) - -#define I8042_ENABLE_FIRST_PORT 0xAE -#define I8042_ENABLE_SECOND_PORT 0xA8 -#define I8042_DISABLE_FIRST_PORT 0xAD -#define I8042_DISABLE_SECOND_PORT 0xA7 - -#define I8042_TEST_CONTROLLER 0xAA -#define I8042_TEST_CONTROLLER_PASS 0x55 - -#define I8042_TEST_FIRST_PORT 0xAB -#define I8042_TEST_FIRST_PORT_PASS 0x00 - -#define I8042_TEST_SECOND_PORT 0xA9 -#define I8042_TEST_SECOND_PORT_PASS 0x00 - -#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_LED_SCROLL_LOCK (1 << 0) -#define I8042_KB_LED_NUM_LOCK (1 << 1) -#define I8042_KB_LED_CAPS_LOCK (1 << 2) - -#define I8042_MOUSE_ACK 0xFA -#define I8042_MOUSE_RESET 0xFF -#define I8042_MOUSE_SELF_TEST_PASS 0xAA -#define I8042_MOUSE_ENABLE 0xF4 -#define I8042_MOUSE_DISABLE 0xF5 - -#define I8042_TIMEOUT_MS 1000 - -#define KEYBOARD_IRQ 0x01 -#define MOUSE_IRQ 0x0C - -#define TARGET_KEYBOARD 1 -#define TARGET_MOUSE 2 - -#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 Input -{ - - static bool s_keyboard_state[0xFF] = {}; - - struct Command - { - uint8_t target = 0; - uint8_t command = 0; - uint8_t data = 0; - bool has_data = false; - uint8_t resp_cnt = 0; - uint8_t _sent = 0; - uint8_t _ack = 0; - bool _done = false; - }; - static uint64_t s_command_sent = 0; - static BAN::Queue s_command_queue; - static uint8_t s_command_response[3] = {}; - static uint8_t s_command_response_index = 0; - - static BAN::Queue s_key_event_queue; - static uint8_t s_keyboard_key_buffer[10] = {}; - static uint8_t s_keyboard_key_buffer_size = 0; - - static BAN::Queue s_mouse_button_event_queue; - static BAN::Queue s_mouse_move_event_queue; - static uint8_t s_mouse_data_buffer[3] = {}; - static uint8_t s_mouse_data_buffer_index = 0; - - static uint8_t s_led_states = 0b000; - static uint8_t s_modifiers = 0x00; - - static BAN::Function s_key_event_callback; - static BAN::Function s_mouse_button_event_callback; - static BAN::Function s_mouse_move_event_callback; - - static const char* s_key_to_utf8_lower[] - { - nullptr, nullptr, - "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", - "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", - "å", "ä", "ö", - - ",", ":", ".", ";", "-", "_", "'", "*", "^", "~", - "!", "?", "\"", "#", "%", "&", "/", "\\", "+", "=", - "(", ")", "[", "]", "{", "}", - "$", "£", "€", "¤", "\n", " ", "\t", nullptr, "<", ">", "´", "`", "§", "½", "@", "|", - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, - - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, - - "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", - ",", "+", "*", "/", "-", "\n", - - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, - - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, - }; - static_assert(sizeof(s_key_to_utf8_lower) == (int)Key::Count * sizeof(*s_key_to_utf8_lower)); - - static const char* s_key_to_utf8_upper[] - { - nullptr, nullptr, - "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", - "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", - "Å", "Ä", "Ö", - - ",", ":", ".", ";", "-", "_", "'", "*", "^", "~", - "!", "?", "\"", "#", "%", "&", "/", "\\", "+", "=", - "(", ")", "[", "]", "{", "}", - "$", "£", "€", "¤", "\n", " ", "\t", nullptr, "<", ">", "´", "`", "§", "½", "@", "|", - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, - - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, - - "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", - ",", "+", "*", "/", "-", "\n", - - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, - - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, - }; - static_assert(sizeof(s_key_to_utf8_upper) == (int)Key::Count * sizeof(*s_key_to_utf8_upper)); - - - - static void keyboard_new_key(); - - - static uint8_t wait_and_read() - { - while ((IO::inb(I8042_STATUS_REGISTER) & I8042_STATUS_OUT_FULL) == 0) - continue; - return IO::inb(I8042_DATA_PORT); - } - - static void i8042_controller_command(uint8_t command) - { - IO::outb(I8042_COMMAND_REGISTER, command); - } - - static void i8042_controller_command(uint8_t command, uint8_t data) - { - IO::outb(I8042_COMMAND_REGISTER, command); - while ((IO::inb(I8042_STATUS_REGISTER) & I8042_STATUS_IN_FULL) != 0) - continue; - IO::outb(I8042_DATA_PORT, data); - } - - static bool i8042_command(uint8_t target, uint8_t command) - { - if (target == TARGET_MOUSE) - IO::outb(I8042_COMMAND_REGISTER, 0xD4); - - auto timeout = PIT::ms_since_boot() + I8042_TIMEOUT_MS; - - while (PIT::ms_since_boot() < timeout) - { - if ((IO::inb(I8042_STATUS_REGISTER) & I8042_STATUS_IN_FULL) == 0) - { - IO::outb(I8042_DATA_PORT, command); - s_command_sent = PIT::ms_since_boot(); - return true; - } - } - - return false; - } - - static void i8042_handle_byte(uint8_t target, uint8_t raw) - { - bool waiting_response = false; - - if (!s_command_queue.empty()) - { - auto& command = s_command_queue.front(); - if (command.target == target && command._sent && !command._done) - waiting_response = true; - } - - if (target == TARGET_KEYBOARD) - { - if (waiting_response) - { - auto& command = s_command_queue.front(); - - if (raw == I8042_KB_RESEND) - { - dprintln("PS/2 Keyboard: Resend 0x{H}", command._sent == 2 ? command.data : command.command); - command._sent--; - } - else if (raw == I8042_KB_ACK) - { - command._ack++; - if (command.resp_cnt == 0) - command._done = (command._ack >= (1 + command.has_data)); - } - else if (raw == 0x00) - { - dprintln("\e[33mKey detection error or internal buffer overrun\e[m"); - command._sent = 0; - command._ack = 0; - command._done = false; - s_command_response_index = 0; - } - else if (raw == 0xEE && command.command == 0xEE) - { - s_command_queue.pop(); - } - else - { - s_command_response[s_command_response_index++] = raw; - if (s_command_response_index >= command.resp_cnt) - command._done = true; - } - } - else - { - s_keyboard_key_buffer[s_keyboard_key_buffer_size++] = raw; - if (raw != 0xE0) - keyboard_new_key(); - } - } - else if (target == TARGET_MOUSE) - { - if (waiting_response) - { - auto& command = s_command_queue.front(); - - if (raw == I8042_MOUSE_ACK) - { - command._ack++; - if (command.resp_cnt == 0) - command._done = (command._ack >= (1 + command.has_data)); - } - else - { - s_command_response[s_command_response_index++] = raw; - if (s_command_response_index >= command.resp_cnt) - command._done = true; - } - } - else - { - s_mouse_data_buffer[s_mouse_data_buffer_index++] = raw; - - if (s_mouse_data_buffer_index >= 3) - { - if (s_mouse_data_buffer[0] & 0x07) - { - bool left = s_mouse_data_buffer[0] & (1 << 0); - bool right = s_mouse_data_buffer[0] & (1 << 1); - bool middle = s_mouse_data_buffer[0] & (1 << 2); - - if (left) MUST(s_mouse_button_event_queue.push({ .button = MouseButton::Left })); - if (right) MUST(s_mouse_button_event_queue.push({ .button = MouseButton::Right })); - if (middle) MUST(s_mouse_button_event_queue.push({ .button = MouseButton::Middle })); - } - - if (s_mouse_data_buffer[1] || s_mouse_data_buffer[2]) - { - int16_t rel_x = (int16_t)s_mouse_data_buffer[1] - ((s_mouse_data_buffer[0] << 4) & 0x100); - int16_t rel_y = (int16_t)s_mouse_data_buffer[2] - ((s_mouse_data_buffer[0] << 3) & 0x100); - - MUST(s_mouse_move_event_queue.push({ .dx = rel_x, .dy = rel_y })); - } - - s_mouse_data_buffer_index = 0; - } - } - } - else - { - Kernel::panic("Unknown target"); - } - } - - void update() - { - if (!s_command_queue.empty()) - { - auto& command = s_command_queue.front(); - if (command.target != TARGET_KEYBOARD && command.target != TARGET_MOUSE) - Kernel::panic("Undefined target for command 0x{2H}", command.command); - - if (command._sent == 0 && command._ack == 0) - { - command._sent++; - if (!i8042_command(command.target, command.command)) - Kernel::panic("PS/2 command oof {}, 0x{2H}", command.target, command.command); - } - - if (command._sent == 1 && command._ack == 1 && command.has_data) - { - command._sent++; - if (!i8042_command(command.target, command.data)) - Kernel::panic("PS/2 data oof {}, 0x{2H}", command.target, command.data); - } - - if (command._sent > 0 && PIT::ms_since_boot() > s_command_sent + 1000) - { - dprintln("PS/2 command 0x{2H} timed out on {}", command.command, command.target); - // Discard command on timeout? - command._done = true; - command.target = 0; - } - - if (command._done) - { - if (command.target == TARGET_KEYBOARD) - { - switch (command.command) - { - case I8042_KB_RESET: - if (s_command_response[0] != 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; - default: - Kernel::panic("PS/2 Keyboard unhandled command"); - } - } - else if (command.target == TARGET_MOUSE) - { - switch (command.command) - { - case I8042_MOUSE_RESET: - if (s_command_response[0] != I8042_MOUSE_SELF_TEST_PASS) - Kernel::panic("PS/2 Mouse self test failed"); - if (s_command_response[1] != 0x00) - Kernel::panic("PS/2 Mouse invalid byte sent after self test"); - break; - case I8042_MOUSE_ENABLE: - break; - case I8042_MOUSE_DISABLE: - break; - default: - Kernel::panic("PS/2 Mouse unhandled command"); - } - } - - s_command_response_index = 0; - s_command_queue.pop(); - } - } - - while (!s_key_event_queue.empty()) - { - if (s_key_event_callback) - s_key_event_callback(s_key_event_queue.front()); - s_key_event_queue.pop(); - } - - while (!s_mouse_button_event_queue.empty()) - { - if (s_mouse_button_event_callback) - s_mouse_button_event_callback(s_mouse_button_event_queue.front()); - s_mouse_button_event_queue.pop(); - } - - while (!s_mouse_move_event_queue.empty()) - { - if (s_mouse_move_event_callback) - s_mouse_move_event_callback(s_mouse_move_event_queue.front()); - s_mouse_move_event_queue.pop(); - } - } - - bool is_key_down(Key key) - { - return s_keyboard_state[(int)key]; - } - - 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 KEYBOARD_SHOW_UNKNOWN - if (key == Key::INVALID) - kprintln("{} {}", ch, extended ? 'E' : ' '); -#endif - - s_keyboard_state[(int)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) - { - MUST(s_command_queue.push({ - .target = TARGET_KEYBOARD, - .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.is_error()) - dwarnln("{}", error_or.error()); - } - s_keyboard_key_buffer_size -= index + 1; - memmove(s_keyboard_key_buffer, s_keyboard_key_buffer + index, s_keyboard_key_buffer_size); - } - - static void keyboard_irq_handler() - { - uint8_t raw = IO::inb(I8042_DATA_PORT); -#if DEBUG_ALL_IRQ - dprintln("k 0x{2H}", raw); -#endif - i8042_handle_byte(TARGET_KEYBOARD, raw); - } - - static void mouse_irq_handler() - { - uint8_t raw = IO::inb(I8042_DATA_PORT); -#if DEBUG_ALL_IRQ - dprintln("m 0x{2H}", raw); -#endif - i8042_handle_byte(TARGET_MOUSE, raw); - } - - static void initialize_keyboard() - { - // Register callback and IRQ - IDT::register_irq_handler(KEYBOARD_IRQ, keyboard_irq_handler); - InterruptController::get().enable_irq(KEYBOARD_IRQ); - i8042_controller_command(I8042_ENABLE_FIRST_PORT); - - MUST(s_command_queue.push({ - .target = TARGET_KEYBOARD, - .command = I8042_KB_RESET, - .resp_cnt = 1, - })); - - // Set scan code set 2 - MUST(s_command_queue.push({ - .target = TARGET_KEYBOARD, - .command = I8042_KB_SET_SCAN_CODE_SET, - .data = 0x02, - .has_data = true, - })); - - // Turn LEDs off - MUST(s_command_queue.push({ - .target = TARGET_KEYBOARD, - .command = I8042_KB_SET_LEDS, - .data = s_led_states, - .has_data = true, - })); - } - - static void initialize_mouse() - { - // Register callback and IRQ - IDT::register_irq_handler(MOUSE_IRQ, mouse_irq_handler); - InterruptController::get().enable_irq(MOUSE_IRQ); - i8042_controller_command(I8042_ENABLE_SECOND_PORT); - - MUST(s_command_queue.push({ - .target = TARGET_MOUSE, - .command = I8042_MOUSE_RESET, - .resp_cnt = 2, - })); - - // Mouse should be disabled when sending commands - MUST(s_command_queue.push({ - .target = TARGET_MOUSE, - .command = I8042_MOUSE_ENABLE, - })); - } - - bool initialize() - { - // https://wiki.osdev.org/%228042%22_PS/2_Controller - - // Step 1: Initialize USB Controllers - // TODO - - // Stem 2: Determine if the PS/2 Controller Exists - // TODO - - // Step 3: Disable Devices - i8042_controller_command(I8042_DISABLE_FIRST_PORT); - i8042_controller_command(I8042_DISABLE_SECOND_PORT); - - // Step 4: Flush The Ouput Buffer - while ((IO::inb(I8042_STATUS_REGISTER) & I8042_STATUS_OUT_FULL) != 0) - IO::inb(I8042_DATA_PORT); - - // Step 5: Set the Controller Configuration Byte - 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 - i8042_controller_command(I8042_TEST_CONTROLLER); - if (wait_and_read() != I8042_TEST_CONTROLLER_PASS) - { - derrorln("PS/2 controller self test failed"); - return false; - } - - // Step 7: Determine If There Are 2 Channels - bool dual_channel = MOUSE_ENABLED ? config & I8042_CONFING_DUAL_CHANNEL : false; - if (dual_channel) - { - i8042_controller_command(I8042_ENABLE_SECOND_PORT); - i8042_controller_command(I8042_READ_CONFIG); - if (wait_and_read() & I8042_CONFING_DUAL_CHANNEL) - dual_channel = false; - else - i8042_controller_command(I8042_DISABLE_SECOND_PORT); - } - - // Step 8: Perform Interface Tests - i8042_controller_command(I8042_TEST_FIRST_PORT); - if (wait_and_read() != I8042_TEST_FIRST_PORT_PASS) - { - derrorln("PS/2 first port test failed"); - return false; - } - - if (dual_channel) - { - i8042_controller_command(I8042_TEST_SECOND_PORT); - if (wait_and_read() != I8042_TEST_SECOND_PORT_PASS) - { - dwarnln("PS/2 second port test failed. Mouse will be disabled"); - dual_channel = false; - } - } - - // Step 9: Enable Devices - config |= I8042_CONFING_IRQ_FIRST; - if (dual_channel) - config |= I8042_CONFING_IRQ_SECOND; - i8042_controller_command(I8042_WRITE_CONFIG, config); - - // Step 10: Reset Devices - initialize_keyboard(); - if (dual_channel) - initialize_mouse(); - - return true; - } - - void register_key_event_callback(const BAN::Function& callback) - { - s_key_event_callback = callback; - } - - void register_mouse_button_event_callback(const BAN::Function& callback) - { - s_mouse_button_event_callback = callback; - } - - void register_mouse_move_event_callback(const BAN::Function& callback) - { - s_mouse_move_event_callback = callback; - } - - const char* key_event_to_utf8(KeyEvent event) - { - bool shift = event.modifiers & MOD_SHIFT; - bool caps = event.modifiers & MOD_CAPS; - if (shift ^ caps) - return s_key_to_utf8_upper[(int)event.key]; - return s_key_to_utf8_lower[(int)event.key]; - } - -} \ No newline at end of file diff --git a/kernel/kernel/Input/PS2Controller.cpp b/kernel/kernel/Input/PS2Controller.cpp new file mode 100644 index 000000000..2d0ae56c1 --- /dev/null +++ b/kernel/kernel/Input/PS2Controller.cpp @@ -0,0 +1,334 @@ +#include +#include +#include +#include +#include +#include +#include + +namespace Kernel::Input +{ + + namespace PS2 + { + + enum IOPort : uint8_t + { + DATA = 0x60, + STATUS = 0x64, + COMMAND = 0x64, + }; + + enum Status : uint8_t + { + OUTPUT_FULL = (1 << 0), + INPUT_FULL = (1 << 1), + SYSTEM = (1 << 2), + DEVICE_OR_CONTROLLER = (1 << 3), + TIMEOUT_ERROR = (1 << 6), + PARITY_ERROR = (1 << 7), + }; + + enum Config : uint8_t + { + INTERRUPT_FIRST_PORT = (1 << 0), + INTERRUPT_SECOND_PORT = (1 << 1), + SYSTEM_FLAG = (1 << 2), + ZERO1 = (1 << 3), + CLOCK_FIRST_PORT = (1 << 4), + CLOCK_SECOND_PORT = (1 << 5), + TRANSLATION_FIRST_PORT = (1 << 6), + ZERO2 = (1 << 7), + }; + + enum Command : uint8_t + { + READ_CONFIG = 0x20, + WRITE_CONFIG = 0x60, + DISABLE_SECOND_PORT = 0xA7, + ENABLE_SECOND_PORT = 0xA8, + TEST_SECOND_PORT = 0xA9, + TEST_CONTROLLER = 0xAA, + TEST_FIRST_PORT = 0xAB, + DISABLE_FIRST_PORT = 0xAD, + ENABLE_FIRST_PORT = 0xAE, + WRITE_TO_SECOND_PORT = 0xD4, + }; + + enum Response + { + TEST_FIRST_PORT_PASS = 0x00, + TEST_SECOND_PORT_PASS = 0x00, + TEST_CONTROLLER_PASS = 0x55, + SELF_TEST_PASS = 0xAA, + ACK = 0xFA, + }; + + enum DeviceCommand + { + ENABLE_SCANNING = 0xF4, + DISABLE_SCANNING = 0xF5, + IDENTIFY = 0xF2, + RESET = 0xFF, + }; + + enum IRQ + { + DEVICE0 = 1, + DEVICE1 = 12, + }; + + } + + static constexpr uint64_t s_device_timeout_ms = 100; + + static void controller_send_command(PS2::Command command) + { + IO::outb(PS2::IOPort::COMMAND, command); + } + + static void controller_send_command(PS2::Command command, uint8_t data) + { + IO::outb(PS2::IOPort::COMMAND, command); + while (IO::inb(PS2::IOPort::STATUS) & PS2::Status::INPUT_FULL) + continue; + IO::outb(PS2::IOPort::DATA, data); + } + + static uint8_t wait_and_read() + { + while (!(IO::inb(PS2::IOPort::STATUS) & PS2::Status::OUTPUT_FULL)) + continue; + return IO::inb(PS2::IOPort::DATA); + } + + static BAN::ErrorOr device_send_byte(uint8_t device, uint8_t byte) + { + if (device == 1) + IO::outb(PS2::IOPort::COMMAND, PS2::Command::WRITE_TO_SECOND_PORT); + uint64_t timeout = PIT::ms_since_boot() + s_device_timeout_ms; + while (PIT::ms_since_boot() < timeout) + { + if (!(IO::inb(PS2::IOPort::STATUS) & PS2::Status::INPUT_FULL)) + { + IO::outb(PS2::IOPort::DATA, byte); + return {}; + } + } + return BAN::Error::from_c_string("PS/2 device timeout"); + } + + static BAN::ErrorOr device_read_byte() + { + uint64_t timeout = PIT::ms_since_boot() + s_device_timeout_ms; + while (PIT::ms_since_boot() < timeout) + if (IO::inb(PS2::IOPort::STATUS) & PS2::Status::OUTPUT_FULL) + return IO::inb(PS2::IOPort::DATA); + return BAN::Error::from_c_string("PS/2 device timeout"); + } + + static BAN::ErrorOr device_wait_ack() + { + while (TRY(device_read_byte()) != PS2::Response::ACK) + continue;; + return {}; + } + + void PS2Controller::device0_irq() + { + auto& controller = PS2Controller::get(); + ASSERT(controller.m_devices[0] != nullptr); + controller.m_devices[0]->on_byte(IO::inb(PS2::IOPort::DATA)); + } + + void PS2Controller::device1_irq() + { + auto& controller = PS2Controller::get(); + ASSERT(controller.m_devices[1] != nullptr); + controller.m_devices[1]->on_byte(IO::inb(PS2::IOPort::DATA)); + } + + static PS2Controller* s_instance = nullptr; + + BAN::ErrorOr PS2Controller::initialize() + { + ASSERT(s_instance == nullptr); + s_instance = new PS2Controller; + if (s_instance == nullptr) + return BAN::Error::from_errno(ENOMEM); + BAN::ScopeGuard guard([] { delete s_instance; }); + TRY(s_instance->initialize_impl()); + guard.disable(); + return {}; + } + + PS2Controller& PS2Controller::get() + { + ASSERT(s_instance != nullptr); + return *s_instance; + } + + BAN::ErrorOr PS2Controller::initialize_impl() + { + // Step 1: Initialise USB Controllers + // FIXME + + // Step 2: Determine if the PS/2 Controller Exists + if (false) + { + const ACPI::FADT* fadt = (const ACPI::FADT*)TRY(ACPI::get().get_header("FACP")); + bool ps2_exists = fadt->iapc_boot_arch & (1 << 1); + ACPI::get().unmap_header(fadt); + + if (!ps2_exists) + return BAN::Error::from_c_string("PS2 Controller does not exist"); + } + + // Step 3: Disable Devices + controller_send_command(PS2::Command::DISABLE_FIRST_PORT); + controller_send_command(PS2::Command::DISABLE_SECOND_PORT); + + // Step 4: Flush The Output Buffer + IO::inb(PS2::IOPort::DATA); + + // Step 5: Set the Controller Configuration Byte + controller_send_command(PS2::Command::READ_CONFIG); + uint8_t config = wait_and_read(); + config &= ~PS2::Config::INTERRUPT_FIRST_PORT; + config &= ~PS2::Config::INTERRUPT_SECOND_PORT; + config &= ~PS2::Config::TRANSLATION_FIRST_PORT; + controller_send_command(PS2::Command::WRITE_CONFIG, config); + + // Step 6: Perform Controller Self Test + controller_send_command(PS2::Command::TEST_CONTROLLER); + if (wait_and_read() != PS2::Response::TEST_CONTROLLER_PASS) + return BAN::Error::from_c_string("PS/2 Controller self test failed"); + // NOTE: self test might reset the device so we set the config byte again + controller_send_command(PS2::Command::WRITE_CONFIG, config); + + // Step 7: Determine If There Are 2 Channels + bool valid_ports[2] { true, false }; + if (config & PS2::Config::CLOCK_SECOND_PORT) + { + controller_send_command(PS2::Command::ENABLE_SECOND_PORT); + controller_send_command(PS2::Command::READ_CONFIG); + if (!(wait_and_read() & PS2::Config::CLOCK_SECOND_PORT)) + valid_ports[1] = true; + controller_send_command(PS2::Command::DISABLE_SECOND_PORT); + } + + // Step 8: Perform Interface Tests + controller_send_command(PS2::Command::TEST_FIRST_PORT); + if (wait_and_read() != PS2::Response::TEST_FIRST_PORT_PASS) + valid_ports[0] = false; + if (valid_ports[1]) + { + controller_send_command(PS2::Command::TEST_SECOND_PORT); + if (wait_and_read() != PS2::Response::TEST_SECOND_PORT_PASS) + valid_ports[1] = false; + } + if (!valid_ports[0] && !valid_ports[1]) + return BAN::Error::from_c_string("No ports available on Controller"); + + // Step 9: Enable Devices (and disable scanning) + for (uint8_t device = 0; device < 2; device++) + { + if (!valid_ports[device]) + continue; + controller_send_command(device == 0 ? PS2::Command::ENABLE_FIRST_PORT : PS2::Command::ENABLE_SECOND_PORT); + if (set_scanning(device, false).is_error()) + valid_ports[device] = false; + } + + // Step 10: Reset Devices + for (uint8_t device = 0; device < 2; device++) + { + if (!valid_ports[device]) + continue; + if (reset_device(device).is_error()) + valid_ports[device] = false; + if (set_scanning(device, false).is_error()) + valid_ports[device] = false; + } + + // Step 11: Initialize Device Drivers + for (uint8_t device = 0; device < 2; device++) + { + if (!valid_ports[device]) + continue; + if (auto res = initialize_device(device); res.is_error()) + dprintln("{}", res.error()); + } + + if (m_devices[0]) + { + IDT::register_irq_handler(PS2::IRQ::DEVICE0, device0_irq); + InterruptController::get().enable_irq(PS2::IRQ::DEVICE0); + config |= PS2::Config::INTERRUPT_FIRST_PORT; + DeviceManager::get().add_device(m_devices[0]); + } + if (m_devices[1]) + { + IDT::register_irq_handler(PS2::IRQ::DEVICE1, device1_irq); + InterruptController::get().enable_irq(PS2::IRQ::DEVICE1); + config |= PS2::Config::INTERRUPT_SECOND_PORT; + DeviceManager::get().add_device(m_devices[1]); + } + + controller_send_command(PS2::Command::WRITE_CONFIG, config); + + return {}; + } + + BAN::ErrorOr PS2Controller::initialize_device(uint8_t device) + { + TRY(device_send_byte(device, PS2::DeviceCommand::IDENTIFY)); + TRY(device_wait_ack()); + + uint8_t bytes[2] {}; + uint8_t index = 0; + for (uint8_t i = 0; i < 2; i++) + { + auto res = device_read_byte(); + if (res.is_error()) + break; + bytes[index++] = res.value(); + } + + // Standard PS/2 Mouse + if (index == 1 && (bytes[0] == 0x00)) + return BAN::Error::from_c_string("PS/2 mouse not supported"); + + // MF2 Keyboard + if (index == 2 && (bytes[0] == 0xAB && bytes[1] == 0x83)) + m_devices[device] = TRY(PS2Keyboard::create(*this)); + + if (m_devices[device]) + return {}; + return BAN::Error::from_format("Unhandled PS/2 device {}{} ({} bytes)", bytes[0], bytes[1], index); + } + + void PS2Controller::send_byte(const PS2Device* device, uint8_t byte) + { + ASSERT(device != nullptr && (device == m_devices[0] || device == m_devices[1])); + uint8_t device_index = (device == m_devices[0]) ? 0 : 1; + MUST(device_send_byte(device_index, byte)); + } + + BAN::ErrorOr PS2Controller::reset_device(uint8_t device) + { + TRY(device_send_byte(device, PS2::DeviceCommand::RESET)); + TRY(device_wait_ack()); + if (TRY(device_read_byte()) != PS2::Response::SELF_TEST_PASS) + return BAN::Error::from_c_string("Device reset failed"); + return {}; + } + + BAN::ErrorOr PS2Controller::set_scanning(uint8_t device, bool enabled) + { + TRY(device_send_byte(device, enabled ? PS2::DeviceCommand::ENABLE_SCANNING : PS2::DeviceCommand::DISABLE_SCANNING)); + TRY(device_wait_ack()); + return {}; + } + +} \ No newline at end of file diff --git a/kernel/kernel/Input/PS2Keyboard.cpp b/kernel/kernel/Input/PS2Keyboard.cpp new file mode 100644 index 000000000..bda81b429 --- /dev/null +++ b/kernel/kernel/Input/PS2Keyboard.cpp @@ -0,0 +1,244 @@ +#include +#include +#include + +#define SET_MASK(byte, mask, on_off) ((on_off) ? ((byte) | (mask)) : ((byte) & ~(mask))) +#define TOGGLE_MASK(byte, mask) ((byte) ^ (mask)) + +namespace Kernel::Input +{ + + namespace PS2 + { + + enum Response + { + KEY_ERROR_OR_BUFFER_OVERRUN1 = 0x00, + SELF_TEST_PASSED = 0xAA, + ECHO_RESPONSE = 0xEE, + ACK = 0xFA, + RESEND = 0xFE, + KEY_ERROR_OR_BUFFER_OVERRUN2 = 0xFF, + }; + + enum Scancode + { + SET_SCANCODE_SET1 = 1, + SET_SCANCODE_SET2 = 2, + SET_SCANCODE_SET3 = 3, + }; + + enum Leds + { + SCROLL_LOCK = (1 << 0), + NUM_LOCK = (1 << 1), + CAPS_LOCK = (1 << 2), + }; + + } + + BAN::ErrorOr PS2Keyboard::create(PS2Controller& controller) + { + PS2Keyboard* keyboard = new PS2Keyboard(controller); + if (keyboard == nullptr) + return BAN::Error::from_errno(ENOMEM); + BAN::ScopeGuard guard([keyboard] { delete keyboard; }); + TRY(keyboard->initialize()); + guard.disable(); + return keyboard; + } + + void PS2Keyboard::on_byte(uint8_t byte) + { + // NOTE: This implementation does not allow using commands + // that respond with more bytes than ACK + switch (m_state) + { + case State::WaitingAck: + { + switch (byte) + { + case PS2::Response::ACK: + m_command_queue.pop(); + m_state = State::Normal; + break; + case PS2::Response::RESEND: + m_state = State::Normal; + break; + case PS2::Response::KEY_ERROR_OR_BUFFER_OVERRUN1: + case PS2::Response::KEY_ERROR_OR_BUFFER_OVERRUN2: + dwarnln("Key detection error or internal buffer overrun"); + break; + default: + dwarnln("Unhandeled byte {2H}", byte); + break; + } + break; + } + case State::Normal: + { + m_byte_buffer[m_byte_index++] = byte; + if (byte != 0xE0 && byte != 0xF0) + buffer_has_key(); + break; + } + } + } + + BAN::ErrorOr PS2Keyboard::initialize() + { + append_command_queue(Command::SET_LEDS, 0x00); + append_command_queue(Command::SCANCODE, PS2::Scancode::SET_SCANCODE_SET2); + append_command_queue(Command::ENABLE_SCANNING); + return {}; + } + + void PS2Keyboard::update() + { + if (m_state == State::WaitingAck) + return; + if (m_command_queue.empty()) + return; + m_state = State::WaitingAck; + m_controller.send_byte(this, m_command_queue.front()); + } + + void PS2Keyboard::append_command_queue(uint8_t byte) + { + if (m_command_queue.full()) + { + dwarnln("PS/2 command queue full"); + return; + } + m_command_queue.push(byte); + } + + void PS2Keyboard::append_command_queue(uint8_t byte1, uint8_t byte2) + { + if (m_command_queue.size() + 2 > m_command_queue.capacity()) + { + dwarnln("PS/2 command queue full"); + return; + } + m_command_queue.push(byte1); + m_command_queue.push(byte2); + } + + void PS2Keyboard::buffer_has_key() + { + uint32_t scancode = 0; + bool extended = false; + bool released = false; + + for (uint8_t i = 0; i < m_byte_index; i++) + { + if (m_byte_buffer[i] == 0xE0) + extended = true; + else if (m_byte_buffer[i] == 0xF0) + released = true; + else + scancode = (scancode << 8) | m_byte_buffer[i]; + } + + if (extended) + scancode |= 0x80000000; + + m_byte_index = 0; + + Key key = m_keymap.key_for_scancode_and_modifiers(scancode, m_modifiers); + + if (key == Key::None) + return; + + if (key == Input::Key::Invalid) + { + dprintln("unknown key for scancode {2H} {}", scancode & 0x7FFFFFFF, extended ? 'E' : ' '); + return; + } + + uint8_t modifier_mask = 0; + uint8_t toggle_mask = 0; + switch (key) + { + case Input::Key::LeftShift: + case Input::Key::RightShift: + modifier_mask = (uint8_t)Input::KeyEvent::Modifier::Shift; + break; + case Input::Key::LeftCtrl: + case Input::Key::RightCtrl: + modifier_mask = (uint8_t)Input::KeyEvent::Modifier::Ctrl; + break; + case Input::Key::Alt: + modifier_mask = (uint8_t)Input::KeyEvent::Modifier::Alt; + break; + case Input::Key::AltGr: + modifier_mask = (uint8_t)Input::KeyEvent::Modifier::AltGr; + break;; + case Input::Key::ScrollLock: + toggle_mask = (uint8_t)Input::KeyEvent::Modifier::ScrollLock; + break; + case Input::Key::NumLock: + toggle_mask = (uint8_t)Input::KeyEvent::Modifier::NumLock; + break; + case Input::Key::CapsLock: + toggle_mask = (uint8_t)Input::KeyEvent::Modifier::CapsLock; + break; + default: + break; + } + + if (modifier_mask) + { + if (released) + m_modifiers &= ~modifier_mask; + else + m_modifiers |= modifier_mask; + } + + if (toggle_mask && !released) + { + m_modifiers ^= toggle_mask; + update_leds(); + } + + Input::KeyEvent event; + event.modifier = m_modifiers | (released ? (uint8_t)Input::KeyEvent::Modifier::Released : 0); + event.key = key; + + if (m_event_queue.full()) + { + dwarnln("PS/2 event queue full"); + m_event_queue.pop(); + } + m_event_queue.push(event); + } + + + void PS2Keyboard::update_leds() + { + uint8_t new_leds = 0; + if (m_modifiers & (uint8_t)Input::KeyEvent::Modifier::ScrollLock) + new_leds |= PS2::Leds::SCROLL_LOCK; + if (m_modifiers & (uint8_t)Input::KeyEvent::Modifier::NumLock) + new_leds |= PS2::Leds::NUM_LOCK; + if (m_modifiers & (uint8_t)Input::KeyEvent::Modifier::CapsLock) + new_leds |= PS2::Leds::CAPS_LOCK; + append_command_queue(Command::SET_LEDS, new_leds); + } + + BAN::ErrorOr PS2Keyboard::read(BAN::Span output) + { + if (output.size() < sizeof(Input::KeyEvent)) + return BAN::Error::from_c_string("Too small buffer for KeyEvent"); + + while (m_event_queue.empty()) + PIT::sleep(1); + + CriticalScope _; + *(Input::KeyEvent*)output.data() = m_event_queue.front(); + m_event_queue.pop(); + + return {}; + } + +} \ No newline at end of file diff --git a/kernel/kernel/Input/PS2Keymap.cpp b/kernel/kernel/Input/PS2Keymap.cpp new file mode 100644 index 000000000..559d8a6e3 --- /dev/null +++ b/kernel/kernel/Input/PS2Keymap.cpp @@ -0,0 +1,360 @@ +#include + +namespace Kernel::Input +{ + + PS2Keymap::PS2Keymap() + { + MUST(m_normal_keymap.resize(0xFF, Key::Invalid)); + m_normal_keymap[0x01] = Key::F9; + m_normal_keymap[0x03] = Key::F5; + m_normal_keymap[0x04] = Key::F3; + m_normal_keymap[0x05] = Key::F1; + m_normal_keymap[0x06] = Key::F2; + m_normal_keymap[0x07] = Key::F11; + m_normal_keymap[0x09] = Key::F10; + m_normal_keymap[0x0A] = Key::F8; + m_normal_keymap[0x0B] = Key::F6; + m_normal_keymap[0x0C] = Key::F4; + m_normal_keymap[0x0D] = Key::Tab; + m_normal_keymap[0x0E] = Key::Section; + m_normal_keymap[0x11] = Key::Alt; + m_normal_keymap[0x12] = Key::LeftShift; + m_normal_keymap[0x14] = Key::LeftCtrl; + m_normal_keymap[0x15] = Key::Q; + m_normal_keymap[0x16] = Key::_1; + m_normal_keymap[0x1A] = Key::Z; + m_normal_keymap[0x1B] = Key::S; + m_normal_keymap[0x1C] = Key::A; + m_normal_keymap[0x1D] = Key::W; + m_normal_keymap[0x1E] = Key::_2; + m_normal_keymap[0x21] = Key::C; + m_normal_keymap[0x22] = Key::X; + m_normal_keymap[0x23] = Key::D; + m_normal_keymap[0x24] = Key::E; + m_normal_keymap[0x25] = Key::_4; + m_normal_keymap[0x26] = Key::_3; + m_normal_keymap[0x29] = Key::Space; + m_normal_keymap[0x2A] = Key::V; + m_normal_keymap[0x2B] = Key::F; + m_normal_keymap[0x2C] = Key::T; + m_normal_keymap[0x2D] = Key::R; + m_normal_keymap[0x2E] = Key::_5; + m_normal_keymap[0x31] = Key::N; + m_normal_keymap[0x32] = Key::B; + m_normal_keymap[0x33] = Key::H; + m_normal_keymap[0x34] = Key::G; + m_normal_keymap[0x35] = Key::Y; + m_normal_keymap[0x36] = Key::_6; + m_normal_keymap[0x3A] = Key::M; + m_normal_keymap[0x3B] = Key::J; + m_normal_keymap[0x3C] = Key::U; + m_normal_keymap[0x3D] = Key::_7; + m_normal_keymap[0x3E] = Key::_8; + m_normal_keymap[0x41] = Key::Comma; + m_normal_keymap[0x42] = Key::K; + m_normal_keymap[0x43] = Key::I; + m_normal_keymap[0x44] = Key::O; + m_normal_keymap[0x45] = Key::_0; + m_normal_keymap[0x46] = Key::_9; + m_normal_keymap[0x49] = Key::Period; + m_normal_keymap[0x4A] = Key::Hyphen; + m_normal_keymap[0x4B] = Key::L; + m_normal_keymap[0x4C] = Key::O_Umlaut; + m_normal_keymap[0x4D] = Key::P; + m_normal_keymap[0x4E] = Key::Plus; + m_normal_keymap[0x52] = Key::A_Umlaut; + m_normal_keymap[0x54] = Key::A_Ring; + m_normal_keymap[0x55] = Key::Acute; + m_normal_keymap[0x58] = Key::CapsLock; + m_normal_keymap[0x59] = Key::RightShift; + m_normal_keymap[0x59] = Key::RightShift; + m_normal_keymap[0x5A] = Key::Enter; + m_normal_keymap[0x5B] = Key::TwoDots; + m_normal_keymap[0x5D] = Key::SingleQuote; + m_normal_keymap[0x61] = Key::LessThan; + m_normal_keymap[0x66] = Key::Backspace; + m_normal_keymap[0x69] = Key::Numpad1; + m_normal_keymap[0x6B] = Key::Numpad4; + m_normal_keymap[0x6C] = Key::Numpad7; + m_normal_keymap[0x70] = Key::Numpad0; + m_normal_keymap[0x71] = Key::NumpadDecimal; + m_normal_keymap[0x72] = Key::Numpad2; + m_normal_keymap[0x73] = Key::Numpad5; + m_normal_keymap[0x74] = Key::Numpad6; + m_normal_keymap[0x75] = Key::Numpad8; + m_normal_keymap[0x76] = Key::Escape; + m_normal_keymap[0x77] = Key::NumLock; + m_normal_keymap[0x78] = Key::F11; + m_normal_keymap[0x79] = Key::NumpadPlus; + m_normal_keymap[0x7A] = Key::Numpad3; + m_normal_keymap[0x7B] = Key::NumpadMinus; + m_normal_keymap[0x7C] = Key::NumpadMultiply; + m_normal_keymap[0x7D] = Key::Numpad9; + m_normal_keymap[0x83] = Key::F7; + + MUST(m_shift_keymap.resize(0xFF, Key::Invalid)); + m_shift_keymap[0x01] = Key::F9; + m_shift_keymap[0x03] = Key::F5; + m_shift_keymap[0x04] = Key::F3; + m_shift_keymap[0x05] = Key::F1; + m_shift_keymap[0x06] = Key::F2; + m_shift_keymap[0x07] = Key::F11; + m_shift_keymap[0x09] = Key::F10; + m_shift_keymap[0x0A] = Key::F8; + m_shift_keymap[0x0B] = Key::F6; + m_shift_keymap[0x0C] = Key::F4; + m_shift_keymap[0x0D] = Key::Tab; + m_shift_keymap[0x0E] = Key::Half; + m_shift_keymap[0x11] = Key::Alt; + m_shift_keymap[0x12] = Key::LeftShift; + m_shift_keymap[0x14] = Key::LeftCtrl; + m_shift_keymap[0x15] = Key::Q; + m_shift_keymap[0x16] = Key::ExclamationMark; + m_shift_keymap[0x1A] = Key::Z; + m_shift_keymap[0x1B] = Key::S; + m_shift_keymap[0x1C] = Key::A; + m_shift_keymap[0x1D] = Key::W; + m_shift_keymap[0x1E] = Key::DoubleQuote; + m_shift_keymap[0x21] = Key::C; + m_shift_keymap[0x22] = Key::X; + m_shift_keymap[0x23] = Key::D; + m_shift_keymap[0x24] = Key::E; + m_shift_keymap[0x25] = Key::Currency; + m_shift_keymap[0x26] = Key::Hashtag; + m_shift_keymap[0x29] = Key::Space; + m_shift_keymap[0x2A] = Key::V; + m_shift_keymap[0x2B] = Key::F; + m_shift_keymap[0x2C] = Key::T; + m_shift_keymap[0x2D] = Key::R; + m_shift_keymap[0x2E] = Key::Percent; + m_shift_keymap[0x31] = Key::N; + m_shift_keymap[0x32] = Key::B; + m_shift_keymap[0x33] = Key::H; + m_shift_keymap[0x34] = Key::G; + m_shift_keymap[0x35] = Key::Y; + m_shift_keymap[0x36] = Key::Ampersand; + m_shift_keymap[0x3A] = Key::M; + m_shift_keymap[0x3B] = Key::J; + m_shift_keymap[0x3C] = Key::U; + m_shift_keymap[0x3D] = Key::Slash; + m_shift_keymap[0x3E] = Key::OpenBracet; + m_shift_keymap[0x41] = Key::Semicolon; + m_shift_keymap[0x42] = Key::K; + m_shift_keymap[0x43] = Key::I; + m_shift_keymap[0x44] = Key::O; + m_shift_keymap[0x45] = Key::Equals; + m_shift_keymap[0x46] = Key::CloseBracet; + m_shift_keymap[0x49] = Key::Period; + m_shift_keymap[0x4A] = Key::Hyphen; + m_shift_keymap[0x4B] = Key::L; + m_shift_keymap[0x4C] = Key::O_Umlaut; + m_shift_keymap[0x4D] = Key::P; + m_shift_keymap[0x4E] = Key::QuestionMark; + m_shift_keymap[0x52] = Key::A_Umlaut; + m_shift_keymap[0x54] = Key::A_Ring; + m_shift_keymap[0x55] = Key::BackTick; + m_shift_keymap[0x58] = Key::CapsLock; + m_shift_keymap[0x59] = Key::RightShift; + m_shift_keymap[0x59] = Key::RightShift; + m_shift_keymap[0x5A] = Key::Enter; + m_shift_keymap[0x5B] = Key::Caret; + m_shift_keymap[0x5D] = Key::Asterix; + m_shift_keymap[0x61] = Key::GreaterThan; + m_shift_keymap[0x66] = Key::Backspace; + m_shift_keymap[0x69] = Key::Numpad1; + m_shift_keymap[0x6B] = Key::Numpad4; + m_shift_keymap[0x6C] = Key::Numpad7; + m_shift_keymap[0x70] = Key::Numpad0; + m_shift_keymap[0x71] = Key::NumpadDecimal; + m_shift_keymap[0x72] = Key::Numpad2; + m_shift_keymap[0x73] = Key::Numpad5; + m_shift_keymap[0x74] = Key::Numpad6; + m_shift_keymap[0x75] = Key::Numpad8; + m_shift_keymap[0x76] = Key::Escape; + m_shift_keymap[0x77] = Key::NumLock; + m_shift_keymap[0x78] = Key::F11; + m_shift_keymap[0x79] = Key::NumpadPlus; + m_shift_keymap[0x7A] = Key::Numpad3; + m_shift_keymap[0x7B] = Key::NumpadMinus; + m_shift_keymap[0x7C] = Key::NumpadMultiply; + m_shift_keymap[0x7D] = Key::Numpad9; + m_shift_keymap[0x83] = Key::F7; + + MUST(m_altgr_keymap.resize(0xFF, Key::Invalid)); + m_altgr_keymap[0x01] = Key::F9; + m_altgr_keymap[0x03] = Key::F5; + m_altgr_keymap[0x04] = Key::F3; + m_altgr_keymap[0x05] = Key::F1; + m_altgr_keymap[0x06] = Key::F2; + m_altgr_keymap[0x07] = Key::F11; + m_altgr_keymap[0x09] = Key::F10; + m_altgr_keymap[0x0A] = Key::F8; + m_altgr_keymap[0x0B] = Key::F6; + m_altgr_keymap[0x0C] = Key::F4; + m_altgr_keymap[0x0D] = Key::Tab; + m_altgr_keymap[0x0E] = Key::None; + m_altgr_keymap[0x11] = Key::Alt; + m_altgr_keymap[0x12] = Key::LeftShift; + m_altgr_keymap[0x14] = Key::LeftCtrl; + m_altgr_keymap[0x15] = Key::Q; + m_altgr_keymap[0x16] = Key::None; + m_altgr_keymap[0x1A] = Key::Z; + m_altgr_keymap[0x1B] = Key::S; + m_altgr_keymap[0x1C] = Key::A; + m_altgr_keymap[0x1D] = Key::W; + m_altgr_keymap[0x1E] = Key::AtSign; + m_altgr_keymap[0x21] = Key::C; + m_altgr_keymap[0x22] = Key::X; + m_altgr_keymap[0x23] = Key::D; + m_altgr_keymap[0x24] = Key::E; + m_altgr_keymap[0x25] = Key::Dollar; + m_altgr_keymap[0x26] = Key::Pound; + m_altgr_keymap[0x29] = Key::Space; + m_altgr_keymap[0x2A] = Key::V; + m_altgr_keymap[0x2B] = Key::F; + m_altgr_keymap[0x2C] = Key::T; + m_altgr_keymap[0x2D] = Key::R; + m_altgr_keymap[0x2E] = Key::None; + m_altgr_keymap[0x31] = Key::N; + m_altgr_keymap[0x32] = Key::B; + m_altgr_keymap[0x33] = Key::H; + m_altgr_keymap[0x34] = Key::G; + m_altgr_keymap[0x35] = Key::Y; + m_altgr_keymap[0x36] = Key::None; + m_altgr_keymap[0x3A] = Key::M; + m_altgr_keymap[0x3B] = Key::J; + m_altgr_keymap[0x3C] = Key::U; + m_altgr_keymap[0x3D] = Key::OpenCurlyBrace; + m_altgr_keymap[0x3E] = Key::OpenBrace; + m_altgr_keymap[0x41] = Key::None; + m_altgr_keymap[0x42] = Key::K; + m_altgr_keymap[0x43] = Key::I; + m_altgr_keymap[0x44] = Key::O; + m_altgr_keymap[0x45] = Key::CloseCurlyBrace; + m_altgr_keymap[0x46] = Key::CloseBrace; + m_altgr_keymap[0x49] = Key::None; + m_altgr_keymap[0x4A] = Key::None; + m_altgr_keymap[0x4B] = Key::L; + m_altgr_keymap[0x4C] = Key::O_Umlaut; + m_altgr_keymap[0x4D] = Key::P; + m_altgr_keymap[0x4E] = Key::BackSlash; + m_altgr_keymap[0x52] = Key::A_Umlaut; + m_altgr_keymap[0x54] = Key::A_Ring; + m_altgr_keymap[0x55] = Key::None; + m_altgr_keymap[0x58] = Key::CapsLock; + m_altgr_keymap[0x59] = Key::RightShift; + m_altgr_keymap[0x59] = Key::RightShift; + m_altgr_keymap[0x5A] = Key::Enter; + m_altgr_keymap[0x5B] = Key::Tilde; + m_altgr_keymap[0x5D] = Key::None; + m_altgr_keymap[0x61] = Key::Pipe; + m_altgr_keymap[0x66] = Key::Backspace; + m_altgr_keymap[0x69] = Key::Numpad1; + m_altgr_keymap[0x6B] = Key::Numpad4; + m_altgr_keymap[0x6C] = Key::Numpad7; + m_altgr_keymap[0x70] = Key::Numpad0; + m_altgr_keymap[0x71] = Key::NumpadDecimal; + m_altgr_keymap[0x72] = Key::Numpad2; + m_altgr_keymap[0x73] = Key::Numpad5; + m_altgr_keymap[0x74] = Key::Numpad6; + m_altgr_keymap[0x75] = Key::Numpad8; + m_altgr_keymap[0x76] = Key::Escape; + m_altgr_keymap[0x77] = Key::NumLock; + m_altgr_keymap[0x78] = Key::F11; + m_altgr_keymap[0x79] = Key::NumpadPlus; + m_altgr_keymap[0x7A] = Key::Numpad3; + m_altgr_keymap[0x7B] = Key::NumpadMinus; + m_altgr_keymap[0x7C] = Key::NumpadMultiply; + m_altgr_keymap[0x7D] = Key::Numpad9; + m_altgr_keymap[0x83] = Key::F7; + + MUST(m_extended_keymap.resize(0xFF, Key::Invalid)); + m_extended_keymap[0x11] = Key::AltGr; + m_extended_keymap[0x14] = Key::RightCtrl; + m_extended_keymap[0x15] = Key::MediaPrevious; + m_extended_keymap[0x1F] = Key::Super; + m_extended_keymap[0x21] = Key::VolumeUp; + m_extended_keymap[0x23] = Key::VolumeMute; + m_extended_keymap[0x2B] = Key::Calculator; + m_extended_keymap[0x32] = Key::VolumeDown; + m_extended_keymap[0x34] = Key::MediaPlayPause; + m_extended_keymap[0x3B] = Key::MediaStop; + m_extended_keymap[0x4A] = Key::NumpadDivide; + m_extended_keymap[0x4D] = Key::MediaNext; + m_extended_keymap[0x5A] = Key::NumpadEnter; + m_extended_keymap[0x69] = Key::End; + m_extended_keymap[0x6B] = Key::ArrowLeft; + m_extended_keymap[0x6C] = Key::Home; + m_extended_keymap[0x70] = Key::Insert; + m_extended_keymap[0x71] = Key::Delete; + m_extended_keymap[0x72] = Key::ArrowDown; + m_extended_keymap[0x74] = Key::ArrowRight; + m_extended_keymap[0x75] = Key::ArrowUp; + m_extended_keymap[0x7A] = Key::PageUp; + m_extended_keymap[0x7D] = Key::PageDown; + } + + Key PS2Keymap::key_for_scancode_and_modifiers(uint32_t scancode, uint8_t modifiers) + { + bool extended = scancode & 0x80000000; + scancode &= 0x7FFFFFFF; + + KeyEvent dummy; + dummy.modifier = modifiers; + auto& keymap = extended ? m_extended_keymap : + dummy.shift() ? m_shift_keymap : + dummy.altgr() ? m_altgr_keymap : + m_normal_keymap; + + if (scancode >= keymap.size()) + return Key::Invalid; + + Key key = keymap[scancode]; + + if (dummy.num_lock() && !(dummy.shift() || dummy.ctrl() || dummy.alt())) + { + switch (key) + { + case Key::Numpad0: + key = Key::Insert; + break; + case Key::Numpad1: + key = Key::End; + break; + case Key::Numpad2: + key = Key::ArrowDown; + break; + case Key::Numpad3: + key = Key::PageDown; + break; + case Key::Numpad4: + key = Key::ArrowLeft; + break; + case Key::Numpad5: + key = Key::None; + break; + case Key::Numpad6: + key = Key::ArrowRight; + break; + case Key::Numpad7: + key = Key::Home; + break; + case Key::Numpad8: + key = Key::ArrowUp; + break; + case Key::Numpad9: + key = Key::PageUp; + break; + case Key::NumpadDecimal: + key = Key::Delete; + break; + default: + break; + } + } + + return keymap[scancode]; + } + +} \ No newline at end of file diff --git a/kernel/kernel/Shell.cpp b/kernel/kernel/Shell.cpp index 9b9a6e263..18de43565 100644 --- a/kernel/kernel/Shell.cpp +++ b/kernel/kernel/Shell.cpp @@ -3,7 +3,7 @@ #include #include #include -#include +#include #include #include #include @@ -25,7 +25,6 @@ namespace Kernel Shell::Shell(TTY* tty) : m_tty(tty) { - Input::register_key_event_callback({ &Shell::key_event_callback, this }); MUST(set_prompt(s_default_prompt)); MUST(m_buffer.push_back(""sv)); } @@ -83,8 +82,9 @@ namespace Kernel TTY_PRINT("{}", m_prompt); for (;;) { - PIT::sleep(1); // sleep until next reschedule - Input::update(); + Input::KeyEvent event; + MUST(((CharacterDevice*)DeviceManager::get().devices()[0])->read({ (uint8_t*)&event, sizeof(event) })); + key_event_callback(event); } } @@ -560,7 +560,7 @@ argument_done: void Shell::key_event_callback(Input::KeyEvent event) { - if (!event.pressed) + if (event.released()) return; BAN::String& current_buffer = m_buffer[m_cursor_pos.line]; @@ -606,7 +606,7 @@ argument_done: case Input::Key::Tab: break; - case Input::Key::Left: + case Input::Key::ArrowLeft: if (m_cursor_pos.index > 0) { uint32_t len = get_last_length(current_buffer.sv().substring(0, m_cursor_pos.index)); @@ -615,7 +615,7 @@ argument_done: } break; - case Input::Key::Right: + case Input::Key::ArrowRight: if (m_cursor_pos.index < current_buffer.size()) { uint32_t len = get_next_length(current_buffer.sv().substring(m_cursor_pos.index)); @@ -624,7 +624,7 @@ argument_done: } break; - case Input::Key::Up: + case Input::Key::ArrowUp: if (m_cursor_pos.line > 0) { const auto& new_buffer = m_buffer[m_cursor_pos.line - 1]; @@ -635,7 +635,7 @@ argument_done: } break; - case Input::Key::Down: + case Input::Key::ArrowDown: if (m_cursor_pos.line < m_buffer.size() - 1) { const auto& new_buffer = m_buffer[m_cursor_pos.line + 1]; @@ -647,7 +647,7 @@ argument_done: break; case Input::Key::A: - if (event.modifiers & 2) + if (event.ctrl()) { m_cursor_pos.col = m_cursor_pos.index = 0; break; diff --git a/kernel/kernel/kernel.cpp b/kernel/kernel/kernel.cpp index 99fb75632..d1c1bbcc1 100644 --- a/kernel/kernel/kernel.cpp +++ b/kernel/kernel/kernel.cpp @@ -4,7 +4,7 @@ #include #include #include -#include +#include #include #include #include @@ -88,6 +88,7 @@ extern "C" uintptr_t g_userspace_end; extern void userspace_entry(); void init2(void*); +void device_updater(void*); extern "C" void kernel_main() { @@ -136,10 +137,6 @@ extern "C" void kernel_main() PIT::initialize(); dprintln("PIT initialized"); - if (!Input::initialize()) - dprintln("Could not initialize input drivers"); - dprintln("Input initialized"); - MUST(Scheduler::initialize()); Scheduler& scheduler = Scheduler::get(); #if 0 @@ -186,15 +183,26 @@ extern "C" void kernel_main() } )))); #else - MUST(scheduler.add_thread(MUST(Thread::create(init2, tty1, nullptr)))); + MUST(scheduler.add_thread(MUST(Thread::create(init2, tty1)))); + MUST(scheduler.add_thread(MUST(Thread::create(device_updater)))); #endif scheduler.start(); ASSERT(false); } +void device_updater(void*) +{ + while (true) + { + Kernel::DeviceManager::get().update(); + PIT::sleep(1); + } +} + void init2(void* tty1_ptr) { using namespace Kernel; + using namespace Kernel::Input; TTY* tty1 = (TTY*)tty1_ptr; @@ -202,6 +210,9 @@ void init2(void* tty1_ptr) if (auto res = VirtualFileSystem::get().mount_test(); res.is_error()) dwarnln("{}", res.error()); + if (auto res = PS2Controller::initialize(); res.is_error()) + dprintln("{}", res.error()); + MUST(Process::create_kernel( [](void* tty1) {