Kernel: Implement unified input files for device hot-plugging support
/dev/keyboard and /dev/mouse can be read for events from any attached keyboard or mouse respectively. This makes device hot-plugging support pretty much automatic for TTY, GUI, and whatever takes input.
This commit is contained in:
parent
9d7f97ccd5
commit
a5cb4057f9
|
@ -7,7 +7,7 @@
|
||||||
namespace Kernel
|
namespace Kernel
|
||||||
{
|
{
|
||||||
|
|
||||||
class InputDevice : public CharacterDevice
|
class InputDevice : public CharacterDevice, public BAN::Weakable<InputDevice>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
enum class Type
|
enum class Type
|
||||||
|
@ -19,6 +19,9 @@ namespace Kernel
|
||||||
public:
|
public:
|
||||||
InputDevice(Type type);
|
InputDevice(Type type);
|
||||||
|
|
||||||
|
BAN::StringView name() const final override { return m_name; }
|
||||||
|
dev_t rdev() const final override { return m_rdev; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void add_event(BAN::ConstByteSpan);
|
void add_event(BAN::ConstByteSpan);
|
||||||
|
|
||||||
|
@ -28,8 +31,9 @@ namespace Kernel
|
||||||
bool can_write_impl() const override { return false; }
|
bool can_write_impl() const override { return false; }
|
||||||
bool has_error_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:
|
||||||
|
BAN::ErrorOr<size_t> read_non_block(BAN::ByteSpan);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const dev_t m_rdev;
|
const dev_t m_rdev;
|
||||||
|
@ -47,6 +51,63 @@ namespace Kernel
|
||||||
size_t m_event_tail { 0 };
|
size_t m_event_tail { 0 };
|
||||||
size_t m_event_head { 0 };
|
size_t m_event_head { 0 };
|
||||||
size_t m_event_count { 0 };
|
size_t m_event_count { 0 };
|
||||||
|
|
||||||
|
friend class KeyboardDevice;
|
||||||
|
friend class MouseDevice;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class KeyboardDevice : public CharacterDevice
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static BAN::ErrorOr<BAN::RefPtr<KeyboardDevice>> create(mode_t mode, uid_t uid, gid_t gid);
|
||||||
|
|
||||||
|
void notify() { m_semaphore.unblock(); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
KeyboardDevice(mode_t mode, uid_t uid, gid_t gid);
|
||||||
|
BAN::ErrorOr<size_t> read_impl(off_t, BAN::ByteSpan) override;
|
||||||
|
|
||||||
|
bool can_read_impl() const override;
|
||||||
|
bool can_write_impl() const override { return false; }
|
||||||
|
bool has_error_impl() const override { return false; }
|
||||||
|
|
||||||
|
BAN::StringView name() const final override { return m_name; }
|
||||||
|
dev_t rdev() const final override { return m_rdev; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
const dev_t m_rdev;
|
||||||
|
const BAN::StringView m_name;
|
||||||
|
Semaphore m_semaphore;
|
||||||
|
|
||||||
|
friend class BAN::RefPtr<KeyboardDevice>;
|
||||||
|
};
|
||||||
|
|
||||||
|
class MouseDevice : public CharacterDevice
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static BAN::ErrorOr<BAN::RefPtr<MouseDevice>> create(mode_t mode, uid_t uid, gid_t gid);
|
||||||
|
|
||||||
|
void notify() { m_semaphore.unblock(); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
MouseDevice(mode_t mode, uid_t uid, gid_t gid);
|
||||||
|
BAN::ErrorOr<size_t> read_impl(off_t, BAN::ByteSpan) override;
|
||||||
|
|
||||||
|
bool can_read_impl() const override;
|
||||||
|
bool can_write_impl() const override { return false; }
|
||||||
|
bool has_error_impl() const override { return false; }
|
||||||
|
|
||||||
|
BAN::StringView name() const final override { return m_name; }
|
||||||
|
dev_t rdev() const final override { return m_rdev; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
const dev_t m_rdev;
|
||||||
|
const BAN::StringView m_name;
|
||||||
|
Semaphore m_semaphore;
|
||||||
|
|
||||||
|
friend class BAN::RefPtr<MouseDevice>;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#include <kernel/Device/ZeroDevice.h>
|
#include <kernel/Device/ZeroDevice.h>
|
||||||
#include <kernel/FS/DevFS/FileSystem.h>
|
#include <kernel/FS/DevFS/FileSystem.h>
|
||||||
#include <kernel/FS/TmpFS/Inode.h>
|
#include <kernel/FS/TmpFS/Inode.h>
|
||||||
|
#include <kernel/Input/InputDevice.h>
|
||||||
#include <kernel/Lock/LockGuard.h>
|
#include <kernel/Lock/LockGuard.h>
|
||||||
#include <kernel/Process.h>
|
#include <kernel/Process.h>
|
||||||
#include <kernel/Scheduler.h>
|
#include <kernel/Scheduler.h>
|
||||||
|
@ -26,6 +27,8 @@ namespace Kernel
|
||||||
s_instance->add_device(MUST(DebugDevice::create(0666, 0, 0)));
|
s_instance->add_device(MUST(DebugDevice::create(0666, 0, 0)));
|
||||||
s_instance->add_device(MUST(NullDevice::create(0666, 0, 0)));
|
s_instance->add_device(MUST(NullDevice::create(0666, 0, 0)));
|
||||||
s_instance->add_device(MUST(ZeroDevice::create(0666, 0, 0)));
|
s_instance->add_device(MUST(ZeroDevice::create(0666, 0, 0)));
|
||||||
|
s_instance->add_device(MUST(KeyboardDevice::create(0440, 0, 901)));
|
||||||
|
s_instance->add_device(MUST(MouseDevice::create(0440, 0, 901)));
|
||||||
}
|
}
|
||||||
|
|
||||||
DevFileSystem& DevFileSystem::get()
|
DevFileSystem& DevFileSystem::get()
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
#include <kernel/Device/DeviceNumbers.h>
|
#include <kernel/Device/DeviceNumbers.h>
|
||||||
|
#include <kernel/FS/DevFS/FileSystem.h>
|
||||||
#include <kernel/Input/InputDevice.h>
|
#include <kernel/Input/InputDevice.h>
|
||||||
#include <kernel/Lock/LockGuard.h>
|
#include <kernel/Lock/LockGuard.h>
|
||||||
|
|
||||||
|
@ -10,8 +11,11 @@
|
||||||
namespace Kernel
|
namespace Kernel
|
||||||
{
|
{
|
||||||
|
|
||||||
static BAN::Atomic<uint16_t> s_next_keyboard { 0 };
|
static BAN::Vector<BAN::WeakPtr<InputDevice>> s_keyboards;
|
||||||
static BAN::Atomic<uint16_t> s_next_mouse { 0 };
|
static BAN::RefPtr<KeyboardDevice> s_keyboard_device;
|
||||||
|
|
||||||
|
static BAN::Vector<BAN::WeakPtr<InputDevice>> s_mice;
|
||||||
|
static BAN::RefPtr<MouseDevice> s_mouse_device;
|
||||||
|
|
||||||
static const char* get_name_format(InputDevice::Type type)
|
static const char* get_name_format(InputDevice::Type type)
|
||||||
{
|
{
|
||||||
|
@ -30,9 +34,15 @@ namespace Kernel
|
||||||
switch (type)
|
switch (type)
|
||||||
{
|
{
|
||||||
case InputDevice::Type::Keyboard:
|
case InputDevice::Type::Keyboard:
|
||||||
return makedev(DeviceNumber::Keyboard, s_next_keyboard++);
|
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:
|
case InputDevice::Type::Mouse:
|
||||||
return makedev(DeviceNumber::Mouse, s_next_mouse++);
|
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);
|
||||||
}
|
}
|
||||||
ASSERT_NOT_REACHED();
|
ASSERT_NOT_REACHED();
|
||||||
}
|
}
|
||||||
|
@ -52,11 +62,25 @@ namespace Kernel
|
||||||
InputDevice::InputDevice(Type type)
|
InputDevice::InputDevice(Type type)
|
||||||
: CharacterDevice(0440, 0, 901)
|
: CharacterDevice(0440, 0, 901)
|
||||||
, m_rdev(get_rdev(type))
|
, m_rdev(get_rdev(type))
|
||||||
, m_name(MUST(BAN::String::formatted(get_name_format(type), minor(m_rdev))))
|
, m_name(MUST(BAN::String::formatted(get_name_format(type), minor(m_rdev) - 1)))
|
||||||
, m_type(type)
|
, m_type(type)
|
||||||
, m_event_size(get_event_size(type))
|
, m_event_size(get_event_size(type))
|
||||||
{
|
{
|
||||||
MUST(m_event_buffer.resize(m_event_size * m_max_event_count, 0));
|
MUST(m_event_buffer.resize(m_event_size * m_max_event_count, 0));
|
||||||
|
|
||||||
|
if (m_type == Type::Keyboard)
|
||||||
|
{
|
||||||
|
if (s_keyboards.size() < minor(m_rdev))
|
||||||
|
MUST(s_keyboards.resize(minor(m_rdev)));
|
||||||
|
s_keyboards[minor(m_rdev) - 1] = MUST(get_weak_ptr());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_type == Type::Mouse)
|
||||||
|
{
|
||||||
|
if (s_mice.size() < minor(m_rdev))
|
||||||
|
MUST(s_mice.resize(minor(m_rdev)));
|
||||||
|
s_mice[minor(m_rdev) - 1] = MUST(get_weak_ptr());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void InputDevice::add_event(BAN::ConstByteSpan event)
|
void InputDevice::add_event(BAN::ConstByteSpan event)
|
||||||
|
@ -94,6 +118,10 @@ namespace Kernel
|
||||||
m_event_count++;
|
m_event_count++;
|
||||||
|
|
||||||
m_event_semaphore.unblock();
|
m_event_semaphore.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)
|
BAN::ErrorOr<size_t> InputDevice::read_impl(off_t, BAN::ByteSpan buffer)
|
||||||
|
@ -121,4 +149,113 @@ namespace Kernel
|
||||||
return m_event_size;
|
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_rdev(makedev(DeviceNumber::Keyboard, 0))
|
||||||
|
, m_name("keyboard"_sv)
|
||||||
|
{}
|
||||||
|
|
||||||
|
BAN::ErrorOr<size_t> KeyboardDevice::read_impl(off_t, BAN::ByteSpan buffer)
|
||||||
|
{
|
||||||
|
if (buffer.size() < sizeof(LibInput::RawKeyEvent))
|
||||||
|
return BAN::Error::from_errno(ENOBUFS);
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
LockFreeGuard _(m_mutex);
|
||||||
|
TRY(Thread::current().block_or_eintr_indefinite(m_semaphore));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool KeyboardDevice::can_read_impl() const
|
||||||
|
{
|
||||||
|
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_rdev(makedev(DeviceNumber::Mouse, 0))
|
||||||
|
, m_name("mouse"_sv)
|
||||||
|
{}
|
||||||
|
|
||||||
|
BAN::ErrorOr<size_t> MouseDevice::read_impl(off_t, BAN::ByteSpan buffer)
|
||||||
|
{
|
||||||
|
if (buffer.size() < sizeof(LibInput::MouseEvent))
|
||||||
|
return BAN::Error::from_errno(ENOBUFS);
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
LockFreeGuard _(m_mutex);
|
||||||
|
TRY(Thread::current().block_or_eintr_indefinite(m_semaphore));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MouseDevice::can_read_impl() const
|
||||||
|
{
|
||||||
|
for (auto& weak_mouse : s_mice)
|
||||||
|
if (auto mouse = weak_mouse.lock())
|
||||||
|
if (mouse->can_read())
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -83,10 +83,10 @@ namespace Kernel
|
||||||
Process::create_kernel(
|
Process::create_kernel(
|
||||||
[](void*)
|
[](void*)
|
||||||
{
|
{
|
||||||
auto file_or_error = VirtualFileSystem::get().file_from_absolute_path({ 0, 0, 0, 0 }, "/dev/keyboard0"_sv, O_RDONLY);
|
auto file_or_error = VirtualFileSystem::get().file_from_absolute_path({ 0, 0, 0, 0 }, "/dev/keyboard"_sv, O_RDONLY);
|
||||||
if (file_or_error.is_error())
|
if (file_or_error.is_error())
|
||||||
{
|
{
|
||||||
dprintln("no input device found");
|
dprintln("no keyboard found");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -205,9 +205,8 @@ static void init2(void*)
|
||||||
// Initialize empty keymap
|
// Initialize empty keymap
|
||||||
MUST(LibInput::KeyboardLayout::initialize());
|
MUST(LibInput::KeyboardLayout::initialize());
|
||||||
|
|
||||||
// FIXME: implement device hot plugging, so multiple devices is possible
|
if (auto res = PS2Controller::initialize(); res.is_error())
|
||||||
//if (auto res = PS2Controller::initialize(); res.is_error())
|
dprintln("{}", res.error());
|
||||||
// dprintln("{}", res.error());
|
|
||||||
|
|
||||||
MUST(NetworkManager::initialize());
|
MUST(NetworkManager::initialize());
|
||||||
|
|
||||||
|
@ -216,9 +215,6 @@ static void init2(void*)
|
||||||
PCI::PCIManager::get().initialize_devices();
|
PCI::PCIManager::get().initialize_devices();
|
||||||
dprintln("PCI devices initialized");
|
dprintln("PCI devices initialized");
|
||||||
|
|
||||||
// FIXME: This is very hacky way to wait until USB stack is initialized
|
|
||||||
SystemTimer::get().sleep(500);
|
|
||||||
|
|
||||||
VirtualFileSystem::initialize(cmdline.root);
|
VirtualFileSystem::initialize(cmdline.root);
|
||||||
dprintln("VFS initialized");
|
dprintln("VFS initialized");
|
||||||
|
|
||||||
|
|
|
@ -158,11 +158,11 @@ int main()
|
||||||
MUST(LibInput::KeyboardLayout::initialize());
|
MUST(LibInput::KeyboardLayout::initialize());
|
||||||
MUST(LibInput::KeyboardLayout::get().load_from_file("/usr/share/keymaps/us.keymap"_sv));
|
MUST(LibInput::KeyboardLayout::get().load_from_file("/usr/share/keymaps/us.keymap"_sv));
|
||||||
|
|
||||||
int keyboard_fd = open("/dev/keyboard0", O_RDONLY);
|
int keyboard_fd = open("/dev/keyboard", O_RDONLY);
|
||||||
if (keyboard_fd == -1)
|
if (keyboard_fd == -1)
|
||||||
perror("open");
|
perror("open");
|
||||||
|
|
||||||
int mouse_fd = open("/dev/mouse0", O_RDONLY);
|
int mouse_fd = open("/dev/mouse", O_RDONLY);
|
||||||
if (mouse_fd == -1)
|
if (mouse_fd == -1)
|
||||||
perror("open");
|
perror("open");
|
||||||
|
|
||||||
|
|
|
@ -50,7 +50,7 @@ void cleanup()
|
||||||
int main(int argc, char** argv)
|
int main(int argc, char** argv)
|
||||||
{
|
{
|
||||||
const char* fb_path = "/dev/fb0";
|
const char* fb_path = "/dev/fb0";
|
||||||
const char* mouse_path = "/dev/mouse0";
|
const char* mouse_path = "/dev/mouse";
|
||||||
|
|
||||||
if (argc == 1)
|
if (argc == 1)
|
||||||
;
|
;
|
||||||
|
|
Loading…
Reference in New Issue