diff --git a/inc/drivers/ps2/controller.h b/inc/drivers/ps2/controller.h index 92068e2..a3b93e2 100644 --- a/inc/drivers/ps2/controller.h +++ b/inc/drivers/ps2/controller.h @@ -9,13 +9,15 @@ #define PS2_CONTROLLER_STATUS_PORT 0x64 #define PS2_CONTROLLER_COMMAND_PORT 0x64 -#define PS2_CONTROLLER_TIMEOUT 0xFFFFFF +#define PS2_CONTROLLER_TIMEOUT 0xFFFFF void ps2_controller_init (); uint8_t ps2_controller_command (uint8_t command); uint8_t ps2_controller_command_with_data (uint8_t command, uint8_t data); +bool ps2_controller_command_has_response (uint8_t command); bool ps2_controller_wait_until_ready_for_input (); bool ps2_controller_wait_until_ready_for_output (); uint8_t ps2_controller_read_data (); +void ps2_controller_write_data (uint8_t data); #endif //NOX_CONTROLLER_H diff --git a/inc/drivers/ps2/keyboard.h b/inc/drivers/ps2/keyboard.h index 987d303..4c2bea1 100644 --- a/inc/drivers/ps2/keyboard.h +++ b/inc/drivers/ps2/keyboard.h @@ -31,7 +31,7 @@ typedef enum { PS2_KEYBOARD_RESPONSE_KEY_DETECTION_ERROR_2 = 0xFF } ps2_keyboard_response_E; -uint8_t ps2_keyboard_command (ps2_keyboard_command_E command, uint8_t data); +uint8_t ps2_keyboard_command (ps2_keyboard_command_E command); void ps2_keyboard_init (); void ps2_keyboard_read (); string_t ps2_keyboard_command_to_string (ps2_keyboard_command_E command); diff --git a/src/boot/kmain.c b/src/boot/kmain.c index 2b0eaf2..0c1d068 100644 --- a/src/boot/kmain.c +++ b/src/boot/kmain.c @@ -44,15 +44,15 @@ void kernel_init(boot_info_T* boot_info) { sysconfig_default_init(); + scheduler_init(boot_info); + acpi_init(boot_info); pci_init(); - ps2_controller_init(); - - scheduler_init(boot_info); - tty_init(); + + ps2_controller_init(); } void kmain(boot_info_T boot_info) { diff --git a/src/drivers/ps2/controller.c b/src/drivers/ps2/controller.c index 12dfb7f..811b4c7 100644 --- a/src/drivers/ps2/controller.c +++ b/src/drivers/ps2/controller.c @@ -8,6 +8,7 @@ #include "boot/config.h" void ps2_controller_init() { + // check if the ps/2 controller exists if (g_sysconfig->ps2_acpi_validation) { if (!(g_acpi_table_fadt->ia_boot_architecture_flags & (1 << 1))) { log(LOG_ERROR, " ps2 controller initialization failed (ps2 controller not set in fadt boot flags)"); @@ -17,12 +18,48 @@ void ps2_controller_init() { log(LOG_WARNING, " skipping ps2 controller existence acpi check (disabled by sysconfig)"); } + // disable ps/2 devices + ps2_controller_command(0xAD); // keyboard + ps2_controller_command(0xA7); // mouse + + // clear buffer + while (io_in_byte(PS2_CONTROLLER_STATUS_PORT) & 0b00000001) { + io_in_byte(PS2_CONTROLLER_DATA_PORT); + } + + // set the configuration byte + uint8_t config_byte = ps2_controller_command(0x20); + bool dual_channel = (config_byte & 0b00100000); + config_byte &= 0b10111100; + ps2_controller_command_with_data(0x60, config_byte); + + // performing self test + if (ps2_controller_command(0xAA) != 0x55) { + log(LOG_ERROR, " controller driver init failed (controller self test failed)"); + return; + } + // restore the config byte, due to a possible reset by the self test + ps2_controller_command_with_data(0x60, config_byte); + + // check if the controller supports 2 channels + if (dual_channel) { + ps2_controller_command(0xA8); + dual_channel = !(ps2_controller_command(0x20) & 0b00100000); + ps2_controller_command(0xA7); + } + + // perform interface tests + if (ps2_controller_command(0xAB) > 0 && (!dual_channel || ps2_controller_command(0xA9) > 0)) { + log(LOG_ERROR, " controller driver init failed (interface tests failed)"); + } + + // init devices ps2_keyboard_init(); } uint8_t ps2_controller_command(uint8_t command) { io_out_byte(PS2_CONTROLLER_COMMAND_PORT, command); - if (!ps2_controller_wait_until_ready_for_output()) { + if (ps2_controller_command_has_response(command) && !ps2_controller_wait_until_ready_for_output()) { return 0; } return io_in_byte(PS2_CONTROLLER_DATA_PORT); @@ -34,12 +71,21 @@ uint8_t ps2_controller_command_with_data(uint8_t command, uint8_t data) { return 0; } io_out_byte(PS2_CONTROLLER_DATA_PORT, data); - if (!ps2_controller_wait_until_ready_for_output()) { + if (ps2_controller_command_has_response(command) && !ps2_controller_wait_until_ready_for_output()) { return 0; } return io_in_byte(PS2_CONTROLLER_DATA_PORT); } +bool ps2_controller_command_has_response(uint8_t command) { + if (command >= 0x20 && command <= 0x3F) return true; + if (command >= 0xA9 && command <= 0xAC) return true; + if (command == 0xC0) return true; + if (command == 0xD0) return true; + + return false; +} + bool ps2_controller_wait_until_ready_for_input() { uint32_t timeout = 0; while (io_in_byte(PS2_CONTROLLER_STATUS_PORT) & 0b00000010) { @@ -54,7 +100,6 @@ bool ps2_controller_wait_until_ready_for_input() { bool ps2_controller_wait_until_ready_for_output() { uint32_t timeout = 0; - log(LOG_DEBUG, "status register: 0b%.8b", io_in_byte(PS2_CONTROLLER_STATUS_PORT)); while (!(io_in_byte(PS2_CONTROLLER_STATUS_PORT) & 0b00000001)) { if (timeout > PS2_CONTROLLER_TIMEOUT) { log(LOG_WARNING, " Controller not ready for output (timeout)"); @@ -68,3 +113,7 @@ bool ps2_controller_wait_until_ready_for_output() { uint8_t ps2_controller_read_data() { return io_in_byte(PS2_CONTROLLER_DATA_PORT); } + +void ps2_controller_write_data(uint8_t data) { + io_out_byte(PS2_CONTROLLER_DATA_PORT, data); +} diff --git a/src/drivers/ps2/keyboard.c b/src/drivers/ps2/keyboard.c index 7f699f3..f9280fc 100644 --- a/src/drivers/ps2/keyboard.c +++ b/src/drivers/ps2/keyboard.c @@ -12,13 +12,24 @@ char scancode_set_1[] = " 1234567890-= qwertyuiop[] asdfghjkl;'` \\zxcvbnm,./ bool shift_enabled = false; bool extended_key = false; -uint8_t ps2_keyboard_command(ps2_keyboard_command_E command, uint8_t data) { +uint8_t ps2_keyboard_command(ps2_keyboard_command_E command) { uint8_t response = PS2_KEYBOARD_RESPONSE_RESEND; uint8_t tries = 0; while (response == PS2_KEYBOARD_RESPONSE_RESEND) { - response = ps2_controller_command(command); - log(LOG_DEBUG, " '%s' + 0x%xb -> 0x%xb", ps2_keyboard_command_to_string(command), data, response); + if (!ps2_controller_wait_until_ready_for_input()) { + return 0; + } + ps2_controller_write_data(command); + if (!ps2_controller_wait_until_ready_for_output()) { + return 0; + } + while (io_in_byte(PS2_CONTROLLER_STATUS_PORT) & 0b00000001) { + response = ps2_controller_read_data(); + } + + + log(LOG_DEBUG, " '%s' -> 0x%xb", ps2_keyboard_command_to_string(command), response); tries++; if (tries >= 3) { @@ -32,10 +43,20 @@ uint8_t ps2_keyboard_command(ps2_keyboard_command_E command, uint8_t data) { void ps2_keyboard_init() { -// uint8_t data = ps2_keyboard_command(PS2_KEYBOARD_COMMAND_ECHO, 0); -// log(LOG_DEBUG, "response: 0x%xb", data); + // re-enable the ps/2 keyboard + ps2_controller_command(0xAE); - io_in_byte(PS2_CONTROLLER_DATA_PORT); + // reset the keyboard + ps2_keyboard_command(PS2_KEYBOARD_COMMAND_SELF_TEST); + + // set scancode set to 1 + ps2_keyboard_command(PS2_KEYBOARD_COMMAND_SET_SCANCODE_SET); + ps2_keyboard_command(1); + + // enable keyboard interrupt on ps/2 controller + uint8_t config_byte = ps2_controller_command(0x20); + config_byte |= 0b00000001; + ps2_controller_command_with_data(0x60, config_byte); pic_unmask_irq(IRQ_KEYBOARD); }