Kernel: Update PS/2 controller
This commit is contained in:
parent
fcec793873
commit
a12ddfa12a
|
@ -9,7 +9,10 @@
|
||||||
|
|
||||||
#include <kernel/KeyboardLayout/FI.h>
|
#include <kernel/KeyboardLayout/FI.h>
|
||||||
|
|
||||||
#define KB_DEBUG_PRINT 1
|
#define DEBUG_ALL_IRQ 0
|
||||||
|
#define KEYBOARD_SHOW_UNKNOWN 1
|
||||||
|
|
||||||
|
#define MOUSE_ENABLED 0
|
||||||
|
|
||||||
#define I8042_DATA_PORT 0x60
|
#define I8042_DATA_PORT 0x60
|
||||||
#define I8042_STATUS_REGISTER 0x64
|
#define I8042_STATUS_REGISTER 0x64
|
||||||
|
@ -46,7 +49,6 @@
|
||||||
#define I8042_KB_SELF_TEST_PASS 0xAA
|
#define I8042_KB_SELF_TEST_PASS 0xAA
|
||||||
#define I8042_KB_SET_SCAN_CODE_SET 0xF0
|
#define I8042_KB_SET_SCAN_CODE_SET 0xF0
|
||||||
#define I8042_KB_SET_LEDS 0xED
|
#define I8042_KB_SET_LEDS 0xED
|
||||||
#define I8042_KB_TIMEOUT_MS 1000
|
|
||||||
#define I8042_KB_LED_SCROLL_LOCK (1 << 0)
|
#define I8042_KB_LED_SCROLL_LOCK (1 << 0)
|
||||||
#define I8042_KB_LED_NUM_LOCK (1 << 1)
|
#define I8042_KB_LED_NUM_LOCK (1 << 1)
|
||||||
#define I8042_KB_LED_CAPS_LOCK (1 << 2)
|
#define I8042_KB_LED_CAPS_LOCK (1 << 2)
|
||||||
|
@ -57,6 +59,8 @@
|
||||||
#define I8042_MOUSE_ENABLE 0xF4
|
#define I8042_MOUSE_ENABLE 0xF4
|
||||||
#define I8042_MOUSE_DISABLE 0xF5
|
#define I8042_MOUSE_DISABLE 0xF5
|
||||||
|
|
||||||
|
#define I8042_TIMEOUT_MS 1000
|
||||||
|
|
||||||
#define KEYBOARD_IRQ 0x01
|
#define KEYBOARD_IRQ 0x01
|
||||||
#define MOUSE_IRQ 0x0C
|
#define MOUSE_IRQ 0x0C
|
||||||
|
|
||||||
|
@ -85,6 +89,7 @@ namespace Input
|
||||||
uint8_t _ack = 0;
|
uint8_t _ack = 0;
|
||||||
bool _done = false;
|
bool _done = false;
|
||||||
};
|
};
|
||||||
|
static uint64_t s_command_sent = 0;
|
||||||
static BAN::Queue<Command> s_command_queue;
|
static BAN::Queue<Command> s_command_queue;
|
||||||
static uint8_t s_command_response[3] = {};
|
static uint8_t s_command_response[3] = {};
|
||||||
static uint8_t s_command_response_index = 0;
|
static uint8_t s_command_response_index = 0;
|
||||||
|
@ -153,6 +158,11 @@ namespace Input
|
||||||
};
|
};
|
||||||
static_assert(sizeof(s_key_to_utf8_upper) == (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 void keyboard_new_key();
|
||||||
|
|
||||||
|
|
||||||
static uint8_t wait_and_read()
|
static uint8_t wait_and_read()
|
||||||
{
|
{
|
||||||
while ((IO::inb(I8042_STATUS_REGISTER) & I8042_STATUS_OUT_FULL) == 0)
|
while ((IO::inb(I8042_STATUS_REGISTER) & I8042_STATUS_OUT_FULL) == 0)
|
||||||
|
@ -176,15 +186,16 @@ namespace Input
|
||||||
static bool i8042_command(uint8_t target, uint8_t command)
|
static bool i8042_command(uint8_t target, uint8_t command)
|
||||||
{
|
{
|
||||||
if (target == TARGET_MOUSE)
|
if (target == TARGET_MOUSE)
|
||||||
IO::outb(I8042_STATUS_REGISTER, 0xD4);
|
IO::outb(I8042_COMMAND_REGISTER, 0xD4);
|
||||||
|
|
||||||
auto timeout = PIT::ms_since_boot() + I8042_KB_TIMEOUT_MS;
|
auto timeout = PIT::ms_since_boot() + I8042_TIMEOUT_MS;
|
||||||
|
|
||||||
while (PIT::ms_since_boot() < timeout)
|
while (PIT::ms_since_boot() < timeout)
|
||||||
{
|
{
|
||||||
if ((IO::inb(I8042_STATUS_REGISTER) & I8042_STATUS_IN_FULL) == 0)
|
if ((IO::inb(I8042_STATUS_REGISTER) & I8042_STATUS_IN_FULL) == 0)
|
||||||
{
|
{
|
||||||
IO::outb(I8042_DATA_PORT, command);
|
IO::outb(I8042_DATA_PORT, command);
|
||||||
|
s_command_sent = PIT::ms_since_boot();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -192,6 +203,114 @@ namespace Input
|
||||||
return false;
|
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) 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Kernel::panic("Unknown target");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void update()
|
void update()
|
||||||
{
|
{
|
||||||
if (!s_command_queue.Empty())
|
if (!s_command_queue.Empty())
|
||||||
|
@ -202,16 +321,24 @@ namespace Input
|
||||||
|
|
||||||
if (command._sent == 0 && command._ack == 0)
|
if (command._sent == 0 && command._ack == 0)
|
||||||
{
|
{
|
||||||
|
command._sent++;
|
||||||
if (!i8042_command(command.target, command.command))
|
if (!i8042_command(command.target, command.command))
|
||||||
Kernel::panic("PS/2 command oof {}, 0x{2H}", 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 (command._sent == 1 && command._ack == 1 && command.has_data)
|
||||||
{
|
{
|
||||||
|
command._sent++;
|
||||||
if (!i8042_command(command.target, command.data))
|
if (!i8042_command(command.target, command.data))
|
||||||
Kernel::panic("PS/2 data oof {}, 0x{2H}", command.target, command.data);
|
Kernel::panic("PS/2 data oof {}, 0x{2H}", command.target, command.data);
|
||||||
command._sent++;
|
}
|
||||||
|
|
||||||
|
if (command._sent > 0 && PIT::ms_since_boot() > s_command_sent + 1000)
|
||||||
|
{
|
||||||
|
kprintln("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._done)
|
||||||
|
@ -250,6 +377,7 @@ namespace Input
|
||||||
Kernel::panic("PS/2 Mouse unhandled command");
|
Kernel::panic("PS/2 Mouse unhandled command");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
s_command_response_index = 0;
|
s_command_response_index = 0;
|
||||||
s_command_queue.Pop();
|
s_command_queue.Pop();
|
||||||
}
|
}
|
||||||
|
@ -328,7 +456,7 @@ namespace Input
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#if KB_DEBUG_PRINT
|
#if KEYBOARD_SHOW_UNKNOWN
|
||||||
if (key == Key::INVALID)
|
if (key == Key::INVALID)
|
||||||
kprintln("{} {}", ch, extended ? 'E' : ' ');
|
kprintln("{} {}", ch, extended ? 'E' : ' ');
|
||||||
#endif
|
#endif
|
||||||
|
@ -360,6 +488,7 @@ namespace Input
|
||||||
if (update_leds)
|
if (update_leds)
|
||||||
{
|
{
|
||||||
s_command_queue.Push({
|
s_command_queue.Push({
|
||||||
|
.target = TARGET_KEYBOARD,
|
||||||
.command = I8042_KB_SET_LEDS,
|
.command = I8042_KB_SET_LEDS,
|
||||||
.data = s_led_states,
|
.data = s_led_states,
|
||||||
.has_data = true,
|
.has_data = true,
|
||||||
|
@ -392,120 +521,28 @@ namespace Input
|
||||||
static void keyboard_irq_handler()
|
static void keyboard_irq_handler()
|
||||||
{
|
{
|
||||||
uint8_t raw = IO::inb(I8042_DATA_PORT);
|
uint8_t raw = IO::inb(I8042_DATA_PORT);
|
||||||
|
#if DEBUG_ALL_IRQ
|
||||||
bool waiting_response = false;
|
dprintln("k 0x{2H}", raw);
|
||||||
if (!s_command_queue.Empty())
|
#endif
|
||||||
{
|
i8042_handle_byte(TARGET_KEYBOARD, raw);
|
||||||
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 (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();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mouse_irq_handler()
|
static void mouse_irq_handler()
|
||||||
{
|
{
|
||||||
uint8_t raw = IO::inb(I8042_DATA_PORT);
|
uint8_t raw = IO::inb(I8042_DATA_PORT);
|
||||||
|
#if DEBUG_ALL_IRQ
|
||||||
bool waiting_response = false;
|
dprintln("m 0x{2H}", raw);
|
||||||
if (!s_command_queue.Empty())
|
#endif
|
||||||
{
|
i8042_handle_byte(TARGET_MOUSE, raw);
|
||||||
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()
|
static void initialize_keyboard()
|
||||||
{
|
{
|
||||||
|
// Register callback and IRQ
|
||||||
|
IDT::register_irq_handler(KEYBOARD_IRQ, keyboard_irq_handler);
|
||||||
|
APIC::EnableIRQ(KEYBOARD_IRQ);
|
||||||
|
i8042_controller_command(I8042_ENABLE_FIRST_PORT);
|
||||||
|
|
||||||
MUST(s_command_queue.Push({
|
MUST(s_command_queue.Push({
|
||||||
.target = TARGET_KEYBOARD,
|
.target = TARGET_KEYBOARD,
|
||||||
.command = I8042_KB_RESET,
|
.command = I8042_KB_RESET,
|
||||||
|
@ -527,14 +564,15 @@ namespace Input
|
||||||
.data = s_led_states,
|
.data = s_led_states,
|
||||||
.has_data = true,
|
.has_data = true,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
// Register callback and IRQ
|
|
||||||
IDT::register_irq_handler(KEYBOARD_IRQ, keyboard_irq_handler);
|
|
||||||
APIC::EnableIRQ(KEYBOARD_IRQ);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void initialize_mouse()
|
static void initialize_mouse()
|
||||||
{
|
{
|
||||||
|
// Register callback and IRQ
|
||||||
|
IDT::register_irq_handler(MOUSE_IRQ, mouse_irq_handler);
|
||||||
|
APIC::EnableIRQ(MOUSE_IRQ);
|
||||||
|
i8042_controller_command(I8042_ENABLE_SECOND_PORT);
|
||||||
|
|
||||||
MUST(s_command_queue.Push({
|
MUST(s_command_queue.Push({
|
||||||
.target = TARGET_MOUSE,
|
.target = TARGET_MOUSE,
|
||||||
.command = I8042_MOUSE_RESET,
|
.command = I8042_MOUSE_RESET,
|
||||||
|
@ -546,10 +584,6 @@ namespace Input
|
||||||
.target = TARGET_MOUSE,
|
.target = TARGET_MOUSE,
|
||||||
.command = I8042_MOUSE_ENABLE,
|
.command = I8042_MOUSE_ENABLE,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
// Register callback and IRQ
|
|
||||||
IDT::register_irq_handler(MOUSE_IRQ, mouse_irq_handler);
|
|
||||||
APIC::EnableIRQ(MOUSE_IRQ);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool initialize()
|
bool initialize()
|
||||||
|
@ -586,7 +620,7 @@ namespace Input
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 7: Determine If There Are 2 Channels
|
// Step 7: Determine If There Are 2 Channels
|
||||||
bool dual_channel = config & I8042_CONFING_DUAL_CHANNEL;
|
bool dual_channel = MOUSE_ENABLED ? config & I8042_CONFING_DUAL_CHANNEL : false;
|
||||||
if (dual_channel)
|
if (dual_channel)
|
||||||
{
|
{
|
||||||
i8042_controller_command(I8042_ENABLE_SECOND_PORT);
|
i8042_controller_command(I8042_ENABLE_SECOND_PORT);
|
||||||
|
@ -620,8 +654,6 @@ namespace Input
|
||||||
if (dual_channel)
|
if (dual_channel)
|
||||||
config |= I8042_CONFING_IRQ_SECOND;
|
config |= I8042_CONFING_IRQ_SECOND;
|
||||||
i8042_controller_command(I8042_WRITE_CONFIG, config);
|
i8042_controller_command(I8042_WRITE_CONFIG, config);
|
||||||
i8042_controller_command(I8042_ENABLE_FIRST_PORT);
|
|
||||||
i8042_controller_command(I8042_ENABLE_SECOND_PORT);
|
|
||||||
|
|
||||||
// Step 10: Reset Devices
|
// Step 10: Reset Devices
|
||||||
initialize_keyboard();
|
initialize_keyboard();
|
||||||
|
|
|
@ -80,15 +80,15 @@ extern "C" void kernel_main(multiboot_info_t* mbi, uint32_t magic)
|
||||||
gdt_initialize();
|
gdt_initialize();
|
||||||
IDT::initialize();
|
IDT::initialize();
|
||||||
|
|
||||||
PIT::initialize();
|
|
||||||
kmalloc_initialize();
|
kmalloc_initialize();
|
||||||
|
|
||||||
|
PIT::initialize();
|
||||||
|
if (!Input::initialize())
|
||||||
|
return;
|
||||||
|
|
||||||
TTY* tty1 = new TTY;
|
TTY* tty1 = new TTY;
|
||||||
tty1->SetCursorPosition(0, 2);
|
tty1->SetCursorPosition(0, 2);
|
||||||
|
|
||||||
if (!Input::initialize())
|
|
||||||
return;
|
|
||||||
|
|
||||||
ENABLE_INTERRUPTS();
|
ENABLE_INTERRUPTS();
|
||||||
|
|
||||||
kprintln("Hello from the kernel!");
|
kprintln("Hello from the kernel!");
|
||||||
|
|
Loading…
Reference in New Issue