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 2925999d..1c2e763c 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 a60184e8..0f019e13 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 940da841..3e7feee7 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 00000000..fe3f3ca7 --- /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 c620ddcb..0eeb695b 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 ba399b91..a5869d58 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 93b8dc53..b4a07009 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 caba0369..bdf14288 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 426e7967..92c40ec2 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 00000000..95b9a616 --- /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 e48ae961..cdc83b1b 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 37d10218..011d98a2 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 8aff4426..2e73e5cc 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 a7b66a49..6d3f6e26 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 8fac3a2e..45ec8db7 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 2a63fb8d..75594063 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 399f726b..906a9505 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) ;