diff --git a/kernel/CMakeLists.txt b/kernel/CMakeLists.txt index 2925999db..1c2e763c4 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 a60184e84..0f019e138 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 940da8411..3e7feee79 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 000000000..fe3f3ca71 --- /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 c620ddcbd..0eeb695b6 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 ba399b914..a5869d587 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 93b8dc534..b4a070092 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 caba0369d..bdf142889 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 426e79670..92c40ec25 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 000000000..95b9a6164 --- /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 e48ae9613..cdc83b1b1 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 37d102187..011d98a2c 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 8aff44269..2e73e5ccb 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 a7b66a499..6d3f6e26b 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 8fac3a2eb..45ec8db7e 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 2a63fb8dd..755940630 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 399f726bf..906a9505e 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) ;