Files
banan-os/kernel/kernel/Input/InputDevice.cpp
DcraftBg 647d6a273d Kernel: Changed stat values from func to be field
- Removed virtual functions for all of the stat stuff.
This did however introduce some issues, mainly with /proc
becoming out of sync if you changed your ID. I propose we
do the linux thing and just have a stat update function
which is optional, but allows dynamic updates of stat fields
for cases such as those in uid/gid in /proc.
- Simplified the API, although still kind of annoying
it is a bit simpler.
- Moved some of the FS structure from having the FS inode inside
the in memory inode to a Serialise <-> Deserialise model where
Inodes are deserialised from disk into in memory ones and then
back into on disk ones when it comes time for syncing.
This makes it semantically better in my opinion, as it explicitly
separates disk and non-disk functionality.
2026-05-15 20:49:04 +03:00

378 lines
10 KiB
C++

#include <kernel/Device/DeviceNumbers.h>
#include <kernel/FS/DevFS/FileSystem.h>
#include <kernel/Input/InputDevice.h>
#include <kernel/Lock/SpinLockAsMutex.h>
#include <LibInput/Joystick.h>
#include <LibInput/KeyEvent.h>
#include <LibInput/MouseEvent.h>
#include <sys/epoll.h>
#include <sys/sysmacros.h>
namespace Kernel
{
static SpinLock s_keyboard_lock;
static BAN::Vector<BAN::WeakPtr<InputDevice>> s_keyboards;
static BAN::RefPtr<KeyboardDevice> s_keyboard_device;
static SpinLock s_mouse_lock;
static BAN::Vector<BAN::WeakPtr<InputDevice>> s_mice;
static BAN::RefPtr<MouseDevice> s_mouse_device;
static SpinLock s_joystick_lock;
static BAN::Vector<BAN::WeakPtr<InputDevice>> s_joysticks;
static const char* get_name_format(InputDevice::Type type)
{
switch (type)
{
case InputDevice::Type::Keyboard:
return "keyboard{}";
case InputDevice::Type::Mouse:
return "mouse{}";
case InputDevice::Type::Joystick:
return "joystick{}";
}
ASSERT_NOT_REACHED();
}
static dev_t get_rdev(InputDevice::Type type)
{
switch (type)
{
case InputDevice::Type::Keyboard:
{
SpinLockGuard _(s_keyboard_lock);
for (size_t i = 0; i < s_keyboards.size(); i++)
if (!s_keyboards[i].valid())
return makedev(DeviceNumber::Keyboard, i + 1);
return makedev(DeviceNumber::Keyboard, s_keyboards.size() + 1);
}
case InputDevice::Type::Mouse:
{
SpinLockGuard _(s_mouse_lock);
for (size_t i = 0; i < s_mice.size(); i++)
if (!s_mice[i].valid())
return makedev(DeviceNumber::Mouse, i + 1);
return makedev(DeviceNumber::Mouse, s_mice.size() + 1);
}
case InputDevice::Type::Joystick:
{
SpinLockGuard _(s_joystick_lock);
for (size_t i = 0; i < s_joysticks.size(); i++)
if (!s_joysticks[i].valid())
return makedev(DeviceNumber::Joystick, i + 1);
return makedev(DeviceNumber::Joystick, s_joysticks.size() + 1);
}
}
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);
case InputDevice::Type::Joystick:
return sizeof(LibInput::JoystickEvent);
}
ASSERT_NOT_REACHED();
}
InputDevice::InputDevice(Type type)
: CharacterDevice(0440, 0, 901)
, m_type(type)
, m_event_size(get_event_size(type))
{
m_rdev = get_rdev(type);
m_name = MUST(BAN::String::formatted(get_name_format(type), minor(m_rdev) - 1));
MUST(m_event_buffer.resize(m_event_size * m_max_event_count, 0));
switch (m_type)
{
case Type::Keyboard:
{
SpinLockGuard _(s_keyboard_lock);
if (s_keyboards.size() < minor(m_rdev))
MUST(s_keyboards.resize(minor(m_rdev)));
s_keyboards[minor(m_rdev) - 1] = MUST(get_weak_ptr());
break;
}
case Type::Mouse:
{
SpinLockGuard _(s_mouse_lock);
if (s_mice.size() < minor(m_rdev))
MUST(s_mice.resize(minor(m_rdev)));
s_mice[minor(m_rdev) - 1] = MUST(get_weak_ptr());
break;
}
case Type::Joystick:
{
SpinLockGuard _(s_joystick_lock);
if (s_joysticks.size() < minor(m_rdev))
MUST(s_joysticks.resize(minor(m_rdev)));
s_joysticks[minor(m_rdev) - 1] = MUST(get_weak_ptr());
break;
}
}
}
void InputDevice::add_event(BAN::ConstByteSpan event)
{
{
SpinLockGuard _(m_event_lock);
ASSERT(event.size() == m_event_size);
if (m_type == Type::Mouse && m_event_count > 0)
{
const size_t last_index = (m_event_head + m_max_event_count - 1) % m_max_event_count;
auto& last_event = *reinterpret_cast<LibInput::MouseEvent*>(&m_event_buffer[last_index * m_event_size]);
auto& curr_event = event.as<const LibInput::MouseEvent>();
if (last_event.type == LibInput::MouseEventType::MouseMoveEvent && curr_event.type == LibInput::MouseEventType::MouseMoveEvent)
{
last_event.move_event.rel_x += curr_event.move_event.rel_x;
last_event.move_event.rel_y += curr_event.move_event.rel_y;
return;
}
if (last_event.type == LibInput::MouseEventType::MouseMoveAbsEvent && curr_event.type == LibInput::MouseEventType::MouseMoveAbsEvent)
{
last_event.move_abs_event.abs_x = curr_event.move_abs_event.abs_x;
last_event.move_abs_event.abs_y = curr_event.move_abs_event.abs_y;
return;
}
if (last_event.type == LibInput::MouseEventType::MouseScrollEvent && curr_event.type == LibInput::MouseEventType::MouseScrollEvent)
{
last_event.scroll_event.scroll += curr_event.scroll_event.scroll;
return;
}
}
if (m_type == Type::Keyboard)
{
auto& key_event = event.as<const LibInput::RawKeyEvent>();
if (key_event.modifier & LibInput::KeyEvent::Modifier::Pressed)
{
if (key_event.modifier & LibInput::KeyEvent::Modifier::LCtrl)
{
const auto processor_count = Processor::count();
switch (key_event.keycode)
{
#define DUMP_CPU_STACK_TRACE(idx) \
case LibInput::keycode_function(idx + 1): \
if (idx >= processor_count) \
break; \
Processor::send_smp_message(Processor::id_from_index(idx), { \
.type = Processor::SMPMessage::Type::StackTrace, \
.dummy = false, \
}); \
break
// F1-F12
DUMP_CPU_STACK_TRACE(0);
DUMP_CPU_STACK_TRACE(1);
DUMP_CPU_STACK_TRACE(2);
DUMP_CPU_STACK_TRACE(3);
DUMP_CPU_STACK_TRACE(4);
DUMP_CPU_STACK_TRACE(5);
DUMP_CPU_STACK_TRACE(6);
DUMP_CPU_STACK_TRACE(7);
DUMP_CPU_STACK_TRACE(8);
DUMP_CPU_STACK_TRACE(9);
DUMP_CPU_STACK_TRACE(10);
DUMP_CPU_STACK_TRACE(11);
#undef DUMP_CPU_STACK_TRACE
}
}
else switch (key_event.keycode)
{
case LibInput::keycode_function(1):
Processor::toggle_should_print_cpu_load();
break;
case LibInput::keycode_function(11):
DevFileSystem::get().initiate_disk_cache_drop();
break;
case LibInput::keycode_function(12):
Kernel::panic("Keyboard kernel panic :)");
break;
}
}
}
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++;
}
epoll_notify(EPOLLIN);
m_event_thread_blocker.unblock();
if (m_type == Type::Keyboard && s_keyboard_device)
s_keyboard_device->notify();
if (m_type == Type::Mouse && s_mouse_device)
s_mouse_device->notify();
}
BAN::ErrorOr<size_t> InputDevice::read_impl(off_t, BAN::ByteSpan buffer)
{
if (buffer.size() < m_event_size)
return BAN::Error::from_errno(ENOBUFS);
SpinLockGuard guard(m_event_lock);
while (m_event_count == 0)
{
// FIXME: should m_mutex be unlocked?
SpinLockGuardAsMutex smutex(guard);
TRY(Thread::current().block_or_eintr_indefinite(m_event_thread_blocker, &smutex));
}
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--;
return m_event_size;
}
BAN::ErrorOr<size_t> InputDevice::read_non_block(BAN::ByteSpan buffer)
{
if (buffer.size() < m_event_size)
return BAN::Error::from_errno(ENOBUFS);
SpinLockGuard _(m_event_lock);
if (m_event_count == 0)
return 0;
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--;
return m_event_size;
}
BAN::ErrorOr<BAN::RefPtr<KeyboardDevice>> KeyboardDevice::create(mode_t mode, uid_t uid, gid_t gid)
{
s_keyboard_device = TRY(BAN::RefPtr<KeyboardDevice>::create(mode, uid, gid));
return s_keyboard_device;
}
KeyboardDevice::KeyboardDevice(mode_t mode, uid_t uid, gid_t gid)
: CharacterDevice(mode, uid, gid)
, m_name("keyboard"_sv)
{
m_rdev = makedev(DeviceNumber::Keyboard, 0);
}
void KeyboardDevice::notify()
{
epoll_notify(EPOLLIN);
SpinLockGuard _(s_keyboard_lock);
m_thread_blocker.unblock();
}
BAN::ErrorOr<size_t> KeyboardDevice::read_impl(off_t, BAN::ByteSpan buffer)
{
if (buffer.size() < sizeof(LibInput::RawKeyEvent))
return BAN::Error::from_errno(ENOBUFS);
SpinLockGuard keyboard_guard(s_keyboard_lock);
for (;;)
{
for (auto& weak_keyboard : s_keyboards)
{
auto keyboard = weak_keyboard.lock();
if (!keyboard)
continue;
auto bytes = TRY(keyboard->read_non_block(buffer));
if (bytes > 0)
return bytes;
}
SpinLockGuardAsMutex smutex(keyboard_guard);
TRY(Thread::current().block_or_eintr_indefinite(m_thread_blocker, &smutex));
}
}
bool KeyboardDevice::can_read_impl() const
{
SpinLockGuard _(s_keyboard_lock);
for (auto& weak_keyboard : s_keyboards)
if (auto keyboard = weak_keyboard.lock())
if (keyboard->can_read())
return true;
return false;
}
BAN::ErrorOr<BAN::RefPtr<MouseDevice>> MouseDevice::create(mode_t mode, uid_t uid, gid_t gid)
{
s_mouse_device = TRY(BAN::RefPtr<MouseDevice>::create(mode, uid, gid));
return s_mouse_device;
}
MouseDevice::MouseDevice(mode_t mode, uid_t uid, gid_t gid)
: CharacterDevice(mode, uid, gid)
, m_name("mouse"_sv)
{
m_rdev = makedev(DeviceNumber::Mouse, 0);
}
void MouseDevice::notify()
{
epoll_notify(EPOLLIN);
SpinLockGuard _(s_mouse_lock);
m_thread_blocker.unblock();
}
BAN::ErrorOr<size_t> MouseDevice::read_impl(off_t, BAN::ByteSpan buffer)
{
if (buffer.size() < sizeof(LibInput::MouseEvent))
return BAN::Error::from_errno(ENOBUFS);
SpinLockGuard mouse_guard(s_mouse_lock);
for (;;)
{
for (auto& weak_mouse : s_mice)
{
auto mouse = weak_mouse.lock();
if (!mouse)
continue;
auto bytes = TRY(mouse->read_non_block(buffer));
if (bytes > 0)
return bytes;
}
SpinLockGuardAsMutex smutex(mouse_guard);
TRY(Thread::current().block_or_eintr_indefinite(m_thread_blocker, &smutex));
}
}
bool MouseDevice::can_read_impl() const
{
SpinLockGuard _(s_mouse_lock);
for (auto& weak_mouse : s_mice)
if (auto mouse = weak_mouse.lock())
if (mouse->can_read())
return true;
return false;
}
}