#include #include #include #include #include /* PS/2 Controller IO Ports The PS/2 Controller itself uses 2 IO ports (IO ports 0x60 and 0x64). Like many IO ports, reads and writes may access different internal registers. Historical note: The PC-XT PPI had used port 0x61 to reset the keyboard interrupt request signal (among other unrelated functions). Port 0x61 has no keyboard related functions on AT and PS/2 compatibles. IO Port Access Type Purpose 0x60 Read/Write Data Port 0x64 Read Status Register 0x64 Write Command Register */ /* Note: The interrupt number for keyboard input in 1. */ #define PS2_DATA_PORT 0x60 #define PS2_STATUS_PORT 0x64 #define KEYBOARD_IRQ 1 bool ps2keyboard_initialized = false; /* State for shift key */ static bool shift_pressed = false; /* State for caps-lock key */ static bool capslock_pressed = false; volatile char current_char; volatile char* current_string = NULL; volatile int32_t current_length = 0; volatile int32_t capacity = 0; static const char scancode_map[128] = { 0, 27, '1','2','3','4','5','6','7','8','9','0','-','=','\b', /* Backspace */ '\t', // Tab 'q','w','e','r','t','y','u','i','o','p','[',']','\n', /* Enter */ 0, /* Control */ 'a','s','d','f','g','h','j','k','l',';','\'','`', 0, /* Left shift */ '\\','z','x','c','v','b','n','m',',','.','/', 0, /* Right shift */ '*', 0, /* Alt */ ' ', /* Spacebar */ 0, /* Caps lock */ /* The rest are function and control keys */ }; void keyboard_init(void) { outb(0x64, 0xAE); /* Enable keyboard interface (often optional, but here for safety) */ ps2keyboard_initialized = true; } char get_char(void) { return current_char; } char* get_string(void) { return current_string; } static void append_char(char c) { if (current_length + 1 >= capacity) { /* Need more space (+1 for the null zero) */ int new_capacity = (capacity == 0) ? 16 : capacity * 2; char* new_str = (char*)malloc(new_capacity); if (!new_str) { return; } if (current_string) { memcpy(new_str, current_string, current_length); free(current_string); } if (!current_string) { return; } current_string = new_str; capacity = new_capacity; } current_string[current_length] = c; current_length++; current_string[current_length] = '\0'; /* Maintain null terminator */ } static void free_current_string(void) { if (current_string) { free(current_string); current_string = NULL; current_length = 0; capacity = 0; } } void keyboard_handler(void) { uint8_t scancode = inb(PS2_DATA_PORT); /* Handle shift press/release */ if (scancode == 0x2A || scancode == 0x36) { shift_pressed = true; return; } else if (scancode == 0xAA || scancode == 0xB6) { shift_pressed = false; return; } else if (scancode == 0x3A) { capslock_pressed = !capslock_pressed; return; } if (scancode & 0x80) { /* Key release event, ignore for now */ } else { char c = scancode_map[scancode]; if ((shift_pressed ^ capslock_pressed) && c >= 'a' && c <= 'z') { c -= 32; /* Convert to uppercase */ } else if (shift_pressed) { c = (char) terminal_get_shifted((unsigned char) c); } if (scancode == 0x1C) { printf("\n"); return; } if (c) { current_char = c; if (c == '\n') { free_current_string(); } else { append_char(c); printf("%c", c); } } } }