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/CPUID.o \
|
||||
kernel/Debug.o \
|
||||
kernel/Device.o \
|
||||
kernel/Font.o \
|
||||
kernel/FS/Ext2.o \
|
||||
kernel/FS/Inode.o \
|
||||
kernel/FS/VirtualFileSystem.o \
|
||||
kernel/Input.o \
|
||||
kernel/Input/PS2Controller.o \
|
||||
kernel/Input/PS2Keyboard.o \
|
||||
kernel/Input/PS2Keymap.o \
|
||||
kernel/InterruptController.o \
|
||||
kernel/kernel.o \
|
||||
kernel/kmalloc.o \
|
||||
|
@ -113,6 +116,7 @@ always:
|
|||
mkdir -p $(BUILDDIR)/$(ARCHDIR)
|
||||
mkdir -p $(BUILDDIR)/kernel
|
||||
mkdir -p $(BUILDDIR)/kernel/FS
|
||||
mkdir -p $(BUILDDIR)/kernel/Input
|
||||
mkdir -p $(BUILDDIR)/kernel/Storage
|
||||
mkdir -p $(BUILDDIR)/userspace
|
||||
mkdir -p $(BUILDDIR)/font
|
||||
|
|
|
@ -21,6 +21,65 @@ namespace Kernel
|
|||
uint32_t creator_revision;
|
||||
} __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:
|
||||
static BAN::ErrorOr<void> initialize();
|
||||
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/Vector.h>
|
||||
#include <kernel/Input.h>
|
||||
#include <kernel/Input/KeyEvent.h>
|
||||
#include <kernel/TTY.h>
|
||||
|
||||
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/Vector.h>
|
||||
#include <kernel/CPUID.h>
|
||||
#include <kernel/Input.h>
|
||||
#include <kernel/Device.h>
|
||||
#include <kernel/IO.h>
|
||||
#include <kernel/PIT.h>
|
||||
#include <kernel/PCI.h>
|
||||
|
@ -25,7 +25,6 @@ namespace Kernel
|
|||
Shell::Shell(TTY* tty)
|
||||
: m_tty(tty)
|
||||
{
|
||||
Input::register_key_event_callback({ &Shell::key_event_callback, this });
|
||||
MUST(set_prompt(s_default_prompt));
|
||||
MUST(m_buffer.push_back(""sv));
|
||||
}
|
||||
|
@ -83,8 +82,9 @@ namespace Kernel
|
|||
TTY_PRINT("{}", m_prompt);
|
||||
for (;;)
|
||||
{
|
||||
PIT::sleep(1); // sleep until next reschedule
|
||||
Input::update();
|
||||
Input::KeyEvent event;
|
||||
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)
|
||||
{
|
||||
if (!event.pressed)
|
||||
if (event.released())
|
||||
return;
|
||||
|
||||
BAN::String& current_buffer = m_buffer[m_cursor_pos.line];
|
||||
|
@ -606,7 +606,7 @@ argument_done:
|
|||
case Input::Key::Tab:
|
||||
break;
|
||||
|
||||
case Input::Key::Left:
|
||||
case Input::Key::ArrowLeft:
|
||||
if (m_cursor_pos.index > 0)
|
||||
{
|
||||
uint32_t len = get_last_length(current_buffer.sv().substring(0, m_cursor_pos.index));
|
||||
|
@ -615,7 +615,7 @@ argument_done:
|
|||
}
|
||||
break;
|
||||
|
||||
case Input::Key::Right:
|
||||
case Input::Key::ArrowRight:
|
||||
if (m_cursor_pos.index < current_buffer.size())
|
||||
{
|
||||
uint32_t len = get_next_length(current_buffer.sv().substring(m_cursor_pos.index));
|
||||
|
@ -624,7 +624,7 @@ argument_done:
|
|||
}
|
||||
break;
|
||||
|
||||
case Input::Key::Up:
|
||||
case Input::Key::ArrowUp:
|
||||
if (m_cursor_pos.line > 0)
|
||||
{
|
||||
const auto& new_buffer = m_buffer[m_cursor_pos.line - 1];
|
||||
|
@ -635,7 +635,7 @@ argument_done:
|
|||
}
|
||||
break;
|
||||
|
||||
case Input::Key::Down:
|
||||
case Input::Key::ArrowDown:
|
||||
if (m_cursor_pos.line < m_buffer.size() - 1)
|
||||
{
|
||||
const auto& new_buffer = m_buffer[m_cursor_pos.line + 1];
|
||||
|
@ -647,7 +647,7 @@ argument_done:
|
|||
break;
|
||||
|
||||
case Input::Key::A:
|
||||
if (event.modifiers & 2)
|
||||
if (event.ctrl())
|
||||
{
|
||||
m_cursor_pos.col = m_cursor_pos.index = 0;
|
||||
break;
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
#include <kernel/FS/VirtualFileSystem.h>
|
||||
#include <kernel/GDT.h>
|
||||
#include <kernel/IDT.h>
|
||||
#include <kernel/Input.h>
|
||||
#include <kernel/Input/PS2Controller.h>
|
||||
#include <kernel/InterruptController.h>
|
||||
#include <kernel/kmalloc.h>
|
||||
#include <kernel/kprint.h>
|
||||
|
@ -88,6 +88,7 @@ extern "C" uintptr_t g_userspace_end;
|
|||
extern void userspace_entry();
|
||||
|
||||
void init2(void*);
|
||||
void device_updater(void*);
|
||||
|
||||
extern "C" void kernel_main()
|
||||
{
|
||||
|
@ -136,10 +137,6 @@ extern "C" void kernel_main()
|
|||
PIT::initialize();
|
||||
dprintln("PIT initialized");
|
||||
|
||||
if (!Input::initialize())
|
||||
dprintln("Could not initialize input drivers");
|
||||
dprintln("Input initialized");
|
||||
|
||||
MUST(Scheduler::initialize());
|
||||
Scheduler& scheduler = Scheduler::get();
|
||||
#if 0
|
||||
|
@ -186,15 +183,26 @@ extern "C" void kernel_main()
|
|||
}
|
||||
))));
|
||||
#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
|
||||
scheduler.start();
|
||||
ASSERT(false);
|
||||
}
|
||||
|
||||
void device_updater(void*)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
Kernel::DeviceManager::get().update();
|
||||
PIT::sleep(1);
|
||||
}
|
||||
}
|
||||
|
||||
void init2(void* tty1_ptr)
|
||||
{
|
||||
using namespace Kernel;
|
||||
using namespace Kernel::Input;
|
||||
|
||||
TTY* tty1 = (TTY*)tty1_ptr;
|
||||
|
||||
|
@ -202,6 +210,9 @@ void init2(void* tty1_ptr)
|
|||
if (auto res = VirtualFileSystem::get().mount_test(); res.is_error())
|
||||
dwarnln("{}", res.error());
|
||||
|
||||
if (auto res = PS2Controller::initialize(); res.is_error())
|
||||
dprintln("{}", res.error());
|
||||
|
||||
MUST(Process::create_kernel(
|
||||
[](void* tty1)
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue