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:
@@ -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++;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
104
kernel/kernel/Input/InputDevice.cpp
Normal file
104
kernel/kernel/Input/InputDevice.cpp
Normal 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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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 {};
|
||||
|
||||
@@ -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)
|
||||
{ }
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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");
|
||||
|
||||
Reference in New Issue
Block a user