keyboard driver

This commit is contained in:
nub31
2025-08-29 15:16:49 +02:00
parent 573398bb0f
commit 9c1b4a2c94
10 changed files with 143 additions and 28 deletions

View File

@@ -4,7 +4,7 @@ LD = x86_64-elf-ld
CFLAGS = -m64 -ffreestanding -fno-builtin -Wall -Wextra -Wshadow -std=c23 CFLAGS = -m64 -ffreestanding -fno-builtin -Wall -Wextra -Wshadow -std=c23
LDFLAGS = LDFLAGS =
SRC_C := src/kernel.c src/vga.c src/idt.c src/string.c SRC_C := src/kernel.c src/vga.c src/idt.c src/string.c src/keyboard.c
SRC_ASM := src/boot.asm src/idt_stub.asm SRC_ASM := src/boot.asm src/idt_stub.asm
OBJ_C := $(SRC_C:src/%.c=.build/%.o) OBJ_C := $(SRC_C:src/%.c=.build/%.o)

View File

@@ -195,8 +195,8 @@ long_mode_start:
mov fs, ax mov fs, ax
mov gs, ax mov gs, ax
extern kernel_main extern kmain
call kernel_main call kmain
cli cli
.hang: .hang:

View File

@@ -66,18 +66,6 @@ static const char* exception_messages[32] = { "divide by zero",
static interrupt_descriptor idt[IDT_SIZE]; static interrupt_descriptor idt[IDT_SIZE];
static inline void outb(uint16_t port, uint8_t val)
{
__asm__ volatile("outb %0, %1" : : "a"(val), "Nd"(port));
}
static inline uint8_t inb(uint16_t port)
{
uint8_t ret;
__asm__ volatile("inb %1, %0" : "=a"(ret) : "Nd"(port));
return ret;
}
static void pic_remap(int offset1, int offset2) static void pic_remap(int offset1, int offset2)
{ {
uint8_t a1, a2; uint8_t a1, a2;
@@ -129,7 +117,7 @@ static inline void idt_set_descriptor(uint8_t vector, void* handler, uint8_t dpl
entry->reserved = 0; entry->reserved = 0;
} }
void idt_init(void) void init_idt(void)
{ {
pic_remap(0x20, 0x28); pic_remap(0x20, 0x28);
@@ -144,11 +132,6 @@ void idt_init(void)
__asm__ volatile("sti"); __asm__ volatile("sti");
} }
void idt_enable(void)
{
__asm__ volatile("sti");
}
void handle_isr(isr_frame_t* frame) void handle_isr(isr_frame_t* frame)
{ {
if (frame->int_no < 32) if (frame->int_no < 32)

View File

@@ -13,6 +13,18 @@ typedef struct
typedef void (*irq_handler_t)(isr_frame_t*); typedef void (*irq_handler_t)(isr_frame_t*);
void idt_init(void); void init_idt(void);
void idt_enable(void);
static inline void outb(uint16_t port, uint8_t val)
{
__asm__ volatile("outb %0, %1" : : "a"(val), "Nd"(port));
}
static inline uint8_t inb(uint16_t port)
{
uint8_t ret;
__asm__ volatile("inb %1, %0" : "=a"(ret) : "Nd"(port));
return ret;
}
void register_irq_handler(uint8_t irq, irq_handler_t handler); void register_irq_handler(uint8_t irq, irq_handler_t handler);

View File

@@ -1,21 +1,43 @@
#include "kernel.h"
#include "idt.h" #include "idt.h"
#include "keyboard.h"
#include "vga.h" #include "vga.h"
#include <stdbool.h> #include <stdbool.h>
void kernel_main(void) void keyboard_handler(keyboard_event_t* event)
{
if (event->pressed)
{
vga_print_int(event->scan_code);
vga_print("\n");
}
}
void kmain(void)
{ {
vga_clear(); vga_clear();
vga_print_success(); vga_print_success();
vga_print(" VGA intialzied\n"); vga_print(" VGA intialzied\n");
idt_init(); init_idt();
idt_enable();
vga_print_success(); vga_print_success();
vga_print(" IDT intialzied\n"); vga_print(" IDT intialzied\n");
init_keyboard();
vga_print_success();
vga_print(" Keyboard driver intialzied\n");
vga_print("\nWelcome to nub OS\n"); vga_print("\nWelcome to nub OS\n");
register_keypress_handler(keyboard_handler);
while (true) while (true)
{ {
} }
} }
void kpanic()
{
vga_print("Kernel panic!\n");
__asm__ volatile("cli; hlt");
}

3
src/kernel.h Normal file
View File

@@ -0,0 +1,3 @@
#pragma once
void kpanic();

72
src/keyboard.c Normal file
View File

@@ -0,0 +1,72 @@
#include "keyboard.h"
#include "idt.h"
#include "kernel.h"
#include "vga.h"
#include <stdbool.h>
#include <stdint.h>
#define SCANCODE_LEFT_SHIFT 42
#define SCANCODE_RIGHT_SHIFT 54
#define SCANCODE_CAPS_LOCK 58
#define KEYBOARD_HANDLERS_LENGTH 32
bool shift = false;
bool caps_lock = false;
// todo(nub): make dynamic when a memory allocator is implemented
static keyboard_handler_t keyboard_handlers[KEYBOARD_HANDLERS_LENGTH];
static int handler_index = 0;
void handle_keyboard(isr_frame_t* frame)
{
uint8_t code = inb(0x60);
uint8_t scan_code = code & 0x7F;
bool pressed = (code & 0x80) == 0;
switch (scan_code)
{
case SCANCODE_LEFT_SHIFT:
case SCANCODE_RIGHT_SHIFT:
{
shift = pressed;
break;
}
case SCANCODE_CAPS_LOCK:
{
if (pressed)
{
caps_lock = !caps_lock;
}
break;
}
default:
{
keyboard_event_t event = { .scan_code = scan_code, .pressed = pressed, .caps_lock = caps_lock, .shift = shift };
for (int i = 0; i < handler_index; i++)
{
keyboard_handlers[i](&event);
}
}
}
}
void register_keypress_handler(keyboard_handler_t handler)
{
// todo(nub31): remove when a memory allocator is implemented and keyboard_handlers is a dynamic list
if (handler_index >= KEYBOARD_HANDLERS_LENGTH)
{
vga_print_error();
vga_print(" Maximum keyboard handlers reached\n");
kpanic();
}
keyboard_handlers[handler_index] = handler;
handler_index += 1;
}
void init_keyboard()
{
register_irq_handler(1, handle_keyboard);
}

17
src/keyboard.h Normal file
View File

@@ -0,0 +1,17 @@
#pragma once
#include <stdbool.h>
#include <stdint.h>
typedef struct
{
uint8_t scan_code;
bool pressed;
bool shift;
bool caps_lock;
} keyboard_event_t;
typedef void (*keyboard_handler_t)(keyboard_event_t*);
void init_keyboard();
void register_keypress_handler(keyboard_handler_t handler);

View File

@@ -51,7 +51,7 @@ void vga_set_cursor_position(uint8_t row, uint8_t col)
} }
} }
void vga_print_char(char character, vga_color_t color) void vga_print_char_colored(char character, vga_color_t color)
{ {
switch (character) switch (character)
{ {
@@ -101,11 +101,16 @@ void vga_print_char(char character, vga_color_t color)
} }
} }
void vga_print_char(char character)
{
vga_print_char_colored(character, vga_default_color());
}
void vga_print_colored(const char* string, vga_color_t color) void vga_print_colored(const char* string, vga_color_t color)
{ {
for (uint8_t i = 0; string[i] != '\0'; i++) for (uint8_t i = 0; string[i] != '\0'; i++)
{ {
vga_print_char(string[i], color); vga_print_char_colored(string[i], color);
} }
} }

View File

@@ -24,6 +24,7 @@ typedef uint8_t vga_color_t;
void vga_clear(void); void vga_clear(void);
void vga_set_cursor_position(uint8_t row, uint8_t col); void vga_set_cursor_position(uint8_t row, uint8_t col);
void vga_print_char(char character);
void vga_print_colored(const char* string, vga_color_t color); void vga_print_colored(const char* string, vga_color_t color);
void vga_print(const char* string); void vga_print(const char* string);