forked from Bananymous/banan-os
- 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.
378 lines
10 KiB
C++
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;
|
|
}
|
|
|
|
}
|