diff --git a/kernel/hid.c b/kernel/hid.c new file mode 100644 index 0000000..45578f2 --- /dev/null +++ b/kernel/hid.c @@ -0,0 +1,65 @@ +#include "hid.h" +#include "usb.h" +#include "mouse.h" +#include "keyboard.h" +#include "print.h" +#include +#include + +// Global variables +static bool hid_initialized = false; + +void hid_init(void) { + if (hid_initialized) return; + hid_initialized = true; + + // Initialize keyboard and mouse HID handling + keyboard_init(); + // Assume USB mouse has been initialized and is connected. + usb_hid_init(); // Initializes USB HID for both keyboard and mouse +} + +void hid_process_report(uint8_t* report, uint8_t length) { + // Process the HID report based on its type + if (length == 8) { // Assuming a standard 8-byte report for HID keyboard + keyboard_hid_report_t* k_report = (keyboard_hid_report_t*) report; + hid_process_keyboard_report(k_report); + } else if (length == 3) { // Assuming a standard 3-byte report for HID mouse + mouse_hid_report_t* m_report = (mouse_hid_report_t*) report; + hid_process_mouse_report(m_report); + } +} + +// Handle HID keyboard report +void hid_process_keyboard_report(const keyboard_hid_report_t* report) { + // Iterate over the keycodes and process key presses + for (int i = 0; i < 6; i++) { + uint8_t keycode = report->keycodes[i]; + if (keycode != 0) { + char key = scancode_map[keycode]; + if (key) { + keyboard_buffer_add(key); + } + } + } +} + +// Handle HID mouse report +void hid_process_mouse_report(const mouse_hid_report_t* report) { + // Process mouse movement and button clicks + mouse_data.x += report->x; + mouse_data.y += report->y; + mouse_data.left_button = (report->buttons & 0x01) != 0; + mouse_data.right_button = (report->buttons & 0x02) != 0; + + print_hex((uint32_t)mouse_data.x, 1, 1); + print_hex((uint32_t)mouse_data.y, 1, 1); + print_hex((uint32_t)report->buttons, 1, 1); +} + +// Parse the HID descriptor (for parsing USB HID device descriptors) +bool hid_parse_descriptor(uint8_t* descriptor, uint32_t length) { + // HID descriptors are defined in the USB HID specification, we'll need to parse them here. + // For now, just return true assuming we have a valid descriptor. + return true; +} diff --git a/kernel/hid.h b/kernel/hid.h new file mode 100644 index 0000000..68029ae --- /dev/null +++ b/kernel/hid.h @@ -0,0 +1,46 @@ +#ifndef HID_H +#define HID_H + +#include +#include + +// HID Report types +#define HID_REPORT_INPUT 0x01 +#define HID_REPORT_OUTPUT 0x02 +#define HID_REPORT_FEATURE 0x03 + +// HID usage page constants (USB HID) +#define HID_USAGE_PAGE_GENERIC 0x01 +#define HID_USAGE_KEYBOARD 0x06 +#define HID_USAGE_MOUSE 0x02 + +// HID keyboard and mouse data +typedef struct { + uint8_t modifier; // Modifier keys (shift, ctrl, alt, etc.) + uint8_t reserved; // Reserved byte + uint8_t keycodes[6]; // Keycodes for keys pressed +} keyboard_hid_report_t; + +typedef struct { + uint8_t buttons; // Mouse buttons (bitwise: 0x01 = left, 0x02 = right, 0x04 = middle) + int8_t x; // X axis movement + int8_t y; // Y axis movement + int8_t wheel; // Mouse wheel +} mouse_hid_report_t; + +// Initialize the HID subsystem +void hid_init(void); + +// Process an incoming HID report +void hid_process_report(uint8_t* report, uint8_t length); + +// Process HID keyboard report +void hid_process_keyboard_report(const keyboard_hid_report_t* report); + +// Process HID mouse report +void hid_process_mouse_report(const mouse_hid_report_t* report); + +// USB HID report descriptor parsing +bool hid_parse_descriptor(uint8_t* descriptor, uint32_t length); + +#endif // HID_H diff --git a/kernel/keyboard.c b/kernel/keyboard.c index 8d83d8e..4e34d72 100644 --- a/kernel/keyboard.c +++ b/kernel/keyboard.c @@ -2,64 +2,91 @@ #include "io.h" #include "isr.h" #include "terminal.h" +#include #define KEYBOARD_DATA_PORT 0x60 #define KEY_BUFFER_SIZE 256 -static char key_buffer[KEY_BUFFER_SIZE]; -static uint8_t buffer_head = 0; // Write position (interrupt) -static uint8_t buffer_tail = 0; // Read position (get_char) -static uint8_t buffer_count = 0; -static uint8_t buffer_index = 0; +// Use volatile so the compiler knows these change inside interrupts +static volatile char key_buffer[KEY_BUFFER_SIZE]; +static volatile uint8_t buffer_head = 0; +static volatile uint8_t buffer_tail = 0; +static volatile uint8_t buffer_count = 0; -// Basic US QWERTY keymap (scancode to ASCII) -static const char scancode_map[128] = { - 0, 27, '1', '2', '3', '4', '5', '6', '7', '8', // 0x00 - 0x09 - '9', '0', '-', '=', '\b', '\t', 'q', 'w', 'e', 'r', // 0x0A - 0x13 - 't', 'y', 'z', 'u', 'i', 'o', 'p', '[', ']', '\n', // 0x14 - 0x1D - 0, 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', // 0x1E - 0x27 - ';', '\'', '`', 0, '\\', 'x', 'c', 'v', 'b', // 0x28 - 0x31 - 'n', 'm', ',', '.', '/', 0, '*', 0, ' ', 0, // 0x32 - 0x3B - // rest can be filled as needed +// Exported map: Removed 'static' so hid.c can reference it if needed +const char scancode_map[128] = { + 0, 27, '1', '2', '3', '4', '5', '6', '7', '8', + '9', '0', '-', '=', '\b', '\t', 'q', 'w', 'e', 'r', + 't', 'y', 'u', 'i', 'o', 'p', '[', ']', '\n', 0, + 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', + '\'', '`', 0, '\\', 'z', 'x', 'c', 'v', 'b', 'n', + 'm', ',', '.', '/', 0, '*', 0, ' ', 0 }; -// Interrupt handler for IRQ1 -void keyboard_callback(void) { - uint8_t scancode = inb(KEYBOARD_DATA_PORT); - - if (scancode & 0x80) return; // Ignore key release - - char c = scancode_map[scancode]; +/** + * Shared function used by both PS/2 (callback) and USB (hid.c) + * This fixes the "undefined reference to keyboard_buffer_add" error. + */ +void keyboard_buffer_add(char c) { if (!c) return; uint8_t next_head = (buffer_head + 1) % KEY_BUFFER_SIZE; - // Drop key if buffer full - if (next_head == buffer_tail) return; + // If buffer is full, we must drop the key + if (next_head == buffer_tail) { + return; + } key_buffer[buffer_head] = c; buffer_head = next_head; buffer_count++; + // Echo to terminal terminal_putchar(c); } -void keyboard_init() { - register_interrupt_handler(33, keyboard_callback); // IRQ1 = int 33 (0x21) +/** + * Hardware Interrupt Handler for PS/2 + */ +void keyboard_callback(void) { + uint8_t scancode = inb(KEYBOARD_DATA_PORT); + + // Ignore break codes (key release) + if (scancode & 0x80) return; + + char c = scancode_map[scancode]; + keyboard_buffer_add(c); } -// Blocking read (returns one char) +void keyboard_init(void) { + buffer_head = 0; + buffer_tail = 0; + buffer_count = 0; + // IRQ1 is usually mapped to IDT entry 33 + register_interrupt_handler(33, keyboard_callback); +} + +/** + * Blocking read with a safe HLT to prevent CPU 100% usage + */ char keyboard_get_char(void) { - while (buffer_count == 0) { - __asm__ __volatile__("hlt"); // Better than busy loop - } - char c; - __asm__ __volatile__("cli"); - c = key_buffer[buffer_tail]; - buffer_tail = (buffer_tail + 1) % KEY_BUFFER_SIZE; - buffer_count--; - __asm__ __volatile__("sti"); - return c; + while (1) { + __asm__ __volatile__("cli"); // Disable interrupts to check buffer_count safely + + if (buffer_count > 0) { + c = key_buffer[buffer_tail]; + buffer_tail = (buffer_tail + 1) % KEY_BUFFER_SIZE; + buffer_count--; + __asm__ __volatile__("sti"); // Re-enable interrupts after reading + return c; + } + + /* * IMPORTANT: 'sti' followed by 'hlt' is guaranteed by x86 + * to execute 'hlt' BEFORE the next interrupt can trigger. + * This prevents the race condition hang. + */ + __asm__ __volatile__("sti; hlt"); + } } diff --git a/kernel/keyboard.h b/kernel/keyboard.h index 4f269ed..86e6bde 100644 --- a/kernel/keyboard.h +++ b/kernel/keyboard.h @@ -1,7 +1,12 @@ #ifndef KEYBOARD_H #define KEYBOARD_H +#include + void keyboard_init(void); -char keyboard_get_char(void); // Blocking read from buffer +void keyboard_buffer_add(char c); +char keyboard_get_char(void); + +extern const char scancode_map[128]; #endif diff --git a/kernel/mouse.c b/kernel/mouse.c index 8d6ece6..c03e014 100644 --- a/kernel/mouse.c +++ b/kernel/mouse.c @@ -5,7 +5,7 @@ #include // Mouse buffer -static mouse_data_t mouse_data; +mouse_data_t mouse_data; // Read USB mouse data mouse_data_t usb_read_mouse(void) { diff --git a/kernel/mouse.h b/kernel/mouse.h index 96a4f85..d8ec913 100644 --- a/kernel/mouse.h +++ b/kernel/mouse.h @@ -12,6 +12,8 @@ typedef struct { bool right_button; } mouse_data_t; +extern mouse_data_t mouse_data; + // Function declarations for USB 1.x HID mouse support bool usb_mouse_init(void); bool usb_mouse_detected(void);