From a12ddfa12a39c9f2defe55489dc0a82cc9efebde Mon Sep 17 00:00:00 2001 From: Bananymous Date: Wed, 4 Jan 2023 19:22:23 +0200 Subject: [PATCH] Kernel: Update PS/2 controller --- kernel/kernel/Input.cpp | 280 ++++++++++++++++++++++----------------- kernel/kernel/kernel.cpp | 8 +- 2 files changed, 160 insertions(+), 128 deletions(-) diff --git a/kernel/kernel/Input.cpp b/kernel/kernel/Input.cpp index e9769e67..fccf1b63 100644 --- a/kernel/kernel/Input.cpp +++ b/kernel/kernel/Input.cpp @@ -9,7 +9,10 @@ #include -#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_STATUS_REGISTER 0x64 @@ -46,7 +49,6 @@ #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) @@ -57,6 +59,8 @@ #define I8042_MOUSE_ENABLE 0xF4 #define I8042_MOUSE_DISABLE 0xF5 +#define I8042_TIMEOUT_MS 1000 + #define KEYBOARD_IRQ 0x01 #define MOUSE_IRQ 0x0C @@ -85,6 +89,7 @@ namespace Input uint8_t _ack = 0; bool _done = false; }; + static uint64_t s_command_sent = 0; static BAN::Queue s_command_queue; static uint8_t s_command_response[3] = {}; 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 void keyboard_new_key(); + + static uint8_t wait_and_read() { 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) { 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) { 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; } } @@ -192,6 +203,114 @@ namespace Input 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() { if (!s_command_queue.Empty()) @@ -202,18 +321,26 @@ namespace Input 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); - command._sent++; } 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); - 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.target == TARGET_KEYBOARD) @@ -250,6 +377,7 @@ namespace Input Kernel::panic("PS/2 Mouse unhandled command"); } } + s_command_response_index = 0; s_command_queue.Pop(); } @@ -328,7 +456,7 @@ namespace Input } -#if KB_DEBUG_PRINT +#if KEYBOARD_SHOW_UNKNOWN if (key == Key::INVALID) kprintln("{} {}", ch, extended ? 'E' : ' '); #endif @@ -360,6 +488,7 @@ namespace Input if (update_leds) { s_command_queue.Push({ + .target = TARGET_KEYBOARD, .command = I8042_KB_SET_LEDS, .data = s_led_states, .has_data = true, @@ -392,120 +521,28 @@ namespace Input static void keyboard_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_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(); - } +#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); - - 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; - } - } +#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); + APIC::EnableIRQ(KEYBOARD_IRQ); + i8042_controller_command(I8042_ENABLE_FIRST_PORT); + MUST(s_command_queue.Push({ .target = TARGET_KEYBOARD, .command = I8042_KB_RESET, @@ -527,14 +564,15 @@ namespace Input .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() { + // 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({ .target = TARGET_MOUSE, .command = I8042_MOUSE_RESET, @@ -546,10 +584,6 @@ namespace Input .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() @@ -586,7 +620,7 @@ namespace Input } // 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) { i8042_controller_command(I8042_ENABLE_SECOND_PORT); @@ -620,13 +654,11 @@ namespace Input if (dual_channel) config |= I8042_CONFING_IRQ_SECOND; 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 initialize_keyboard(); if (dual_channel) - initialize_mouse(); + initialize_mouse(); return true; } diff --git a/kernel/kernel/kernel.cpp b/kernel/kernel/kernel.cpp index acb9f3fb..c280d974 100644 --- a/kernel/kernel/kernel.cpp +++ b/kernel/kernel/kernel.cpp @@ -80,15 +80,15 @@ extern "C" void kernel_main(multiboot_info_t* mbi, uint32_t magic) gdt_initialize(); IDT::initialize(); - PIT::initialize(); kmalloc_initialize(); + PIT::initialize(); + if (!Input::initialize()) + return; + TTY* tty1 = new TTY; tty1->SetCursorPosition(0, 2); - if (!Input::initialize()) - return; - ENABLE_INTERRUPTS(); kprintln("Hello from the kernel!");