From 8f8d6bddc04f9671a9010cfa836ef9323c229d1d Mon Sep 17 00:00:00 2001 From: Bananymous Date: Thu, 4 Jan 2024 10:43:14 +0200 Subject: [PATCH] Kernel: Unify PS2Device to handle commands instead of inherited --- kernel/include/kernel/Input/PS2Config.h | 4 +- kernel/include/kernel/Input/PS2Controller.h | 26 ++++++- kernel/include/kernel/Input/PS2Keyboard.h | 24 +------ kernel/kernel/Input/PS2Controller.cpp | 73 +++++++++++++++++-- kernel/kernel/Input/PS2Keyboard.cpp | 79 ++++----------------- 5 files changed, 111 insertions(+), 95 deletions(-) diff --git a/kernel/include/kernel/Input/PS2Config.h b/kernel/include/kernel/Input/PS2Config.h index 71fbdbc2..b7c708ec 100644 --- a/kernel/include/kernel/Input/PS2Config.h +++ b/kernel/include/kernel/Input/PS2Config.h @@ -55,6 +55,7 @@ namespace Kernel::Input::PS2 TEST_CONTROLLER_PASS = 0x55, SELF_TEST_PASS = 0xAA, ACK = 0xFA, + RESEND = 0xFE, }; enum DeviceCommand : uint8_t @@ -74,9 +75,6 @@ namespace Kernel::Input::PS2 enum KBResponse : uint8_t { KEY_ERROR_OR_BUFFER_OVERRUN1 = 0x00, - SELF_TEST_PASSED = 0xAA, - ECHO_RESPONSE = 0xEE, - RESEND = 0xFE, KEY_ERROR_OR_BUFFER_OVERRUN2 = 0xFF, }; diff --git a/kernel/include/kernel/Input/PS2Controller.h b/kernel/include/kernel/Input/PS2Controller.h index e451313d..07ea3db7 100644 --- a/kernel/include/kernel/Input/PS2Controller.h +++ b/kernel/include/kernel/Input/PS2Controller.h @@ -1,23 +1,47 @@ #pragma once +#include #include #include namespace Kernel::Input { + class PS2Controller; + class PS2Device : public CharacterDevice, public Interruptable { public: - PS2Device(); + PS2Device(PS2Controller&); virtual ~PS2Device() {} virtual void send_initialize() = 0; + bool append_command_queue(uint8_t command); + bool append_command_queue(uint8_t command, uint8_t data); + virtual void handle_irq() final override; + + virtual void handle_byte(uint8_t) = 0; + virtual void handle_device_command_response(uint8_t) = 0; + virtual BAN::StringView name() const override { return m_name; } + protected: + void update(); + + private: + enum class State + { + Normal, + WaitingAck, + }; + private: const BAN::String m_name; + + PS2Controller& m_controller; + State m_state = State::Normal; + BAN::CircularQueue m_command_queue; }; class PS2Controller diff --git a/kernel/include/kernel/Input/PS2Keyboard.h b/kernel/include/kernel/Input/PS2Keyboard.h index 84907754..04e6681e 100644 --- a/kernel/include/kernel/Input/PS2Keyboard.h +++ b/kernel/include/kernel/Input/PS2Keyboard.h @@ -1,6 +1,5 @@ #pragma once -#include #include #include #include @@ -15,48 +14,31 @@ namespace Kernel::Input enum Command : uint8_t { SET_LEDS = 0xED, - SCANCODE = 0xF0, - ENABLE_SCANNING = 0xF4, - DISABLE_SCANNING = 0xF5, - }; - - enum class State - { - Normal, - WaitingAck, + SCANCODE = 0xF0 }; public: static BAN::ErrorOr create(PS2Controller&); virtual void send_initialize() override; - virtual void handle_irq() override; - virtual void update() override; + virtual void handle_byte(uint8_t) final override; + virtual void handle_device_command_response(uint8_t) final override; private: PS2Keyboard(PS2Controller& controller); - 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 }; - Semaphore m_semaphore; public: diff --git a/kernel/kernel/Input/PS2Controller.cpp b/kernel/kernel/Input/PS2Controller.cpp index 6faa2593..6abc87ff 100644 --- a/kernel/kernel/Input/PS2Controller.cpp +++ b/kernel/kernel/Input/PS2Controller.cpp @@ -68,11 +68,6 @@ namespace Kernel::Input static PS2Controller* s_instance = nullptr; - PS2Device::PS2Device() - : CharacterDevice(0440, 0, 901) - , m_name(BAN::String::formatted("input{}", DevFileSystem::get().get_next_input_device())) - { } - BAN::ErrorOr PS2Controller::initialize() { ASSERT(s_instance == nullptr); @@ -253,4 +248,72 @@ namespace Kernel::Input return {}; } + PS2Device::PS2Device(PS2Controller& controller) + : CharacterDevice(0440, 0, 901) + , m_name(BAN::String::formatted("input{}", DevFileSystem::get().get_next_input_device())) + , m_controller(controller) + { } + + bool PS2Device::append_command_queue(uint8_t command) + { + if (m_command_queue.size() + 1 >= m_command_queue.capacity()) + return false; + m_command_queue.push(command); + return true; + } + + bool PS2Device::append_command_queue(uint8_t command, uint8_t data) + { + if (m_command_queue.size() + 2 >= m_command_queue.capacity()) + return false; + m_command_queue.push(command); + m_command_queue.push(data); + return true; + } + + void PS2Device::handle_irq() + { + uint8_t byte = IO::inb(PS2::IOPort::DATA); + + // 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; + default: + handle_device_command_response(byte); + break; + } + break; + } + case State::Normal: + { + handle_byte(byte); + break; + } + } + + update(); + } + + void PS2Device::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()); + } + } \ No newline at end of file diff --git a/kernel/kernel/Input/PS2Keyboard.cpp b/kernel/kernel/Input/PS2Keyboard.cpp index a9ea3340..a33e4f04 100644 --- a/kernel/kernel/Input/PS2Keyboard.cpp +++ b/kernel/kernel/Input/PS2Keyboard.cpp @@ -23,89 +23,38 @@ namespace Kernel::Input } PS2Keyboard::PS2Keyboard(PS2Controller& controller) - : m_controller(controller) + : PS2Device(controller) , m_rdev(makedev(DevFileSystem::get().get_next_dev(), 0)) { } - void PS2Keyboard::handle_irq() - { - uint8_t byte = IO::inb(PS2::IOPort::DATA); - - // 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::KBResponse::RESEND: - m_state = State::Normal; - break; - case PS2::KBResponse::KEY_ERROR_OR_BUFFER_OVERRUN1: - case PS2::KBResponse::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; - } - } - } - void PS2Keyboard::send_initialize() { append_command_queue(Command::SET_LEDS, 0x00); append_command_queue(Command::SCANCODE, PS2::KBScancode::SET_SCANCODE_SET2); append_command_queue(Command::ENABLE_SCANNING); + update(); } - void PS2Keyboard::update() + void PS2Keyboard::handle_device_command_response(uint8_t byte) { - 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()) + switch (byte) { - dwarnln("PS/2 command queue full"); - return; + case PS2::KBResponse::KEY_ERROR_OR_BUFFER_OVERRUN1: + case PS2::KBResponse::KEY_ERROR_OR_BUFFER_OVERRUN2: + dwarnln("Key detection error or internal buffer overrun"); + break; + default: + dwarnln("Unhandeled byte {2H}", byte); + break; } - m_command_queue.push(byte); } - void PS2Keyboard::append_command_queue(uint8_t byte1, uint8_t byte2) + void PS2Keyboard::handle_byte(uint8_t byte) { - if (m_command_queue.size() + 2 > m_command_queue.capacity()) - { - dwarnln("PS/2 command queue full"); + m_byte_buffer[m_byte_index++] = byte; + if (byte == 0xE0 || byte == 0xF0) 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;