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:
Bananymous 2023-03-29 03:05:16 +03:00
parent 779912d8af
commit ac094a48d6
16 changed files with 1339 additions and 775 deletions

View File

@ -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

View File

@ -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();

View File

@ -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;
};
}

View File

@ -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);
}

View File

@ -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];
}
}

View File

@ -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 };
};
}

View File

@ -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 };
};
}

View File

@ -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;
};
}

View File

@ -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

26
kernel/kernel/Device.cpp Normal file
View File

@ -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));
}
}

View File

@ -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];
}
}

View File

@ -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 {};
}
}

View File

@ -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 {};
}
}

View File

@ -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];
}
}

View File

@ -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;

View File

@ -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)
{