forked from Bananymous/banan-os
Kernel: Add basic PS/2 Mouse driver
This commit is contained in:
parent
3c92aa45fb
commit
ef0b2010e0
|
@ -32,8 +32,8 @@ BUILDDIR=$(abspath build)
|
|||
KERNEL_OBJS= \
|
||||
$(KERNEL_ARCH_OBJS) \
|
||||
kernel/build_libc.o \
|
||||
kernel/Input.o \
|
||||
kernel/kernel.o \
|
||||
kernel/Keyboard.o \
|
||||
kernel/kmalloc.o \
|
||||
kernel/PIC.o \
|
||||
kernel/PIT.o \
|
||||
|
|
|
@ -406,10 +406,10 @@ namespace APIC
|
|||
}
|
||||
}
|
||||
|
||||
void EOI()
|
||||
void EOI(uint8_t irq)
|
||||
{
|
||||
if (s_using_fallback_pic)
|
||||
return PIC::EOI(0);
|
||||
return PIC::EOI(irq);
|
||||
WriteLocalAPIC(0xB0, 0);
|
||||
}
|
||||
|
||||
|
|
|
@ -144,7 +144,7 @@ found:
|
|||
else
|
||||
Kernel::panic("no handler for irq 0x{2H}\n", irq);
|
||||
|
||||
APIC::EOI();
|
||||
APIC::EOI(irq);
|
||||
}
|
||||
|
||||
extern "C" void handle_irq_common();
|
||||
|
|
|
@ -6,7 +6,7 @@ namespace APIC
|
|||
{
|
||||
|
||||
void Initialize(bool force_pic = false);
|
||||
void EOI();
|
||||
void EOI(uint8_t irq);
|
||||
void GetISR(uint32_t[8]);
|
||||
void EnableIRQ(uint8_t irq);
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
#include <stdint.h>
|
||||
|
||||
namespace Keyboard
|
||||
namespace Input
|
||||
{
|
||||
|
||||
enum class Key : uint8_t
|
||||
|
@ -37,13 +37,30 @@ namespace Keyboard
|
|||
bool pressed;
|
||||
};
|
||||
|
||||
bool initialize();
|
||||
void update_keyboard();
|
||||
enum class MouseButton
|
||||
{
|
||||
Left, Right, Middle,
|
||||
};
|
||||
struct MouseButtonEvent
|
||||
{
|
||||
MouseButton button;
|
||||
};
|
||||
|
||||
void register_key_event_callback(void(*callback)(KeyEvent));
|
||||
struct MouseMoveEvent
|
||||
{
|
||||
int16_t dx;
|
||||
int16_t dy;
|
||||
};
|
||||
|
||||
|
||||
bool initialize();
|
||||
void update();
|
||||
bool is_key_down(Key);
|
||||
|
||||
void register_key_event_callback(void (*callback)(KeyEvent));
|
||||
void register_mouse_button_event_callback(void (*callback)(MouseButtonEvent));
|
||||
void register_mouse_move_event_callback(void (*callback)(MouseMoveEvent));
|
||||
|
||||
const char* key_event_to_utf8(KeyEvent);
|
||||
|
||||
void led_disco();
|
||||
|
||||
}
|
|
@ -1,8 +1,8 @@
|
|||
#pragma once
|
||||
|
||||
#include <kernel/Keyboard.h>
|
||||
#include <kernel/Input.h>
|
||||
|
||||
namespace Keyboard
|
||||
namespace Input
|
||||
{
|
||||
|
||||
constexpr Key scan_code_to_key_extended[0xFF]
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <BAN/String.h>
|
||||
#include <kernel/Keyboard.h>
|
||||
#include <kernel/Input.h>
|
||||
#include <kernel/TTY.h>
|
||||
|
||||
namespace Kernel
|
||||
|
@ -22,7 +22,7 @@ namespace Kernel
|
|||
Shell();
|
||||
void PrintPrompt();
|
||||
void ProcessCommand(const BAN::Vector<BAN::StringView>&);
|
||||
void KeyEventCallback(Keyboard::KeyEvent);
|
||||
void KeyEventCallback(Input::KeyEvent);
|
||||
|
||||
private:
|
||||
TTY* m_tty;
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
#include <BAN/Queue.h>
|
||||
#include <kernel/APIC.h>
|
||||
#include <kernel/IDT.h>
|
||||
#include <kernel/Input.h>
|
||||
#include <kernel/IO.h>
|
||||
#include <kernel/Keyboard.h>
|
||||
#include <kernel/kprint.h>
|
||||
#include <kernel/PIT.h>
|
||||
#include <kernel/Serial.h>
|
||||
|
@ -23,12 +23,13 @@
|
|||
|
||||
#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 0xAE
|
||||
#define I8042_ENABLE_SECOND 0xA8
|
||||
#define I8042_DISABLE_FIRST 0xAD
|
||||
#define I8042_DISABLE_SECOND 0xA7
|
||||
#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
|
||||
|
@ -50,7 +51,17 @@
|
|||
#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 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)
|
||||
|
@ -58,32 +69,41 @@
|
|||
#define MOD_ALTGR (1 << 3)
|
||||
#define MOD_CAPS (1 << 4)
|
||||
|
||||
namespace Keyboard
|
||||
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;
|
||||
bool extra = false;
|
||||
uint8_t resp_cnt = 0;
|
||||
uint8_t _sent = 0;
|
||||
uint8_t _ack = 0;
|
||||
bool _done = false;
|
||||
};
|
||||
static BAN::Queue<Command> s_keyboard_command_queue;
|
||||
static uint8_t s_keyboard_command_extra = 0x00;
|
||||
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 void (*s_key_event_callback)(KeyEvent) = nullptr;
|
||||
static void (*s_mouse_button_event_callback)(MouseButtonEvent) = nullptr;
|
||||
static void (*s_mouse_move_event_callback)(MouseMoveEvent) = nullptr;
|
||||
|
||||
static const char* s_key_to_utf8_lower[]
|
||||
{
|
||||
|
@ -107,7 +127,7 @@ namespace Keyboard
|
|||
|
||||
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
|
||||
};
|
||||
static_assert(sizeof(s_key_to_utf8_lower) == static_cast<int>(Key::Count) * sizeof(*s_key_to_utf8_lower));
|
||||
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[]
|
||||
{
|
||||
|
@ -131,7 +151,7 @@ namespace Keyboard
|
|||
|
||||
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
|
||||
};
|
||||
static_assert(sizeof(s_key_to_utf8_upper) == static_cast<int>(Key::Count) * sizeof(*s_key_to_utf8_upper));
|
||||
static_assert(sizeof(s_key_to_utf8_upper) == (int)Key::Count * sizeof(*s_key_to_utf8_upper));
|
||||
|
||||
static uint8_t wait_and_read()
|
||||
{
|
||||
|
@ -153,8 +173,11 @@ namespace Keyboard
|
|||
IO::outb(I8042_DATA_PORT, data);
|
||||
}
|
||||
|
||||
static bool i8042_keyboard_command(uint8_t command)
|
||||
static bool i8042_command(uint8_t target, uint8_t command)
|
||||
{
|
||||
if (target == TARGET_MOUSE)
|
||||
IO::outb(I8042_STATUS_REGISTER, 0xD4);
|
||||
|
||||
auto timeout = PIT::ms_since_boot() + I8042_KB_TIMEOUT_MS;
|
||||
|
||||
while (PIT::ms_since_boot() < timeout)
|
||||
|
@ -169,40 +192,66 @@ namespace Keyboard
|
|||
return false;
|
||||
}
|
||||
|
||||
void update_keyboard()
|
||||
void update()
|
||||
{
|
||||
if (!s_keyboard_command_queue.Empty())
|
||||
if (!s_command_queue.Empty())
|
||||
{
|
||||
auto& command = s_keyboard_command_queue.Front();
|
||||
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)
|
||||
{
|
||||
if (!i8042_keyboard_command(command.command))
|
||||
Kernel::panic("oof 1");
|
||||
if (!i8042_command(command.target, command.command))
|
||||
Kernel::panic("PS/2 command oof {}, 0x{2H}", command.target, command.command);
|
||||
command._sent++;
|
||||
}
|
||||
|
||||
if (command._sent == 1 && command._ack == 1 && command.has_data)
|
||||
{
|
||||
if (!i8042_keyboard_command(command.data))
|
||||
Kernel::panic("oof 2");
|
||||
if (!i8042_command(command.target, command.data))
|
||||
Kernel::panic("PS/2 data oof {}, 0x{2H}", command.target, command.data);
|
||||
command._sent++;
|
||||
}
|
||||
|
||||
if (command._done)
|
||||
{
|
||||
switch (command.command)
|
||||
if (command.target == TARGET_KEYBOARD)
|
||||
{
|
||||
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;
|
||||
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");
|
||||
}
|
||||
}
|
||||
s_keyboard_command_queue.Pop();
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -212,6 +261,25 @@ namespace Keyboard
|
|||
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()
|
||||
|
@ -265,7 +333,7 @@ namespace Keyboard
|
|||
kprintln("{} {}", ch, extended ? 'E' : ' ');
|
||||
#endif
|
||||
|
||||
s_keyboard_state[static_cast<int>(key)] = pressed;
|
||||
s_keyboard_state[(int)key] = pressed;
|
||||
|
||||
bool update_leds = false;
|
||||
switch (key)
|
||||
|
@ -291,7 +359,7 @@ namespace Keyboard
|
|||
|
||||
if (update_leds)
|
||||
{
|
||||
s_keyboard_command_queue.Push({
|
||||
s_command_queue.Push({
|
||||
.command = I8042_KB_SET_LEDS,
|
||||
.data = s_led_states,
|
||||
.has_data = true,
|
||||
|
@ -321,54 +389,52 @@ namespace Keyboard
|
|||
memmove(s_keyboard_key_buffer, s_keyboard_key_buffer + index, s_keyboard_key_buffer_size);
|
||||
}
|
||||
|
||||
void keyboard_irq_handler()
|
||||
static void keyboard_irq_handler()
|
||||
{
|
||||
uint8_t raw = IO::inb(I8042_DATA_PORT);
|
||||
|
||||
bool command_waiting = false;
|
||||
if (!s_keyboard_command_queue.Empty())
|
||||
bool waiting_response = false;
|
||||
if (!s_command_queue.Empty())
|
||||
{
|
||||
auto& command = s_keyboard_command_queue.Front();
|
||||
command_waiting = (command._sent > 0 && !command._done);
|
||||
auto& command = s_command_queue.Front();
|
||||
if (command.target == TARGET_MOUSE)
|
||||
Kernel::panic("Please no :( (PS/2 Keyboard got irq while Mouse was waiting)");
|
||||
waiting_response = (command._sent > 0 && !command._done);
|
||||
}
|
||||
|
||||
if (command_waiting)
|
||||
if (waiting_response)
|
||||
{
|
||||
auto& command = s_keyboard_command_queue.Front();
|
||||
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--;
|
||||
return;
|
||||
}
|
||||
|
||||
if (raw == I8042_KB_ACK)
|
||||
else if (raw == I8042_KB_ACK)
|
||||
{
|
||||
command._ack++;
|
||||
if (command.extra > 0)
|
||||
return;
|
||||
command._done = command.has_data ? (command._ack == 2) : true;
|
||||
return;
|
||||
if (command.resp_cnt == 0)
|
||||
command._done = (command._ack >= (1 + command.has_data));
|
||||
}
|
||||
|
||||
if (raw == 0x00)
|
||||
else if (raw == 0x00)
|
||||
{
|
||||
dprintln("\e[33mKey detection error or internal buffer overrun\e[m");
|
||||
command._sent = 0;
|
||||
command._ack = 0;
|
||||
command._done = false;
|
||||
return;
|
||||
s_command_response_index = 0;
|
||||
}
|
||||
|
||||
if (raw == 0xEE && command.command == 0xEE)
|
||||
else if (raw == 0xEE && command.command == 0xEE)
|
||||
{
|
||||
s_keyboard_command_queue.Pop();
|
||||
return;
|
||||
s_command_queue.Pop();
|
||||
}
|
||||
else
|
||||
{
|
||||
s_command_response[s_command_response_index++] = raw;
|
||||
if (s_command_response_index >= command.resp_cnt)
|
||||
command._done = true;
|
||||
}
|
||||
|
||||
s_keyboard_command_extra = raw;
|
||||
command._done = true;
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -378,12 +444,118 @@ namespace Keyboard
|
|||
}
|
||||
}
|
||||
|
||||
static void mouse_irq_handler()
|
||||
{
|
||||
uint8_t raw = IO::inb(I8042_DATA_PORT);
|
||||
|
||||
bool waiting_response = false;
|
||||
if (!s_command_queue.Empty())
|
||||
{
|
||||
auto& command = s_command_queue.Front();
|
||||
if (command.target == TARGET_KEYBOARD)
|
||||
Kernel::panic("Please no :( (PS/2 Mouse got irq while Keyboard was waiting)");
|
||||
waiting_response = (command._sent > 0 && !command._done);
|
||||
}
|
||||
|
||||
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) s_mouse_button_event_queue.Push({ .button = MouseButton::Left });
|
||||
if (right) s_mouse_button_event_queue.Push({ .button = MouseButton::Right });
|
||||
if (middle) 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);
|
||||
|
||||
s_mouse_move_event_queue.Push({ .dx = rel_x, .dy = rel_y });
|
||||
}
|
||||
|
||||
s_mouse_data_buffer_index = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void initialize_keyboard()
|
||||
{
|
||||
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,
|
||||
}));
|
||||
|
||||
// Register callback and IRQ
|
||||
IDT::register_irq_handler(KEYBOARD_IRQ, keyboard_irq_handler);
|
||||
APIC::EnableIRQ(KEYBOARD_IRQ);
|
||||
}
|
||||
|
||||
static void initialize_mouse()
|
||||
{
|
||||
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,
|
||||
}));
|
||||
|
||||
// Register callback and IRQ
|
||||
IDT::register_irq_handler(MOUSE_IRQ, mouse_irq_handler);
|
||||
APIC::EnableIRQ(MOUSE_IRQ);
|
||||
}
|
||||
|
||||
bool initialize()
|
||||
{
|
||||
// https://wiki.osdev.org/%228042%22_PS/2_Controller
|
||||
|
||||
// TODO: support dual channel
|
||||
|
||||
// Step 1: Initialize USB Controllers
|
||||
// TODO
|
||||
|
||||
|
@ -391,8 +563,8 @@ namespace Keyboard
|
|||
// TODO
|
||||
|
||||
// Step 3: Disable Devices
|
||||
i8042_controller_command(I8042_DISABLE_FIRST);
|
||||
i8042_controller_command(I8042_DISABLE_SECOND);
|
||||
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)
|
||||
|
@ -404,6 +576,7 @@ namespace Keyboard
|
|||
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)
|
||||
|
@ -413,6 +586,16 @@ namespace Keyboard
|
|||
}
|
||||
|
||||
// Step 7: Determine If There Are 2 Channels
|
||||
bool dual_channel = config & I8042_CONFING_DUAL_CHANNEL;
|
||||
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);
|
||||
|
@ -422,73 +605,54 @@ namespace Keyboard
|
|||
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);
|
||||
i8042_controller_command(I8042_ENABLE_FIRST);
|
||||
i8042_controller_command(I8042_ENABLE_FIRST_PORT);
|
||||
i8042_controller_command(I8042_ENABLE_SECOND_PORT);
|
||||
|
||||
// Step 10: Reset Devices
|
||||
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
|
||||
IDT::register_irq_handler(KEYBOARD_IRQ, keyboard_irq_handler);
|
||||
APIC::EnableIRQ(KEYBOARD_IRQ);
|
||||
initialize_keyboard();
|
||||
if (dual_channel)
|
||||
initialize_mouse();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void register_key_event_callback(void(*callback)(KeyEvent))
|
||||
void register_key_event_callback(void (*callback)(KeyEvent))
|
||||
{
|
||||
s_key_event_callback = callback;
|
||||
}
|
||||
|
||||
void register_mouse_button_event_callback(void (*callback)(MouseButtonEvent))
|
||||
{
|
||||
s_mouse_button_event_callback = callback;
|
||||
}
|
||||
|
||||
void register_mouse_move_event_callback(void (*callback)(MouseMoveEvent))
|
||||
{
|
||||
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[static_cast<uint8_t>(event.key)];
|
||||
return s_key_to_utf8_lower[static_cast<uint8_t>(event.key)];
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
return s_key_to_utf8_upper[(int)event.key];
|
||||
return s_key_to_utf8_lower[(int)event.key];
|
||||
}
|
||||
|
||||
}
|
|
@ -1,12 +1,12 @@
|
|||
#include <BAN/StringView.h>
|
||||
#include <BAN/Vector.h>
|
||||
#include <kernel/CPUID.h>
|
||||
#include <kernel/Input.h>
|
||||
#include <kernel/IO.h>
|
||||
#include <kernel/Keyboard.h>
|
||||
#include <kernel/PIT.h>
|
||||
#include <kernel/RTC.h>
|
||||
#include <kernel/Shell.h>
|
||||
#include <kernel/Serial.h>
|
||||
#include <kernel/Shell.h>
|
||||
#include <kernel/TTY.h>
|
||||
|
||||
#define TTY_PRINT(...) BAN::Formatter::print([this](char c) { m_tty->PutChar(c); }, __VA_ARGS__)
|
||||
|
@ -26,7 +26,7 @@ namespace Kernel
|
|||
|
||||
Shell::Shell()
|
||||
{
|
||||
Keyboard::register_key_event_callback([](Keyboard::KeyEvent event) { Shell::Get().KeyEventCallback(event); });
|
||||
Input::register_key_event_callback([](Input::KeyEvent event) { Shell::Get().KeyEventCallback(event); });
|
||||
m_buffer.Reserve(128);
|
||||
}
|
||||
|
||||
|
@ -46,7 +46,7 @@ namespace Kernel
|
|||
for (;;)
|
||||
{
|
||||
asm volatile("hlt");
|
||||
Keyboard::update_keyboard();
|
||||
Input::update();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -213,14 +213,14 @@ namespace Kernel
|
|||
return 1;
|
||||
}
|
||||
|
||||
void Shell::KeyEventCallback(Keyboard::KeyEvent event)
|
||||
void Shell::KeyEventCallback(Input::KeyEvent event)
|
||||
{
|
||||
if (!event.pressed)
|
||||
return;
|
||||
|
||||
switch (event.key)
|
||||
{
|
||||
case Keyboard::Key::Backspace:
|
||||
case Input::Key::Backspace:
|
||||
{
|
||||
if (!m_buffer.Empty())
|
||||
{
|
||||
|
@ -233,8 +233,8 @@ namespace Kernel
|
|||
break;
|
||||
}
|
||||
|
||||
case Keyboard::Key::Enter:
|
||||
case Keyboard::Key::NumpadEnter:
|
||||
case Input::Key::Enter:
|
||||
case Input::Key::NumpadEnter:
|
||||
{
|
||||
TTY_PRINT("\n");
|
||||
ProcessCommand(MUST(m_buffer.SV().Split(' ')));
|
||||
|
@ -243,16 +243,16 @@ namespace Kernel
|
|||
break;
|
||||
}
|
||||
|
||||
case Keyboard::Key::Escape:
|
||||
case Input::Key::Escape:
|
||||
TTY_PRINTLN("time since boot {} ms", PIT::ms_since_boot());
|
||||
break;
|
||||
|
||||
case Keyboard::Key::Tab:
|
||||
case Input::Key::Tab:
|
||||
break;
|
||||
|
||||
default:
|
||||
{
|
||||
const char* utf8 = Keyboard::key_event_to_utf8(event);
|
||||
const char* utf8 = Input::key_event_to_utf8(event);
|
||||
if (utf8)
|
||||
{
|
||||
TTY_PRINT("{}", utf8);
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
#include <kernel/APIC.h>
|
||||
#include <kernel/GDT.h>
|
||||
#include <kernel/IDT.h>
|
||||
#include <kernel/Input.h>
|
||||
#include <kernel/IO.h>
|
||||
#include <kernel/Keyboard.h>
|
||||
#include <kernel/kmalloc.h>
|
||||
#include <kernel/kprint.h>
|
||||
#include <kernel/multiboot.h>
|
||||
|
@ -86,7 +86,7 @@ extern "C" void kernel_main(multiboot_info_t* mbi, uint32_t magic)
|
|||
TTY* tty1 = new TTY;
|
||||
tty1->SetCursorPosition(0, 2);
|
||||
|
||||
if (!Keyboard::initialize())
|
||||
if (!Input::initialize())
|
||||
return;
|
||||
|
||||
ENABLE_INTERRUPTS();
|
||||
|
|
Loading…
Reference in New Issue