feature (PS/2): implemented a basic ps/2 keyboard driver and TTY

This commit is contained in:
antifallobst 2023-04-30 12:07:54 +02:00
parent aa5ca306ca
commit 2b8a39feac
10 changed files with 430 additions and 3 deletions

View File

@ -0,0 +1,21 @@
// This file is part of noxos and licensed under the MIT open source license
#ifndef NOX_CONTROLLER_H
#define NOX_CONTROLLER_H
#include "utils/stdtypes.h"
#define PS2_CONTROLLER_DATA_PORT 0x60
#define PS2_CONTROLLER_STATUS_PORT 0x64
#define PS2_CONTROLLER_COMMAND_PORT 0x64
#define PS2_CONTROLLER_TIMEOUT 0xFFFFFF
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_wait_until_ready_for_input ();
bool ps2_controller_wait_until_ready_for_output ();
uint8_t ps2_controller_read_data ();
#endif //NOX_CONTROLLER_H

View File

@ -0,0 +1,39 @@
// This file is part of noxos and licensed under the MIT open source license
#ifndef NOX_KEYBOARD_H
#define NOX_KEYBOARD_H
#include "utils/stdtypes.h"
#include "utils/string.h"
typedef enum {
PS2_KEYBOARD_COMMAND_SET_LEDS = 0xED,
PS2_KEYBOARD_COMMAND_ECHO = 0xEE,
PS2_KEYBOARD_COMMAND_SET_SCANCODE_SET = 0xF0,
PS2_KEYBOARD_COMMAND_IDENTIFY = 0xF2,
PS2_KEYBOARD_COMMAND_SET_TYPEMATIC = 0xF3,
PS2_KEYBOARD_COMMAND_ENABLE_SCAN = 0xF4,
PS2_KEYBOARD_COMMAND_DISABLE_SCAN = 0xF5,
PS2_KEYBOARD_COMMAND_SET_DEFAULT_PARAMS = 0xF6,
PS2_KEYBOARD_COMMAND_RESEND_LAST_BYTE = 0xFE,
PS2_KEYBOARD_COMMAND_SELF_TEST = 0xFF
} ps2_keyboard_command_E;
typedef enum {
PS2_KEYBOARD_RESPONSE_KEY_DETECTION_ERROR_1 = 0x00,
PS2_KEYBOARD_RESPONSE_SELF_TEST_PASSED = 0xAA,
PS2_KEYBOARD_RESPONSE_ECHO = 0xEE,
PS2_KEYBOARD_RESPONSE_ACKNOWLEDGED = 0xFA,
PS2_KEYBOARD_RESPONSE_SELF_TEST_FAILED_1 = 0xFC,
PS2_KEYBOARD_RESPONSE_SELF_TEST_FAILED_2 = 0xFD,
PS2_KEYBOARD_RESPONSE_RESEND = 0xFE,
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);
void ps2_keyboard_init ();
void ps2_keyboard_read ();
string_t ps2_keyboard_command_to_string (ps2_keyboard_command_E command);
#endif //NOX_KEYBOARD_H

View File

@ -0,0 +1,34 @@
// This file is part of noxos and licensed under the MIT open source license
#ifndef NOX_SCANCODES_H
#define NOX_SCANCODES_H
#define PS2_SCANCODE_SET_1_ESCAPE 0x01
#define PS2_SCANCODE_SET_1_BACKSPACE 0x0E
#define PS2_SCANCODE_SET_1_TABULATOR 0x0F
#define PS2_SCANCODE_SET_1_RETURN 0x1C
#define PS2_SCANCODE_SET_1_SHIFT_LEFT 0x2A
#define PS2_SCANCODE_SET_1_SHIFT_RIGHT 0x36
#define PS2_SCANCODE_SET_1_ALT_LEFT 0x38
#define PS2_SCANCODE_SET_1_SPACE 0x39
#define PS2_SCANCODE_SET_1_CAPSLOCK 0x3A
#define PS2_SCANCODE_SET_1_NUMLOCK 0x45
#define PS2_SCANCODE_SET_1_SCROLLLOCK 0x46
#define PS2_SCANCODE_SET_1_F1 0x3B
#define PS2_SCANCODE_SET_1_F2 0x3C
#define PS2_SCANCODE_SET_1_F3 0x3D
#define PS2_SCANCODE_SET_1_F4 0x3E
#define PS2_SCANCODE_SET_1_F5 0x3F
#define PS2_SCANCODE_SET_1_F6 0x40
#define PS2_SCANCODE_SET_1_F7 0x41
#define PS2_SCANCODE_SET_1_F8 0x42
#define PS2_SCANCODE_SET_1_F9 0x43
#define PS2_SCANCODE_SET_1_F10 0x44
#define PS2_SCANCODE_SET_1_F11 0x57
#define PS2_SCANCODE_SET_1_F12 0x58
#define PS2_SCANCODE_SET_1_RELEASE 0x80
#define PS2_SCANCODE_SET_1_MODIFIER 0xE0
#endif //NOX_SCANCODES_H

26
inc/drivers/tty.h Normal file
View File

@ -0,0 +1,26 @@
// This file is part of noxos and licensed under the MIT open source license
#ifndef NOXOS_TTY_H
#define NOXOS_TTY_H
#include "drivers/graphics/renderer.h"
#include "utils/stream.h"
#define TTY_STD_STREAM_SIZE 0x800 // 2048 bytes
typedef struct {
graphics_buffer_T* graphics_buffer;
stream_T* stream;
position_T cursor;
color_argb_T color;
} tty_T;
void tty_init ();
tty_T* tty_get_active ();
tty_T* tty_alloc (uint32_t stream_size);
void tty_destruct (tty_T* tty);
void tty_update (tty_T* tty);
uint32_t tty_write (tty_T* tty, string_t string);
#endif //NOXOS_TTY_H

View File

@ -16,6 +16,7 @@
#include "drivers/acpi/acpi.h"
#include "drivers/pci.h"
#include "drivers/ps2/controller.h"
#include "drivers/tty.h"
#include "proc/scheduler.h"
void limine_terminal_print(boot_info_T* boot_info, string_t string) {
@ -37,7 +38,7 @@ void kernel_init(boot_info_T* boot_info) {
memory_allocator_init((void*)MEM_REGION_KERNEL_HEAP);
graphics_renderer_init(boot_info);
graphical_log_init();
// graphical_log_init();
vfs_init(boot_info);
@ -50,6 +51,8 @@ void kernel_init(boot_info_T* boot_info) {
ps2_controller_init();
scheduler_init(boot_info);
tty_init();
}
void kmain(boot_info_T boot_info) {
@ -61,7 +64,5 @@ void kmain(boot_info_T boot_info) {
log(LOG_INFO, "!=====[ Kernel Initialized ]=====!\n");
pci_device_T* ahci_controller = pci_manager_find_device(PCI_CLASS_MASS_STORAGE_CONTROLLER, PCI_SUBCLASS_SERIAL_ATA_CONTROLLER, 1);
CORE_HALT_FOREVER
}

View File

@ -104,6 +104,17 @@ position_T graphics_buffer_draw_string(graphics_buffer_T* graphics_buffer, uint3
pos.x = 0;
break;
}
case '\b': {
if (pos.x >= g_renderer.font.width) {
pos.x -= g_renderer.font.width;
} else if (pos.y >= g_renderer.font.height) {
pos.y -= g_renderer.font.height;
pos.x = FLOOR_TO(graphics_buffer->width, g_renderer.font.width) - g_renderer.font.width;
} else break;
graphics_buffer_draw_char(graphics_buffer, pos.x, pos.y, color, ' ');
break;
}
default: {
if (pos.x + g_renderer.font.width >= graphics_buffer->width) {

View File

@ -0,0 +1,70 @@
// This file is part of noxos and licensed under the MIT open source license
#include "drivers/ps2/controller.h"
#include "drivers/ps2/keyboard.h"
#include "drivers/acpi/fadt.h"
#include "utils/io.h"
#include "utils/logger.h"
#include "boot/config.h"
void ps2_controller_init() {
if (g_sysconfig->ps2_acpi_validation) {
if (!(g_acpi_table_fadt->ia_boot_architecture_flags & (1 << 1))) {
log(LOG_ERROR, "<PS2> ps2 controller initialization failed (ps2 controller not set in fadt boot flags)");
return;
}
} else {
log(LOG_WARNING, "<PS2> skipping ps2 controller existence acpi check (disabled by sysconfig)");
}
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()) {
return 0;
}
return io_in_byte(PS2_CONTROLLER_DATA_PORT);
}
uint8_t ps2_controller_command_with_data(uint8_t command, uint8_t data) {
io_out_byte(PS2_CONTROLLER_COMMAND_PORT, command);
if (!ps2_controller_wait_until_ready_for_input()) {
return 0;
}
io_out_byte(PS2_CONTROLLER_DATA_PORT, data);
if (!ps2_controller_wait_until_ready_for_output()) {
return 0;
}
return io_in_byte(PS2_CONTROLLER_DATA_PORT);
}
bool ps2_controller_wait_until_ready_for_input() {
uint32_t timeout = 0;
while (io_in_byte(PS2_CONTROLLER_STATUS_PORT) & 0b00000010) {
if (timeout > PS2_CONTROLLER_TIMEOUT) {
log(LOG_WARNING, "<PS2 Controller> Controller not ready for input (timeout)");
return false;
}
timeout++;
}
return true;
}
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, "<PS2 Controller> Controller not ready for output (timeout)");
return false;
}
timeout++;
}
return true;
}
uint8_t ps2_controller_read_data() {
return io_in_byte(PS2_CONTROLLER_DATA_PORT);
}

166
src/drivers/ps2/keyboard.c Normal file
View File

@ -0,0 +1,166 @@
// This file is part of noxos and licensed under the MIT open source license
#include "drivers/ps2/keyboard.h"
#include "drivers/ps2/scancodes.h"
#include "drivers/ps2/controller.h"
#include "drivers/tty.h"
#include "utils/logger.h"
#include "utils/io.h"
#include "platform/interrupts.h"
char scancode_set_1[] = " 1234567890-= qwertyuiop[] asdfghjkl;'` \\zxcvbnm,./ * 789-456+1230.";
bool shift_enabled = false;
bool extended_key = false;
uint8_t ps2_keyboard_command(ps2_keyboard_command_E command, uint8_t data) {
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, "<PS2> '%s' + 0x%xb -> 0x%xb", ps2_keyboard_command_to_string(command), data, response);
tries++;
if (tries >= 3) {
log(LOG_WARNING, "<PS2> Command %s not supported by keyboard (to many resend responses)", ps2_keyboard_command_to_string(command));
return 0;
}
}
return response;
}
void ps2_keyboard_init() {
// uint8_t data = ps2_keyboard_command(PS2_KEYBOARD_COMMAND_ECHO, 0);
// log(LOG_DEBUG, "response: 0x%xb", data);
io_in_byte(PS2_CONTROLLER_DATA_PORT);
pic_unmask_irq(IRQ_KEYBOARD);
}
void ps2_keyboard_read() {
uint8_t scancode = ps2_controller_read_data();
char chr;
if (extended_key) {
extended_key = false;
return;
}
if (scancode == PS2_SCANCODE_SET_1_MODIFIER) {
extended_key = true;
return;
}
if (scancode >= PS2_SCANCODE_SET_1_RELEASE) {
scancode -= PS2_SCANCODE_SET_1_RELEASE;
switch (scancode) {
case PS2_SCANCODE_SET_1_SHIFT_LEFT:
case PS2_SCANCODE_SET_1_SHIFT_RIGHT: {
shift_enabled = !shift_enabled;
return;
}
}
return;
}
switch (scancode) {
case PS2_SCANCODE_SET_1_ESCAPE:
case PS2_SCANCODE_SET_1_TABULATOR:
case PS2_SCANCODE_SET_1_ALT_LEFT:
case PS2_SCANCODE_SET_1_NUMLOCK:
case PS2_SCANCODE_SET_1_SCROLLLOCK:
case PS2_SCANCODE_SET_1_F1:
case PS2_SCANCODE_SET_1_F2:
case PS2_SCANCODE_SET_1_F3:
case PS2_SCANCODE_SET_1_F4:
case PS2_SCANCODE_SET_1_F5:
case PS2_SCANCODE_SET_1_F6:
case PS2_SCANCODE_SET_1_F7:
case PS2_SCANCODE_SET_1_F8:
case PS2_SCANCODE_SET_1_F9:
case PS2_SCANCODE_SET_1_F10:
case PS2_SCANCODE_SET_1_F11:
case PS2_SCANCODE_SET_1_F12: {
log(LOG_WARNING, "special keys aren't implemented yet");
return;
}
case PS2_SCANCODE_SET_1_BACKSPACE: {
chr = '\b';
break;
}
case PS2_SCANCODE_SET_1_SPACE: {
chr = ' ';
break;
}
case PS2_SCANCODE_SET_1_RETURN: {
chr = '\n';
break;
}
case PS2_SCANCODE_SET_1_SHIFT_LEFT:
case PS2_SCANCODE_SET_1_SHIFT_RIGHT:
case PS2_SCANCODE_SET_1_CAPSLOCK: {
shift_enabled = !shift_enabled;
return;
}
default: {
chr = scancode_set_1[scancode];
if (shift_enabled) {
if (string_is_char_lowercase(chr)) chr -= 32;
else if (string_is_char_uppercase(chr)) chr += 32;
}
break;
}
}
char buffer[2];
buffer[0] = chr;
buffer[1] = '\0';
tty_write(tty_get_active(), buffer);
}
string_t ps2_keyboard_command_to_string(ps2_keyboard_command_E command) {
switch (command) {
case PS2_KEYBOARD_COMMAND_SET_LEDS: {
return "Set LEDs";
}
case PS2_KEYBOARD_COMMAND_ECHO: {
return "Echo";
}
case PS2_KEYBOARD_COMMAND_SET_SCANCODE_SET: {
return "Get/Set Scancode Set";
}
case PS2_KEYBOARD_COMMAND_IDENTIFY: {
return "Identify";
}
case PS2_KEYBOARD_COMMAND_SET_TYPEMATIC: {
return "Set Typematic";
}
case PS2_KEYBOARD_COMMAND_ENABLE_SCAN: {
return "Enable Scan";
}
case PS2_KEYBOARD_COMMAND_DISABLE_SCAN: {
return "Disable Scan";
}
case PS2_KEYBOARD_COMMAND_SET_DEFAULT_PARAMS: {
return "Set Default Parameter";
}
case PS2_KEYBOARD_COMMAND_RESEND_LAST_BYTE: {
return "Resend Last Byte";
}
case PS2_KEYBOARD_COMMAND_SELF_TEST: {
return "Self Test";
}
default: {
return "Invalid Command";
}
}
}

54
src/drivers/tty.c Normal file
View File

@ -0,0 +1,54 @@
// This file is part of noxos and licensed under the MIT open source license
#include "drivers/tty.h"
#include "utils/memory.h"
// this global state tty is just a placeholder
tty_T* g_tty;
void tty_init() {
g_tty = tty_alloc(TTY_STD_STREAM_SIZE);
}
tty_T* tty_get_active() {
return g_tty;
}
tty_T* tty_alloc(uint32_t stream_size) {
tty_T* tty = memory_allocate(sizeof(tty_T));
tty->graphics_buffer = graphics_buffer_request(0, 0, graphics_renderer_get_width(), graphics_renderer_get_height(), GRAPHICS_BUFFER_STANDARD);
tty->stream = stream_alloc(stream_size);
tty->cursor.x = 0;
tty->cursor.y = 0;
tty->color = g_color_palette[COLOR_PAL_GREY_LIGHT];
return tty;
}
void tty_destruct(tty_T* tty) {
graphics_buffer_destruct(tty->graphics_buffer);
stream_destruct(tty->stream);
memory_free(tty);
}
void tty_update(tty_T* tty) {
char buffer[256];
uint32_t read_bytes = 255;
while (read_bytes == 255) {
read_bytes = stream_read(tty->stream, buffer, 255);
buffer[read_bytes] = '\0';
tty->cursor = graphics_buffer_draw_string(tty->graphics_buffer, tty->cursor.x, tty->cursor.y, tty->color, buffer);
}
graphics_renderer_update();
}
uint32_t tty_write(tty_T* tty, string_t string) {
uint32_t num = stream_write(tty->stream, (void*)string, string_length(string));
tty_update(tty);
return num;
}

View File

@ -9,6 +9,7 @@
#include "utils/logger.h"
#include "utils/io.h"
#include "proc/scheduler.h"
#include "drivers/ps2/keyboard.h"
idt_register_T g_idt_register;
uint8_t g_handling_interrupt;
@ -225,6 +226,10 @@ cpu_state_T* irq_handle(cpu_state_T* state, pic_irq_E irq) {
// log(LOG_DEBUG, "PIT -> Tick");
break;
}
case IRQ_KEYBOARD: {
ps2_keyboard_read();
break;
}
default: {
log(LOG_WARNING, "Unhandled IRQ");
break;