Kernel: Improve keyboard input by a lot

Seems to work on my 2 computerss
This commit is contained in:
Bananymous 2022-12-13 10:42:49 +02:00
parent 7ebe727a29
commit e62a626b39
5 changed files with 818 additions and 476 deletions

View File

@ -36,6 +36,7 @@ kernel/Keyboard.o \
kernel/kmalloc.o \
kernel/PIC.o \
kernel/PIT.o \
kernel/RTC.o \
kernel/Serial.o \
kernel/SSP.o \
icxxabi.o \

View File

@ -18,18 +18,30 @@ namespace Keyboard
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, Ctrl, Alt, NumLock, Escape,
LeftShift, RightShift, CapsLock, LeftCtrl, RightCtrl, LeftAlt, RightAlt, NumLock, ScrollLock, Escape,
Numpad0, Numpad1, Numpad2, Numpad3, Numpad4, Numpad5, Numpad6, Numpad7, Numpad8, Numpad9,
NumpadComma, NumpadPlus, NumpadMult, NumpadDiv, NumpadMinus,
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
};
void initialize(void (*callback)(Key, uint8_t, bool));
struct KeyEvent
{
Key key;
uint8_t modifiers;
bool pressed;
};
char key_to_ascii(Key, uint8_t);
bool initialize(void (*callback)(KeyEvent));
void update_keyboard();
char key_event_to_ascii(KeyEvent);
void led_disco();
}

View File

@ -5,412 +5,519 @@
namespace Keyboard
{
static Key scs2_to_key_altgr[0xFF]
constexpr Key scan_code_to_key_extended[0xFF]
{
Key::INVALID,
Key::F9,
Key::INVALID,
Key::F5,
Key::F3,
Key::F1,
Key::F2,
Key::F12,
Key::INVALID,
Key::F10,
Key::F8,
Key::F6,
Key::F4,
Key::Tab,
Key::None,
Key::INVALID,
Key::INVALID,
Key::Alt,
Key::LeftShift,
Key::INVALID,
Key::Ctrl,
Key::Q,
Key::None,
Key::INVALID,
Key::INVALID,
Key::INVALID,
Key::None,
Key::None,
Key::None,
Key::INVALID,
Key::INVALID,
Key::INVALID,
Key::INVALID,
Key::INVALID,
Key::INVALID,
Key::INVALID,
Key::INVALID,
Key::INVALID,
Key::INVALID,
Key::INVALID,
Key::INVALID,
Key::PreviousTrack,
Key::INVALID,
Key::INVALID,
Key::INVALID,
Key::INVALID,
Key::INVALID,
Key::INVALID,
Key::INVALID,
Key::INVALID,
Key::NextTrack,
Key::INVALID,
Key::INVALID,
Key::NumpadEnter,
Key::RightCtrl,
Key::INVALID,
Key::INVALID,
Key::Mute,
Key::Calculator,
Key::PlayPause,
Key::INVALID,
Key::Stop,
Key::INVALID,
Key::INVALID,
Key::INVALID,
Key::INVALID,
Key::INVALID,
Key::INVALID,
Key::INVALID,
Key::INVALID,
Key::INVALID,
Key::VolumeDown,
Key::INVALID,
Key::VolumeUp,
Key::INVALID,
Key::INVALID,
Key::INVALID,
Key::INVALID,
Key::NumpadDiv,
Key::INVALID,
Key::INVALID,
Key::RightAlt,
Key::INVALID,
Key::INVALID,
Key::INVALID,
Key::INVALID,
Key::INVALID,
Key::INVALID,
Key::INVALID,
Key::INVALID,
Key::INVALID,
Key::INVALID,
Key::INVALID,
Key::INVALID,
Key::INVALID,
Key::INVALID,
Key::Home,
Key::Up,
Key::PageUp,
Key::INVALID,
Key::Left,
Key::INVALID,
Key::Right,
Key::INVALID,
Key::End,
Key::Down,
Key::PageDown,
Key::Insert,
Key::Delete,
Key::INVALID,
Key::INVALID,
Key::INVALID,
Key::INVALID,
Key::INVALID,
Key::INVALID,
Key::INVALID,
Key::Super,
Key::INVALID,
Key::INVALID,
Key::INVALID,
Key::INVALID,
Key::INVALID,
Key::INVALID,
Key::INVALID,
Key::INVALID,
Key::INVALID,
Key::INVALID,
Key::INVALID,
Key::INVALID,
Key::INVALID,
Key::INVALID,
Key::INVALID,
Key::INVALID,
Key::INVALID,
Key::INVALID,
Key::INVALID,
Key::INVALID,
Key::INVALID,
Key::INVALID,
Key::INVALID,
Key::INVALID,
Key::INVALID,
Key::INVALID,
Key::INVALID,
Key::INVALID,
Key::INVALID,
Key::INVALID,
Key::INVALID,
Key::INVALID,
Key::INVALID,
Key::INVALID,
Key::INVALID,
Key::INVALID,
Key::INVALID,
Key::INVALID,
Key::INVALID,
Key::INVALID,
Key::INVALID,
Key::INVALID,
Key::INVALID,
Key::INVALID,
Key::INVALID,
Key::INVALID,
Key::INVALID,
Key::INVALID,
Key::INVALID,
Key::INVALID,
};
constexpr Key scan_code_to_key_altgr[0xFF]
{
Key::INVALID,
Key::Escape,
Key::None,
Key::At,
Key::INVALID,
Key::INVALID,
Key::Pound,
Key::Dollar,
Key::None,
Key::None,
Key::OpenBracket,
Key::OpenBrace,
Key::CloseBrace,
Key::CloseBracket,
Key::BackSlash,
Key::BackTick,
Key::Backspace,
Key::Tab,
Key::None,
Key::None,
Key::Euro,
Key::Dollar,
Key::Pound,
Key::INVALID,
Key::INVALID,
Key::Space,
Key::None,
Key::None,
Key::None,
Key::None,
Key::None,
Key::INVALID,
Key::INVALID,
Key::None,
Key::None,
Key::None,
Key::None,
Key::None,
Key::None,
Key::INVALID,
Key::INVALID,
Key::INVALID,
Key::None,
Key::None,
Key::None,
Key::OpenBrace,
Key::OpenBracket,
Key::INVALID,
Key::INVALID,
Key::None,
Key::None,
Key::None,
Key::None,
Key::CloseBrace,
Key::CloseBracket,
Key::INVALID,
Key::INVALID,
Key::None,
Key::None,
Key::None,
Key::None,
Key::None,
Key::BackSlash,
Key::INVALID,
Key::INVALID,
Key::INVALID,
Key::None,
Key::INVALID,
Key::None,
Key::None,
Key::INVALID,
Key::INVALID,
Key::CapsLock,
Key::RightShift,
Key::Enter,
Key::Tilde,
Key::INVALID,
Key::Enter,
Key::LeftCtrl,
Key::None,
Key::INVALID,
Key::None,
Key::None,
Key::None,
Key::None,
Key::None,
Key::None,
Key::None,
Key::None,
Key::None,
Key::None,
Key::None,
Key::LeftShift,
Key::None,
Key::None,
Key::None,
Key::None,
Key::None,
Key::None,
Key::None,
Key::None,
Key::None,
Key::None,
Key::None,
Key::RightShift,
Key::NumpadMult,
Key::LeftAlt,
Key::Space,
Key::CapsLock,
Key::F1,
Key::F2,
Key::F3,
Key::F4,
Key::F5,
Key::F6,
Key::F7,
Key::F8,
Key::F9,
Key::F10,
Key::NumLock,
Key::ScrollLock,
Key::Numpad7,
Key::Numpad8,
Key::Numpad9,
Key::NumpadMinus,
Key::Numpad4,
Key::Numpad5,
Key::Numpad6,
Key::NumpadPlus,
Key::Numpad1,
Key::Numpad2,
Key::Numpad3,
Key::Numpad0,
Key::NumpadSep,
Key::INVALID,
Key::INVALID,
Key::Pipe,
Key::INVALID,
Key::INVALID,
Key::INVALID,
Key::INVALID,
Key::Backspace,
Key::INVALID,
Key::INVALID,
Key::Numpad1,
Key::INVALID,
Key::Numpad4,
Key::Numpad7,
Key::INVALID,
Key::INVALID,
Key::INVALID,
Key::Numpad0,
Key::NumpadComma,
Key::Numpad2,
Key::Numpad5,
Key::Numpad6,
Key::Numpad8,
Key::Escape,
Key::NumLock,
Key::F11,
Key::NumpadPlus,
Key::Numpad3,
Key::NumpadMinus,
Key::NumpadMult,
Key::Numpad9,
Key::INVALID,
Key::INVALID,
Key::INVALID,
Key::INVALID,
Key::INVALID,
Key::F7,
Key::F12,
};
static Key scs2_to_key_shift[0xFF]
constexpr Key scan_code_to_key_shift[0xFF]
{
Key::INVALID,
Key::F9,
Key::INVALID,
Key::F5,
Key::F3,
Key::F1,
Key::F2,
Key::F12,
Key::INVALID,
Key::F10,
Key::F8,
Key::F6,
Key::F4,
Key::Tab,
Key::Half,
Key::INVALID,
Key::INVALID,
Key::Alt,
Key::LeftShift,
Key::INVALID,
Key::Ctrl,
Key::Q,
Key::Escape,
Key::ExclamationMark,
Key::INVALID,
Key::INVALID,
Key::INVALID,
Key::Z,
Key::S,
Key::A,
Key::W,
Key::DoubleQuote,
Key::INVALID,
Key::INVALID,
Key::C,
Key::X,
Key::D,
Key::E,
Key::Currency,
Key::Hashtag,
Key::INVALID,
Key::INVALID,
Key::Space,
Key::V,
Key::F,
Key::T,
Key::R,
Key::Currency,
Key::Percent,
Key::INVALID,
Key::INVALID,
Key::N,
Key::B,
Key::H,
Key::G,
Key::Y,
Key::Ampersand,
Key::INVALID,
Key::INVALID,
Key::INVALID,
Key::M,
Key::J,
Key::U,
Key::Slash,
Key::OpenParen,
Key::INVALID,
Key::INVALID,
Key::Semicolon,
Key::K,
Key::CloseParen,
Key::Equals,
Key::QuestionMark,
Key::BackTick,
Key::Backspace,
Key::Tab,
Key::Q,
Key::W,
Key::E,
Key::R,
Key::T,
Key::Y,
Key::U,
Key::I,
Key::O,
Key::Equals,
Key::CloseParen,
Key::INVALID,
Key::INVALID,
Key::Colon,
Key::Underscore,
Key::P,
Key::A_Dot,
Key::Caret,
Key::Enter,
Key::LeftCtrl,
Key::A,
Key::S,
Key::D,
Key::F,
Key::G,
Key::H,
Key::J,
Key::K,
Key::L,
Key::O_Dots,
Key::P,
Key::QuestionMark,
Key::INVALID,
Key::INVALID,
Key::INVALID,
Key::A_Dots,
Key::INVALID,
Key::A_Dot,
Key::BackTick,
Key::INVALID,
Key::INVALID,
Key::CapsLock,
Key::RightShift,
Key::Enter,
Key::Caret,
Key::INVALID,
Key::Half,
Key::LeftShift,
Key::Asterix,
Key::INVALID,
Key::Z,
Key::X,
Key::C,
Key::V,
Key::B,
Key::N,
Key::M,
Key::Semicolon,
Key::Colon,
Key::Underscore,
Key::RightShift,
Key::NumpadMult,
Key::LeftAlt,
Key::Space,
Key::CapsLock,
Key::None,
Key::None,
Key::None,
Key::None,
Key::None,
Key::None,
Key::None,
Key::None,
Key::None,
Key::None,
Key::NumLock,
Key::ScrollLock,
Key::Home,
Key::Up,
Key::PageUp,
Key::NumpadMinus,
Key::Left,
Key::None,
Key::Right,
Key::NumpadPlus,
Key::End,
Key::Down,
Key::PageDown,
Key::Insert,
Key::Delete,
Key::INVALID,
Key::INVALID,
Key::MoreThan,
Key::INVALID,
Key::INVALID,
Key::INVALID,
Key::INVALID,
Key::Backspace,
Key::INVALID,
Key::INVALID,
Key::End,
Key::INVALID,
Key::Left,
Key::Right,
Key::INVALID,
Key::INVALID,
Key::INVALID,
Key::Insert,
Key::Delete,
Key::Down,
Key::None,
Key::Right,
Key::Up,
Key::Escape,
Key::NumLock,
Key::F11,
Key::NumpadPlus,
Key::PageDown,
Key::NumpadMinus,
Key::NumpadMult,
Key::PageUp,
Key::INVALID,
Key::INVALID,
Key::INVALID,
Key::INVALID,
Key::INVALID,
Key::F7,
Key::None,
};
static Key scs2_to_key[0xFF]
constexpr Key scan_code_to_key_normal[0xFF]
{
Key::INVALID,
Key::F9,
Key::INVALID,
Key::F5,
Key::F3,
Key::F1,
Key::F2,
Key::F12,
Key::INVALID,
Key::F10,
Key::F8,
Key::F6,
Key::F4,
Key::Tab,
Key::Section,
Key::INVALID,
Key::INVALID,
Key::Alt,
Key::LeftShift,
Key::INVALID,
Key::Ctrl,
Key::Q,
Key::Escape,
Key::_1,
Key::INVALID,
Key::INVALID,
Key::INVALID,
Key::Z,
Key::S,
Key::A,
Key::W,
Key::_2,
Key::INVALID,
Key::INVALID,
Key::C,
Key::X,
Key::D,
Key::E,
Key::_4,
Key::_3,
Key::INVALID,
Key::INVALID,
Key::Space,
Key::V,
Key::F,
Key::T,
Key::R,
Key::_4,
Key::_5,
Key::INVALID,
Key::INVALID,
Key::N,
Key::B,
Key::H,
Key::G,
Key::Y,
Key::_6,
Key::INVALID,
Key::INVALID,
Key::INVALID,
Key::M,
Key::J,
Key::U,
Key::_7,
Key::_8,
Key::INVALID,
Key::INVALID,
Key::Comma,
Key::K,
Key::_9,
Key::_0,
Key::Plus,
Key::Tick,
Key::Backspace,
Key::Tab,
Key::Q,
Key::W,
Key::E,
Key::R,
Key::T,
Key::Y,
Key::U,
Key::I,
Key::O,
Key::_0,
Key::_9,
Key::INVALID,
Key::INVALID,
Key::Period,
Key::Hyphen,
Key::P,
Key::A_Dot,
Key::Caret,
Key::Enter,
Key::LeftCtrl,
Key::A,
Key::S,
Key::D,
Key::F,
Key::G,
Key::H,
Key::J,
Key::K,
Key::L,
Key::O_Dots,
Key::P,
Key::Plus,
Key::INVALID,
Key::INVALID,
Key::INVALID,
Key::A_Dots,
Key::INVALID,
Key::A_Dot,
Key::Tick,
Key::INVALID,
Key::INVALID,
Key::CapsLock,
Key::RightShift,
Key::Enter,
Key::Caret,
Key::INVALID,
Key::Section,
Key::LeftShift,
Key::SingleQuote,
Key::INVALID,
Key::Z,
Key::X,
Key::C,
Key::V,
Key::B,
Key::N,
Key::M,
Key::Comma,
Key::Period,
Key::Hyphen,
Key::RightShift,
Key::NumpadMult,
Key::LeftAlt,
Key::Space,
Key::CapsLock,
Key::F1,
Key::F2,
Key::F3,
Key::F4,
Key::F5,
Key::F6,
Key::F7,
Key::F8,
Key::F9,
Key::F10,
Key::NumLock,
Key::ScrollLock,
Key::Numpad7,
Key::Numpad8,
Key::Numpad9,
Key::NumpadMinus,
Key::Numpad4,
Key::Numpad5,
Key::Numpad6,
Key::NumpadPlus,
Key::Numpad1,
Key::Numpad2,
Key::Numpad3,
Key::Numpad0,
Key::NumpadSep,
Key::INVALID,
Key::INVALID,
Key::LessThan,
Key::INVALID,
Key::INVALID,
Key::INVALID,
Key::INVALID,
Key::Backspace,
Key::INVALID,
Key::INVALID,
Key::Numpad1,
Key::INVALID,
Key::Numpad4,
Key::Numpad7,
Key::INVALID,
Key::INVALID,
Key::INVALID,
Key::Numpad0,
Key::NumpadComma,
Key::Numpad2,
Key::Numpad5,
Key::Numpad6,
Key::Numpad8,
Key::Escape,
Key::NumLock,
Key::F11,
Key::NumpadPlus,
Key::Numpad3,
Key::NumpadMinus,
Key::NumpadMult,
Key::Numpad9,
Key::INVALID,
Key::INVALID,
Key::INVALID,
Key::INVALID,
Key::INVALID,
Key::F7,
Key::F12,
};
}

View File

@ -1,50 +1,89 @@
#include <kernel/IDT.h>
#include <kernel/IO.h>
#include <kernel/Keyboard.h>
#include <kernel/PIC.h>
#include <kernel/kprint.h>
#include <kernel/PIC.h>
#include <kernel/PIT.h>
#include <kernel/Queue.h>
#include <kernel/Serial.h>
#include <kernel/KeyboardLayout/FI.h>
#define I8042_DATA_PORT 0x60
#define I8042_STATUS_REGISTER 0x64
#define I8042_COMMAND_REGISTER 0x64
#define KB_DEBUG_PRINT 1
#define I8042_READ_BYTE0 0x20
#define I8042_WRITE_BYTE0 0x60
#define I8042_DATA_PORT 0x60
#define I8042_STATUS_REGISTER 0x64
#define I8042_COMMAND_REGISTER 0x64
#define I8042_ENABLE_FIRST 0xAE
#define I8042_ENABLE_SECOND 0xA8
#define I8042_DISABLE_FIRST 0xAD
#define I8042_DISABLE_SECOND 0xA7
#define I8042_STATUS_OUT_FULL (1 << 0)
#define I8042_STATUS_IN_FULL (1 << 1)
#define I8042_TEST_CONTROLLER 0xAA
#define I8042_CONTROLLER_TEST_PASS 0x55
#define I8042_READ_CONFIG 0x20
#define I8042_WRITE_CONFIG 0x60
#define I8042_TEST_FIRST_PORT 0xAB
#define I8042_FIRST_PORT_TEST_PASS 0x00
#define I8042_CONFING_IRQ_FIRST (1 << 0)
#define I8042_CONFING_IRQ_SECOND (1 << 1)
#define I8042_CONFING_TRANSLATION (1 << 6)
#define I8042_TEST_SECOND 0xA9
#define I8042_SECOND_PORT_TEST_PASS 0x00
#define I8042_ENABLE_FIRST 0xAE
#define I8042_ENABLE_SECOND 0xA8
#define I8042_DISABLE_FIRST 0xAD
#define I8042_DISABLE_SECOND 0xA7
#define I8042_ACK 0xfa
#define I8042_TEST_CONTROLLER 0xAA
#define I8042_TEST_CONTROLLER_PASS 0x55
#define KEYBOARD_IRQ 0x01
#define I8042_TEST_FIRST_PORT 0xAB
#define I8042_TEST_FIRST_PORT_PASS 0x00
#define MOD_ALT 0b0001
#define MOD_CTRL 0b0010
#define MOD_SHIFT 0b0100
#define MOD_ALTGR 0b1000
#define I8042_TEST_SECOND_PORT 0xA9
#define I8042_TEST_SECOND_PORT_PASS 0x00
#define KEYBOARD_FI
#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_TIMEOUT_MS 1000
#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 KEYBOARD_IRQ 0x01
#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 Keyboard
{
static bool s_keyboard_state[0xFF] = {};
static uint8_t s_modifiers = 0;
static void (*s_key_callback)(Key, uint8_t, bool) = nullptr;
struct Command
{
uint8_t command = 0;
uint8_t data = 0;
bool has_data = false;
bool extra = false;
uint8_t _sent = 0;
uint8_t _ack = 0;
bool _done = false;
};
static Queue<Command> s_keyboard_command_queue;
static uint8_t s_keyboard_command_extra = 0x00;
static Queue<KeyEvent> s_key_event_queue;
static uint8_t s_keyboard_key_buffer[10] = {};
static uint8_t s_keyboard_key_buffer_size = 0;
static uint8_t s_led_states = 0b000;
static uint8_t s_modifiers = 0x00;
static void (*s_key_callback)(KeyEvent) = nullptr;
static char s_key_to_char[]
{
@ -59,110 +98,263 @@ namespace Keyboard
'$', '\0', '\0', '\0', '\n', ' ', '\t', '\b', '<', '>', '\0', '`', '\0', '\0', '@', '|',
'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0',
'\0', '\0', '\0', '\0', '\0', '\0', '\0',
'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0',
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
',', '+', '*', '/', '-',
',', '+', '*', '/', '-', '\n',
'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0',
'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0',
};
static_assert(sizeof(s_key_to_char) == static_cast<int>(Key::Count));
static uint8_t kb_read()
static uint8_t wait_and_read()
{
while (!(IO::inb(I8042_STATUS_REGISTER) & 0x01))
while ((IO::inb(I8042_STATUS_REGISTER) & I8042_STATUS_OUT_FULL) == 0)
continue;
return IO::inb(I8042_DATA_PORT);
}
static bool kb_try_read(uint8_t& out)
static void i8042_controller_command(uint8_t command)
{
if (IO::inb(I8042_STATUS_REGISTER) & 0x01)
{
out = IO::inb(I8042_DATA_PORT);
return true;
}
return false;
}
static void kb_command(uint8_t command)
{
IO::io_wait();
IO::outb(I8042_COMMAND_REGISTER, command);
}
static void kb_command(uint8_t command, uint8_t data)
static void i8042_controller_command(uint8_t command, uint8_t data)
{
IO::io_wait();
IO::outb(I8042_COMMAND_REGISTER, command);
IO::io_wait();
while ((IO::inb(I8042_STATUS_REGISTER) & I8042_STATUS_IN_FULL) != 0)
continue;
IO::outb(I8042_DATA_PORT, data);
}
void irq_handler()
static bool i8042_keyboard_command(uint8_t command)
{
uint8_t ch;
while (kb_try_read(ch))
auto timeout = PIT::ms_since_boot() + I8042_KB_TIMEOUT_MS;
while (PIT::ms_since_boot() < timeout)
{
bool multimedia = false, pressed = true;
if (ch == 0xE0)
if ((IO::inb(I8042_STATUS_REGISTER) & I8042_STATUS_IN_FULL) == 0)
{
multimedia = true;
ch = kb_read();
IO::outb(I8042_DATA_PORT, command);
return true;
}
}
return false;
}
void update_keyboard()
{
if (!s_keyboard_command_queue.Empty())
{
auto& command = s_keyboard_command_queue.Front();
if (command._sent == 0 && command._ack == 0)
{
if (!i8042_keyboard_command(command.command))
Kernel::panic("oof 1");
command._sent++;
}
if (ch == 0xF0)
if (command._sent == 1 && command._ack == 1 && command.has_data)
{
pressed = false;
ch = kb_read();
}
// TODO: Handle multimedia keys
if (multimedia)
{
if (ch == 17)
pressed ? (s_modifiers |= MOD_ALTGR) : (s_modifiers &= ~MOD_ALTGR);
if (pressed && false)
kprint("<M{}>", ch);
continue;
if (!i8042_keyboard_command(command.data))
Kernel::panic("oof 2");
command._sent++;
}
s_keyboard_state[ch] = pressed;
switch (ch)
if (command._done)
{
case 17:
pressed ? (s_modifiers |= MOD_ALT) : (s_modifiers &= ~MOD_ALT);
break;
case 18:
case 89:
pressed ? (s_modifiers |= MOD_SHIFT) : (s_modifiers &= ~MOD_SHIFT);
break;
case 20:
pressed ? (s_modifiers |= MOD_CTRL) : (s_modifiers &= ~MOD_CTRL);
break;
default:
break;
switch (command.command)
{
case I8042_KB_RESET:
if (s_keyboard_command_extra != 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;
}
s_keyboard_command_queue.Pop();
}
}
Key key;
if (s_modifiers & MOD_ALTGR)
key = scs2_to_key_altgr[ch];
else if (s_modifiers & MOD_SHIFT)
key = scs2_to_key_shift[ch];
else
key = scs2_to_key[ch];
// Debug print for unregistered keys
if (key == Key::INVALID && pressed)
kprint("<{}>", ch);
s_key_callback(key, s_modifiers, pressed);
while (!s_key_event_queue.Empty())
{
s_key_callback(s_key_event_queue.Front());
s_key_event_queue.Pop();
}
}
void initialize(void (*callback)(Key, uint8_t, bool))
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 KB_DEBUG_PRINT
if (key == Key::INVALID)
kprintln("{} {}", ch, extended ? 'E' : ' ');
#endif
s_keyboard_state[static_cast<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)
{
s_keyboard_command_queue.Push({
.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.HasError())
dprintln("PS/2 Keyboard: {}", error_or.GetError().message);
}
s_keyboard_key_buffer_size -= index + 1;
memmove(s_keyboard_key_buffer, s_keyboard_key_buffer + index, s_keyboard_key_buffer_size);
}
void keyboard_irq_handler()
{
uint8_t raw = IO::inb(I8042_DATA_PORT);
bool command_waiting = false;
if (!s_keyboard_command_queue.Empty())
{
auto& command = s_keyboard_command_queue.Front();
command_waiting = (command._sent > 0 && !command._done);
}
if (command_waiting)
{
auto& command = s_keyboard_command_queue.Front();
if (raw == I8042_KB_RESEND)
{
dprintln("PS/2 Keyboard: Resend 0x{H}", command._sent == 2 ? command.data : command.command);
command._sent--;
return;
}
if (raw == I8042_KB_ACK)
{
command._ack++;
if (command.extra > 0)
return;
command._done = command.has_data ? (command._ack == 2) : true;
return;
}
if (raw == 0x00)
{
dprintln("\e[33mKey detection error or internal buffer overrun\e[m");
command._sent = 0;
command._ack = 0;
command._done = false;
return;
}
if (raw == 0xEE && command.command == 0xEE)
{
s_keyboard_command_queue.Pop();
return;
}
s_keyboard_command_extra = raw;
command._done = true;
return;
}
else
{
s_keyboard_key_buffer[s_keyboard_key_buffer_size++] = raw;
if (raw != 0xE0)
keyboard_new_key();
}
}
bool initialize(void (*callback)(KeyEvent))
{
// https://wiki.osdev.org/%228042%22_PS/2_Controller
@ -175,74 +367,102 @@ namespace Keyboard
// TODO
// Step 3: Disable Devices
kb_command(I8042_DISABLE_FIRST);
kb_command(I8042_DISABLE_SECOND);
i8042_controller_command(I8042_DISABLE_FIRST);
i8042_controller_command(I8042_DISABLE_SECOND);
// Step 4: Flush The Ouput Buffer
uint8_t tmp;
while(kb_try_read(tmp))
continue;
while ((IO::inb(I8042_STATUS_REGISTER) & I8042_STATUS_OUT_FULL) != 0)
IO::inb(I8042_DATA_PORT);
// Step 5: Set the Controller Configuration Byte
kb_command(I8042_READ_BYTE0);
uint8_t conf = kb_read();
conf &= 0b10111100;
kb_command(I8042_WRITE_BYTE0, conf);
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
kb_command(I8042_TEST_CONTROLLER);
uint8_t resp = kb_read();
if (resp != I8042_CONTROLLER_TEST_PASS)
i8042_controller_command(I8042_TEST_CONTROLLER);
if (wait_and_read() != I8042_TEST_CONTROLLER_PASS)
{
kprint("ERROR: PS/2 self test failed\n");
return;
kprintln("\e[33mERROR: PS/2 controller self test failed\e[m");
return false;
}
// Step 7: Determine If There Are 2 Channels
// Step 8: Perform Interface Tests
kb_command(I8042_TEST_FIRST_PORT);
resp = kb_read();
if (resp != I8042_FIRST_PORT_TEST_PASS)
i8042_controller_command(I8042_TEST_FIRST_PORT);
if (wait_and_read() != I8042_TEST_FIRST_PORT_PASS)
{
kprint("ERROR: PS/2 interface test failed\n");
return;
kprintln("\e[33mERROR: PS/2 first port test failed\e[m");
return false;
}
// Step 9: Enable Devices
kb_command(I8042_WRITE_BYTE0, conf | 0x01); // enable IRQs
kb_command(I8042_ENABLE_FIRST);
config |= I8042_CONFING_IRQ_FIRST;
i8042_controller_command(I8042_WRITE_CONFIG, config);
i8042_controller_command(I8042_ENABLE_FIRST);
// Step 10: Reset Devices
/* TODO: doesnt seem to respond
kb_command(0xFF);
resp = kb_read();
if (resp != PS2_ACK)
{
kprint("ERROR: PS/2 could not restart devices\n");
return;
}
*/
MUST(s_keyboard_command_queue.Push({
.command = I8042_KB_RESET,
.extra = true,
}));
// Set scan code set 2
MUST(s_keyboard_command_queue.Push({
.command = I8042_KB_SET_SCAN_CODE_SET,
.data = 0x02,
.has_data = true,
}));
// Turn LEDs off
MUST(s_keyboard_command_queue.Push({
.command = I8042_KB_SET_LEDS,
.data = s_led_states,
.has_data = true,
}));
// Register callback and IRQ
s_key_callback = callback;
IDT::register_irq_handler(KEYBOARD_IRQ, irq_handler);
IDT::register_irq_handler(KEYBOARD_IRQ, keyboard_irq_handler);
PIC::unmask(KEYBOARD_IRQ);
kb_command(0xED, 0b111);
IO::io_wait();
while (kb_try_read(tmp));
return true;
}
char key_to_ascii(Key key, uint8_t modifiers)
char key_event_to_ascii(KeyEvent event)
{
char res = s_key_to_char[static_cast<uint8_t>(key)];
char res = s_key_to_char[static_cast<uint8_t>(event.key)];
if (!(modifiers & MOD_SHIFT))
if (!(event.modifiers & (MOD_SHIFT | MOD_CAPS)))
if (res >= 'A' && res <= 'Z')
res = res - 'A' + 'a';
return res;
}
void led_disco()
{
uint64_t time = PIT::ms_since_boot();
uint64_t freq = 100;
bool state = false;
for(;;)
{
if (PIT::ms_since_boot() > time + freq)
{
time += freq;
state = !state;
MUST(s_keyboard_command_queue.Push({
.command = I8042_KB_SET_LEDS,
.data = (uint8_t)(state ? 0b111 : 0b000),
.has_data = true,
}));
}
update_keyboard();
}
}
}

View File

@ -62,7 +62,8 @@ void kernel_main(multiboot_info_t* mbi, uint32_t magic)
IDT::initialize();
PIT::initialize();
Keyboard::initialize(on_key_press);
if (!Keyboard::initialize(on_key_press))
return;
auto time = RTC::GetCurrentTime();
kprintln("Today is {2}:{2}:{2} {2}.{2}.{4}", time.hour, time.minute, time.second, time.day, time.month, time.year);
@ -71,8 +72,9 @@ void kernel_main(multiboot_info_t* mbi, uint32_t magic)
ENABLE_INTERRUPTS();
for (;;)
{
asm("hlt");
Keyboard::update_keyboard();
}
}