Kernel: Rework the whole input system
We now use Device abstraction that will allow us to provide devices to userspace through /dev. Currently Shell reads from first and only device (it being PS/2 Keyboard).
This commit is contained in:
parent
779912d8af
commit
ac094a48d6
|
@ -41,11 +41,14 @@ kernel/APIC.o \
|
||||||
kernel/build_libc.o \
|
kernel/build_libc.o \
|
||||||
kernel/CPUID.o \
|
kernel/CPUID.o \
|
||||||
kernel/Debug.o \
|
kernel/Debug.o \
|
||||||
|
kernel/Device.o \
|
||||||
kernel/Font.o \
|
kernel/Font.o \
|
||||||
kernel/FS/Ext2.o \
|
kernel/FS/Ext2.o \
|
||||||
kernel/FS/Inode.o \
|
kernel/FS/Inode.o \
|
||||||
kernel/FS/VirtualFileSystem.o \
|
kernel/FS/VirtualFileSystem.o \
|
||||||
kernel/Input.o \
|
kernel/Input/PS2Controller.o \
|
||||||
|
kernel/Input/PS2Keyboard.o \
|
||||||
|
kernel/Input/PS2Keymap.o \
|
||||||
kernel/InterruptController.o \
|
kernel/InterruptController.o \
|
||||||
kernel/kernel.o \
|
kernel/kernel.o \
|
||||||
kernel/kmalloc.o \
|
kernel/kmalloc.o \
|
||||||
|
@ -113,6 +116,7 @@ always:
|
||||||
mkdir -p $(BUILDDIR)/$(ARCHDIR)
|
mkdir -p $(BUILDDIR)/$(ARCHDIR)
|
||||||
mkdir -p $(BUILDDIR)/kernel
|
mkdir -p $(BUILDDIR)/kernel
|
||||||
mkdir -p $(BUILDDIR)/kernel/FS
|
mkdir -p $(BUILDDIR)/kernel/FS
|
||||||
|
mkdir -p $(BUILDDIR)/kernel/Input
|
||||||
mkdir -p $(BUILDDIR)/kernel/Storage
|
mkdir -p $(BUILDDIR)/kernel/Storage
|
||||||
mkdir -p $(BUILDDIR)/userspace
|
mkdir -p $(BUILDDIR)/userspace
|
||||||
mkdir -p $(BUILDDIR)/font
|
mkdir -p $(BUILDDIR)/font
|
||||||
|
|
|
@ -21,6 +21,65 @@ namespace Kernel
|
||||||
uint32_t creator_revision;
|
uint32_t creator_revision;
|
||||||
} __attribute__((packed));
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
struct FADT : public SDTHeader
|
||||||
|
{
|
||||||
|
uint32_t firmware_ctrl;
|
||||||
|
uint32_t dsdt;
|
||||||
|
uint8_t __reserved;
|
||||||
|
uint8_t preferred_pm_profile;
|
||||||
|
uint16_t sci_int;
|
||||||
|
uint32_t smi_cmd;
|
||||||
|
uint8_t acpi_enable;
|
||||||
|
uint8_t acpi_disable;
|
||||||
|
uint8_t s4bios_req;
|
||||||
|
uint8_t pstate_cnt;
|
||||||
|
uint32_t pm1a_evt_blk;
|
||||||
|
uint32_t pm1b_evt_blk;
|
||||||
|
uint32_t pm1a_cnt_blk;
|
||||||
|
uint32_t pm1b_cnt_blk;
|
||||||
|
uint32_t pm2_cnt_blk;
|
||||||
|
uint32_t pm_tmr_blk;
|
||||||
|
uint32_t gpe0_blk;
|
||||||
|
uint32_t gpe1_blk;
|
||||||
|
uint8_t pm1_evt_len;
|
||||||
|
uint8_t pm1_cnt_len;
|
||||||
|
uint8_t pm2_cnt_len;
|
||||||
|
uint8_t pm_tmr_len;
|
||||||
|
uint8_t gpe0_blk_len;
|
||||||
|
uint8_t gpe1_blk_len;
|
||||||
|
uint8_t gpe1_base;
|
||||||
|
uint8_t cst_cnt;
|
||||||
|
uint16_t p_lvl2_lat;
|
||||||
|
uint16_t p_lvl3_lat;
|
||||||
|
uint16_t flush_size;
|
||||||
|
uint16_t flush_stride;
|
||||||
|
uint8_t duty_offset;
|
||||||
|
uint8_t duty_width;
|
||||||
|
uint8_t day_alrm;
|
||||||
|
uint8_t mon_alrm;
|
||||||
|
uint8_t century;
|
||||||
|
uint16_t iapc_boot_arch;
|
||||||
|
uint8_t __reserved2;
|
||||||
|
uint32_t flags;
|
||||||
|
uint8_t reset_reg[12];
|
||||||
|
uint8_t reset_value;
|
||||||
|
uint16_t arm_boot_arch;
|
||||||
|
uint8_t fadt_minor_version;
|
||||||
|
uint64_t x_firmware_version;
|
||||||
|
uint64_t x_dsdt;
|
||||||
|
uint8_t x_pm1a_evt_blk[12];
|
||||||
|
uint8_t x_pm1b_evt_blk[12];
|
||||||
|
uint8_t x_pm1a_cnt_blk[12];
|
||||||
|
uint8_t x_pm1b_cnt_blk[12];
|
||||||
|
uint8_t x_pm2_cnt_blk[12];
|
||||||
|
uint8_t x_pm_tmr_blk[12];
|
||||||
|
uint8_t x_gpe0_blk[12];
|
||||||
|
uint8_t x_gpe1_blk[12];
|
||||||
|
uint8_t sleep_control_reg[12];
|
||||||
|
uint8_t sleep_status_reg[12];
|
||||||
|
uint64_t hypervison_vendor_identity;
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static BAN::ErrorOr<void> initialize();
|
static BAN::ErrorOr<void> initialize();
|
||||||
static ACPI& get();
|
static ACPI& get();
|
||||||
|
|
|
@ -0,0 +1,59 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <BAN/Vector.h>
|
||||||
|
#include <kernel/SpinLock.h>
|
||||||
|
|
||||||
|
namespace Kernel
|
||||||
|
{
|
||||||
|
|
||||||
|
class Device
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum class Type
|
||||||
|
{
|
||||||
|
BlockDevice,
|
||||||
|
CharacterDevice,
|
||||||
|
DeviceController
|
||||||
|
};
|
||||||
|
|
||||||
|
virtual ~Device() {}
|
||||||
|
virtual Type type() const = 0;
|
||||||
|
virtual void update() {}
|
||||||
|
};
|
||||||
|
|
||||||
|
class BlockDevice : public Device
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual Type type() const override { return Type::BlockDevice; }
|
||||||
|
};
|
||||||
|
|
||||||
|
class CharacterDevice : public Device
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual Type type() const override { return Type::CharacterDevice; }
|
||||||
|
|
||||||
|
virtual BAN::ErrorOr<void> read(BAN::Span<uint8_t>);
|
||||||
|
};
|
||||||
|
|
||||||
|
class DeviceManager
|
||||||
|
{
|
||||||
|
BAN_NON_COPYABLE(DeviceManager);
|
||||||
|
BAN_NON_MOVABLE(DeviceManager);
|
||||||
|
|
||||||
|
public:
|
||||||
|
static DeviceManager& get();
|
||||||
|
|
||||||
|
void update();
|
||||||
|
void add_device(Device*);
|
||||||
|
|
||||||
|
BAN::Vector<Device*> devices() { return m_devices; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
DeviceManager() = default;
|
||||||
|
|
||||||
|
private:
|
||||||
|
SpinLock m_lock;
|
||||||
|
BAN::Vector<Device*> m_devices;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -1,67 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <BAN/Function.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
namespace Input
|
|
||||||
{
|
|
||||||
|
|
||||||
enum class Key : uint8_t
|
|
||||||
{
|
|
||||||
INVALID, None,
|
|
||||||
_0, _1, _2, _3, _4, _5, _6, _7, _8, _9,
|
|
||||||
A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z,
|
|
||||||
A_Dot, A_Dots, O_Dots,
|
|
||||||
|
|
||||||
Comma, Colon, Period, Semicolon, Hyphen, Underscore, SingleQuote, Asterix, Caret, Tilde,
|
|
||||||
ExclamationMark, QuestionMark, DoubleQuote, Hashtag, Percent, Ampersand, Slash, BackSlash, Plus, Equals,
|
|
||||||
OpenParen, CloseParen, OpenBracket, CloseBracket, OpenBrace, CloseBrace,
|
|
||||||
Dollar, Pound, Euro, Currency, Enter, Space, Tab, Backspace, LessThan, MoreThan, Tick, BackTick, Section, Half, At, Pipe,
|
|
||||||
End, Home, Insert, Delete, Super, PageUp, PageDown, PrintScreen, Left, Right, Up, Down,
|
|
||||||
|
|
||||||
LeftShift, RightShift, CapsLock, LeftCtrl, RightCtrl, LeftAlt, RightAlt, NumLock, ScrollLock, Escape,
|
|
||||||
|
|
||||||
Numpad0, Numpad1, Numpad2, Numpad3, Numpad4, Numpad5, Numpad6, Numpad7, Numpad8, Numpad9,
|
|
||||||
NumpadSep, NumpadPlus, NumpadMult, NumpadDiv, NumpadMinus, NumpadEnter,
|
|
||||||
|
|
||||||
Mute, VolumeDown, VolumeUp, Calculator, PlayPause, Stop, PreviousTrack, NextTrack,
|
|
||||||
|
|
||||||
F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12,
|
|
||||||
|
|
||||||
Count
|
|
||||||
};
|
|
||||||
|
|
||||||
struct KeyEvent
|
|
||||||
{
|
|
||||||
Key key;
|
|
||||||
uint8_t modifiers;
|
|
||||||
bool pressed;
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class MouseButton
|
|
||||||
{
|
|
||||||
Left, Right, Middle,
|
|
||||||
};
|
|
||||||
struct MouseButtonEvent
|
|
||||||
{
|
|
||||||
MouseButton button;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct MouseMoveEvent
|
|
||||||
{
|
|
||||||
int16_t dx;
|
|
||||||
int16_t dy;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
bool initialize();
|
|
||||||
void update();
|
|
||||||
bool is_key_down(Key);
|
|
||||||
|
|
||||||
void register_key_event_callback(const BAN::Function<void(KeyEvent)>&);
|
|
||||||
void register_mouse_button_event_callback(const BAN::Function<void(MouseButtonEvent)>&);
|
|
||||||
void register_mouse_move_event_callback(const BAN::Function<void(MouseMoveEvent)>&);
|
|
||||||
|
|
||||||
const char* key_event_to_utf8(KeyEvent);
|
|
||||||
|
|
||||||
}
|
|
|
@ -0,0 +1,99 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
namespace Kernel::Input
|
||||||
|
{
|
||||||
|
|
||||||
|
enum class Key
|
||||||
|
{
|
||||||
|
Invalid, None,
|
||||||
|
A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z,
|
||||||
|
A_Ring, A_Umlaut, O_Umlaut,
|
||||||
|
_0, _1, _2, _3, _4, _5, _6, _7, _8, _9,
|
||||||
|
F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12,
|
||||||
|
Insert, PrintScreen, Delete, Home, End, PageUp, PageDown, Enter, Space,
|
||||||
|
ExclamationMark, DoubleQuote, Hashtag, Currency, Percent, Ampersand, Slash, Section, Half,
|
||||||
|
OpenBracet, CloseBracet, OpenBrace, CloseBrace, OpenCurlyBrace, CloseCurlyBrace,
|
||||||
|
Equals, QuestionMark, Plus, BackSlash, Acute, BackTick, TwoDots, Backspace, AtSign, Pound, Dollar, Euro,
|
||||||
|
Escape, Tab, CapsLock, LeftShift, LeftCtrl, Super, Alt, AltGr, RightCtrl, RightShift,
|
||||||
|
SingleQuote, Asterix, Caret, Tilde, ArrowUp, ArrowDown, ArrowLeft, ArrowRight,
|
||||||
|
Comma, Semicolon, Period, Colon, Hyphen, Underscore, NumLock, ScrollLock, LessThan, GreaterThan, Pipe,
|
||||||
|
Numpad0, Numpad1, Numpad2, Numpad3, Numpad4, Numpad5, Numpad6, Numpad7, Numpad8, Numpad9,
|
||||||
|
NumpadPlus, NumpadMinus, NumpadMultiply, NumpadDivide, NumpadEnter, NumpadDecimal,
|
||||||
|
VolumeMute, VolumeUp, VolumeDown, Calculator, MediaPlayPause, MediaStop, MediaPrevious, MediaNext,
|
||||||
|
Count,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct KeyEvent
|
||||||
|
{
|
||||||
|
enum class Modifier : uint8_t
|
||||||
|
{
|
||||||
|
Shift = (1 << 0),
|
||||||
|
Ctrl = (1 << 1),
|
||||||
|
Alt = (1 << 2),
|
||||||
|
AltGr = (1 << 3),
|
||||||
|
CapsLock = (1 << 4),
|
||||||
|
NumLock = (1 << 5),
|
||||||
|
ScrollLock = (1 << 6),
|
||||||
|
Released = (1 << 7),
|
||||||
|
};
|
||||||
|
|
||||||
|
bool shift() const { return modifier & (uint8_t)Modifier::Shift; }
|
||||||
|
bool ctrl() const { return modifier & (uint8_t)Modifier::Ctrl; }
|
||||||
|
bool alt() const { return modifier & (uint8_t)Modifier::Alt; }
|
||||||
|
bool altgr() const { return modifier & (uint8_t)Modifier::AltGr; }
|
||||||
|
bool caps_lock() const { return modifier & (uint8_t)Modifier::CapsLock; }
|
||||||
|
bool num_lock() const { return modifier & (uint8_t)Modifier::NumLock; }
|
||||||
|
bool scroll_lock() const { return modifier & (uint8_t)Modifier::ScrollLock; }
|
||||||
|
bool released() const { return modifier & (uint8_t)Modifier::Released; }
|
||||||
|
bool pressed() const { return !released(); }
|
||||||
|
|
||||||
|
uint8_t modifier;
|
||||||
|
Key key;
|
||||||
|
};
|
||||||
|
|
||||||
|
inline const char* key_event_to_utf8(KeyEvent event)
|
||||||
|
{
|
||||||
|
static constexpr const char* utf8_lower[] = {
|
||||||
|
nullptr, nullptr,
|
||||||
|
"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z",
|
||||||
|
"å", "ä", "ö",
|
||||||
|
"0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
|
||||||
|
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
|
||||||
|
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, " ",
|
||||||
|
"!", "\"", "#", "¤", "%", "&", "/", "§", "½",
|
||||||
|
"(", ")", "[", "]", "{", "}",
|
||||||
|
"=", "?", "+", "\\", "´", "`", "¨", nullptr, "@", "£", "$", "€",
|
||||||
|
nullptr, "\t", nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
|
||||||
|
"'", "*", "^", "~", nullptr, nullptr, nullptr, nullptr,
|
||||||
|
",", ";", ".", ":", "-", "_", nullptr, nullptr, "<", ">", "|",
|
||||||
|
"0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
|
||||||
|
"+", "-", "*", "/", nullptr, ",",
|
||||||
|
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
|
||||||
|
};
|
||||||
|
static_assert((size_t)Key::Count == sizeof(utf8_lower) / sizeof(*utf8_lower));
|
||||||
|
|
||||||
|
static constexpr const char* utf8_upper[] = {
|
||||||
|
nullptr, nullptr,
|
||||||
|
"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z",
|
||||||
|
"Å", "Ä", "Ö",
|
||||||
|
"0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
|
||||||
|
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
|
||||||
|
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, " ",
|
||||||
|
"!", "\"", "#", "¤", "%", "&", "/", "§", "½",
|
||||||
|
"(", ")", "[", "]", "{", "}",
|
||||||
|
"=", "?", "+", "\\", "´", "`", "¨", nullptr, "@", "£", "$", "€",
|
||||||
|
nullptr, "\t", nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
|
||||||
|
"'", "*", "^", "~", nullptr, nullptr, nullptr, nullptr,
|
||||||
|
",", ";", ".", ":", "-", "_", nullptr, nullptr, "<", ">", "|",
|
||||||
|
"0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
|
||||||
|
"+", "-", "*", "/", nullptr, ",",
|
||||||
|
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
|
||||||
|
};
|
||||||
|
static_assert((size_t)Key::Count == sizeof(utf8_upper) / sizeof(*utf8_lower));
|
||||||
|
|
||||||
|
return (event.shift() ^ event.caps_lock()) ? utf8_upper[(uint8_t)event.key] : utf8_lower[(uint8_t)event.key];
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,38 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <kernel/Device.h>
|
||||||
|
|
||||||
|
namespace Kernel::Input
|
||||||
|
{
|
||||||
|
|
||||||
|
class PS2Device : public CharacterDevice
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual ~PS2Device() {}
|
||||||
|
virtual void on_byte(uint8_t) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class PS2Controller
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static BAN::ErrorOr<void> initialize();
|
||||||
|
static PS2Controller& get();
|
||||||
|
|
||||||
|
void send_byte(const PS2Device*, uint8_t);
|
||||||
|
|
||||||
|
private:
|
||||||
|
PS2Controller() = default;
|
||||||
|
BAN::ErrorOr<void> initialize_impl();
|
||||||
|
BAN::ErrorOr<void> initialize_device(uint8_t);
|
||||||
|
|
||||||
|
BAN::ErrorOr<void> reset_device(uint8_t);
|
||||||
|
BAN::ErrorOr<void> set_scanning(uint8_t, bool);
|
||||||
|
|
||||||
|
static void device0_irq();
|
||||||
|
static void device1_irq();
|
||||||
|
|
||||||
|
private:
|
||||||
|
PS2Device* m_devices[2] { nullptr, nullptr };
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,64 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <BAN/CircularQueue.h>
|
||||||
|
#include <kernel/Input/KeyEvent.h>
|
||||||
|
#include <kernel/Input/PS2Controller.h>
|
||||||
|
#include <kernel/Input/PS2Keymap.h>
|
||||||
|
|
||||||
|
namespace Kernel::Input
|
||||||
|
{
|
||||||
|
|
||||||
|
class PS2Keyboard final : public PS2Device
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
enum Command : uint8_t
|
||||||
|
{
|
||||||
|
SET_LEDS = 0xED,
|
||||||
|
SCANCODE = 0xF0,
|
||||||
|
ENABLE_SCANNING = 0xF4,
|
||||||
|
DISABLE_SCANNING = 0xF5,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class State
|
||||||
|
{
|
||||||
|
Normal,
|
||||||
|
WaitingAck,
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
static BAN::ErrorOr<PS2Keyboard*> create(PS2Controller&);
|
||||||
|
|
||||||
|
virtual void on_byte(uint8_t) override;
|
||||||
|
virtual void update() override;
|
||||||
|
|
||||||
|
virtual BAN::ErrorOr<void> read(BAN::Span<uint8_t>) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
PS2Keyboard(PS2Controller& controller)
|
||||||
|
: m_controller(controller)
|
||||||
|
{}
|
||||||
|
BAN::ErrorOr<void> initialize();
|
||||||
|
|
||||||
|
void append_command_queue(uint8_t);
|
||||||
|
void append_command_queue(uint8_t, uint8_t);
|
||||||
|
|
||||||
|
void buffer_has_key();
|
||||||
|
|
||||||
|
void update_leds();
|
||||||
|
|
||||||
|
private:
|
||||||
|
PS2Controller& m_controller;
|
||||||
|
uint8_t m_byte_buffer[10];
|
||||||
|
uint8_t m_byte_index { 0 };
|
||||||
|
|
||||||
|
uint8_t m_modifiers { 0 };
|
||||||
|
|
||||||
|
BAN::CircularQueue<KeyEvent, 10> m_event_queue;
|
||||||
|
BAN::CircularQueue<uint8_t, 10> m_command_queue;
|
||||||
|
|
||||||
|
PS2Keymap m_keymap;
|
||||||
|
|
||||||
|
State m_state { State::Normal };
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <BAN/Vector.h>
|
||||||
|
#include <kernel/Input/KeyEvent.h>
|
||||||
|
|
||||||
|
namespace Kernel::Input
|
||||||
|
{
|
||||||
|
|
||||||
|
class PS2Keymap
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
PS2Keymap();
|
||||||
|
|
||||||
|
Key key_for_scancode_and_modifiers(uint32_t, uint8_t);
|
||||||
|
|
||||||
|
private:
|
||||||
|
BAN::Vector<Key> m_normal_keymap;
|
||||||
|
BAN::Vector<Key> m_shift_keymap;
|
||||||
|
BAN::Vector<Key> m_altgr_keymap;
|
||||||
|
BAN::Vector<Key> m_extended_keymap;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
#include <BAN/String.h>
|
#include <BAN/String.h>
|
||||||
#include <BAN/Vector.h>
|
#include <BAN/Vector.h>
|
||||||
#include <kernel/Input.h>
|
#include <kernel/Input/KeyEvent.h>
|
||||||
#include <kernel/TTY.h>
|
#include <kernel/TTY.h>
|
||||||
|
|
||||||
namespace Kernel
|
namespace Kernel
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
#include <kernel/Device.h>
|
||||||
|
#include <kernel/LockGuard.h>
|
||||||
|
|
||||||
|
namespace Kernel
|
||||||
|
{
|
||||||
|
|
||||||
|
DeviceManager& DeviceManager::get()
|
||||||
|
{
|
||||||
|
static DeviceManager instance;
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeviceManager::update()
|
||||||
|
{
|
||||||
|
LockGuard _(m_lock);
|
||||||
|
for (Device* device : m_devices)
|
||||||
|
device->update();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeviceManager::add_device(Device* device)
|
||||||
|
{
|
||||||
|
LockGuard _(m_lock);
|
||||||
|
MUST(m_devices.push_back(device));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,690 +0,0 @@
|
||||||
#include <BAN/Queue.h>
|
|
||||||
#include <kernel/Debug.h>
|
|
||||||
#include <kernel/IDT.h>
|
|
||||||
#include <kernel/Input.h>
|
|
||||||
#include <kernel/InterruptController.h>
|
|
||||||
#include <kernel/IO.h>
|
|
||||||
#include <kernel/kprint.h>
|
|
||||||
#include <kernel/PIT.h>
|
|
||||||
|
|
||||||
#include <kernel/KeyboardLayout/FI.h>
|
|
||||||
|
|
||||||
#define DEBUG_ALL_IRQ 0
|
|
||||||
#define KEYBOARD_SHOW_UNKNOWN 1
|
|
||||||
|
|
||||||
#define MOUSE_ENABLED 0
|
|
||||||
|
|
||||||
#define I8042_DATA_PORT 0x60
|
|
||||||
#define I8042_STATUS_REGISTER 0x64
|
|
||||||
#define I8042_COMMAND_REGISTER 0x64
|
|
||||||
|
|
||||||
#define I8042_STATUS_OUT_FULL (1 << 0)
|
|
||||||
#define I8042_STATUS_IN_FULL (1 << 1)
|
|
||||||
|
|
||||||
#define I8042_READ_CONFIG 0x20
|
|
||||||
#define I8042_WRITE_CONFIG 0x60
|
|
||||||
|
|
||||||
#define I8042_CONFING_IRQ_FIRST (1 << 0)
|
|
||||||
#define I8042_CONFING_IRQ_SECOND (1 << 1)
|
|
||||||
#define I8042_CONFING_DUAL_CHANNEL (1 << 5)
|
|
||||||
#define I8042_CONFING_TRANSLATION (1 << 6)
|
|
||||||
|
|
||||||
#define I8042_ENABLE_FIRST_PORT 0xAE
|
|
||||||
#define I8042_ENABLE_SECOND_PORT 0xA8
|
|
||||||
#define I8042_DISABLE_FIRST_PORT 0xAD
|
|
||||||
#define I8042_DISABLE_SECOND_PORT 0xA7
|
|
||||||
|
|
||||||
#define I8042_TEST_CONTROLLER 0xAA
|
|
||||||
#define I8042_TEST_CONTROLLER_PASS 0x55
|
|
||||||
|
|
||||||
#define I8042_TEST_FIRST_PORT 0xAB
|
|
||||||
#define I8042_TEST_FIRST_PORT_PASS 0x00
|
|
||||||
|
|
||||||
#define I8042_TEST_SECOND_PORT 0xA9
|
|
||||||
#define I8042_TEST_SECOND_PORT_PASS 0x00
|
|
||||||
|
|
||||||
#define I8042_KB_ACK 0xFA
|
|
||||||
#define I8042_KB_RESEND 0xFE
|
|
||||||
#define I8042_KB_RESET 0xFF
|
|
||||||
#define I8042_KB_SELF_TEST_PASS 0xAA
|
|
||||||
#define I8042_KB_SET_SCAN_CODE_SET 0xF0
|
|
||||||
#define I8042_KB_SET_LEDS 0xED
|
|
||||||
#define I8042_KB_LED_SCROLL_LOCK (1 << 0)
|
|
||||||
#define I8042_KB_LED_NUM_LOCK (1 << 1)
|
|
||||||
#define I8042_KB_LED_CAPS_LOCK (1 << 2)
|
|
||||||
|
|
||||||
#define I8042_MOUSE_ACK 0xFA
|
|
||||||
#define I8042_MOUSE_RESET 0xFF
|
|
||||||
#define I8042_MOUSE_SELF_TEST_PASS 0xAA
|
|
||||||
#define I8042_MOUSE_ENABLE 0xF4
|
|
||||||
#define I8042_MOUSE_DISABLE 0xF5
|
|
||||||
|
|
||||||
#define I8042_TIMEOUT_MS 1000
|
|
||||||
|
|
||||||
#define KEYBOARD_IRQ 0x01
|
|
||||||
#define MOUSE_IRQ 0x0C
|
|
||||||
|
|
||||||
#define TARGET_KEYBOARD 1
|
|
||||||
#define TARGET_MOUSE 2
|
|
||||||
|
|
||||||
#define MOD_ALT (1 << 0)
|
|
||||||
#define MOD_CTRL (1 << 1)
|
|
||||||
#define MOD_SHIFT (1 << 2)
|
|
||||||
#define MOD_ALTGR (1 << 3)
|
|
||||||
#define MOD_CAPS (1 << 4)
|
|
||||||
|
|
||||||
namespace Input
|
|
||||||
{
|
|
||||||
|
|
||||||
static bool s_keyboard_state[0xFF] = {};
|
|
||||||
|
|
||||||
struct Command
|
|
||||||
{
|
|
||||||
uint8_t target = 0;
|
|
||||||
uint8_t command = 0;
|
|
||||||
uint8_t data = 0;
|
|
||||||
bool has_data = false;
|
|
||||||
uint8_t resp_cnt = 0;
|
|
||||||
uint8_t _sent = 0;
|
|
||||||
uint8_t _ack = 0;
|
|
||||||
bool _done = false;
|
|
||||||
};
|
|
||||||
static uint64_t s_command_sent = 0;
|
|
||||||
static BAN::Queue<Command> s_command_queue;
|
|
||||||
static uint8_t s_command_response[3] = {};
|
|
||||||
static uint8_t s_command_response_index = 0;
|
|
||||||
|
|
||||||
static BAN::Queue<KeyEvent> s_key_event_queue;
|
|
||||||
static uint8_t s_keyboard_key_buffer[10] = {};
|
|
||||||
static uint8_t s_keyboard_key_buffer_size = 0;
|
|
||||||
|
|
||||||
static BAN::Queue<MouseButtonEvent> s_mouse_button_event_queue;
|
|
||||||
static BAN::Queue<MouseMoveEvent> s_mouse_move_event_queue;
|
|
||||||
static uint8_t s_mouse_data_buffer[3] = {};
|
|
||||||
static uint8_t s_mouse_data_buffer_index = 0;
|
|
||||||
|
|
||||||
static uint8_t s_led_states = 0b000;
|
|
||||||
static uint8_t s_modifiers = 0x00;
|
|
||||||
|
|
||||||
static BAN::Function<void(KeyEvent)> s_key_event_callback;
|
|
||||||
static BAN::Function<void(MouseButtonEvent)> s_mouse_button_event_callback;
|
|
||||||
static BAN::Function<void(MouseMoveEvent)> s_mouse_move_event_callback;
|
|
||||||
|
|
||||||
static const char* s_key_to_utf8_lower[]
|
|
||||||
{
|
|
||||||
nullptr, nullptr,
|
|
||||||
"0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
|
|
||||||
"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z",
|
|
||||||
"å", "ä", "ö",
|
|
||||||
|
|
||||||
",", ":", ".", ";", "-", "_", "'", "*", "^", "~",
|
|
||||||
"!", "?", "\"", "#", "%", "&", "/", "\\", "+", "=",
|
|
||||||
"(", ")", "[", "]", "{", "}",
|
|
||||||
"$", "£", "€", "¤", "\n", " ", "\t", nullptr, "<", ">", "´", "`", "§", "½", "@", "|",
|
|
||||||
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
|
|
||||||
|
|
||||||
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
|
|
||||||
|
|
||||||
"0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
|
|
||||||
",", "+", "*", "/", "-", "\n",
|
|
||||||
|
|
||||||
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
|
|
||||||
|
|
||||||
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
|
|
||||||
};
|
|
||||||
static_assert(sizeof(s_key_to_utf8_lower) == (int)Key::Count * sizeof(*s_key_to_utf8_lower));
|
|
||||||
|
|
||||||
static const char* s_key_to_utf8_upper[]
|
|
||||||
{
|
|
||||||
nullptr, nullptr,
|
|
||||||
"0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
|
|
||||||
"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z",
|
|
||||||
"Å", "Ä", "Ö",
|
|
||||||
|
|
||||||
",", ":", ".", ";", "-", "_", "'", "*", "^", "~",
|
|
||||||
"!", "?", "\"", "#", "%", "&", "/", "\\", "+", "=",
|
|
||||||
"(", ")", "[", "]", "{", "}",
|
|
||||||
"$", "£", "€", "¤", "\n", " ", "\t", nullptr, "<", ">", "´", "`", "§", "½", "@", "|",
|
|
||||||
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
|
|
||||||
|
|
||||||
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
|
|
||||||
|
|
||||||
"0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
|
|
||||||
",", "+", "*", "/", "-", "\n",
|
|
||||||
|
|
||||||
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
|
|
||||||
|
|
||||||
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
|
|
||||||
};
|
|
||||||
static_assert(sizeof(s_key_to_utf8_upper) == (int)Key::Count * sizeof(*s_key_to_utf8_upper));
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static void keyboard_new_key();
|
|
||||||
|
|
||||||
|
|
||||||
static uint8_t wait_and_read()
|
|
||||||
{
|
|
||||||
while ((IO::inb(I8042_STATUS_REGISTER) & I8042_STATUS_OUT_FULL) == 0)
|
|
||||||
continue;
|
|
||||||
return IO::inb(I8042_DATA_PORT);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void i8042_controller_command(uint8_t command)
|
|
||||||
{
|
|
||||||
IO::outb(I8042_COMMAND_REGISTER, command);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void i8042_controller_command(uint8_t command, uint8_t data)
|
|
||||||
{
|
|
||||||
IO::outb(I8042_COMMAND_REGISTER, command);
|
|
||||||
while ((IO::inb(I8042_STATUS_REGISTER) & I8042_STATUS_IN_FULL) != 0)
|
|
||||||
continue;
|
|
||||||
IO::outb(I8042_DATA_PORT, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool i8042_command(uint8_t target, uint8_t command)
|
|
||||||
{
|
|
||||||
if (target == TARGET_MOUSE)
|
|
||||||
IO::outb(I8042_COMMAND_REGISTER, 0xD4);
|
|
||||||
|
|
||||||
auto timeout = PIT::ms_since_boot() + I8042_TIMEOUT_MS;
|
|
||||||
|
|
||||||
while (PIT::ms_since_boot() < timeout)
|
|
||||||
{
|
|
||||||
if ((IO::inb(I8042_STATUS_REGISTER) & I8042_STATUS_IN_FULL) == 0)
|
|
||||||
{
|
|
||||||
IO::outb(I8042_DATA_PORT, command);
|
|
||||||
s_command_sent = PIT::ms_since_boot();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void i8042_handle_byte(uint8_t target, uint8_t raw)
|
|
||||||
{
|
|
||||||
bool waiting_response = false;
|
|
||||||
|
|
||||||
if (!s_command_queue.empty())
|
|
||||||
{
|
|
||||||
auto& command = s_command_queue.front();
|
|
||||||
if (command.target == target && command._sent && !command._done)
|
|
||||||
waiting_response = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (target == TARGET_KEYBOARD)
|
|
||||||
{
|
|
||||||
if (waiting_response)
|
|
||||||
{
|
|
||||||
auto& command = s_command_queue.front();
|
|
||||||
|
|
||||||
if (raw == I8042_KB_RESEND)
|
|
||||||
{
|
|
||||||
dprintln("PS/2 Keyboard: Resend 0x{H}", command._sent == 2 ? command.data : command.command);
|
|
||||||
command._sent--;
|
|
||||||
}
|
|
||||||
else if (raw == I8042_KB_ACK)
|
|
||||||
{
|
|
||||||
command._ack++;
|
|
||||||
if (command.resp_cnt == 0)
|
|
||||||
command._done = (command._ack >= (1 + command.has_data));
|
|
||||||
}
|
|
||||||
else if (raw == 0x00)
|
|
||||||
{
|
|
||||||
dprintln("\e[33mKey detection error or internal buffer overrun\e[m");
|
|
||||||
command._sent = 0;
|
|
||||||
command._ack = 0;
|
|
||||||
command._done = false;
|
|
||||||
s_command_response_index = 0;
|
|
||||||
}
|
|
||||||
else if (raw == 0xEE && command.command == 0xEE)
|
|
||||||
{
|
|
||||||
s_command_queue.pop();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
s_command_response[s_command_response_index++] = raw;
|
|
||||||
if (s_command_response_index >= command.resp_cnt)
|
|
||||||
command._done = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
s_keyboard_key_buffer[s_keyboard_key_buffer_size++] = raw;
|
|
||||||
if (raw != 0xE0)
|
|
||||||
keyboard_new_key();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (target == TARGET_MOUSE)
|
|
||||||
{
|
|
||||||
if (waiting_response)
|
|
||||||
{
|
|
||||||
auto& command = s_command_queue.front();
|
|
||||||
|
|
||||||
if (raw == I8042_MOUSE_ACK)
|
|
||||||
{
|
|
||||||
command._ack++;
|
|
||||||
if (command.resp_cnt == 0)
|
|
||||||
command._done = (command._ack >= (1 + command.has_data));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
s_command_response[s_command_response_index++] = raw;
|
|
||||||
if (s_command_response_index >= command.resp_cnt)
|
|
||||||
command._done = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
s_mouse_data_buffer[s_mouse_data_buffer_index++] = raw;
|
|
||||||
|
|
||||||
if (s_mouse_data_buffer_index >= 3)
|
|
||||||
{
|
|
||||||
if (s_mouse_data_buffer[0] & 0x07)
|
|
||||||
{
|
|
||||||
bool left = s_mouse_data_buffer[0] & (1 << 0);
|
|
||||||
bool right = s_mouse_data_buffer[0] & (1 << 1);
|
|
||||||
bool middle = s_mouse_data_buffer[0] & (1 << 2);
|
|
||||||
|
|
||||||
if (left) MUST(s_mouse_button_event_queue.push({ .button = MouseButton::Left }));
|
|
||||||
if (right) MUST(s_mouse_button_event_queue.push({ .button = MouseButton::Right }));
|
|
||||||
if (middle) MUST(s_mouse_button_event_queue.push({ .button = MouseButton::Middle }));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (s_mouse_data_buffer[1] || s_mouse_data_buffer[2])
|
|
||||||
{
|
|
||||||
int16_t rel_x = (int16_t)s_mouse_data_buffer[1] - ((s_mouse_data_buffer[0] << 4) & 0x100);
|
|
||||||
int16_t rel_y = (int16_t)s_mouse_data_buffer[2] - ((s_mouse_data_buffer[0] << 3) & 0x100);
|
|
||||||
|
|
||||||
MUST(s_mouse_move_event_queue.push({ .dx = rel_x, .dy = rel_y }));
|
|
||||||
}
|
|
||||||
|
|
||||||
s_mouse_data_buffer_index = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Kernel::panic("Unknown target");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void update()
|
|
||||||
{
|
|
||||||
if (!s_command_queue.empty())
|
|
||||||
{
|
|
||||||
auto& command = s_command_queue.front();
|
|
||||||
if (command.target != TARGET_KEYBOARD && command.target != TARGET_MOUSE)
|
|
||||||
Kernel::panic("Undefined target for command 0x{2H}", command.command);
|
|
||||||
|
|
||||||
if (command._sent == 0 && command._ack == 0)
|
|
||||||
{
|
|
||||||
command._sent++;
|
|
||||||
if (!i8042_command(command.target, command.command))
|
|
||||||
Kernel::panic("PS/2 command oof {}, 0x{2H}", command.target, command.command);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (command._sent == 1 && command._ack == 1 && command.has_data)
|
|
||||||
{
|
|
||||||
command._sent++;
|
|
||||||
if (!i8042_command(command.target, command.data))
|
|
||||||
Kernel::panic("PS/2 data oof {}, 0x{2H}", command.target, command.data);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (command._sent > 0 && PIT::ms_since_boot() > s_command_sent + 1000)
|
|
||||||
{
|
|
||||||
dprintln("PS/2 command 0x{2H} timed out on {}", command.command, command.target);
|
|
||||||
// Discard command on timeout?
|
|
||||||
command._done = true;
|
|
||||||
command.target = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (command._done)
|
|
||||||
{
|
|
||||||
if (command.target == TARGET_KEYBOARD)
|
|
||||||
{
|
|
||||||
switch (command.command)
|
|
||||||
{
|
|
||||||
case I8042_KB_RESET:
|
|
||||||
if (s_command_response[0] != I8042_KB_SELF_TEST_PASS)
|
|
||||||
Kernel::panic("PS/2 Keyboard self test failed");
|
|
||||||
break;
|
|
||||||
case I8042_KB_SET_SCAN_CODE_SET:
|
|
||||||
break;
|
|
||||||
case I8042_KB_SET_LEDS:
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
Kernel::panic("PS/2 Keyboard unhandled command");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (command.target == TARGET_MOUSE)
|
|
||||||
{
|
|
||||||
switch (command.command)
|
|
||||||
{
|
|
||||||
case I8042_MOUSE_RESET:
|
|
||||||
if (s_command_response[0] != I8042_MOUSE_SELF_TEST_PASS)
|
|
||||||
Kernel::panic("PS/2 Mouse self test failed");
|
|
||||||
if (s_command_response[1] != 0x00)
|
|
||||||
Kernel::panic("PS/2 Mouse invalid byte sent after self test");
|
|
||||||
break;
|
|
||||||
case I8042_MOUSE_ENABLE:
|
|
||||||
break;
|
|
||||||
case I8042_MOUSE_DISABLE:
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
Kernel::panic("PS/2 Mouse unhandled command");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
s_command_response_index = 0;
|
|
||||||
s_command_queue.pop();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
while (!s_key_event_queue.empty())
|
|
||||||
{
|
|
||||||
if (s_key_event_callback)
|
|
||||||
s_key_event_callback(s_key_event_queue.front());
|
|
||||||
s_key_event_queue.pop();
|
|
||||||
}
|
|
||||||
|
|
||||||
while (!s_mouse_button_event_queue.empty())
|
|
||||||
{
|
|
||||||
if (s_mouse_button_event_callback)
|
|
||||||
s_mouse_button_event_callback(s_mouse_button_event_queue.front());
|
|
||||||
s_mouse_button_event_queue.pop();
|
|
||||||
}
|
|
||||||
|
|
||||||
while (!s_mouse_move_event_queue.empty())
|
|
||||||
{
|
|
||||||
if (s_mouse_move_event_callback)
|
|
||||||
s_mouse_move_event_callback(s_mouse_move_event_queue.front());
|
|
||||||
s_mouse_move_event_queue.pop();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool is_key_down(Key key)
|
|
||||||
{
|
|
||||||
return s_keyboard_state[(int)key];
|
|
||||||
}
|
|
||||||
|
|
||||||
static void keyboard_new_key()
|
|
||||||
{
|
|
||||||
uint8_t index = 0;
|
|
||||||
bool extended = (s_keyboard_key_buffer[index] == 0xE0);
|
|
||||||
if (extended)
|
|
||||||
index++;
|
|
||||||
|
|
||||||
bool pressed = (s_keyboard_key_buffer[index] & 0x80) == 0;
|
|
||||||
uint8_t ch = s_keyboard_key_buffer[index] & ~0x80;
|
|
||||||
|
|
||||||
Key key = Key::INVALID;
|
|
||||||
|
|
||||||
if (extended)
|
|
||||||
{
|
|
||||||
key = scan_code_to_key_extended[ch];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (s_modifiers & MOD_SHIFT)
|
|
||||||
key = scan_code_to_key_shift[ch];
|
|
||||||
else if (s_modifiers & MOD_ALTGR)
|
|
||||||
key = scan_code_to_key_altgr[ch];
|
|
||||||
else
|
|
||||||
key = scan_code_to_key_normal[ch];
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((s_led_states & I8042_KB_LED_NUM_LOCK))
|
|
||||||
{
|
|
||||||
switch (key)
|
|
||||||
{
|
|
||||||
case Key::Numpad0: key = Key::Insert; break;
|
|
||||||
case Key::Numpad1: key = Key::End; break;
|
|
||||||
case Key::Numpad2: key = Key::Down; break;
|
|
||||||
case Key::Numpad3: key = Key::PageDown; break;
|
|
||||||
case Key::Numpad4: key = Key::Left; break;
|
|
||||||
case Key::Numpad5: key = Key::None; break;
|
|
||||||
case Key::Numpad6: key = Key::Right; break;
|
|
||||||
case Key::Numpad7: key = Key::Home; break;
|
|
||||||
case Key::Numpad8: key = Key::Up; break;
|
|
||||||
case Key::Numpad9: key = Key::PageUp; break;
|
|
||||||
case Key::NumpadSep: key = Key::Delete; break;
|
|
||||||
default: break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#if KEYBOARD_SHOW_UNKNOWN
|
|
||||||
if (key == Key::INVALID)
|
|
||||||
kprintln("{} {}", ch, extended ? 'E' : ' ');
|
|
||||||
#endif
|
|
||||||
|
|
||||||
s_keyboard_state[(int)key] = pressed;
|
|
||||||
|
|
||||||
bool update_leds = false;
|
|
||||||
switch (key)
|
|
||||||
{
|
|
||||||
case Key::ScrollLock:
|
|
||||||
update_leds = pressed;
|
|
||||||
if (update_leds)
|
|
||||||
s_led_states ^= I8042_KB_LED_SCROLL_LOCK;
|
|
||||||
break;
|
|
||||||
case Key::NumLock:
|
|
||||||
update_leds = pressed;
|
|
||||||
if (update_leds)
|
|
||||||
s_led_states ^= I8042_KB_LED_NUM_LOCK;
|
|
||||||
break;
|
|
||||||
case Key::CapsLock:
|
|
||||||
update_leds = pressed;
|
|
||||||
if (update_leds)
|
|
||||||
s_led_states ^= I8042_KB_LED_CAPS_LOCK;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (update_leds)
|
|
||||||
{
|
|
||||||
MUST(s_command_queue.push({
|
|
||||||
.target = TARGET_KEYBOARD,
|
|
||||||
.command = I8042_KB_SET_LEDS,
|
|
||||||
.data = s_led_states,
|
|
||||||
.has_data = true,
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t modifiers = 0;
|
|
||||||
if (s_keyboard_state[(int)Key::LeftShift] || s_keyboard_state[(int)Key::RightShift])
|
|
||||||
modifiers |= MOD_SHIFT;
|
|
||||||
if (s_keyboard_state[(int)Key::LeftCtrl] || s_keyboard_state[(int)Key::RightCtrl])
|
|
||||||
modifiers |= MOD_CTRL;
|
|
||||||
if (s_keyboard_state[(int)Key::LeftAlt])
|
|
||||||
modifiers |= MOD_ALT;
|
|
||||||
if (s_keyboard_state[(int)Key::RightAlt])
|
|
||||||
modifiers |= MOD_ALTGR;
|
|
||||||
if (s_led_states & I8042_KB_LED_CAPS_LOCK)
|
|
||||||
modifiers |= MOD_CAPS;
|
|
||||||
s_modifiers = modifiers;
|
|
||||||
|
|
||||||
if (key != Key::INVALID)
|
|
||||||
{
|
|
||||||
auto error_or = s_key_event_queue.push({ .key = key, .modifiers = modifiers, .pressed = pressed });
|
|
||||||
if (error_or.is_error())
|
|
||||||
dwarnln("{}", error_or.error());
|
|
||||||
}
|
|
||||||
s_keyboard_key_buffer_size -= index + 1;
|
|
||||||
memmove(s_keyboard_key_buffer, s_keyboard_key_buffer + index, s_keyboard_key_buffer_size);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void keyboard_irq_handler()
|
|
||||||
{
|
|
||||||
uint8_t raw = IO::inb(I8042_DATA_PORT);
|
|
||||||
#if DEBUG_ALL_IRQ
|
|
||||||
dprintln("k 0x{2H}", raw);
|
|
||||||
#endif
|
|
||||||
i8042_handle_byte(TARGET_KEYBOARD, raw);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void mouse_irq_handler()
|
|
||||||
{
|
|
||||||
uint8_t raw = IO::inb(I8042_DATA_PORT);
|
|
||||||
#if DEBUG_ALL_IRQ
|
|
||||||
dprintln("m 0x{2H}", raw);
|
|
||||||
#endif
|
|
||||||
i8042_handle_byte(TARGET_MOUSE, raw);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void initialize_keyboard()
|
|
||||||
{
|
|
||||||
// Register callback and IRQ
|
|
||||||
IDT::register_irq_handler(KEYBOARD_IRQ, keyboard_irq_handler);
|
|
||||||
InterruptController::get().enable_irq(KEYBOARD_IRQ);
|
|
||||||
i8042_controller_command(I8042_ENABLE_FIRST_PORT);
|
|
||||||
|
|
||||||
MUST(s_command_queue.push({
|
|
||||||
.target = TARGET_KEYBOARD,
|
|
||||||
.command = I8042_KB_RESET,
|
|
||||||
.resp_cnt = 1,
|
|
||||||
}));
|
|
||||||
|
|
||||||
// Set scan code set 2
|
|
||||||
MUST(s_command_queue.push({
|
|
||||||
.target = TARGET_KEYBOARD,
|
|
||||||
.command = I8042_KB_SET_SCAN_CODE_SET,
|
|
||||||
.data = 0x02,
|
|
||||||
.has_data = true,
|
|
||||||
}));
|
|
||||||
|
|
||||||
// Turn LEDs off
|
|
||||||
MUST(s_command_queue.push({
|
|
||||||
.target = TARGET_KEYBOARD,
|
|
||||||
.command = I8042_KB_SET_LEDS,
|
|
||||||
.data = s_led_states,
|
|
||||||
.has_data = true,
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
static void initialize_mouse()
|
|
||||||
{
|
|
||||||
// Register callback and IRQ
|
|
||||||
IDT::register_irq_handler(MOUSE_IRQ, mouse_irq_handler);
|
|
||||||
InterruptController::get().enable_irq(MOUSE_IRQ);
|
|
||||||
i8042_controller_command(I8042_ENABLE_SECOND_PORT);
|
|
||||||
|
|
||||||
MUST(s_command_queue.push({
|
|
||||||
.target = TARGET_MOUSE,
|
|
||||||
.command = I8042_MOUSE_RESET,
|
|
||||||
.resp_cnt = 2,
|
|
||||||
}));
|
|
||||||
|
|
||||||
// Mouse should be disabled when sending commands
|
|
||||||
MUST(s_command_queue.push({
|
|
||||||
.target = TARGET_MOUSE,
|
|
||||||
.command = I8042_MOUSE_ENABLE,
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
bool initialize()
|
|
||||||
{
|
|
||||||
// https://wiki.osdev.org/%228042%22_PS/2_Controller
|
|
||||||
|
|
||||||
// Step 1: Initialize USB Controllers
|
|
||||||
// TODO
|
|
||||||
|
|
||||||
// Stem 2: Determine if the PS/2 Controller Exists
|
|
||||||
// TODO
|
|
||||||
|
|
||||||
// Step 3: Disable Devices
|
|
||||||
i8042_controller_command(I8042_DISABLE_FIRST_PORT);
|
|
||||||
i8042_controller_command(I8042_DISABLE_SECOND_PORT);
|
|
||||||
|
|
||||||
// Step 4: Flush The Ouput Buffer
|
|
||||||
while ((IO::inb(I8042_STATUS_REGISTER) & I8042_STATUS_OUT_FULL) != 0)
|
|
||||||
IO::inb(I8042_DATA_PORT);
|
|
||||||
|
|
||||||
// Step 5: Set the Controller Configuration Byte
|
|
||||||
i8042_controller_command(I8042_READ_CONFIG);
|
|
||||||
uint8_t config = wait_and_read();
|
|
||||||
config &= ~(I8042_CONFING_IRQ_FIRST | I8042_CONFING_IRQ_SECOND);
|
|
||||||
i8042_controller_command(I8042_WRITE_CONFIG, config);
|
|
||||||
|
|
||||||
|
|
||||||
// Step 6: Perform Controller Self Test
|
|
||||||
i8042_controller_command(I8042_TEST_CONTROLLER);
|
|
||||||
if (wait_and_read() != I8042_TEST_CONTROLLER_PASS)
|
|
||||||
{
|
|
||||||
derrorln("PS/2 controller self test failed");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Step 7: Determine If There Are 2 Channels
|
|
||||||
bool dual_channel = MOUSE_ENABLED ? config & I8042_CONFING_DUAL_CHANNEL : false;
|
|
||||||
if (dual_channel)
|
|
||||||
{
|
|
||||||
i8042_controller_command(I8042_ENABLE_SECOND_PORT);
|
|
||||||
i8042_controller_command(I8042_READ_CONFIG);
|
|
||||||
if (wait_and_read() & I8042_CONFING_DUAL_CHANNEL)
|
|
||||||
dual_channel = false;
|
|
||||||
else
|
|
||||||
i8042_controller_command(I8042_DISABLE_SECOND_PORT);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Step 8: Perform Interface Tests
|
|
||||||
i8042_controller_command(I8042_TEST_FIRST_PORT);
|
|
||||||
if (wait_and_read() != I8042_TEST_FIRST_PORT_PASS)
|
|
||||||
{
|
|
||||||
derrorln("PS/2 first port test failed");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dual_channel)
|
|
||||||
{
|
|
||||||
i8042_controller_command(I8042_TEST_SECOND_PORT);
|
|
||||||
if (wait_and_read() != I8042_TEST_SECOND_PORT_PASS)
|
|
||||||
{
|
|
||||||
dwarnln("PS/2 second port test failed. Mouse will be disabled");
|
|
||||||
dual_channel = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Step 9: Enable Devices
|
|
||||||
config |= I8042_CONFING_IRQ_FIRST;
|
|
||||||
if (dual_channel)
|
|
||||||
config |= I8042_CONFING_IRQ_SECOND;
|
|
||||||
i8042_controller_command(I8042_WRITE_CONFIG, config);
|
|
||||||
|
|
||||||
// Step 10: Reset Devices
|
|
||||||
initialize_keyboard();
|
|
||||||
if (dual_channel)
|
|
||||||
initialize_mouse();
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void register_key_event_callback(const BAN::Function<void(KeyEvent)>& callback)
|
|
||||||
{
|
|
||||||
s_key_event_callback = callback;
|
|
||||||
}
|
|
||||||
|
|
||||||
void register_mouse_button_event_callback(const BAN::Function<void(MouseButtonEvent)>& callback)
|
|
||||||
{
|
|
||||||
s_mouse_button_event_callback = callback;
|
|
||||||
}
|
|
||||||
|
|
||||||
void register_mouse_move_event_callback(const BAN::Function<void(MouseMoveEvent)>& callback)
|
|
||||||
{
|
|
||||||
s_mouse_move_event_callback = callback;
|
|
||||||
}
|
|
||||||
|
|
||||||
const char* key_event_to_utf8(KeyEvent event)
|
|
||||||
{
|
|
||||||
bool shift = event.modifiers & MOD_SHIFT;
|
|
||||||
bool caps = event.modifiers & MOD_CAPS;
|
|
||||||
if (shift ^ caps)
|
|
||||||
return s_key_to_utf8_upper[(int)event.key];
|
|
||||||
return s_key_to_utf8_lower[(int)event.key];
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -0,0 +1,334 @@
|
||||||
|
#include <BAN/ScopeGuard.h>
|
||||||
|
#include <kernel/ACPI.h>
|
||||||
|
#include <kernel/IDT.h>
|
||||||
|
#include <kernel/Input/PS2Controller.h>
|
||||||
|
#include <kernel/Input/PS2Keyboard.h>
|
||||||
|
#include <kernel/InterruptController.h>
|
||||||
|
#include <kernel/IO.h>
|
||||||
|
|
||||||
|
namespace Kernel::Input
|
||||||
|
{
|
||||||
|
|
||||||
|
namespace PS2
|
||||||
|
{
|
||||||
|
|
||||||
|
enum IOPort : uint8_t
|
||||||
|
{
|
||||||
|
DATA = 0x60,
|
||||||
|
STATUS = 0x64,
|
||||||
|
COMMAND = 0x64,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum Status : uint8_t
|
||||||
|
{
|
||||||
|
OUTPUT_FULL = (1 << 0),
|
||||||
|
INPUT_FULL = (1 << 1),
|
||||||
|
SYSTEM = (1 << 2),
|
||||||
|
DEVICE_OR_CONTROLLER = (1 << 3),
|
||||||
|
TIMEOUT_ERROR = (1 << 6),
|
||||||
|
PARITY_ERROR = (1 << 7),
|
||||||
|
};
|
||||||
|
|
||||||
|
enum Config : uint8_t
|
||||||
|
{
|
||||||
|
INTERRUPT_FIRST_PORT = (1 << 0),
|
||||||
|
INTERRUPT_SECOND_PORT = (1 << 1),
|
||||||
|
SYSTEM_FLAG = (1 << 2),
|
||||||
|
ZERO1 = (1 << 3),
|
||||||
|
CLOCK_FIRST_PORT = (1 << 4),
|
||||||
|
CLOCK_SECOND_PORT = (1 << 5),
|
||||||
|
TRANSLATION_FIRST_PORT = (1 << 6),
|
||||||
|
ZERO2 = (1 << 7),
|
||||||
|
};
|
||||||
|
|
||||||
|
enum Command : uint8_t
|
||||||
|
{
|
||||||
|
READ_CONFIG = 0x20,
|
||||||
|
WRITE_CONFIG = 0x60,
|
||||||
|
DISABLE_SECOND_PORT = 0xA7,
|
||||||
|
ENABLE_SECOND_PORT = 0xA8,
|
||||||
|
TEST_SECOND_PORT = 0xA9,
|
||||||
|
TEST_CONTROLLER = 0xAA,
|
||||||
|
TEST_FIRST_PORT = 0xAB,
|
||||||
|
DISABLE_FIRST_PORT = 0xAD,
|
||||||
|
ENABLE_FIRST_PORT = 0xAE,
|
||||||
|
WRITE_TO_SECOND_PORT = 0xD4,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum Response
|
||||||
|
{
|
||||||
|
TEST_FIRST_PORT_PASS = 0x00,
|
||||||
|
TEST_SECOND_PORT_PASS = 0x00,
|
||||||
|
TEST_CONTROLLER_PASS = 0x55,
|
||||||
|
SELF_TEST_PASS = 0xAA,
|
||||||
|
ACK = 0xFA,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum DeviceCommand
|
||||||
|
{
|
||||||
|
ENABLE_SCANNING = 0xF4,
|
||||||
|
DISABLE_SCANNING = 0xF5,
|
||||||
|
IDENTIFY = 0xF2,
|
||||||
|
RESET = 0xFF,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum IRQ
|
||||||
|
{
|
||||||
|
DEVICE0 = 1,
|
||||||
|
DEVICE1 = 12,
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr uint64_t s_device_timeout_ms = 100;
|
||||||
|
|
||||||
|
static void controller_send_command(PS2::Command command)
|
||||||
|
{
|
||||||
|
IO::outb(PS2::IOPort::COMMAND, command);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void controller_send_command(PS2::Command command, uint8_t data)
|
||||||
|
{
|
||||||
|
IO::outb(PS2::IOPort::COMMAND, command);
|
||||||
|
while (IO::inb(PS2::IOPort::STATUS) & PS2::Status::INPUT_FULL)
|
||||||
|
continue;
|
||||||
|
IO::outb(PS2::IOPort::DATA, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint8_t wait_and_read()
|
||||||
|
{
|
||||||
|
while (!(IO::inb(PS2::IOPort::STATUS) & PS2::Status::OUTPUT_FULL))
|
||||||
|
continue;
|
||||||
|
return IO::inb(PS2::IOPort::DATA);
|
||||||
|
}
|
||||||
|
|
||||||
|
static BAN::ErrorOr<void> device_send_byte(uint8_t device, uint8_t byte)
|
||||||
|
{
|
||||||
|
if (device == 1)
|
||||||
|
IO::outb(PS2::IOPort::COMMAND, PS2::Command::WRITE_TO_SECOND_PORT);
|
||||||
|
uint64_t timeout = PIT::ms_since_boot() + s_device_timeout_ms;
|
||||||
|
while (PIT::ms_since_boot() < timeout)
|
||||||
|
{
|
||||||
|
if (!(IO::inb(PS2::IOPort::STATUS) & PS2::Status::INPUT_FULL))
|
||||||
|
{
|
||||||
|
IO::outb(PS2::IOPort::DATA, byte);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return BAN::Error::from_c_string("PS/2 device timeout");
|
||||||
|
}
|
||||||
|
|
||||||
|
static BAN::ErrorOr<uint8_t> device_read_byte()
|
||||||
|
{
|
||||||
|
uint64_t timeout = PIT::ms_since_boot() + s_device_timeout_ms;
|
||||||
|
while (PIT::ms_since_boot() < timeout)
|
||||||
|
if (IO::inb(PS2::IOPort::STATUS) & PS2::Status::OUTPUT_FULL)
|
||||||
|
return IO::inb(PS2::IOPort::DATA);
|
||||||
|
return BAN::Error::from_c_string("PS/2 device timeout");
|
||||||
|
}
|
||||||
|
|
||||||
|
static BAN::ErrorOr<void> device_wait_ack()
|
||||||
|
{
|
||||||
|
while (TRY(device_read_byte()) != PS2::Response::ACK)
|
||||||
|
continue;;
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
void PS2Controller::device0_irq()
|
||||||
|
{
|
||||||
|
auto& controller = PS2Controller::get();
|
||||||
|
ASSERT(controller.m_devices[0] != nullptr);
|
||||||
|
controller.m_devices[0]->on_byte(IO::inb(PS2::IOPort::DATA));
|
||||||
|
}
|
||||||
|
|
||||||
|
void PS2Controller::device1_irq()
|
||||||
|
{
|
||||||
|
auto& controller = PS2Controller::get();
|
||||||
|
ASSERT(controller.m_devices[1] != nullptr);
|
||||||
|
controller.m_devices[1]->on_byte(IO::inb(PS2::IOPort::DATA));
|
||||||
|
}
|
||||||
|
|
||||||
|
static PS2Controller* s_instance = nullptr;
|
||||||
|
|
||||||
|
BAN::ErrorOr<void> PS2Controller::initialize()
|
||||||
|
{
|
||||||
|
ASSERT(s_instance == nullptr);
|
||||||
|
s_instance = new PS2Controller;
|
||||||
|
if (s_instance == nullptr)
|
||||||
|
return BAN::Error::from_errno(ENOMEM);
|
||||||
|
BAN::ScopeGuard guard([] { delete s_instance; });
|
||||||
|
TRY(s_instance->initialize_impl());
|
||||||
|
guard.disable();
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
PS2Controller& PS2Controller::get()
|
||||||
|
{
|
||||||
|
ASSERT(s_instance != nullptr);
|
||||||
|
return *s_instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
BAN::ErrorOr<void> PS2Controller::initialize_impl()
|
||||||
|
{
|
||||||
|
// Step 1: Initialise USB Controllers
|
||||||
|
// FIXME
|
||||||
|
|
||||||
|
// Step 2: Determine if the PS/2 Controller Exists
|
||||||
|
if (false)
|
||||||
|
{
|
||||||
|
const ACPI::FADT* fadt = (const ACPI::FADT*)TRY(ACPI::get().get_header("FACP"));
|
||||||
|
bool ps2_exists = fadt->iapc_boot_arch & (1 << 1);
|
||||||
|
ACPI::get().unmap_header(fadt);
|
||||||
|
|
||||||
|
if (!ps2_exists)
|
||||||
|
return BAN::Error::from_c_string("PS2 Controller does not exist");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 3: Disable Devices
|
||||||
|
controller_send_command(PS2::Command::DISABLE_FIRST_PORT);
|
||||||
|
controller_send_command(PS2::Command::DISABLE_SECOND_PORT);
|
||||||
|
|
||||||
|
// Step 4: Flush The Output Buffer
|
||||||
|
IO::inb(PS2::IOPort::DATA);
|
||||||
|
|
||||||
|
// Step 5: Set the Controller Configuration Byte
|
||||||
|
controller_send_command(PS2::Command::READ_CONFIG);
|
||||||
|
uint8_t config = wait_and_read();
|
||||||
|
config &= ~PS2::Config::INTERRUPT_FIRST_PORT;
|
||||||
|
config &= ~PS2::Config::INTERRUPT_SECOND_PORT;
|
||||||
|
config &= ~PS2::Config::TRANSLATION_FIRST_PORT;
|
||||||
|
controller_send_command(PS2::Command::WRITE_CONFIG, config);
|
||||||
|
|
||||||
|
// Step 6: Perform Controller Self Test
|
||||||
|
controller_send_command(PS2::Command::TEST_CONTROLLER);
|
||||||
|
if (wait_and_read() != PS2::Response::TEST_CONTROLLER_PASS)
|
||||||
|
return BAN::Error::from_c_string("PS/2 Controller self test failed");
|
||||||
|
// NOTE: self test might reset the device so we set the config byte again
|
||||||
|
controller_send_command(PS2::Command::WRITE_CONFIG, config);
|
||||||
|
|
||||||
|
// Step 7: Determine If There Are 2 Channels
|
||||||
|
bool valid_ports[2] { true, false };
|
||||||
|
if (config & PS2::Config::CLOCK_SECOND_PORT)
|
||||||
|
{
|
||||||
|
controller_send_command(PS2::Command::ENABLE_SECOND_PORT);
|
||||||
|
controller_send_command(PS2::Command::READ_CONFIG);
|
||||||
|
if (!(wait_and_read() & PS2::Config::CLOCK_SECOND_PORT))
|
||||||
|
valid_ports[1] = true;
|
||||||
|
controller_send_command(PS2::Command::DISABLE_SECOND_PORT);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 8: Perform Interface Tests
|
||||||
|
controller_send_command(PS2::Command::TEST_FIRST_PORT);
|
||||||
|
if (wait_and_read() != PS2::Response::TEST_FIRST_PORT_PASS)
|
||||||
|
valid_ports[0] = false;
|
||||||
|
if (valid_ports[1])
|
||||||
|
{
|
||||||
|
controller_send_command(PS2::Command::TEST_SECOND_PORT);
|
||||||
|
if (wait_and_read() != PS2::Response::TEST_SECOND_PORT_PASS)
|
||||||
|
valid_ports[1] = false;
|
||||||
|
}
|
||||||
|
if (!valid_ports[0] && !valid_ports[1])
|
||||||
|
return BAN::Error::from_c_string("No ports available on Controller");
|
||||||
|
|
||||||
|
// Step 9: Enable Devices (and disable scanning)
|
||||||
|
for (uint8_t device = 0; device < 2; device++)
|
||||||
|
{
|
||||||
|
if (!valid_ports[device])
|
||||||
|
continue;
|
||||||
|
controller_send_command(device == 0 ? PS2::Command::ENABLE_FIRST_PORT : PS2::Command::ENABLE_SECOND_PORT);
|
||||||
|
if (set_scanning(device, false).is_error())
|
||||||
|
valid_ports[device] = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 10: Reset Devices
|
||||||
|
for (uint8_t device = 0; device < 2; device++)
|
||||||
|
{
|
||||||
|
if (!valid_ports[device])
|
||||||
|
continue;
|
||||||
|
if (reset_device(device).is_error())
|
||||||
|
valid_ports[device] = false;
|
||||||
|
if (set_scanning(device, false).is_error())
|
||||||
|
valid_ports[device] = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 11: Initialize Device Drivers
|
||||||
|
for (uint8_t device = 0; device < 2; device++)
|
||||||
|
{
|
||||||
|
if (!valid_ports[device])
|
||||||
|
continue;
|
||||||
|
if (auto res = initialize_device(device); res.is_error())
|
||||||
|
dprintln("{}", res.error());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_devices[0])
|
||||||
|
{
|
||||||
|
IDT::register_irq_handler(PS2::IRQ::DEVICE0, device0_irq);
|
||||||
|
InterruptController::get().enable_irq(PS2::IRQ::DEVICE0);
|
||||||
|
config |= PS2::Config::INTERRUPT_FIRST_PORT;
|
||||||
|
DeviceManager::get().add_device(m_devices[0]);
|
||||||
|
}
|
||||||
|
if (m_devices[1])
|
||||||
|
{
|
||||||
|
IDT::register_irq_handler(PS2::IRQ::DEVICE1, device1_irq);
|
||||||
|
InterruptController::get().enable_irq(PS2::IRQ::DEVICE1);
|
||||||
|
config |= PS2::Config::INTERRUPT_SECOND_PORT;
|
||||||
|
DeviceManager::get().add_device(m_devices[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
controller_send_command(PS2::Command::WRITE_CONFIG, config);
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
BAN::ErrorOr<void> PS2Controller::initialize_device(uint8_t device)
|
||||||
|
{
|
||||||
|
TRY(device_send_byte(device, PS2::DeviceCommand::IDENTIFY));
|
||||||
|
TRY(device_wait_ack());
|
||||||
|
|
||||||
|
uint8_t bytes[2] {};
|
||||||
|
uint8_t index = 0;
|
||||||
|
for (uint8_t i = 0; i < 2; i++)
|
||||||
|
{
|
||||||
|
auto res = device_read_byte();
|
||||||
|
if (res.is_error())
|
||||||
|
break;
|
||||||
|
bytes[index++] = res.value();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Standard PS/2 Mouse
|
||||||
|
if (index == 1 && (bytes[0] == 0x00))
|
||||||
|
return BAN::Error::from_c_string("PS/2 mouse not supported");
|
||||||
|
|
||||||
|
// MF2 Keyboard
|
||||||
|
if (index == 2 && (bytes[0] == 0xAB && bytes[1] == 0x83))
|
||||||
|
m_devices[device] = TRY(PS2Keyboard::create(*this));
|
||||||
|
|
||||||
|
if (m_devices[device])
|
||||||
|
return {};
|
||||||
|
return BAN::Error::from_format("Unhandled PS/2 device {}{} ({} bytes)", bytes[0], bytes[1], index);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PS2Controller::send_byte(const PS2Device* device, uint8_t byte)
|
||||||
|
{
|
||||||
|
ASSERT(device != nullptr && (device == m_devices[0] || device == m_devices[1]));
|
||||||
|
uint8_t device_index = (device == m_devices[0]) ? 0 : 1;
|
||||||
|
MUST(device_send_byte(device_index, byte));
|
||||||
|
}
|
||||||
|
|
||||||
|
BAN::ErrorOr<void> PS2Controller::reset_device(uint8_t device)
|
||||||
|
{
|
||||||
|
TRY(device_send_byte(device, PS2::DeviceCommand::RESET));
|
||||||
|
TRY(device_wait_ack());
|
||||||
|
if (TRY(device_read_byte()) != PS2::Response::SELF_TEST_PASS)
|
||||||
|
return BAN::Error::from_c_string("Device reset failed");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
BAN::ErrorOr<void> PS2Controller::set_scanning(uint8_t device, bool enabled)
|
||||||
|
{
|
||||||
|
TRY(device_send_byte(device, enabled ? PS2::DeviceCommand::ENABLE_SCANNING : PS2::DeviceCommand::DISABLE_SCANNING));
|
||||||
|
TRY(device_wait_ack());
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,244 @@
|
||||||
|
#include <BAN/ScopeGuard.h>
|
||||||
|
#include <kernel/CriticalScope.h>
|
||||||
|
#include <kernel/Input/PS2Keyboard.h>
|
||||||
|
|
||||||
|
#define SET_MASK(byte, mask, on_off) ((on_off) ? ((byte) | (mask)) : ((byte) & ~(mask)))
|
||||||
|
#define TOGGLE_MASK(byte, mask) ((byte) ^ (mask))
|
||||||
|
|
||||||
|
namespace Kernel::Input
|
||||||
|
{
|
||||||
|
|
||||||
|
namespace PS2
|
||||||
|
{
|
||||||
|
|
||||||
|
enum Response
|
||||||
|
{
|
||||||
|
KEY_ERROR_OR_BUFFER_OVERRUN1 = 0x00,
|
||||||
|
SELF_TEST_PASSED = 0xAA,
|
||||||
|
ECHO_RESPONSE = 0xEE,
|
||||||
|
ACK = 0xFA,
|
||||||
|
RESEND = 0xFE,
|
||||||
|
KEY_ERROR_OR_BUFFER_OVERRUN2 = 0xFF,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum Scancode
|
||||||
|
{
|
||||||
|
SET_SCANCODE_SET1 = 1,
|
||||||
|
SET_SCANCODE_SET2 = 2,
|
||||||
|
SET_SCANCODE_SET3 = 3,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum Leds
|
||||||
|
{
|
||||||
|
SCROLL_LOCK = (1 << 0),
|
||||||
|
NUM_LOCK = (1 << 1),
|
||||||
|
CAPS_LOCK = (1 << 2),
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
BAN::ErrorOr<PS2Keyboard*> PS2Keyboard::create(PS2Controller& controller)
|
||||||
|
{
|
||||||
|
PS2Keyboard* keyboard = new PS2Keyboard(controller);
|
||||||
|
if (keyboard == nullptr)
|
||||||
|
return BAN::Error::from_errno(ENOMEM);
|
||||||
|
BAN::ScopeGuard guard([keyboard] { delete keyboard; });
|
||||||
|
TRY(keyboard->initialize());
|
||||||
|
guard.disable();
|
||||||
|
return keyboard;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PS2Keyboard::on_byte(uint8_t byte)
|
||||||
|
{
|
||||||
|
// NOTE: This implementation does not allow using commands
|
||||||
|
// that respond with more bytes than ACK
|
||||||
|
switch (m_state)
|
||||||
|
{
|
||||||
|
case State::WaitingAck:
|
||||||
|
{
|
||||||
|
switch (byte)
|
||||||
|
{
|
||||||
|
case PS2::Response::ACK:
|
||||||
|
m_command_queue.pop();
|
||||||
|
m_state = State::Normal;
|
||||||
|
break;
|
||||||
|
case PS2::Response::RESEND:
|
||||||
|
m_state = State::Normal;
|
||||||
|
break;
|
||||||
|
case PS2::Response::KEY_ERROR_OR_BUFFER_OVERRUN1:
|
||||||
|
case PS2::Response::KEY_ERROR_OR_BUFFER_OVERRUN2:
|
||||||
|
dwarnln("Key detection error or internal buffer overrun");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
dwarnln("Unhandeled byte {2H}", byte);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case State::Normal:
|
||||||
|
{
|
||||||
|
m_byte_buffer[m_byte_index++] = byte;
|
||||||
|
if (byte != 0xE0 && byte != 0xF0)
|
||||||
|
buffer_has_key();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BAN::ErrorOr<void> PS2Keyboard::initialize()
|
||||||
|
{
|
||||||
|
append_command_queue(Command::SET_LEDS, 0x00);
|
||||||
|
append_command_queue(Command::SCANCODE, PS2::Scancode::SET_SCANCODE_SET2);
|
||||||
|
append_command_queue(Command::ENABLE_SCANNING);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
void PS2Keyboard::update()
|
||||||
|
{
|
||||||
|
if (m_state == State::WaitingAck)
|
||||||
|
return;
|
||||||
|
if (m_command_queue.empty())
|
||||||
|
return;
|
||||||
|
m_state = State::WaitingAck;
|
||||||
|
m_controller.send_byte(this, m_command_queue.front());
|
||||||
|
}
|
||||||
|
|
||||||
|
void PS2Keyboard::append_command_queue(uint8_t byte)
|
||||||
|
{
|
||||||
|
if (m_command_queue.full())
|
||||||
|
{
|
||||||
|
dwarnln("PS/2 command queue full");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
m_command_queue.push(byte);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PS2Keyboard::append_command_queue(uint8_t byte1, uint8_t byte2)
|
||||||
|
{
|
||||||
|
if (m_command_queue.size() + 2 > m_command_queue.capacity())
|
||||||
|
{
|
||||||
|
dwarnln("PS/2 command queue full");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
m_command_queue.push(byte1);
|
||||||
|
m_command_queue.push(byte2);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PS2Keyboard::buffer_has_key()
|
||||||
|
{
|
||||||
|
uint32_t scancode = 0;
|
||||||
|
bool extended = false;
|
||||||
|
bool released = false;
|
||||||
|
|
||||||
|
for (uint8_t i = 0; i < m_byte_index; i++)
|
||||||
|
{
|
||||||
|
if (m_byte_buffer[i] == 0xE0)
|
||||||
|
extended = true;
|
||||||
|
else if (m_byte_buffer[i] == 0xF0)
|
||||||
|
released = true;
|
||||||
|
else
|
||||||
|
scancode = (scancode << 8) | m_byte_buffer[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (extended)
|
||||||
|
scancode |= 0x80000000;
|
||||||
|
|
||||||
|
m_byte_index = 0;
|
||||||
|
|
||||||
|
Key key = m_keymap.key_for_scancode_and_modifiers(scancode, m_modifiers);
|
||||||
|
|
||||||
|
if (key == Key::None)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (key == Input::Key::Invalid)
|
||||||
|
{
|
||||||
|
dprintln("unknown key for scancode {2H} {}", scancode & 0x7FFFFFFF, extended ? 'E' : ' ');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t modifier_mask = 0;
|
||||||
|
uint8_t toggle_mask = 0;
|
||||||
|
switch (key)
|
||||||
|
{
|
||||||
|
case Input::Key::LeftShift:
|
||||||
|
case Input::Key::RightShift:
|
||||||
|
modifier_mask = (uint8_t)Input::KeyEvent::Modifier::Shift;
|
||||||
|
break;
|
||||||
|
case Input::Key::LeftCtrl:
|
||||||
|
case Input::Key::RightCtrl:
|
||||||
|
modifier_mask = (uint8_t)Input::KeyEvent::Modifier::Ctrl;
|
||||||
|
break;
|
||||||
|
case Input::Key::Alt:
|
||||||
|
modifier_mask = (uint8_t)Input::KeyEvent::Modifier::Alt;
|
||||||
|
break;
|
||||||
|
case Input::Key::AltGr:
|
||||||
|
modifier_mask = (uint8_t)Input::KeyEvent::Modifier::AltGr;
|
||||||
|
break;;
|
||||||
|
case Input::Key::ScrollLock:
|
||||||
|
toggle_mask = (uint8_t)Input::KeyEvent::Modifier::ScrollLock;
|
||||||
|
break;
|
||||||
|
case Input::Key::NumLock:
|
||||||
|
toggle_mask = (uint8_t)Input::KeyEvent::Modifier::NumLock;
|
||||||
|
break;
|
||||||
|
case Input::Key::CapsLock:
|
||||||
|
toggle_mask = (uint8_t)Input::KeyEvent::Modifier::CapsLock;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (modifier_mask)
|
||||||
|
{
|
||||||
|
if (released)
|
||||||
|
m_modifiers &= ~modifier_mask;
|
||||||
|
else
|
||||||
|
m_modifiers |= modifier_mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (toggle_mask && !released)
|
||||||
|
{
|
||||||
|
m_modifiers ^= toggle_mask;
|
||||||
|
update_leds();
|
||||||
|
}
|
||||||
|
|
||||||
|
Input::KeyEvent event;
|
||||||
|
event.modifier = m_modifiers | (released ? (uint8_t)Input::KeyEvent::Modifier::Released : 0);
|
||||||
|
event.key = key;
|
||||||
|
|
||||||
|
if (m_event_queue.full())
|
||||||
|
{
|
||||||
|
dwarnln("PS/2 event queue full");
|
||||||
|
m_event_queue.pop();
|
||||||
|
}
|
||||||
|
m_event_queue.push(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void PS2Keyboard::update_leds()
|
||||||
|
{
|
||||||
|
uint8_t new_leds = 0;
|
||||||
|
if (m_modifiers & (uint8_t)Input::KeyEvent::Modifier::ScrollLock)
|
||||||
|
new_leds |= PS2::Leds::SCROLL_LOCK;
|
||||||
|
if (m_modifiers & (uint8_t)Input::KeyEvent::Modifier::NumLock)
|
||||||
|
new_leds |= PS2::Leds::NUM_LOCK;
|
||||||
|
if (m_modifiers & (uint8_t)Input::KeyEvent::Modifier::CapsLock)
|
||||||
|
new_leds |= PS2::Leds::CAPS_LOCK;
|
||||||
|
append_command_queue(Command::SET_LEDS, new_leds);
|
||||||
|
}
|
||||||
|
|
||||||
|
BAN::ErrorOr<void> PS2Keyboard::read(BAN::Span<uint8_t> output)
|
||||||
|
{
|
||||||
|
if (output.size() < sizeof(Input::KeyEvent))
|
||||||
|
return BAN::Error::from_c_string("Too small buffer for KeyEvent");
|
||||||
|
|
||||||
|
while (m_event_queue.empty())
|
||||||
|
PIT::sleep(1);
|
||||||
|
|
||||||
|
CriticalScope _;
|
||||||
|
*(Input::KeyEvent*)output.data() = m_event_queue.front();
|
||||||
|
m_event_queue.pop();
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,360 @@
|
||||||
|
#include <kernel/Input/PS2Keymap.h>
|
||||||
|
|
||||||
|
namespace Kernel::Input
|
||||||
|
{
|
||||||
|
|
||||||
|
PS2Keymap::PS2Keymap()
|
||||||
|
{
|
||||||
|
MUST(m_normal_keymap.resize(0xFF, Key::Invalid));
|
||||||
|
m_normal_keymap[0x01] = Key::F9;
|
||||||
|
m_normal_keymap[0x03] = Key::F5;
|
||||||
|
m_normal_keymap[0x04] = Key::F3;
|
||||||
|
m_normal_keymap[0x05] = Key::F1;
|
||||||
|
m_normal_keymap[0x06] = Key::F2;
|
||||||
|
m_normal_keymap[0x07] = Key::F11;
|
||||||
|
m_normal_keymap[0x09] = Key::F10;
|
||||||
|
m_normal_keymap[0x0A] = Key::F8;
|
||||||
|
m_normal_keymap[0x0B] = Key::F6;
|
||||||
|
m_normal_keymap[0x0C] = Key::F4;
|
||||||
|
m_normal_keymap[0x0D] = Key::Tab;
|
||||||
|
m_normal_keymap[0x0E] = Key::Section;
|
||||||
|
m_normal_keymap[0x11] = Key::Alt;
|
||||||
|
m_normal_keymap[0x12] = Key::LeftShift;
|
||||||
|
m_normal_keymap[0x14] = Key::LeftCtrl;
|
||||||
|
m_normal_keymap[0x15] = Key::Q;
|
||||||
|
m_normal_keymap[0x16] = Key::_1;
|
||||||
|
m_normal_keymap[0x1A] = Key::Z;
|
||||||
|
m_normal_keymap[0x1B] = Key::S;
|
||||||
|
m_normal_keymap[0x1C] = Key::A;
|
||||||
|
m_normal_keymap[0x1D] = Key::W;
|
||||||
|
m_normal_keymap[0x1E] = Key::_2;
|
||||||
|
m_normal_keymap[0x21] = Key::C;
|
||||||
|
m_normal_keymap[0x22] = Key::X;
|
||||||
|
m_normal_keymap[0x23] = Key::D;
|
||||||
|
m_normal_keymap[0x24] = Key::E;
|
||||||
|
m_normal_keymap[0x25] = Key::_4;
|
||||||
|
m_normal_keymap[0x26] = Key::_3;
|
||||||
|
m_normal_keymap[0x29] = Key::Space;
|
||||||
|
m_normal_keymap[0x2A] = Key::V;
|
||||||
|
m_normal_keymap[0x2B] = Key::F;
|
||||||
|
m_normal_keymap[0x2C] = Key::T;
|
||||||
|
m_normal_keymap[0x2D] = Key::R;
|
||||||
|
m_normal_keymap[0x2E] = Key::_5;
|
||||||
|
m_normal_keymap[0x31] = Key::N;
|
||||||
|
m_normal_keymap[0x32] = Key::B;
|
||||||
|
m_normal_keymap[0x33] = Key::H;
|
||||||
|
m_normal_keymap[0x34] = Key::G;
|
||||||
|
m_normal_keymap[0x35] = Key::Y;
|
||||||
|
m_normal_keymap[0x36] = Key::_6;
|
||||||
|
m_normal_keymap[0x3A] = Key::M;
|
||||||
|
m_normal_keymap[0x3B] = Key::J;
|
||||||
|
m_normal_keymap[0x3C] = Key::U;
|
||||||
|
m_normal_keymap[0x3D] = Key::_7;
|
||||||
|
m_normal_keymap[0x3E] = Key::_8;
|
||||||
|
m_normal_keymap[0x41] = Key::Comma;
|
||||||
|
m_normal_keymap[0x42] = Key::K;
|
||||||
|
m_normal_keymap[0x43] = Key::I;
|
||||||
|
m_normal_keymap[0x44] = Key::O;
|
||||||
|
m_normal_keymap[0x45] = Key::_0;
|
||||||
|
m_normal_keymap[0x46] = Key::_9;
|
||||||
|
m_normal_keymap[0x49] = Key::Period;
|
||||||
|
m_normal_keymap[0x4A] = Key::Hyphen;
|
||||||
|
m_normal_keymap[0x4B] = Key::L;
|
||||||
|
m_normal_keymap[0x4C] = Key::O_Umlaut;
|
||||||
|
m_normal_keymap[0x4D] = Key::P;
|
||||||
|
m_normal_keymap[0x4E] = Key::Plus;
|
||||||
|
m_normal_keymap[0x52] = Key::A_Umlaut;
|
||||||
|
m_normal_keymap[0x54] = Key::A_Ring;
|
||||||
|
m_normal_keymap[0x55] = Key::Acute;
|
||||||
|
m_normal_keymap[0x58] = Key::CapsLock;
|
||||||
|
m_normal_keymap[0x59] = Key::RightShift;
|
||||||
|
m_normal_keymap[0x59] = Key::RightShift;
|
||||||
|
m_normal_keymap[0x5A] = Key::Enter;
|
||||||
|
m_normal_keymap[0x5B] = Key::TwoDots;
|
||||||
|
m_normal_keymap[0x5D] = Key::SingleQuote;
|
||||||
|
m_normal_keymap[0x61] = Key::LessThan;
|
||||||
|
m_normal_keymap[0x66] = Key::Backspace;
|
||||||
|
m_normal_keymap[0x69] = Key::Numpad1;
|
||||||
|
m_normal_keymap[0x6B] = Key::Numpad4;
|
||||||
|
m_normal_keymap[0x6C] = Key::Numpad7;
|
||||||
|
m_normal_keymap[0x70] = Key::Numpad0;
|
||||||
|
m_normal_keymap[0x71] = Key::NumpadDecimal;
|
||||||
|
m_normal_keymap[0x72] = Key::Numpad2;
|
||||||
|
m_normal_keymap[0x73] = Key::Numpad5;
|
||||||
|
m_normal_keymap[0x74] = Key::Numpad6;
|
||||||
|
m_normal_keymap[0x75] = Key::Numpad8;
|
||||||
|
m_normal_keymap[0x76] = Key::Escape;
|
||||||
|
m_normal_keymap[0x77] = Key::NumLock;
|
||||||
|
m_normal_keymap[0x78] = Key::F11;
|
||||||
|
m_normal_keymap[0x79] = Key::NumpadPlus;
|
||||||
|
m_normal_keymap[0x7A] = Key::Numpad3;
|
||||||
|
m_normal_keymap[0x7B] = Key::NumpadMinus;
|
||||||
|
m_normal_keymap[0x7C] = Key::NumpadMultiply;
|
||||||
|
m_normal_keymap[0x7D] = Key::Numpad9;
|
||||||
|
m_normal_keymap[0x83] = Key::F7;
|
||||||
|
|
||||||
|
MUST(m_shift_keymap.resize(0xFF, Key::Invalid));
|
||||||
|
m_shift_keymap[0x01] = Key::F9;
|
||||||
|
m_shift_keymap[0x03] = Key::F5;
|
||||||
|
m_shift_keymap[0x04] = Key::F3;
|
||||||
|
m_shift_keymap[0x05] = Key::F1;
|
||||||
|
m_shift_keymap[0x06] = Key::F2;
|
||||||
|
m_shift_keymap[0x07] = Key::F11;
|
||||||
|
m_shift_keymap[0x09] = Key::F10;
|
||||||
|
m_shift_keymap[0x0A] = Key::F8;
|
||||||
|
m_shift_keymap[0x0B] = Key::F6;
|
||||||
|
m_shift_keymap[0x0C] = Key::F4;
|
||||||
|
m_shift_keymap[0x0D] = Key::Tab;
|
||||||
|
m_shift_keymap[0x0E] = Key::Half;
|
||||||
|
m_shift_keymap[0x11] = Key::Alt;
|
||||||
|
m_shift_keymap[0x12] = Key::LeftShift;
|
||||||
|
m_shift_keymap[0x14] = Key::LeftCtrl;
|
||||||
|
m_shift_keymap[0x15] = Key::Q;
|
||||||
|
m_shift_keymap[0x16] = Key::ExclamationMark;
|
||||||
|
m_shift_keymap[0x1A] = Key::Z;
|
||||||
|
m_shift_keymap[0x1B] = Key::S;
|
||||||
|
m_shift_keymap[0x1C] = Key::A;
|
||||||
|
m_shift_keymap[0x1D] = Key::W;
|
||||||
|
m_shift_keymap[0x1E] = Key::DoubleQuote;
|
||||||
|
m_shift_keymap[0x21] = Key::C;
|
||||||
|
m_shift_keymap[0x22] = Key::X;
|
||||||
|
m_shift_keymap[0x23] = Key::D;
|
||||||
|
m_shift_keymap[0x24] = Key::E;
|
||||||
|
m_shift_keymap[0x25] = Key::Currency;
|
||||||
|
m_shift_keymap[0x26] = Key::Hashtag;
|
||||||
|
m_shift_keymap[0x29] = Key::Space;
|
||||||
|
m_shift_keymap[0x2A] = Key::V;
|
||||||
|
m_shift_keymap[0x2B] = Key::F;
|
||||||
|
m_shift_keymap[0x2C] = Key::T;
|
||||||
|
m_shift_keymap[0x2D] = Key::R;
|
||||||
|
m_shift_keymap[0x2E] = Key::Percent;
|
||||||
|
m_shift_keymap[0x31] = Key::N;
|
||||||
|
m_shift_keymap[0x32] = Key::B;
|
||||||
|
m_shift_keymap[0x33] = Key::H;
|
||||||
|
m_shift_keymap[0x34] = Key::G;
|
||||||
|
m_shift_keymap[0x35] = Key::Y;
|
||||||
|
m_shift_keymap[0x36] = Key::Ampersand;
|
||||||
|
m_shift_keymap[0x3A] = Key::M;
|
||||||
|
m_shift_keymap[0x3B] = Key::J;
|
||||||
|
m_shift_keymap[0x3C] = Key::U;
|
||||||
|
m_shift_keymap[0x3D] = Key::Slash;
|
||||||
|
m_shift_keymap[0x3E] = Key::OpenBracet;
|
||||||
|
m_shift_keymap[0x41] = Key::Semicolon;
|
||||||
|
m_shift_keymap[0x42] = Key::K;
|
||||||
|
m_shift_keymap[0x43] = Key::I;
|
||||||
|
m_shift_keymap[0x44] = Key::O;
|
||||||
|
m_shift_keymap[0x45] = Key::Equals;
|
||||||
|
m_shift_keymap[0x46] = Key::CloseBracet;
|
||||||
|
m_shift_keymap[0x49] = Key::Period;
|
||||||
|
m_shift_keymap[0x4A] = Key::Hyphen;
|
||||||
|
m_shift_keymap[0x4B] = Key::L;
|
||||||
|
m_shift_keymap[0x4C] = Key::O_Umlaut;
|
||||||
|
m_shift_keymap[0x4D] = Key::P;
|
||||||
|
m_shift_keymap[0x4E] = Key::QuestionMark;
|
||||||
|
m_shift_keymap[0x52] = Key::A_Umlaut;
|
||||||
|
m_shift_keymap[0x54] = Key::A_Ring;
|
||||||
|
m_shift_keymap[0x55] = Key::BackTick;
|
||||||
|
m_shift_keymap[0x58] = Key::CapsLock;
|
||||||
|
m_shift_keymap[0x59] = Key::RightShift;
|
||||||
|
m_shift_keymap[0x59] = Key::RightShift;
|
||||||
|
m_shift_keymap[0x5A] = Key::Enter;
|
||||||
|
m_shift_keymap[0x5B] = Key::Caret;
|
||||||
|
m_shift_keymap[0x5D] = Key::Asterix;
|
||||||
|
m_shift_keymap[0x61] = Key::GreaterThan;
|
||||||
|
m_shift_keymap[0x66] = Key::Backspace;
|
||||||
|
m_shift_keymap[0x69] = Key::Numpad1;
|
||||||
|
m_shift_keymap[0x6B] = Key::Numpad4;
|
||||||
|
m_shift_keymap[0x6C] = Key::Numpad7;
|
||||||
|
m_shift_keymap[0x70] = Key::Numpad0;
|
||||||
|
m_shift_keymap[0x71] = Key::NumpadDecimal;
|
||||||
|
m_shift_keymap[0x72] = Key::Numpad2;
|
||||||
|
m_shift_keymap[0x73] = Key::Numpad5;
|
||||||
|
m_shift_keymap[0x74] = Key::Numpad6;
|
||||||
|
m_shift_keymap[0x75] = Key::Numpad8;
|
||||||
|
m_shift_keymap[0x76] = Key::Escape;
|
||||||
|
m_shift_keymap[0x77] = Key::NumLock;
|
||||||
|
m_shift_keymap[0x78] = Key::F11;
|
||||||
|
m_shift_keymap[0x79] = Key::NumpadPlus;
|
||||||
|
m_shift_keymap[0x7A] = Key::Numpad3;
|
||||||
|
m_shift_keymap[0x7B] = Key::NumpadMinus;
|
||||||
|
m_shift_keymap[0x7C] = Key::NumpadMultiply;
|
||||||
|
m_shift_keymap[0x7D] = Key::Numpad9;
|
||||||
|
m_shift_keymap[0x83] = Key::F7;
|
||||||
|
|
||||||
|
MUST(m_altgr_keymap.resize(0xFF, Key::Invalid));
|
||||||
|
m_altgr_keymap[0x01] = Key::F9;
|
||||||
|
m_altgr_keymap[0x03] = Key::F5;
|
||||||
|
m_altgr_keymap[0x04] = Key::F3;
|
||||||
|
m_altgr_keymap[0x05] = Key::F1;
|
||||||
|
m_altgr_keymap[0x06] = Key::F2;
|
||||||
|
m_altgr_keymap[0x07] = Key::F11;
|
||||||
|
m_altgr_keymap[0x09] = Key::F10;
|
||||||
|
m_altgr_keymap[0x0A] = Key::F8;
|
||||||
|
m_altgr_keymap[0x0B] = Key::F6;
|
||||||
|
m_altgr_keymap[0x0C] = Key::F4;
|
||||||
|
m_altgr_keymap[0x0D] = Key::Tab;
|
||||||
|
m_altgr_keymap[0x0E] = Key::None;
|
||||||
|
m_altgr_keymap[0x11] = Key::Alt;
|
||||||
|
m_altgr_keymap[0x12] = Key::LeftShift;
|
||||||
|
m_altgr_keymap[0x14] = Key::LeftCtrl;
|
||||||
|
m_altgr_keymap[0x15] = Key::Q;
|
||||||
|
m_altgr_keymap[0x16] = Key::None;
|
||||||
|
m_altgr_keymap[0x1A] = Key::Z;
|
||||||
|
m_altgr_keymap[0x1B] = Key::S;
|
||||||
|
m_altgr_keymap[0x1C] = Key::A;
|
||||||
|
m_altgr_keymap[0x1D] = Key::W;
|
||||||
|
m_altgr_keymap[0x1E] = Key::AtSign;
|
||||||
|
m_altgr_keymap[0x21] = Key::C;
|
||||||
|
m_altgr_keymap[0x22] = Key::X;
|
||||||
|
m_altgr_keymap[0x23] = Key::D;
|
||||||
|
m_altgr_keymap[0x24] = Key::E;
|
||||||
|
m_altgr_keymap[0x25] = Key::Dollar;
|
||||||
|
m_altgr_keymap[0x26] = Key::Pound;
|
||||||
|
m_altgr_keymap[0x29] = Key::Space;
|
||||||
|
m_altgr_keymap[0x2A] = Key::V;
|
||||||
|
m_altgr_keymap[0x2B] = Key::F;
|
||||||
|
m_altgr_keymap[0x2C] = Key::T;
|
||||||
|
m_altgr_keymap[0x2D] = Key::R;
|
||||||
|
m_altgr_keymap[0x2E] = Key::None;
|
||||||
|
m_altgr_keymap[0x31] = Key::N;
|
||||||
|
m_altgr_keymap[0x32] = Key::B;
|
||||||
|
m_altgr_keymap[0x33] = Key::H;
|
||||||
|
m_altgr_keymap[0x34] = Key::G;
|
||||||
|
m_altgr_keymap[0x35] = Key::Y;
|
||||||
|
m_altgr_keymap[0x36] = Key::None;
|
||||||
|
m_altgr_keymap[0x3A] = Key::M;
|
||||||
|
m_altgr_keymap[0x3B] = Key::J;
|
||||||
|
m_altgr_keymap[0x3C] = Key::U;
|
||||||
|
m_altgr_keymap[0x3D] = Key::OpenCurlyBrace;
|
||||||
|
m_altgr_keymap[0x3E] = Key::OpenBrace;
|
||||||
|
m_altgr_keymap[0x41] = Key::None;
|
||||||
|
m_altgr_keymap[0x42] = Key::K;
|
||||||
|
m_altgr_keymap[0x43] = Key::I;
|
||||||
|
m_altgr_keymap[0x44] = Key::O;
|
||||||
|
m_altgr_keymap[0x45] = Key::CloseCurlyBrace;
|
||||||
|
m_altgr_keymap[0x46] = Key::CloseBrace;
|
||||||
|
m_altgr_keymap[0x49] = Key::None;
|
||||||
|
m_altgr_keymap[0x4A] = Key::None;
|
||||||
|
m_altgr_keymap[0x4B] = Key::L;
|
||||||
|
m_altgr_keymap[0x4C] = Key::O_Umlaut;
|
||||||
|
m_altgr_keymap[0x4D] = Key::P;
|
||||||
|
m_altgr_keymap[0x4E] = Key::BackSlash;
|
||||||
|
m_altgr_keymap[0x52] = Key::A_Umlaut;
|
||||||
|
m_altgr_keymap[0x54] = Key::A_Ring;
|
||||||
|
m_altgr_keymap[0x55] = Key::None;
|
||||||
|
m_altgr_keymap[0x58] = Key::CapsLock;
|
||||||
|
m_altgr_keymap[0x59] = Key::RightShift;
|
||||||
|
m_altgr_keymap[0x59] = Key::RightShift;
|
||||||
|
m_altgr_keymap[0x5A] = Key::Enter;
|
||||||
|
m_altgr_keymap[0x5B] = Key::Tilde;
|
||||||
|
m_altgr_keymap[0x5D] = Key::None;
|
||||||
|
m_altgr_keymap[0x61] = Key::Pipe;
|
||||||
|
m_altgr_keymap[0x66] = Key::Backspace;
|
||||||
|
m_altgr_keymap[0x69] = Key::Numpad1;
|
||||||
|
m_altgr_keymap[0x6B] = Key::Numpad4;
|
||||||
|
m_altgr_keymap[0x6C] = Key::Numpad7;
|
||||||
|
m_altgr_keymap[0x70] = Key::Numpad0;
|
||||||
|
m_altgr_keymap[0x71] = Key::NumpadDecimal;
|
||||||
|
m_altgr_keymap[0x72] = Key::Numpad2;
|
||||||
|
m_altgr_keymap[0x73] = Key::Numpad5;
|
||||||
|
m_altgr_keymap[0x74] = Key::Numpad6;
|
||||||
|
m_altgr_keymap[0x75] = Key::Numpad8;
|
||||||
|
m_altgr_keymap[0x76] = Key::Escape;
|
||||||
|
m_altgr_keymap[0x77] = Key::NumLock;
|
||||||
|
m_altgr_keymap[0x78] = Key::F11;
|
||||||
|
m_altgr_keymap[0x79] = Key::NumpadPlus;
|
||||||
|
m_altgr_keymap[0x7A] = Key::Numpad3;
|
||||||
|
m_altgr_keymap[0x7B] = Key::NumpadMinus;
|
||||||
|
m_altgr_keymap[0x7C] = Key::NumpadMultiply;
|
||||||
|
m_altgr_keymap[0x7D] = Key::Numpad9;
|
||||||
|
m_altgr_keymap[0x83] = Key::F7;
|
||||||
|
|
||||||
|
MUST(m_extended_keymap.resize(0xFF, Key::Invalid));
|
||||||
|
m_extended_keymap[0x11] = Key::AltGr;
|
||||||
|
m_extended_keymap[0x14] = Key::RightCtrl;
|
||||||
|
m_extended_keymap[0x15] = Key::MediaPrevious;
|
||||||
|
m_extended_keymap[0x1F] = Key::Super;
|
||||||
|
m_extended_keymap[0x21] = Key::VolumeUp;
|
||||||
|
m_extended_keymap[0x23] = Key::VolumeMute;
|
||||||
|
m_extended_keymap[0x2B] = Key::Calculator;
|
||||||
|
m_extended_keymap[0x32] = Key::VolumeDown;
|
||||||
|
m_extended_keymap[0x34] = Key::MediaPlayPause;
|
||||||
|
m_extended_keymap[0x3B] = Key::MediaStop;
|
||||||
|
m_extended_keymap[0x4A] = Key::NumpadDivide;
|
||||||
|
m_extended_keymap[0x4D] = Key::MediaNext;
|
||||||
|
m_extended_keymap[0x5A] = Key::NumpadEnter;
|
||||||
|
m_extended_keymap[0x69] = Key::End;
|
||||||
|
m_extended_keymap[0x6B] = Key::ArrowLeft;
|
||||||
|
m_extended_keymap[0x6C] = Key::Home;
|
||||||
|
m_extended_keymap[0x70] = Key::Insert;
|
||||||
|
m_extended_keymap[0x71] = Key::Delete;
|
||||||
|
m_extended_keymap[0x72] = Key::ArrowDown;
|
||||||
|
m_extended_keymap[0x74] = Key::ArrowRight;
|
||||||
|
m_extended_keymap[0x75] = Key::ArrowUp;
|
||||||
|
m_extended_keymap[0x7A] = Key::PageUp;
|
||||||
|
m_extended_keymap[0x7D] = Key::PageDown;
|
||||||
|
}
|
||||||
|
|
||||||
|
Key PS2Keymap::key_for_scancode_and_modifiers(uint32_t scancode, uint8_t modifiers)
|
||||||
|
{
|
||||||
|
bool extended = scancode & 0x80000000;
|
||||||
|
scancode &= 0x7FFFFFFF;
|
||||||
|
|
||||||
|
KeyEvent dummy;
|
||||||
|
dummy.modifier = modifiers;
|
||||||
|
auto& keymap = extended ? m_extended_keymap :
|
||||||
|
dummy.shift() ? m_shift_keymap :
|
||||||
|
dummy.altgr() ? m_altgr_keymap :
|
||||||
|
m_normal_keymap;
|
||||||
|
|
||||||
|
if (scancode >= keymap.size())
|
||||||
|
return Key::Invalid;
|
||||||
|
|
||||||
|
Key key = keymap[scancode];
|
||||||
|
|
||||||
|
if (dummy.num_lock() && !(dummy.shift() || dummy.ctrl() || dummy.alt()))
|
||||||
|
{
|
||||||
|
switch (key)
|
||||||
|
{
|
||||||
|
case Key::Numpad0:
|
||||||
|
key = Key::Insert;
|
||||||
|
break;
|
||||||
|
case Key::Numpad1:
|
||||||
|
key = Key::End;
|
||||||
|
break;
|
||||||
|
case Key::Numpad2:
|
||||||
|
key = Key::ArrowDown;
|
||||||
|
break;
|
||||||
|
case Key::Numpad3:
|
||||||
|
key = Key::PageDown;
|
||||||
|
break;
|
||||||
|
case Key::Numpad4:
|
||||||
|
key = Key::ArrowLeft;
|
||||||
|
break;
|
||||||
|
case Key::Numpad5:
|
||||||
|
key = Key::None;
|
||||||
|
break;
|
||||||
|
case Key::Numpad6:
|
||||||
|
key = Key::ArrowRight;
|
||||||
|
break;
|
||||||
|
case Key::Numpad7:
|
||||||
|
key = Key::Home;
|
||||||
|
break;
|
||||||
|
case Key::Numpad8:
|
||||||
|
key = Key::ArrowUp;
|
||||||
|
break;
|
||||||
|
case Key::Numpad9:
|
||||||
|
key = Key::PageUp;
|
||||||
|
break;
|
||||||
|
case Key::NumpadDecimal:
|
||||||
|
key = Key::Delete;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return keymap[scancode];
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -3,7 +3,7 @@
|
||||||
#include <BAN/StringView.h>
|
#include <BAN/StringView.h>
|
||||||
#include <BAN/Vector.h>
|
#include <BAN/Vector.h>
|
||||||
#include <kernel/CPUID.h>
|
#include <kernel/CPUID.h>
|
||||||
#include <kernel/Input.h>
|
#include <kernel/Device.h>
|
||||||
#include <kernel/IO.h>
|
#include <kernel/IO.h>
|
||||||
#include <kernel/PIT.h>
|
#include <kernel/PIT.h>
|
||||||
#include <kernel/PCI.h>
|
#include <kernel/PCI.h>
|
||||||
|
@ -25,7 +25,6 @@ namespace Kernel
|
||||||
Shell::Shell(TTY* tty)
|
Shell::Shell(TTY* tty)
|
||||||
: m_tty(tty)
|
: m_tty(tty)
|
||||||
{
|
{
|
||||||
Input::register_key_event_callback({ &Shell::key_event_callback, this });
|
|
||||||
MUST(set_prompt(s_default_prompt));
|
MUST(set_prompt(s_default_prompt));
|
||||||
MUST(m_buffer.push_back(""sv));
|
MUST(m_buffer.push_back(""sv));
|
||||||
}
|
}
|
||||||
|
@ -83,8 +82,9 @@ namespace Kernel
|
||||||
TTY_PRINT("{}", m_prompt);
|
TTY_PRINT("{}", m_prompt);
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
PIT::sleep(1); // sleep until next reschedule
|
Input::KeyEvent event;
|
||||||
Input::update();
|
MUST(((CharacterDevice*)DeviceManager::get().devices()[0])->read({ (uint8_t*)&event, sizeof(event) }));
|
||||||
|
key_event_callback(event);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -560,7 +560,7 @@ argument_done:
|
||||||
|
|
||||||
void Shell::key_event_callback(Input::KeyEvent event)
|
void Shell::key_event_callback(Input::KeyEvent event)
|
||||||
{
|
{
|
||||||
if (!event.pressed)
|
if (event.released())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
BAN::String& current_buffer = m_buffer[m_cursor_pos.line];
|
BAN::String& current_buffer = m_buffer[m_cursor_pos.line];
|
||||||
|
@ -606,7 +606,7 @@ argument_done:
|
||||||
case Input::Key::Tab:
|
case Input::Key::Tab:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Input::Key::Left:
|
case Input::Key::ArrowLeft:
|
||||||
if (m_cursor_pos.index > 0)
|
if (m_cursor_pos.index > 0)
|
||||||
{
|
{
|
||||||
uint32_t len = get_last_length(current_buffer.sv().substring(0, m_cursor_pos.index));
|
uint32_t len = get_last_length(current_buffer.sv().substring(0, m_cursor_pos.index));
|
||||||
|
@ -615,7 +615,7 @@ argument_done:
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Input::Key::Right:
|
case Input::Key::ArrowRight:
|
||||||
if (m_cursor_pos.index < current_buffer.size())
|
if (m_cursor_pos.index < current_buffer.size())
|
||||||
{
|
{
|
||||||
uint32_t len = get_next_length(current_buffer.sv().substring(m_cursor_pos.index));
|
uint32_t len = get_next_length(current_buffer.sv().substring(m_cursor_pos.index));
|
||||||
|
@ -624,7 +624,7 @@ argument_done:
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Input::Key::Up:
|
case Input::Key::ArrowUp:
|
||||||
if (m_cursor_pos.line > 0)
|
if (m_cursor_pos.line > 0)
|
||||||
{
|
{
|
||||||
const auto& new_buffer = m_buffer[m_cursor_pos.line - 1];
|
const auto& new_buffer = m_buffer[m_cursor_pos.line - 1];
|
||||||
|
@ -635,7 +635,7 @@ argument_done:
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Input::Key::Down:
|
case Input::Key::ArrowDown:
|
||||||
if (m_cursor_pos.line < m_buffer.size() - 1)
|
if (m_cursor_pos.line < m_buffer.size() - 1)
|
||||||
{
|
{
|
||||||
const auto& new_buffer = m_buffer[m_cursor_pos.line + 1];
|
const auto& new_buffer = m_buffer[m_cursor_pos.line + 1];
|
||||||
|
@ -647,7 +647,7 @@ argument_done:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Input::Key::A:
|
case Input::Key::A:
|
||||||
if (event.modifiers & 2)
|
if (event.ctrl())
|
||||||
{
|
{
|
||||||
m_cursor_pos.col = m_cursor_pos.index = 0;
|
m_cursor_pos.col = m_cursor_pos.index = 0;
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
#include <kernel/FS/VirtualFileSystem.h>
|
#include <kernel/FS/VirtualFileSystem.h>
|
||||||
#include <kernel/GDT.h>
|
#include <kernel/GDT.h>
|
||||||
#include <kernel/IDT.h>
|
#include <kernel/IDT.h>
|
||||||
#include <kernel/Input.h>
|
#include <kernel/Input/PS2Controller.h>
|
||||||
#include <kernel/InterruptController.h>
|
#include <kernel/InterruptController.h>
|
||||||
#include <kernel/kmalloc.h>
|
#include <kernel/kmalloc.h>
|
||||||
#include <kernel/kprint.h>
|
#include <kernel/kprint.h>
|
||||||
|
@ -88,6 +88,7 @@ extern "C" uintptr_t g_userspace_end;
|
||||||
extern void userspace_entry();
|
extern void userspace_entry();
|
||||||
|
|
||||||
void init2(void*);
|
void init2(void*);
|
||||||
|
void device_updater(void*);
|
||||||
|
|
||||||
extern "C" void kernel_main()
|
extern "C" void kernel_main()
|
||||||
{
|
{
|
||||||
|
@ -136,10 +137,6 @@ extern "C" void kernel_main()
|
||||||
PIT::initialize();
|
PIT::initialize();
|
||||||
dprintln("PIT initialized");
|
dprintln("PIT initialized");
|
||||||
|
|
||||||
if (!Input::initialize())
|
|
||||||
dprintln("Could not initialize input drivers");
|
|
||||||
dprintln("Input initialized");
|
|
||||||
|
|
||||||
MUST(Scheduler::initialize());
|
MUST(Scheduler::initialize());
|
||||||
Scheduler& scheduler = Scheduler::get();
|
Scheduler& scheduler = Scheduler::get();
|
||||||
#if 0
|
#if 0
|
||||||
|
@ -186,15 +183,26 @@ extern "C" void kernel_main()
|
||||||
}
|
}
|
||||||
))));
|
))));
|
||||||
#else
|
#else
|
||||||
MUST(scheduler.add_thread(MUST(Thread::create(init2, tty1, nullptr))));
|
MUST(scheduler.add_thread(MUST(Thread::create(init2, tty1))));
|
||||||
|
MUST(scheduler.add_thread(MUST(Thread::create(device_updater))));
|
||||||
#endif
|
#endif
|
||||||
scheduler.start();
|
scheduler.start();
|
||||||
ASSERT(false);
|
ASSERT(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void device_updater(void*)
|
||||||
|
{
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
Kernel::DeviceManager::get().update();
|
||||||
|
PIT::sleep(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void init2(void* tty1_ptr)
|
void init2(void* tty1_ptr)
|
||||||
{
|
{
|
||||||
using namespace Kernel;
|
using namespace Kernel;
|
||||||
|
using namespace Kernel::Input;
|
||||||
|
|
||||||
TTY* tty1 = (TTY*)tty1_ptr;
|
TTY* tty1 = (TTY*)tty1_ptr;
|
||||||
|
|
||||||
|
@ -202,6 +210,9 @@ void init2(void* tty1_ptr)
|
||||||
if (auto res = VirtualFileSystem::get().mount_test(); res.is_error())
|
if (auto res = VirtualFileSystem::get().mount_test(); res.is_error())
|
||||||
dwarnln("{}", res.error());
|
dwarnln("{}", res.error());
|
||||||
|
|
||||||
|
if (auto res = PS2Controller::initialize(); res.is_error())
|
||||||
|
dprintln("{}", res.error());
|
||||||
|
|
||||||
MUST(Process::create_kernel(
|
MUST(Process::create_kernel(
|
||||||
[](void* tty1)
|
[](void* tty1)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue