Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 67 additions & 0 deletions kernel/include/kernel/hw/keyboard.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
#ifndef KEYBOARD_H
#define KEYBOARD_H

#include <stdint.h>

constexpr unsigned short kb_ps2_data_port = 0x60;
constexpr unsigned short kb_ps2_status_port = 0x64;
constexpr unsigned short kb_ps2_cmd_port = 0x64;

constexpr unsigned char kb_ps2_cmd_get_ccb = 0x20;
constexpr unsigned char kb_ps2_cmd_set_ccb = 0x60;
constexpr unsigned char kb_ps2_disable_port_2 = 0xA7;
constexpr unsigned char kb_ps2_enable_port_2 = 0xA8;
constexpr unsigned char kb_ps2_test_port_2 = 0xA9;
constexpr unsigned char kb_ps2_test_controller = 0xAA;
constexpr unsigned char kb_ps2_test_port_1 = 0xAB;
constexpr unsigned char kb_ps2_disable_port_1 = 0xAD;
constexpr unsigned char kb_ps2_enable_port_1 = 0xAE;
constexpr unsigned char kb_ps2_read_controller_ip = 0xC0;
constexpr unsigned char kb_ps2_read_controller_op = 0xD0;
constexpr unsigned char kb_ps2_write_controller_op = 0xD0;
constexpr unsigned char kb_ps2_reset = 0xFF;

typedef union {
uint8_t raw;
struct {
uint8_t irq1_enable : 1;
uint8_t irq12_enable : 1;
uint8_t system_flag : 1;
uint8_t reserved1 : 1;
uint8_t port_1_clock_disable : 1;
uint8_t port_2_clock_disable : 1;
uint8_t port_1_tl_enable : 1;
uint8_t reserved2 : 1;
} __attribute__ ((packed));
} kb_ps2_cfg_byte_t;

typedef union {
uint8_t raw;
struct {
uint8_t system_reset : 1;
uint8_t a20_gate : 1;
uint8_t port_2_clock : 1;
uint8_t port_2_data : 1;
uint8_t op_buffer_is_port_1 : 1;
uint8_t op_buffer_is_port_2 : 1;
uint8_t port_1_clock : 1;
uint8_t port_1_data : 1;
} __attribute__ ((packed));
} kb_ps2_controller_output_port_t;

typedef union {
uint8_t raw;
struct {
uint8_t out_buffer_full : 1;
uint8_t in_buffer_full : 1;
uint8_t system_flag : 1;
uint8_t is_controller_command : 1;
uint8_t reserved : 2;
uint8_t is_timeout_error : 1;
uint8_t is_parity_error : 1;
} __attribute__ ((packed));
} kb_ps2_status_register_t;

void init_kb (void);

#endif
2 changes: 2 additions & 0 deletions kernel/src/kernel/entry.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include <kernel/graphics.h>
#include <kernel/handlers.h>
#include <kernel/hardfonts/classic.h>
#include <kernel/hw/keyboard.h>
#include <kernel/hw/pic.h>
#include <kernel/hw/timer.h>
#include <kernel/idt.h>
Expand Down Expand Up @@ -104,6 +105,7 @@ static void print_info (void) {
__attribute__ ((noreturn)) void _start_stage2 (void) {
init_graphics (framebuffer);
init_console (framebuffer->width, framebuffer->height, 40, 40, 1, 1, 2);
init_kb ();

for (int i = 0; i < 3; i++) // open stdin, stdout and stderr
do_syscall (SYSCALL_SYS_OPEN, (uint64_t)"/dev/tty1", 0, 0);
Expand Down
89 changes: 89 additions & 0 deletions kernel/src/kernel/hw/keyboard.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
#include <kernel/hw/keyboard.h>
#include <kernel/hw/pic.h>
#include <kernel/idt.h>
#include <kernel/io.h>
#include <utils/charqueue.h>

static bool is_kb_setup = false;
static charqueue* kb_keypress_charqueue;

static inline kb_ps2_status_register_t kb_read_status_register (void) {
return (kb_ps2_status_register_t){.raw = inb (kb_ps2_status_port)};
}

static inline unsigned char kb_send_command (unsigned char command, bool will_return) {
while (kb_read_status_register ().in_buffer_full)
;
outb (kb_ps2_cmd_port, command);
if (!will_return) return 0;
while (!(kb_read_status_register ().out_buffer_full))
;
return inb (kb_ps2_data_port);
}

static inline void kb_send_data (unsigned char data) {
while (kb_read_status_register ().in_buffer_full)
;
outb (kb_ps2_data_port, data);
}

static inline unsigned char kb_read_data (void) {
while (!(kb_read_status_register ().out_buffer_full))
;
return inb (kb_ps2_data_port);
}

static inline kb_ps2_cfg_byte_t kb_read_cfg_byte (void) {
return (kb_ps2_cfg_byte_t){.raw = kb_send_command (kb_ps2_cmd_get_ccb, true)};
}

static inline void kb_write_cfg_byte (kb_ps2_cfg_byte_t cfg_byte) {
kb_send_command (kb_ps2_cmd_set_ccb, false);
kb_send_data (cfg_byte.raw);
}

static inline bool kb_reset (void) {
kb_send_data (kb_ps2_reset);
if (kb_read_data () != 0xFA) return false;
if (kb_read_data () != 0XAA) return false;
return true;
}

static registers_t* kb_handler (registers_t* registers) {
unsigned char scancode = kb_read_data ();
pic_send_eoi (1);
push_charqueue (kb_keypress_charqueue, scancode);
return registers;
}

void init_kb (void) {
kb_keypress_charqueue = create_charqueue ();

// TODO: actually verify the PS2 controller exists

kb_send_command (kb_ps2_disable_port_1, false);
kb_send_command (kb_ps2_disable_port_2, false);

while (kb_read_status_register ().out_buffer_full)
inb (kb_ps2_data_port);

kb_ps2_cfg_byte_t cfg_byte = kb_read_cfg_byte ();
cfg_byte.irq1_enable = cfg_byte.irq12_enable = 0;
cfg_byte.port_1_tl_enable = 0;
cfg_byte.port_1_clock_disable = 0;
kb_write_cfg_byte (cfg_byte);

if (kb_send_command (kb_ps2_test_controller, true) != 0x55) return;

kb_write_cfg_byte (cfg_byte);
kb_send_command (kb_ps2_enable_port_1, false);

cfg_byte.irq1_enable = 1;
kb_write_cfg_byte (cfg_byte);
is_kb_setup = kb_reset ();

if (kb_keypress_charqueue != nullptr) {
idt_register_handler (0x21, kb_handler);
pic_clr_mask (1);
}
}
Loading