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.
This commit is contained in:
Bananymous 2024-07-12 20:45:15 +03:00
parent 110a45bee6
commit a97a574718
17 changed files with 197 additions and 177 deletions

View File

@ -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

View File

@ -13,7 +13,8 @@ namespace Kernel
Null,
Zero,
Debug,
Input,
Keyboard,
Mouse,
SCSI,
NVMeController,
NVMeNamespace,

View File

@ -20,8 +20,6 @@ namespace Kernel
void add_device(BAN::RefPtr<Device>);
void add_inode(BAN::StringView path, BAN::RefPtr<TmpInode>);
int get_next_input_device() const;
void initiate_sync(bool should_block);
private:

View File

@ -0,0 +1,50 @@
#pragma once
#include <BAN/ByteSpan.h>
#include <kernel/Device/Device.h>
namespace Kernel
{
class InputDevice : public CharacterDevice
{
public:
enum class Type
{
Mouse,
Keyboard,
};
public:
InputDevice(Type type);
protected:
void add_event(BAN::ConstByteSpan);
BAN::ErrorOr<size_t> 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<uint8_t> 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 };
};
}

View File

@ -60,6 +60,7 @@ namespace Kernel::Input
private:
BAN::RefPtr<PS2Device> m_devices[2];
Mutex m_mutex;
BAN::CircularQueue<Command, 128> m_command_queue;

View File

@ -1,16 +1,15 @@
#pragma once
#include <kernel/Input/PS2/Controller.h>
#include <kernel/Input/InputDevice.h>
#include <kernel/Interruptable.h>
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;
};

View File

@ -1,11 +1,8 @@
#pragma once
#include <BAN/Array.h>
#include <BAN/CircularQueue.h>
#include <kernel/Input/PS2/Device.h>
#include <kernel/Input/PS2/Keymap.h>
#include <kernel/Semaphore.h>
#include <LibInput/KeyEvent.h>
namespace Kernel::Input
{
@ -20,13 +17,15 @@ namespace Kernel::Input
};
public:
static BAN::ErrorOr<PS2Keyboard*> create(PS2Controller&);
static BAN::ErrorOr<BAN::RefPtr<PS2Keyboard>> 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<LibInput::RawKeyEvent, 50> m_event_queue;
SpinLock m_event_lock;
PS2Keymap m_keymap;
Semaphore m_semaphore;
protected:
virtual BAN::ErrorOr<size_t> 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<PS2Keyboard>;
};
}

View File

@ -1,8 +1,6 @@
#pragma once
#include <kernel/Input/PS2/Device.h>
#include <kernel/Semaphore.h>
#include <LibInput/MouseEvent.h>
namespace Kernel::Input
{
@ -16,13 +14,15 @@ namespace Kernel::Input
};
public:
static BAN::ErrorOr<PS2Mouse*> create(PS2Controller&);
static BAN::ErrorOr<BAN::RefPtr<PS2Mouse>> 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<LibInput::MouseEvent, 128> m_event_queue;
SpinLock m_event_lock;
Semaphore m_semaphore;
protected:
virtual BAN::ErrorOr<size_t> 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<PS2Mouse>;
};
}

View File

@ -119,10 +119,4 @@ namespace Kernel
MUST(static_cast<TmpDirectoryInode*>(root_inode().ptr())->link_inode(*inode, path));
}
int DevFileSystem::get_next_input_device() const
{
static BAN::Atomic<dev_t> next_dev = 0;
return next_dev++;
}
}

View File

@ -0,0 +1,104 @@
#include <kernel/Device/DeviceNumbers.h>
#include <kernel/Input/InputDevice.h>
#include <kernel/Lock/LockGuard.h>
#include <LibInput/KeyEvent.h>
#include <LibInput/MouseEvent.h>
#include <sys/sysmacros.h>
namespace Kernel
{
static BAN::Atomic<uint16_t> s_next_keyboard { 0 };
static BAN::Atomic<uint16_t> 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<size_t> 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;
}
}

View File

@ -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 {};

View File

@ -1,18 +1,13 @@
#include <kernel/Device/DeviceNumbers.h>
#include <kernel/FS/DevFS/FileSystem.h>
#include <kernel/Input/PS2/Config.h>
#include <kernel/Input/PS2/Device.h>
#include <kernel/IO.h>
#include <sys/sysmacros.h>
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)
{ }

View File

@ -4,20 +4,18 @@
#include <kernel/Input/PS2/Keyboard.h>
#include <kernel/Thread.h>
#include <LibInput/KeyboardLayout.h>
#include <LibInput/KeyEvent.h>
namespace Kernel::Input
{
BAN::ErrorOr<PS2Keyboard*> PS2Keyboard::create(PS2Controller& controller)
BAN::ErrorOr<BAN::RefPtr<PS2Keyboard>> PS2Keyboard::create(PS2Controller& controller)
{
PS2Keyboard* keyboard = new PS2Keyboard(controller);
if (keyboard == nullptr)
return BAN::Error::from_errno(ENOMEM);
return keyboard;
return TRY(BAN::RefPtr<PS2Keyboard>::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<size_t> 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<RawKeyEvent>() = m_event_queue.front();
m_event_queue.pop();
m_event_lock.unlock(state);
return sizeof(RawKeyEvent);
}
}

View File

@ -3,6 +3,7 @@
#include <kernel/Input/PS2/Config.h>
#include <kernel/Input/PS2/Mouse.h>
#include <kernel/Thread.h>
#include <LibInput/MouseEvent.h>
#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*> PS2Mouse::create(PS2Controller& controller)
BAN::ErrorOr<BAN::RefPtr<PS2Mouse>> PS2Mouse::create(PS2Controller& controller)
{
PS2Mouse* mouse = new PS2Mouse(controller);
if (mouse == nullptr)
return BAN::Error::from_errno(ENOMEM);
return mouse;
return TRY(BAN::RefPtr<PS2Mouse>::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<MouseEvent, 7> 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<size_t> 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<MouseEvent>() = m_event_queue.front();
m_event_queue.pop();
m_event_lock.unlock(state);
return sizeof(MouseEvent);
}
}

View File

@ -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");

View File

@ -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");

View File

@ -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)
;