From a97a574718e1e2712ac4384f6a1b8efeca337429 Mon Sep 17 00:00:00 2001 From: Bananymous Date: Fri, 12 Jul 2024 20:45:15 +0300 Subject: [PATCH] Kernel: Rewrite the whole input system PS/2 code is now kind of messed up, but it works. Keyboards and mice are now an abstract class that is automatically exposed to userspace. This will make adding USB input much nicer. --- kernel/CMakeLists.txt | 1 + kernel/include/kernel/Device/DeviceNumbers.h | 3 +- kernel/include/kernel/FS/DevFS/FileSystem.h | 2 - kernel/include/kernel/Input/InputDevice.h | 50 +++++++++ kernel/include/kernel/Input/PS2/Controller.h | 1 + kernel/include/kernel/Input/PS2/Device.h | 16 +-- kernel/include/kernel/Input/PS2/Keyboard.h | 20 +--- kernel/include/kernel/Input/PS2/Mouse.h | 18 +--- kernel/kernel/FS/DevFS/FileSystem.cpp | 6 -- kernel/kernel/Input/InputDevice.cpp | 104 +++++++++++++++++++ kernel/kernel/Input/PS2/Controller.cpp | 12 +-- kernel/kernel/Input/PS2/Device.cpp | 9 +- kernel/kernel/Input/PS2/Keyboard.cpp | 48 +-------- kernel/kernel/Input/PS2/Mouse.cpp | 76 ++------------ kernel/kernel/Terminal/TTY.cpp | 2 +- userspace/programs/WindowServer/main.cpp | 4 +- userspace/tests/test-mouse/main.cpp | 2 +- 17 files changed, 197 insertions(+), 177 deletions(-) create mode 100644 kernel/include/kernel/Input/InputDevice.h create mode 100644 kernel/kernel/Input/InputDevice.cpp diff --git a/kernel/CMakeLists.txt b/kernel/CMakeLists.txt index 2925999db0..1c2e763c4d 100644 --- a/kernel/CMakeLists.txt +++ b/kernel/CMakeLists.txt @@ -34,6 +34,7 @@ set(KERNEL_SOURCES kernel/FS/VirtualFileSystem.cpp kernel/GDT.cpp kernel/IDT.cpp + kernel/Input/InputDevice.cpp kernel/Input/PS2/Controller.cpp kernel/Input/PS2/Device.cpp kernel/Input/PS2/Keyboard.cpp diff --git a/kernel/include/kernel/Device/DeviceNumbers.h b/kernel/include/kernel/Device/DeviceNumbers.h index a60184e846..0f019e138e 100644 --- a/kernel/include/kernel/Device/DeviceNumbers.h +++ b/kernel/include/kernel/Device/DeviceNumbers.h @@ -13,7 +13,8 @@ namespace Kernel Null, Zero, Debug, - Input, + Keyboard, + Mouse, SCSI, NVMeController, NVMeNamespace, diff --git a/kernel/include/kernel/FS/DevFS/FileSystem.h b/kernel/include/kernel/FS/DevFS/FileSystem.h index 940da8411f..3e7feee796 100644 --- a/kernel/include/kernel/FS/DevFS/FileSystem.h +++ b/kernel/include/kernel/FS/DevFS/FileSystem.h @@ -20,8 +20,6 @@ namespace Kernel void add_device(BAN::RefPtr); void add_inode(BAN::StringView path, BAN::RefPtr); - int get_next_input_device() const; - void initiate_sync(bool should_block); private: diff --git a/kernel/include/kernel/Input/InputDevice.h b/kernel/include/kernel/Input/InputDevice.h new file mode 100644 index 0000000000..fe3f3ca714 --- /dev/null +++ b/kernel/include/kernel/Input/InputDevice.h @@ -0,0 +1,50 @@ +#pragma once + +#include + +#include + +namespace Kernel +{ + + class InputDevice : public CharacterDevice + { + public: + enum class Type + { + Mouse, + Keyboard, + }; + + public: + InputDevice(Type type); + + protected: + void add_event(BAN::ConstByteSpan); + + BAN::ErrorOr read_impl(off_t, BAN::ByteSpan) override; + + bool can_read_impl() const override { SpinLockGuard _(m_event_lock); return m_event_count > 0; } + bool can_write_impl() const override { return false; } + bool has_error_impl() const override { return false; } + + virtual BAN::StringView name() const final override { return m_name; } + virtual dev_t rdev() const final override { return m_rdev; } + + private: + const dev_t m_rdev; + const BAN::String m_name; + + mutable SpinLock m_event_lock; + Semaphore m_event_semaphore; + + static constexpr size_t m_max_event_count { 128 }; + + BAN::Vector m_event_buffer; + const size_t m_event_size; + size_t m_event_tail { 0 }; + size_t m_event_head { 0 }; + size_t m_event_count { 0 }; + }; + +} diff --git a/kernel/include/kernel/Input/PS2/Controller.h b/kernel/include/kernel/Input/PS2/Controller.h index c620ddcbd3..0eeb695b69 100644 --- a/kernel/include/kernel/Input/PS2/Controller.h +++ b/kernel/include/kernel/Input/PS2/Controller.h @@ -60,6 +60,7 @@ namespace Kernel::Input private: BAN::RefPtr m_devices[2]; + Mutex m_mutex; BAN::CircularQueue m_command_queue; diff --git a/kernel/include/kernel/Input/PS2/Device.h b/kernel/include/kernel/Input/PS2/Device.h index ba399b9144..a5869d587c 100644 --- a/kernel/include/kernel/Input/PS2/Device.h +++ b/kernel/include/kernel/Input/PS2/Device.h @@ -1,16 +1,15 @@ #pragma once #include +#include #include namespace Kernel::Input { - class PS2Device : public CharacterDevice, public Interruptable + class PS2Device : public Interruptable, public InputDevice { public: - virtual ~PS2Device() {} - virtual void send_initialize() = 0; virtual void command_timedout(uint8_t* command_data, uint8_t command_size) = 0; @@ -21,17 +20,10 @@ namespace Kernel::Input virtual void handle_byte(uint8_t) = 0; - virtual BAN::StringView name() const final override { return m_name; } - virtual dev_t rdev() const final override { return m_rdev; } - - virtual void update() final override { m_controller.update_command_queue(); } + protected: + PS2Device(PS2Controller&, InputDevice::Type type); protected: - PS2Device(PS2Controller&); - - private: - const dev_t m_rdev; - const BAN::String m_name; PS2Controller& m_controller; }; diff --git a/kernel/include/kernel/Input/PS2/Keyboard.h b/kernel/include/kernel/Input/PS2/Keyboard.h index 93b8dc5342..b4a0700926 100644 --- a/kernel/include/kernel/Input/PS2/Keyboard.h +++ b/kernel/include/kernel/Input/PS2/Keyboard.h @@ -1,11 +1,8 @@ #pragma once #include -#include #include #include -#include -#include namespace Kernel::Input { @@ -20,13 +17,15 @@ namespace Kernel::Input }; public: - static BAN::ErrorOr create(PS2Controller&); + static BAN::ErrorOr> create(PS2Controller&); virtual void send_initialize() override; virtual void command_timedout(uint8_t* command_data, uint8_t command_size) final override; virtual void handle_byte(uint8_t) final override; + virtual void update() final override { m_controller.update_command_queue(); } + private: PS2Keyboard(PS2Controller& controller); @@ -37,22 +36,11 @@ namespace Kernel::Input uint8_t m_byte_index { 0 }; uint8_t m_scancode_set { 0xFF }; - uint16_t m_modifiers { 0 }; - BAN::CircularQueue m_event_queue; - SpinLock m_event_lock; - PS2Keymap m_keymap; - Semaphore m_semaphore; - - protected: - virtual BAN::ErrorOr read_impl(off_t, BAN::ByteSpan) override; - - virtual bool can_read_impl() const override { return !m_event_queue.empty(); } - virtual bool can_write_impl() const override { return false; } - virtual bool has_error_impl() const override { return false; } + friend class BAN::RefPtr; }; } diff --git a/kernel/include/kernel/Input/PS2/Mouse.h b/kernel/include/kernel/Input/PS2/Mouse.h index caba0369de..bdf142889e 100644 --- a/kernel/include/kernel/Input/PS2/Mouse.h +++ b/kernel/include/kernel/Input/PS2/Mouse.h @@ -1,8 +1,6 @@ #pragma once #include -#include -#include namespace Kernel::Input { @@ -16,13 +14,15 @@ namespace Kernel::Input }; public: - static BAN::ErrorOr create(PS2Controller&); + static BAN::ErrorOr> create(PS2Controller&); virtual void send_initialize() override; virtual void command_timedout(uint8_t* command_data, uint8_t command_size) final override { (void)command_data; (void)command_size; } virtual void handle_byte(uint8_t) final override; + virtual void update() final override { m_controller.update_command_queue(); } + private: PS2Mouse(PS2Controller& controller); @@ -36,17 +36,7 @@ namespace Kernel::Input uint8_t m_mouse_id { 0x00 }; uint8_t m_button_mask { 0x00 }; - BAN::CircularQueue m_event_queue; - SpinLock m_event_lock; - - Semaphore m_semaphore; - - protected: - virtual BAN::ErrorOr read_impl(off_t, BAN::ByteSpan) override; - - virtual bool can_read_impl() const override { return !m_event_queue.empty(); } - virtual bool can_write_impl() const override { return false; } - virtual bool has_error_impl() const override { return false; } + friend class BAN::RefPtr; }; } diff --git a/kernel/kernel/FS/DevFS/FileSystem.cpp b/kernel/kernel/FS/DevFS/FileSystem.cpp index 426e796703..92c40ec257 100644 --- a/kernel/kernel/FS/DevFS/FileSystem.cpp +++ b/kernel/kernel/FS/DevFS/FileSystem.cpp @@ -119,10 +119,4 @@ namespace Kernel MUST(static_cast(root_inode().ptr())->link_inode(*inode, path)); } - int DevFileSystem::get_next_input_device() const - { - static BAN::Atomic next_dev = 0; - return next_dev++; - } - } diff --git a/kernel/kernel/Input/InputDevice.cpp b/kernel/kernel/Input/InputDevice.cpp new file mode 100644 index 0000000000..95b9a61648 --- /dev/null +++ b/kernel/kernel/Input/InputDevice.cpp @@ -0,0 +1,104 @@ +#include +#include +#include + +#include +#include + +#include + +namespace Kernel +{ + + static BAN::Atomic s_next_keyboard { 0 }; + static BAN::Atomic s_next_mouse { 0 }; + + static const char* get_name_format(InputDevice::Type type) + { + switch (type) + { + case InputDevice::Type::Keyboard: + return "keyboard{}"; + case InputDevice::Type::Mouse: + return "mouse{}"; + } + ASSERT_NOT_REACHED(); + } + + static dev_t get_rdev(InputDevice::Type type) + { + switch (type) + { + case InputDevice::Type::Keyboard: + return makedev(DeviceNumber::Keyboard, s_next_keyboard++); + case InputDevice::Type::Mouse: + return makedev(DeviceNumber::Mouse, s_next_mouse++); + } + ASSERT_NOT_REACHED(); + } + + static size_t get_event_size(InputDevice::Type type) + { + switch (type) + { + case InputDevice::Type::Keyboard: + return sizeof(LibInput::RawKeyEvent); + case InputDevice::Type::Mouse: + return sizeof(LibInput::MouseEvent); + } + ASSERT_NOT_REACHED(); + } + + InputDevice::InputDevice(Type type) + : CharacterDevice(0440, 0, 901) + , m_rdev(get_rdev(type)) + , m_name(MUST(BAN::String::formatted(get_name_format(type), minor(m_rdev)))) + , m_event_size(get_event_size(type)) + { + MUST(m_event_buffer.resize(m_event_size * m_max_event_count, 0)); + } + + void InputDevice::add_event(BAN::ConstByteSpan event) + { + SpinLockGuard _(m_event_lock); + ASSERT(event.size() == m_event_size); + + if (m_event_count == m_max_event_count) + { + m_event_tail = (m_event_tail + 1) % m_max_event_count; + m_event_count--; + } + + memcpy(&m_event_buffer[m_event_head * m_event_size], event.data(), m_event_size); + m_event_head = (m_event_head + 1) % m_max_event_count; + m_event_count++; + + m_event_semaphore.unblock(); + } + + BAN::ErrorOr InputDevice::read_impl(off_t, BAN::ByteSpan buffer) + { + if (buffer.size() < m_event_size) + return BAN::Error::from_errno(ENOBUFS); + + auto state = m_event_lock.lock(); + while (m_event_count == 0) + { + m_event_lock.unlock(state); + { + LockFreeGuard _(m_mutex); + TRY(Thread::current().block_or_eintr_indefinite(m_event_semaphore)); + } + state = m_event_lock.lock(); + } + + memcpy(buffer.data(), &m_event_buffer[m_event_tail * m_event_size], m_event_size); + m_event_tail = (m_event_tail + 1) % m_max_event_count; + m_event_count--; + + m_event_lock.unlock(state); + + return m_event_size; + } + +} diff --git a/kernel/kernel/Input/PS2/Controller.cpp b/kernel/kernel/Input/PS2/Controller.cpp index e48ae9613a..cdc83b1b10 100644 --- a/kernel/kernel/Input/PS2/Controller.cpp +++ b/kernel/kernel/Input/PS2/Controller.cpp @@ -89,9 +89,9 @@ namespace Kernel::Input uint8_t PS2Controller::get_device_index(PS2Device* device) const { ASSERT(device); - if (m_devices[0] && device == m_devices[0].ptr()) + if (m_devices[0].ptr() == device) return 0; - if (m_devices[1] && device == m_devices[1].ptr()) + if (m_devices[1].ptr() == device) return 1; ASSERT_NOT_REACHED(); } @@ -359,12 +359,12 @@ namespace Kernel::Input TRY(send_command(PS2::Command::WRITE_CONFIG, config)); // Send device initialization sequence after interrupts are enabled - for (uint8_t device = 0; device < 2; device++) + for (uint8_t i = 0; i < 2; i++) { - if (!m_devices[device]) + if (!m_devices[i]) continue; - m_devices[device]->send_initialize(); - DevFileSystem::get().add_device(m_devices[device]); + m_devices[i]->send_initialize(); + DevFileSystem::get().add_device(m_devices[i]); } return {}; diff --git a/kernel/kernel/Input/PS2/Device.cpp b/kernel/kernel/Input/PS2/Device.cpp index 37d102187a..011d98a2c7 100644 --- a/kernel/kernel/Input/PS2/Device.cpp +++ b/kernel/kernel/Input/PS2/Device.cpp @@ -1,18 +1,13 @@ -#include #include #include #include #include -#include - namespace Kernel::Input { - PS2Device::PS2Device(PS2Controller& controller) - : CharacterDevice(0440, 0, 901) - , m_rdev(makedev(DeviceNumber::Input, DevFileSystem::get().get_next_input_device())) - , m_name(MUST(BAN::String::formatted("input{}", minor(m_rdev)))) + PS2Device::PS2Device(PS2Controller& controller, InputDevice::Type type) + : InputDevice(type) , m_controller(controller) { } diff --git a/kernel/kernel/Input/PS2/Keyboard.cpp b/kernel/kernel/Input/PS2/Keyboard.cpp index 8aff442696..2e73e5ccb4 100644 --- a/kernel/kernel/Input/PS2/Keyboard.cpp +++ b/kernel/kernel/Input/PS2/Keyboard.cpp @@ -4,20 +4,18 @@ #include #include #include +#include namespace Kernel::Input { - BAN::ErrorOr PS2Keyboard::create(PS2Controller& controller) + BAN::ErrorOr> PS2Keyboard::create(PS2Controller& controller) { - PS2Keyboard* keyboard = new PS2Keyboard(controller); - if (keyboard == nullptr) - return BAN::Error::from_errno(ENOMEM); - return keyboard; + return TRY(BAN::RefPtr::create(controller)); } PS2Keyboard::PS2Keyboard(PS2Controller& controller) - : PS2Device(controller) + : PS2Device(controller, InputDevice::Type::Keyboard) { } void PS2Keyboard::send_initialize() @@ -166,17 +164,7 @@ namespace Kernel::Input RawKeyEvent event; event.modifier = m_modifiers | (released ? 0 : KeyModifier::Pressed); event.keycode = keycode.value(); - - SpinLockGuard _(m_event_lock); - - if (m_event_queue.full()) - { - dwarnln("PS/2 event queue full"); - m_event_queue.pop(); - } - m_event_queue.push(event); - - m_semaphore.unblock(); + add_event(BAN::ConstByteSpan::from(event)); } void PS2Keyboard::update_leds() @@ -193,30 +181,4 @@ namespace Kernel::Input append_command_queue(Command::SET_LEDS, new_leds, 0); } - BAN::ErrorOr PS2Keyboard::read_impl(off_t, BAN::ByteSpan buffer) - { - using LibInput::RawKeyEvent; - - if (buffer.size() < sizeof(RawKeyEvent)) - return BAN::Error::from_errno(ENOBUFS); - - auto state = m_event_lock.lock(); - while (m_event_queue.empty()) - { - m_event_lock.unlock(state); - { - LockFreeGuard _(m_mutex); - TRY(Thread::current().block_or_eintr_indefinite(m_semaphore)); - } - state = m_event_lock.lock(); - } - - buffer.as() = m_event_queue.front(); - m_event_queue.pop(); - - m_event_lock.unlock(state); - - return sizeof(RawKeyEvent); - } - } diff --git a/kernel/kernel/Input/PS2/Mouse.cpp b/kernel/kernel/Input/PS2/Mouse.cpp index a7b66a4995..6d3f6e26b7 100644 --- a/kernel/kernel/Input/PS2/Mouse.cpp +++ b/kernel/kernel/Input/PS2/Mouse.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #define SET_MASK(byte, mask, on_off) ((on_off) ? ((byte) | (mask)) : ((byte) & ~(mask))) #define TOGGLE_MASK(byte, mask) ((byte) ^ (mask)) @@ -10,16 +11,13 @@ namespace Kernel::Input { - BAN::ErrorOr PS2Mouse::create(PS2Controller& controller) + BAN::ErrorOr> PS2Mouse::create(PS2Controller& controller) { - PS2Mouse* mouse = new PS2Mouse(controller); - if (mouse == nullptr) - return BAN::Error::from_errno(ENOMEM); - return mouse; + return TRY(BAN::RefPtr::create(controller)); } PS2Mouse::PS2Mouse(PS2Controller& controller) - : PS2Device(controller) + : PS2Device(controller, InputDevice::Type::Mouse) { } void PS2Mouse::send_initialize() @@ -110,10 +108,6 @@ namespace Kernel::Input m_byte_index = 0; - // Max 7 events, one for each (5) button, one for movement, one for scroll - BAN::Array events; - int event_count = 0; - auto button_index_to_button = [](int index) -> MouseButton { @@ -137,10 +131,11 @@ namespace Kernel::Input if ((new_button_mask & (1 << i)) == (m_button_mask & (1 << i))) continue; - auto& event = events[event_count++]; + MouseEvent event; event.type = MouseEventType::MouseButtonEvent; event.button_event.button = button_index_to_button(i); event.button_event.pressed = !!(new_button_mask & (1 << i)); + add_event(BAN::ConstByteSpan::from(event)); } m_button_mask = new_button_mask; @@ -148,71 +143,20 @@ namespace Kernel::Input if (rel_x || rel_y) { - auto& event = events[event_count++]; + MouseEvent event; event.type = MouseEventType::MouseMoveEvent; event.move_event.rel_x = rel_x; event.move_event.rel_y = rel_y; + add_event(BAN::ConstByteSpan::from(event)); } if (rel_z) { - auto& event = events[event_count++]; + MouseEvent event; event.type = MouseEventType::MouseScrollEvent; event.scroll_event.scroll = rel_z; + add_event(BAN::ConstByteSpan::from(event)); } - - SpinLockGuard _(m_event_lock); - - for (int i = 0; i < event_count; i++) - { - if (!m_event_queue.empty() && m_event_queue.back().type == events[i].type) - { - if (events[i].type == MouseEventType::MouseMoveEvent) - { - m_event_queue.back().move_event.rel_x += events[i].move_event.rel_x; - m_event_queue.back().move_event.rel_y += events[i].move_event.rel_y; - continue; - } - - if (events[i].type == MouseEventType::MouseScrollEvent) - { - m_event_queue.back().scroll_event.scroll += events[i].scroll_event.scroll; - continue; - } - } - - if (m_event_queue.full()) - { - dwarnln("PS/2 event queue full"); - m_event_queue.pop(); - } - m_event_queue.push(events[i]); - } - - m_semaphore.unblock(); - } - - BAN::ErrorOr PS2Mouse::read_impl(off_t, BAN::ByteSpan buffer) - { - using LibInput::MouseEvent; - - if (buffer.size() < sizeof(MouseEvent)) - return BAN::Error::from_errno(ENOBUFS); - - auto state = m_event_lock.lock(); - while (m_event_queue.empty()) - { - m_event_lock.unlock(state); - TRY(Thread::current().block_or_eintr_indefinite(m_semaphore)); - state = m_event_lock.lock(); - } - - buffer.as() = m_event_queue.front(); - m_event_queue.pop(); - - m_event_lock.unlock(state); - - return sizeof(MouseEvent); } } diff --git a/kernel/kernel/Terminal/TTY.cpp b/kernel/kernel/Terminal/TTY.cpp index 8fac3a2eb9..45ec8db7ea 100644 --- a/kernel/kernel/Terminal/TTY.cpp +++ b/kernel/kernel/Terminal/TTY.cpp @@ -83,7 +83,7 @@ namespace Kernel Process::create_kernel( [](void*) { - auto file_or_error = VirtualFileSystem::get().file_from_absolute_path({ 0, 0, 0, 0 }, "/dev/input0"_sv, O_RDONLY); + auto file_or_error = VirtualFileSystem::get().file_from_absolute_path({ 0, 0, 0, 0 }, "/dev/keyboard0"_sv, O_RDONLY); if (file_or_error.is_error()) { dprintln("no input device found"); diff --git a/userspace/programs/WindowServer/main.cpp b/userspace/programs/WindowServer/main.cpp index 2a63fb8ddf..755940630a 100644 --- a/userspace/programs/WindowServer/main.cpp +++ b/userspace/programs/WindowServer/main.cpp @@ -158,11 +158,11 @@ int main() MUST(LibInput::KeyboardLayout::initialize()); MUST(LibInput::KeyboardLayout::get().load_from_file("/usr/share/keymaps/us.keymap"_sv)); - int keyboard_fd = open("/dev/input0", O_RDONLY); + int keyboard_fd = open("/dev/keyboard0", O_RDONLY); if (keyboard_fd == -1) perror("open"); - int mouse_fd = open("/dev/input1", O_RDONLY); + int mouse_fd = open("/dev/mouse0", O_RDONLY); if (mouse_fd == -1) perror("open"); diff --git a/userspace/tests/test-mouse/main.cpp b/userspace/tests/test-mouse/main.cpp index 399f726bf8..906a9505e0 100644 --- a/userspace/tests/test-mouse/main.cpp +++ b/userspace/tests/test-mouse/main.cpp @@ -50,7 +50,7 @@ void cleanup() int main(int argc, char** argv) { const char* fb_path = "/dev/fb0"; - const char* mouse_path = "/dev/input1"; + const char* mouse_path = "/dev/mouse0"; if (argc == 1) ;