diff --git a/includes/driver/keyboard/event_queue.h b/includes/driver/keyboard/event_queue.h new file mode 100644 index 0000000..bc5ae83 --- /dev/null +++ b/includes/driver/keyboard/event_queue.h @@ -0,0 +1,43 @@ +#ifndef EVENT_QUEUE_H +#define EVENT_QUEUE_H + +#include "keyboard.h" +#include "keyboard_keys.h" +#include "ps2.h" +#include "types.h" + +#define KEYBOARD_EVENT_QUEUE_SIZE 256 + +typedef struct { + key_event_t events[KEYBOARD_EVENT_QUEUE_SIZE]; + uint32_t head; + uint32_t tail; +} keyboard_event_queue_t; + +extern keyboard_event_queue_t keyboard_queue; + +typedef enum { + INPUT_CHAR, + INPUT_ENTER, + INPUT_BACKSPACE, + INPUT_TAB, + INPUT_UP, + INPUT_DOWN, + INPUT_LEFT, + INPUT_RIGHT, +} input_type_t; + +typedef struct { + input_type_t type; + char character; +} input_event_t; + +void input_queue_push(input_event_t event); +void input_queue_pop(input_event_t *event); +void input_queue_print(); +void input_queue_print_last(); +void input_queue_clear(); + +extern input_event_t input_queue[KEYBOARD_EVENT_QUEUE_SIZE]; + +#endif \ No newline at end of file diff --git a/includes/driver/keyboard/handler.h b/includes/driver/keyboard/handler.h new file mode 100644 index 0000000..d81592a --- /dev/null +++ b/includes/driver/keyboard/handler.h @@ -0,0 +1,20 @@ +#ifndef HANDLER_H +#define HANDLER_H + +#include "keyboard.h" +#include "keyboard_keys.h" +#include "ps2.h" +#include "stdio.h" +#include "types.h" + +extern scancode_state_t scan_state; + +void keyboard_irq_handler(void); + +void keyboard_process_scancode(uint8_t data); +void keyboard_handle_key(keycode_t key, key_action_t action); +void keyboard_update_state(keycode_t key, key_action_t action); + +// queue for keyboard events + +#endif \ No newline at end of file diff --git a/includes/driver/keyboard/keyboard.h b/includes/driver/keyboard/keyboard.h new file mode 100644 index 0000000..51842ef --- /dev/null +++ b/includes/driver/keyboard/keyboard.h @@ -0,0 +1,28 @@ +#ifndef keyboard_H +#define keyboard_H + +#include "keyboard_keys.h" +#include "keyboard_layout.h" +#include "ps2.h" +#include "types.h" + +typedef enum { + K_ACK = 0xFA, + K_RESEND = 0xFE, + K_ERROR = 0xFC, + k_BAT = 0xAA, // Basic Assurance Test +} k_response_t; + +void init_keyboard(void); + +void reset_keyboard(void); +void set_scaning(bool state); +void select_scancode_set(uint8_t set); +void keyboard_set_layout(const keyboard_layout_t *layout); +char keyboard_translate(keycode_t key, const keyboard_state_t *state); + +uint8_t keyboard_get_scan_code_set(void); + +void keyboard_irq_handler(void); + +#endif \ No newline at end of file diff --git a/includes/driver/keyboard/keyboard_keys.h b/includes/driver/keyboard/keyboard_keys.h new file mode 100644 index 0000000..40e3dfc --- /dev/null +++ b/includes/driver/keyboard/keyboard_keys.h @@ -0,0 +1,342 @@ +#ifndef keyboard_keys_H +#define keyboard_keys_H + +#include "ps2.h" +#include "types.h" + +#define KP_BREAK 0xF0 +#define KP_EXTENDED 0xE0 +#define KP_EXTENDED_BREAK 0xE0F0 + +typedef enum { + KEY_NONE = 0, + + /* Function keys */ + KEY_ESC, + + KEY_F1, + KEY_F2, + KEY_F3, + KEY_F4, + KEY_F5, + KEY_F6, + KEY_F7, + KEY_F8, + KEY_F9, + KEY_F10, + KEY_F11, + KEY_F12, + + /* Number row */ + KEY_GRAVE, /* ` ~ */ + KEY_1, + KEY_2, + KEY_3, + KEY_4, + KEY_5, + KEY_6, + KEY_7, + KEY_8, + KEY_9, + KEY_0, + KEY_MINUS, /* - _ */ + KEY_EQUAL, /* = + */ + KEY_BACKSPACE, + + /* First row */ + KEY_TAB, + KEY_Q, + KEY_W, + KEY_E, + KEY_R, + KEY_T, + KEY_Y, + KEY_U, + KEY_I, + KEY_O, + KEY_P, + KEY_LEFT_BRACKET, /* [ { */ + KEY_RIGHT_BRACKET, /* ] } */ + KEY_BACKSLASH, /* \ | */ + + /* Second row */ + KEY_CAPS_LOCK, + KEY_A, + KEY_S, + KEY_D, + KEY_F, + KEY_G, + KEY_H, + KEY_J, + KEY_K, + KEY_L, + KEY_SEMICOLON, /* ; : */ + KEY_APOSTROPHE, /* ' " */ + KEY_ENTER, + + /* Third row */ + KEY_LEFT_SHIFT, + KEY_Z, + KEY_X, + KEY_C, + KEY_V, + KEY_B, + KEY_N, + KEY_M, + KEY_COMMA, /* , < */ + KEY_DOT, /* . > */ + KEY_SLASH, /* / ? */ + KEY_RIGHT_SHIFT, + + /* Bottom row */ + KEY_LEFT_CTRL, + KEY_LEFT_GUI, + KEY_LEFT_ALT, + KEY_SPACE, + KEY_RIGHT_ALT, + KEY_RIGHT_GUI, + KEY_MENU, + KEY_RIGHT_CTRL, + + /* Navigation */ + KEY_INSERT, + KEY_DELETE, + KEY_HOME, + KEY_END, + KEY_PAGE_UP, + KEY_PAGE_DOWN, + + /* Arrow keys */ + KEY_UP, + KEY_DOWN, + KEY_LEFT, + KEY_RIGHT, + + /* Numeric keypad */ + KEY_NUM_LOCK, + + KEY_KP_DIVIDE, + KEY_KP_MULTIPLY, + KEY_KP_MINUS, + KEY_KP_PLUS, + KEY_KP_ENTER, + + KEY_KP_0, + KEY_KP_1, + KEY_KP_2, + KEY_KP_3, + KEY_KP_4, + KEY_KP_5, + KEY_KP_6, + KEY_KP_7, + KEY_KP_8, + KEY_KP_9, + + KEY_KP_DOT, + + /* Lock keys */ + KEY_SCROLL_LOCK, + + /* Special / system keys */ + KEY_PRINT_SCREEN, + KEY_PAUSE, + + /* Additional common keys */ + KEY_POWER, + KEY_SLEEP, + KEY_WAKE, + + KEY_VOLUME_UP, + KEY_VOLUME_DOWN, + KEY_MUTE, + + KEY_MEDIA_PLAY_PAUSE, + KEY_MEDIA_STOP, + KEY_MEDIA_PREVIOUS, + KEY_MEDIA_NEXT, + + KEY_CALCULATOR, + + KEY_COUNT +} keycode_t; + +typedef struct { + bool left_shift; + bool right_shift; + + bool left_ctrl; + bool right_ctrl; + + bool left_alt; + bool right_alt; + + bool caps_lock; + bool num_lock; + bool scroll_lock; +} keyboard_state_t; + +typedef enum { + SCAN_STATE_NORMAL, + SCAN_STATE_BREAK, + SCAN_STATE_EXTENDED, + SCAN_STATE_EXTENDED_BREAK +} scancode_state_t; + +typedef enum { KEY_PRESSED, KEY_RELEASED } key_action_t; + +typedef struct { + keycode_t key; + key_action_t action; +} key_event_t; + +typedef struct { + keycode_t normal[256]; + keycode_t extended[256]; +} keyboard_scancode_table_t; + +static const keyboard_scancode_table_t scancode_set2 = {.normal = + { + + [0x76] = KEY_ESC, + + [0x05] = KEY_F1, + [0x06] = KEY_F2, + [0x04] = KEY_F3, + [0x0C] = KEY_F4, + [0x03] = KEY_F5, + [0x0B] = KEY_F6, + [0x83] = KEY_F7, + [0x0A] = KEY_F8, + [0x01] = KEY_F9, + [0x09] = KEY_F10, + [0x78] = KEY_F11, + [0x07] = KEY_F12, + + [0x0E] = KEY_GRAVE, + + [0x16] = KEY_1, + [0x1E] = KEY_2, + [0x26] = KEY_3, + [0x25] = KEY_4, + [0x2E] = KEY_5, + [0x36] = KEY_6, + [0x3D] = KEY_7, + [0x3E] = KEY_8, + [0x46] = KEY_9, + [0x45] = KEY_0, + + [0x4E] = KEY_MINUS, + [0x55] = KEY_EQUAL, + + [0x66] = KEY_BACKSPACE, + + [0x0D] = KEY_TAB, + + [0x15] = KEY_Q, + [0x1D] = KEY_W, + [0x24] = KEY_E, + [0x2D] = KEY_R, + [0x2C] = KEY_T, + [0x35] = KEY_Y, + [0x3C] = KEY_U, + [0x43] = KEY_I, + [0x44] = KEY_O, + [0x4D] = KEY_P, + + [0x54] = KEY_LEFT_BRACKET, + [0x5B] = KEY_RIGHT_BRACKET, + [0x5D] = KEY_BACKSLASH, + + [0x58] = KEY_CAPS_LOCK, + + [0x1C] = KEY_A, + [0x1B] = KEY_S, + [0x23] = KEY_D, + [0x2B] = KEY_F, + [0x34] = KEY_G, + [0x33] = KEY_H, + [0x3B] = KEY_J, + [0x42] = KEY_K, + [0x4B] = KEY_L, + + [0x4C] = KEY_SEMICOLON, + [0x52] = KEY_APOSTROPHE, + + [0x5A] = KEY_ENTER, + + [0x12] = KEY_LEFT_SHIFT, + + [0x1A] = KEY_Z, + [0x22] = KEY_X, + [0x21] = KEY_C, + [0x2A] = KEY_V, + [0x32] = KEY_B, + [0x31] = KEY_N, + [0x3A] = KEY_M, + + [0x41] = KEY_COMMA, + [0x49] = KEY_DOT, + [0x4A] = KEY_SLASH, + + [0x59] = KEY_RIGHT_SHIFT, + + [0x14] = KEY_LEFT_CTRL, + [0x11] = KEY_LEFT_ALT, + + [0x29] = KEY_SPACE, + + [0x77] = KEY_NUM_LOCK, + + [0x7C] = KEY_KP_MULTIPLY, + [0x7B] = KEY_KP_MINUS, + [0x79] = KEY_KP_PLUS, + + [0x70] = KEY_KP_0, + [0x69] = KEY_KP_1, + [0x72] = KEY_KP_2, + [0x7A] = KEY_KP_3, + [0x6B] = KEY_KP_4, + [0x73] = KEY_KP_5, + [0x74] = KEY_KP_6, + [0x6C] = KEY_KP_7, + [0x75] = KEY_KP_8, + [0x7D] = KEY_KP_9, + [0x71] = KEY_KP_DOT, + + [0x7E] = KEY_SCROLL_LOCK, + }, + + .extended = { + + /* Modifiers */ + [0x14] = KEY_RIGHT_CTRL, + [0x11] = KEY_RIGHT_ALT, + + /* Navigation */ + [0x70] = KEY_INSERT, + [0x71] = KEY_DELETE, + [0x6C] = KEY_HOME, + [0x69] = KEY_END, + [0x7D] = KEY_PAGE_UP, + [0x7A] = KEY_PAGE_DOWN, + + /* Arrows */ + [0x75] = KEY_UP, + [0x72] = KEY_DOWN, + [0x6B] = KEY_LEFT, + [0x74] = KEY_RIGHT, + + /* Keypad */ + [0x4A] = KEY_KP_DIVIDE, + [0x5A] = KEY_KP_ENTER, + + /* GUI keys */ + [0x1F] = KEY_LEFT_GUI, + [0x27] = KEY_RIGHT_GUI, + [0x2F] = KEY_MENU, + + /* Print Screen */ + [0x12] = KEY_PRINT_SCREEN, + }}; + +#endif \ No newline at end of file diff --git a/includes/driver/keyboard/keyboard_layout.h b/includes/driver/keyboard/keyboard_layout.h new file mode 100644 index 0000000..47239bb --- /dev/null +++ b/includes/driver/keyboard/keyboard_layout.h @@ -0,0 +1,25 @@ +#ifndef KEYBOARD_LAYOUT_H +#define KEYBOARD_LAYOUT_H + +#include "keyboard_keys.h" +#include "types.h" + +#define KEY_COUNT 256 + +typedef struct { + char normal; + char shift; +} keyboard_layout_entry_t; + +typedef struct { + const char *name; + + keyboard_layout_entry_t keys[KEY_COUNT]; +} keyboard_layout_t; + +extern const keyboard_layout_t keyboard_layout_us; + +char keyboard_layout_translate(const keyboard_layout_t *layout, keycode_t key, + const keyboard_state_t *state); + +#endif \ No newline at end of file diff --git a/includes/driver/ps2.h b/includes/driver/ps2.h index e69de29..d690776 100644 --- a/includes/driver/ps2.h +++ b/includes/driver/ps2.h @@ -0,0 +1,92 @@ +#ifndef PS2_H +#define PS2_H + +#include "types.h" + +#define PS2_DATA_PORT 0x60 +#define PS2_STATUS_PORT 0x64 +#define PS2_COMMAND_PORT PS2_STATUS_PORT + +// control commands +#define PS2_CC_READ_CONFIG 0x20 // read configuration byte +#define PS2_CC_WRITE_CONFIG 0x60 // write configuration byte +#define PS2_CC_SELF_TEST 0xAA // controller self-test +#define PS2_CC_TEST_PORT1 0xAB // test port 1 +#define PS2_CC_TEST_PORT2 0xA9 // test port 2 +#define PS2_CC_DISABLE_PORT1 0xAD // disable port 1 +#define PS2_CC_ENABLE_PORT1 0xAE // enable port 1 +#define PS2_CC_DISABLE_PORT2 0xA7 // disable port 2 +#define PS2_CC_ENABLE_PORT2 0xA8 // enable port 2 +#define PS2_CC_READ_OUTPUT_PORT 0xD0 // read output port +#define PS2_CC_WRITE_OUTPUT_PORT 0xD1 // write output port +#define PS2_CC_WRITE_TO_PORT2 0xD4 // next byte goes to port 2 + +// device commands +#define PS2_DC_RESET 0xFF // reset device +#define PS2_DC_DISABLE_SCANNING 0xF5 // disable scanning +#define PS2_DC_IDENTIFY_DEVICE 0xF2 // identify device +#define PS2_DC_ENABLE_SCANNING 0xF4 // enable scanning +#define PS2_DC_SELECT_SET 0xF0 // select scancode set +#define PS2_DC_SET_LED_STATE 0xED // set LED state + +typedef union ps2_config_t { + uint8_t raw; + + struct { + uint8_t first_port_irq : 1; + uint8_t port2_interrupt : 1; + uint8_t system_flag : 1; + uint8_t zero1 : 1; + uint8_t port1_clock : 1; + uint8_t port2_clock : 1; + uint8_t translation : 1; + uint8_t zero2 : 1; + }; +} ps2_config_t; + +typedef union { + uint8_t raw; + + struct { + uint8_t output_buffer_full : 1; // Bit 0 + uint8_t input_buffer_full : 1; // Bit 1 + uint8_t system_flag : 1; // Bit 2 + uint8_t command_data : 1; // Bit 3 + uint8_t unknown : 1; // Bit 4 + uint8_t timeout_error : 1; // Bit 5 + uint8_t parity_error : 1; // Bit 6 + uint8_t zero : 1; // Bit 7 + }; +} ps2_status_t; + +ps2_status_t ps2_status(void); +bool ps2_output_buffer_full(void); +bool ps2_input_buffer_full(void); +bool ps2_system_flag(void); +bool ps2_command_data(void); +bool ps2_timeout_error(void); +bool ps2_parity_error(void); +bool ps2_wait_input_clear(void); +bool ps2_wait_output_full(void); +void ps2_flush_output(void); + +void ps2_command(uint8_t cmd); + +uint8_t ps2_read(void); +void ps2_write(uint8_t data); +uint8_t ps2_read_config(void); +ps2_config_t ps2_get_config(void); +void ps2_write_config(uint8_t config); +void ps2_set_config(ps2_config_t config); +bool ps2_test_controller(void); +bool ps2_test_port1(void); +bool ps2_test_port2(void); +void ps2_disable_port1(void); +void ps2_enable_port1(void); +void ps2_disable_port2(void); +void ps2_enable_port2(void); +void ps2_init(void); + +uint8_t keyboard_get_scan_code_set(void); + +#endif \ No newline at end of file diff --git a/includes/driver/vga.h b/includes/driver/vga.h index 7ac5eaf..7b90c93 100644 --- a/includes/driver/vga.h +++ b/includes/driver/vga.h @@ -1,13 +1,14 @@ #ifndef VGA_H #define VGA_H -#include +#include "types.h" #define VGA_ADDRESS 0xB8000 -#define VGA_WIDTH 80 -#define VGA_HEIGHT 25 -#define VGA_RES (VGA_HEIGHT * VGA_WIDTH) +#define VGA_WIDTH 80 +#define VGA_HEIGHT 25 +#define VGA_RES (VGA_HEIGHT * VGA_WIDTH) +#define VGA_TAB_WIDTH 4 #define VGA_INDEX_PORT 0x3D4 #define VGA_DATA_PORT 0x3D5 @@ -27,6 +28,15 @@ #define BROWN 0x06 // YELLOW #define LIGHT_GRAY 0x07 // WHITE +#define DARK_GRAY BLACk | LIGHT_FLAG +#define LIGHT_BLUE BLUE | LIGHT_FLAG +#define LIGHT_GREEN GREEN | LIGHT_FLAG +#define LIGHT_CYAN CYAN | LIGHT_FLAG +#define LIGHT_RED RED | LIGHT_FLAG +#define LIGHT_MAGENTA MAGENTA | LIGHT_FLAG +#define YELLOW BROWN | LIGHT_FLAG +#define WHITE LIGHT_GRAY | LIGHT_FLAG + #define LIGHT_FLAG 0x08 #define DEFUALT_F LIGHT_GRAY @@ -45,6 +55,8 @@ void vga_init(void); void vga_clear(void); +void vga_scroll_up(void); + void vga_print_char(char c); void vga_print(const char *str); diff --git a/includes/interrupt/idt.h b/includes/interrupt/idt.h index 95909f4..4eb04e0 100644 --- a/includes/interrupt/idt.h +++ b/includes/interrupt/idt.h @@ -1,7 +1,7 @@ #ifndef IDT_H #define IDT_H -#include +#include "types.h" #define IDT_ENTRIES 256 diff --git a/includes/interrupt/isr.h b/includes/interrupt/isr.h index a719e6e..8946e9f 100644 --- a/includes/interrupt/isr.h +++ b/includes/interrupt/isr.h @@ -1,7 +1,7 @@ #ifndef ISR_H #define ISR_H -#include +#include "types.h" char *EXCEPTIONS[] = { "Division Error", // 00 diff --git a/includes/interrupt/pic.h b/includes/interrupt/pic.h index 54704b7..e569e00 100644 --- a/includes/interrupt/pic.h +++ b/includes/interrupt/pic.h @@ -1,7 +1,7 @@ #ifndef PIC_H #define PIC_H -#include +#include "types.h" #define PIC1 0x20 /* IO base address for master PIC */ #define PIC2 0xA0 /* IO base address for slave PIC */ diff --git a/includes/interrupt/pit.h b/includes/interrupt/pit.h index 80c244e..db9ac75 100644 --- a/includes/interrupt/pit.h +++ b/includes/interrupt/pit.h @@ -7,7 +7,7 @@ #define PIT_COMMAND 0x43 #define PIT_BASE_FREQ 1193182 -#include +#include "types.h" /* Channels */ #define PIT_CHANNEL_0 0 diff --git a/includes/lib/stdio.h b/includes/lib/stdio.h new file mode 100644 index 0000000..d3097bf --- /dev/null +++ b/includes/lib/stdio.h @@ -0,0 +1,19 @@ +#ifndef STDIO_H +#define STDIO_H + +#include "types.h" +#include + +void print(const char *str); +void println(const char *str); +void print_char(char c); +void print_hex(uint32_t value); +void print_at_end(const char *str, uint8_t color); + +void printf(const char *format, ...); +void snprintf(char *buffer, size_t buffer_size, const char *format, ...); + +char *vformatter(const char *format, va_list args); +char *formatter(const char *format, ...); + +#endif \ No newline at end of file diff --git a/includes/lib/string.h b/includes/lib/string.h new file mode 100644 index 0000000..004e7dd --- /dev/null +++ b/includes/lib/string.h @@ -0,0 +1,21 @@ +#ifndef STRING_H +#define STRING_H + +#include "types.h" + +int strlen(char *str); + +void strcpy(char *dest, char *src); +void strcat(char *dest, const char *src); + +int strcmp(const char *str1, const char *str2); + +char *int2str(int num); // convert integer to string +char *uint2str(uint32_t number, uint8_t base, bool uppercase); + +char *strchr(const char *str, int c); // find first occurrence of character c in string str + +char *strstr(const char *str, + const char *substr); // find first occurrence of substring substr in string str + +#endif diff --git a/includes/lib/vga_lib.h b/includes/lib/vga_lib.h index 492d4a5..ab13197 100644 --- a/includes/lib/vga_lib.h +++ b/includes/lib/vga_lib.h @@ -1,7 +1,7 @@ #ifndef VGA_LIB_H #define VGA_LIB_H -#include +#include "types.h" /* * Logging diff --git a/includes/timer.h b/includes/timer.h index c1979dc..2ac048d 100644 --- a/includes/timer.h +++ b/includes/timer.h @@ -1,7 +1,7 @@ #ifndef TIMER_H #define TIMER_H -#include +#include "types.h" void timer_init(uint32_t frequency); diff --git a/includes/utils/types.h b/includes/utils/types.h new file mode 100644 index 0000000..6642d2f --- /dev/null +++ b/includes/utils/types.h @@ -0,0 +1,13 @@ +#ifndef TYPES_H +#define TYPES_H + +#include +#include + +#define bool uint8_t +#define true 1 +#define false 0 +#define True 1 +#define False 0 + +#endif diff --git a/includes/utils.h b/includes/utils/utils.h similarity index 91% rename from includes/utils.h rename to includes/utils/utils.h index eeb906f..0753d4d 100644 --- a/includes/utils.h +++ b/includes/utils/utils.h @@ -1,7 +1,7 @@ #ifndef UTILS_H #define UTILS_H -#include +#include "types.h" void outb(uint16_t port, uint8_t value); uint8_t inb(uint16_t port); diff --git a/src/driver/keyboard/event_queue.c b/src/driver/keyboard/event_queue.c new file mode 100644 index 0000000..5d87d42 --- /dev/null +++ b/src/driver/keyboard/event_queue.c @@ -0,0 +1,54 @@ +#include "event_queue.h" +#include "stdio.h" + +// Input event queue + +input_event_t input_queue[KEYBOARD_EVENT_QUEUE_SIZE]; +uint32_t input_queue_head = 0; +uint32_t input_queue_tail = 0; + +void input_queue_push(input_event_t event) { + uint32_t next = (input_queue_head + 1) % KEYBOARD_EVENT_QUEUE_SIZE; + + if (next == input_queue_tail) { + return; /* queue full */ + } + + input_queue[input_queue_head] = event; + input_queue_head = next; +} + +void input_queue_pop(input_event_t *event) { + if (input_queue_head == input_queue_tail) { + return; /* queue empty */ + } + + *event = input_queue[input_queue_tail]; + + input_queue_tail = (input_queue_tail + 1) % KEYBOARD_EVENT_QUEUE_SIZE; +} + +void input_queue_print() { + printf("\033[32mInput Queue: \033[0m head=%d, tail=%d\n", input_queue_head, input_queue_tail); + for (uint32_t i = 0; i < input_queue_head - input_queue_tail; i++) { + input_event_t event = input_queue[i]; + printf("Event[%d]: type=%d, character=%c\n", i, event.type, event.character); + } +} + +void input_queue_print_last() { + if (input_queue_head == input_queue_tail) { + printf("\033[31mInput Queue: \033[0m Empty\n"); + return; + } + + uint32_t last = (input_queue_head - 1 + KEYBOARD_EVENT_QUEUE_SIZE) % KEYBOARD_EVENT_QUEUE_SIZE; + input_event_t event = input_queue[last]; + printf("\033[32mInput Queue:\033[0m Last event[%d] : type=%d, character=%c\n", last, event.type, + event.character); +} + +void input_queue_clear() { + input_queue_head = 0; + input_queue_tail = 0; +} diff --git a/src/driver/keyboard/handler.c b/src/driver/keyboard/handler.c new file mode 100644 index 0000000..baaf715 --- /dev/null +++ b/src/driver/keyboard/handler.c @@ -0,0 +1,234 @@ +#include "handler.h" +#include "keyboard.h" +#include "keyboard/event_queue.h" +#include "ps2.h" +#include "utils.h" + +scancode_state_t scan_state = SCAN_STATE_NORMAL; + +keyboard_state_t keyboard_state = {0}; + +/* -------------------------------------------------------------------------- */ +/* IRQ handler */ +/* -------------------------------------------------------------------------- */ + +void keyboard_irq_handler(void) { + if (!ps2_wait_output_full()) { + return; + } + + uint8_t data = ps2_read(); + + keyboard_process_scancode(data); +} + +/* -------------------------------------------------------------------------- */ +/* Scan-code processing */ +/* -------------------------------------------------------------------------- */ + +void keyboard_process_scancode(uint8_t data) { + keycode_t key; + + switch (scan_state) { + + case SCAN_STATE_NORMAL: + + if (data == 0xF0) { + scan_state = SCAN_STATE_BREAK; + return; + } + + if (data == 0xE0) { + scan_state = SCAN_STATE_EXTENDED; + return; + } + + key = scancode_set2.normal[data]; + + if (key == KEY_NONE) { + return; + } + + keyboard_handle_key(key, KEY_PRESSED); + return; + + case SCAN_STATE_BREAK: + + key = scancode_set2.normal[data]; + + scan_state = SCAN_STATE_NORMAL; + + if (key == KEY_NONE) { + return; + } + + keyboard_handle_key(key, KEY_RELEASED); + return; + + case SCAN_STATE_EXTENDED: + + if (data == 0xF0) { + scan_state = SCAN_STATE_EXTENDED_BREAK; + return; + } + + key = scancode_set2.extended[data]; + + scan_state = SCAN_STATE_NORMAL; + + if (key == KEY_NONE) { + return; + } + + keyboard_handle_key(key, KEY_PRESSED); + return; + + case SCAN_STATE_EXTENDED_BREAK: + + key = scancode_set2.extended[data]; + + scan_state = SCAN_STATE_NORMAL; + + if (key == KEY_NONE) { + return; + } + + keyboard_handle_key(key, KEY_RELEASED); + return; + } +} + +/* -------------------------------------------------------------------------- */ +/* Key processing */ +/* -------------------------------------------------------------------------- */ + +void keyboard_handle_key(keycode_t key, key_action_t action) { + keyboard_update_state(key, action); + + /* + * Key release events are used only to update the keyboard state. + */ + if (action != KEY_PRESSED) { + return; + } + + input_event_t input = {0}; + + /* ---------------------------------------------------------------------- */ + /* Character input */ + /* ---------------------------------------------------------------------- */ + + char character = keyboard_translate(key, &keyboard_state); + + if (character != '\0') { + + input.type = INPUT_CHAR; + input.character = character; + + input_queue_push(input); + + return; + } + + /* ---------------------------------------------------------------------- */ + /* Special keys */ + /* ---------------------------------------------------------------------- */ + + switch (key) { + + case KEY_ENTER: + input.type = INPUT_ENTER; + break; + + case KEY_BACKSPACE: + input.type = INPUT_BACKSPACE; + break; + + case KEY_TAB: + input.type = INPUT_TAB; + break; + + case KEY_UP: + input.type = INPUT_UP; + break; + + case KEY_DOWN: + input.type = INPUT_DOWN; + break; + + case KEY_LEFT: + input.type = INPUT_LEFT; + break; + + case KEY_RIGHT: + input.type = INPUT_RIGHT; + break; + + default: + return; + } + + input_queue_push(input); +} + +/* -------------------------------------------------------------------------- */ +/* Keyboard state */ +/* -------------------------------------------------------------------------- */ + +void keyboard_update_state(keycode_t key, key_action_t action) { + bool pressed = action == KEY_PRESSED; + + switch (key) { + + case KEY_LEFT_SHIFT: + keyboard_state.left_shift = pressed; + break; + + case KEY_RIGHT_SHIFT: + keyboard_state.right_shift = pressed; + break; + + case KEY_LEFT_CTRL: + keyboard_state.left_ctrl = pressed; + break; + + case KEY_RIGHT_CTRL: + keyboard_state.right_ctrl = pressed; + break; + + case KEY_LEFT_ALT: + keyboard_state.left_alt = pressed; + break; + + case KEY_RIGHT_ALT: + keyboard_state.right_alt = pressed; + break; + + case KEY_CAPS_LOCK: + + if (pressed) { + keyboard_state.caps_lock = !keyboard_state.caps_lock; + } + + break; + + case KEY_NUM_LOCK: + + if (pressed) { + keyboard_state.num_lock = !keyboard_state.num_lock; + } + + break; + + case KEY_SCROLL_LOCK: + + if (pressed) { + keyboard_state.scroll_lock = !keyboard_state.scroll_lock; + } + + break; + + default: + break; + } +} \ No newline at end of file diff --git a/src/driver/keyboard/keyboard.c b/src/driver/keyboard/keyboard.c new file mode 100644 index 0000000..f325aa6 --- /dev/null +++ b/src/driver/keyboard/keyboard.c @@ -0,0 +1,91 @@ +#include "keyboard.h" +#include "ps2.h" +#include "utils.h" + +#include "keyboard_layout.h" + +#include "stdio.h" + +static const keyboard_layout_t *active_layout; + +void init_keyboard(void) { + reset_keyboard(); + set_scaning(false); + select_scancode_set(0x02); + set_scaning(true); + + ps2_flush_output(); + + keyboard_set_layout(&keyboard_layout_us); +} + +void keyboard_set_layout(const keyboard_layout_t *layout) { active_layout = layout; } + +char keyboard_translate(keycode_t key, const keyboard_state_t *state) { + return keyboard_layout_translate(active_layout, key, state); +} + +void reset_keyboard(void) { + ps2_wait_input_clear(); + ps2_write(PS2_DC_RESET); + + ps2_wait_output_full(); + + if (ps2_read() != K_ACK) { + printf("\033[31mERROR:\033[0m Keyboard did not acknowledge reset.\n"); + return; + } + + ps2_wait_output_full(); + + if (ps2_read() != k_BAT) { + printf("\033[31mERROR:\033[0m Keyboard BAT failed.\n"); + return; + } +} + +void set_scaning(bool state) { + ps2_flush_output(); + ps2_wait_input_clear(); + + if (state) { + ps2_write(PS2_DC_ENABLE_SCANNING); + } else { + ps2_write(PS2_DC_DISABLE_SCANNING); + } + + ps2_wait_output_full(); + + if (ps2_read() != K_ACK) { + printf("\033[31mERROR:\033[0m Keyboard did not acknowledge scanning command.\n"); + return; + } +} + +void select_scancode_set(uint8_t set) { + ps2_flush_output(); + ps2_wait_input_clear(); + + if (set <= 3) { + ps2_write(PS2_DC_SELECT_SET); + } + + ps2_wait_output_full(); + + if (ps2_read() != K_ACK) { + printf("\033[31mERROR:\033[0m keyboard.h:53 select_scancode_set .\n"); + return; + } + + ps2_flush_output(); + ps2_wait_input_clear(); + + ps2_write(set); + + ps2_wait_output_full(); + + if (ps2_read() != K_ACK) { + printf("\033[31mERROR:\033[0m keyboard.h:65 select_scancode_set .\n"); + return; + } +} diff --git a/src/driver/keyboard/layout/us.c b/src/driver/keyboard/layout/us.c new file mode 100644 index 0000000..b334008 --- /dev/null +++ b/src/driver/keyboard/layout/us.c @@ -0,0 +1,123 @@ +#include "keyboard_layout.h" + +const keyboard_layout_t keyboard_layout_us = { + .name = "US QWERTY", + + .keys = { + [KEY_A] = {.normal = 'a', .shift = 'A'}, + + [KEY_B] = {.normal = 'b', .shift = 'B'}, + + [KEY_C] = {.normal = 'c', .shift = 'C'}, + + [KEY_D] = {.normal = 'd', .shift = 'D'}, + + [KEY_E] = {.normal = 'e', .shift = 'E'}, + + [KEY_F] = {.normal = 'f', .shift = 'F'}, + + [KEY_G] = {.normal = 'g', .shift = 'G'}, + + [KEY_H] = {.normal = 'h', .shift = 'H'}, + + [KEY_I] = {.normal = 'i', .shift = 'I'}, + + [KEY_J] = {.normal = 'j', .shift = 'J'}, + + [KEY_K] = {.normal = 'k', .shift = 'K'}, + + [KEY_L] = {.normal = 'l', .shift = 'L'}, + + [KEY_M] = {.normal = 'm', .shift = 'M'}, + + [KEY_N] = {.normal = 'n', .shift = 'N'}, + + [KEY_O] = {.normal = 'o', .shift = 'O'}, + + [KEY_P] = {.normal = 'p', .shift = 'P'}, + + [KEY_Q] = {.normal = 'q', .shift = 'Q'}, + + [KEY_R] = {.normal = 'r', .shift = 'R'}, + + [KEY_S] = {.normal = 's', .shift = 'S'}, + + [KEY_T] = {.normal = 't', .shift = 'T'}, + + [KEY_U] = {.normal = 'u', .shift = 'U'}, + + [KEY_V] = {.normal = 'v', .shift = 'V'}, + + [KEY_W] = {.normal = 'w', .shift = 'W'}, + + [KEY_X] = {.normal = 'x', .shift = 'X'}, + + [KEY_Y] = {.normal = 'y', .shift = 'Y'}, + + [KEY_Z] = {.normal = 'z', .shift = 'Z'}, + + [KEY_1] = {.normal = '1', .shift = '!'}, + + [KEY_2] = {.normal = '2', .shift = '@'}, + + [KEY_3] = {.normal = '3', .shift = '#'}, + + [KEY_4] = {.normal = '4', .shift = '$'}, + + [KEY_5] = {.normal = '5', .shift = '%'}, + + [KEY_6] = {.normal = '6', .shift = '^'}, + + [KEY_7] = {.normal = '7', .shift = '&'}, + + [KEY_8] = {.normal = '8', .shift = '*'}, + + [KEY_9] = {.normal = '9', .shift = '('}, + + [KEY_0] = {.normal = '0', .shift = ')'}, + + [KEY_SPACE] = {.normal = ' ', .shift = ' '}, + + [KEY_MINUS] = {.normal = '-', .shift = '_'}, + + [KEY_EQUAL] = {.normal = '=', .shift = '+'}, + + [KEY_COMMA] = {.normal = ',', .shift = '<'}, + + [KEY_DOT] = {.normal = '.', .shift = '>'}, + + [KEY_SLASH] = {.normal = '/', .shift = '?'}, + + [KEY_SEMICOLON] = {.normal = ';', .shift = ':'}, + + [KEY_APOSTROPHE] = {.normal = '\'', .shift = '"'}, + + [KEY_GRAVE] = {.normal = '`', .shift = '~'}, + + [KEY_LEFT_BRACKET] = {.normal = '[', .shift = '{'}, + + [KEY_RIGHT_BRACKET] = {.normal = ']', .shift = '}'}, + + [KEY_BACKSLASH] = {.normal = '\\', .shift = '|'}, + }}; + +char keyboard_layout_translate(const keyboard_layout_t *layout, keycode_t key, + const keyboard_state_t *state) { + if (key >= KEY_COUNT) { + return '\0'; + } + + keyboard_layout_entry_t entry = layout->keys[key]; + + if (entry.normal == '\0') { + return '\0'; + } + + bool shifted = state->left_shift || state->right_shift; + + if (shifted) { + return entry.shift; + } + + return entry.normal; +} \ No newline at end of file diff --git a/src/driver/pit.c b/src/driver/pit.c deleted file mode 100644 index e69de29..0000000 diff --git a/src/driver/ps2.c b/src/driver/ps2.c index e69de29..561de21 100644 --- a/src/driver/ps2.c +++ b/src/driver/ps2.c @@ -0,0 +1,165 @@ +#include "ps2.h" +#include "utils.h" + +// --------------------------------------------------------------------- +ps2_status_t ps2_status(void) { + ps2_status_t status; + status.raw = inb(PS2_STATUS_PORT); + return status; +} + +bool ps2_output_buffer_full(void) { return ps2_status().output_buffer_full; } + +bool ps2_input_buffer_full(void) { return ps2_status().input_buffer_full; } + +bool ps2_system_flag(void) { return ps2_status().system_flag; } + +bool ps2_command_data(void) { return ps2_status().command_data; } + +bool ps2_timeout_error(void) { return ps2_status().timeout_error; } + +bool ps2_parity_error(void) { return ps2_status().parity_error; } + +bool ps2_zero(void) { return ps2_status().zero; } + +bool ps2_wait_input_clear(void) { + while (ps2_input_buffer_full()) + ; + return true; +} + +bool ps2_wait_output_full(void) { + while (!ps2_output_buffer_full()) + ; + return true; +} + +void ps2_flush_output(void) { + while (ps2_output_buffer_full()) { + (void)ps2_read(); + } +} +// --------------------------------------------------------------------- + +void ps2_command(uint8_t cmd) { outb(PS2_COMMAND_PORT, cmd); } + +uint8_t ps2_read(void) { return inb(PS2_DATA_PORT); } + +void ps2_write(uint8_t data) { + ps2_wait_input_clear(); + outb(PS2_DATA_PORT, data); +} + +uint8_t ps2_read_config(void) { + ps2_wait_input_clear(); + ps2_command(PS2_CC_READ_CONFIG); + ps2_wait_output_full(); + return ps2_read(); +} + +ps2_config_t ps2_get_config(void) { + ps2_config_t config; + config.raw = ps2_read_config(); + return config; +} + +void ps2_write_config(uint8_t config) { + ps2_wait_input_clear(); + ps2_command(PS2_CC_WRITE_CONFIG); + ps2_wait_input_clear(); + ps2_write(config); +} + +void ps2_set_config(ps2_config_t config) { ps2_write_config(config.raw); } + +bool ps2_test_controller(void) { + ps2_flush_output(); + ps2_wait_input_clear(); + ps2_command(PS2_CC_SELF_TEST); + ps2_wait_output_full(); + return ps2_read() == 0x55; +} + +bool ps2_test_port1(void) { + ps2_flush_output(); + ps2_wait_input_clear(); + ps2_command(PS2_CC_TEST_PORT1); + ps2_wait_output_full(); + return ps2_read() == 0x00; +} + +bool ps2_test_port2(void) { + ps2_flush_output(); + ps2_wait_input_clear(); + ps2_command(PS2_CC_TEST_PORT2); + ps2_wait_output_full(); + return ps2_read() == 0x00; +} + +void ps2_disable_port1(void) { + ps2_wait_input_clear(); + ps2_command(PS2_CC_DISABLE_PORT1); +} + +void ps2_enable_port1(void) { + ps2_wait_input_clear(); + ps2_command(PS2_CC_ENABLE_PORT1); +} + +void ps2_disable_port2(void) { + ps2_wait_input_clear(); + ps2_command(PS2_CC_DISABLE_PORT2); +} + +void ps2_enable_port2(void) { + ps2_wait_input_clear(); + ps2_command(PS2_CC_ENABLE_PORT2); +} + +void ps2_init(void) { + ps2_flush_output(); + ps2_disable_port1(); + ps2_disable_port2(); + + if (!ps2_test_controller()) { + return; + } + + uint8_t config = ps2_read_config(); + + config |= (1u << 0); // IRQ1 enabled + config &= ~(1u << 1); // IRQ12 disabled + config &= ~(1u << 6); // translation disabled + + ps2_write_config(config); + + if (ps2_test_port1()) { + ps2_enable_port1(); + } + + if (ps2_test_port2()) { + ps2_enable_port2(); + } +} + +uint8_t keyboard_get_scan_code_set(void) { + uint8_t response; + + ps2_write(0xF0); // Command to get the current scan-code set. + + response = ps2_read(); + + if (response != 0xFA) { + return 0; + } + + ps2_write(0x00); // Request to get the current scan-code set. + + response = ps2_read(); + + if (response != 0xFA) { + return 0; + } + + return ps2_read(); +} \ No newline at end of file diff --git a/src/driver/vga.c b/src/driver/vga.c index d489ce7..0fe1104 100644 --- a/src/driver/vga.c +++ b/src/driver/vga.c @@ -21,15 +21,91 @@ void vga_init(void) { vga_cursor_enable(); } +// helper functions + +void vga_cursor_carriage_return(void) { + uint16_t column = cursor_position % VGA_WIDTH; + + cursor_position -= column; + + vga_set_cursor_position(cursor_position); +} + +void vga_cursor_newline(void) { + uint16_t row = cursor_position / VGA_WIDTH; + + row++; + + if (row >= VGA_HEIGHT) { + vga_scroll_up(); + row = VGA_HEIGHT - 1; + } + + cursor_position = row * VGA_WIDTH; + + vga_set_cursor_position(cursor_position); +} + +void vga_cursor_tab(void) { + uint16_t column = cursor_position % VGA_WIDTH; + + uint16_t spaces = VGA_TAB_WIDTH - (column % VGA_TAB_WIDTH); + + for (uint16_t i = 0; i < spaces; i++) { + + if (cursor_position >= VGA_WIDTH * VGA_HEIGHT) { + vga_scroll_up(); + + cursor_position = (VGA_HEIGHT - 1) * VGA_WIDTH; + } + + vga_buf[cursor_position] = ((uint16_t)current_color << 8) | ' '; + + cursor_position++; + } + + vga_set_cursor_position(cursor_position); +} + +void vga_cursor_backspace(void) { + if (cursor_position == 0) + return; + + cursor_position--; + + vga_buf[cursor_position] = ((uint16_t)current_color << 8) | ' '; + + vga_set_cursor_position(cursor_position); +} + // Print void vga_print_char(char c) { + switch (c) { - vga_buf[cursor_position] = (current_color << 8 | c); + case '\n': + vga_cursor_newline(); + break; - vga_set_cursor_position((cursor_position + 1)); -} + case '\r': + vga_cursor_carriage_return(); + break; + + case '\t': + vga_cursor_tab(); + break; + + case '\b': + vga_cursor_backspace(); + break; + + default: + vga_buf[cursor_position] = ((uint16_t)current_color << 8) | (uint8_t)c; + vga_set_cursor_position(cursor_position + 1); + break; + } +} void vga_print(const char *str) { if (str == 0) { return; @@ -38,7 +114,11 @@ void vga_print(const char *str) { for (uint32_t i = 0; str[i] != '\0'; i++) { if (str[i] == '\n') { uint8_t y = vga_get_cursor_y() + 1; - vga_set_cursor(0, y); + if (y >= VGA_HEIGHT) { + vga_scroll_up(); + } else { + vga_set_cursor(0, y); + } } else { vga_print_char(str[i]); @@ -119,6 +199,12 @@ uint8_t vga_get_cursor_x(void) { return vga_get_cursor_position() % VGA_WIDTH; } uint8_t vga_get_cursor_y(void) { return vga_get_cursor_position() / VGA_WIDTH; } +uint8_t vga_calc_cursor_x(uint16_t pos) { return pos % VGA_WIDTH; } + +uint8_t vga_calc_cursor_y(uint16_t pos) { return pos / VGA_WIDTH; } + +uint16_t vga_calc_cursor_position(uint8_t x, uint8_t y) { return y * VGA_WIDTH + x; } + // Clear void vga_clear(void) { @@ -131,3 +217,29 @@ void vga_clear(void) { vga_set_cursor(0, 0); } + +// secrole + +void vga_scroll_up(void) { + /* Move every row one line upward */ + for (uint16_t y = 0; y < VGA_HEIGHT - 1; y++) { + + for (uint16_t x = 0; x < VGA_WIDTH; x++) { + + uint16_t dst = y * VGA_WIDTH + x; + uint16_t src = (y + 1) * VGA_WIDTH + x; + + vga_buf[dst] = vga_buf[src]; + } + } + + /* Clear the new bottom line */ + for (uint16_t x = 0; x < VGA_WIDTH; x++) { + + uint16_t pos = (VGA_HEIGHT - 1) * VGA_WIDTH + x; + + vga_buf[pos] = ((uint16_t)current_color << 8) | ' '; + } + + vga_set_cursor(0, VGA_HEIGHT - 1); +} diff --git a/src/interrupt/irq/irq.c b/src/interrupt/irq/irq.c index 33d5b7a..a22605c 100644 --- a/src/interrupt/irq/irq.c +++ b/src/interrupt/irq/irq.c @@ -1,4 +1,6 @@ #include "irq.h" +#include "keyboard.h" +#include "keyboard/handler.h" #include "pic.h" #include "timer.h" #include "vga.h" @@ -12,6 +14,11 @@ void irq_handler(uint32_t vector) { pic_send_eoi((uint8_t)vector); break; + case 1: + keyboard_irq_handler(); + pic_send_eoi((uint8_t)vector); + break; + default: vga_print("IRQ: "); vga_print_hex(vector); diff --git a/src/interrupt/pit.c b/src/interrupt/pit.c index 1737898..2ba1839 100644 --- a/src/interrupt/pit.c +++ b/src/interrupt/pit.c @@ -1,6 +1,6 @@ #include "pit.h" +#include "types.h" #include "utils.h" -#include uint16_t div; uint32_t freq; diff --git a/src/kernel/kernel.c b/src/kernel/kernel.c index 775cd3c..dfda71f 100644 --- a/src/kernel/kernel.c +++ b/src/kernel/kernel.c @@ -4,44 +4,78 @@ #include "pic.h" #include "pit.h" +#include "ps2.h" #include "timer.h" +#include "keyboard.h" #include "vga.h" + #include "vga_lib.h" #include "panic.h" +#include "stdio.h" #include "utils.h" -void kernel_main() { +#include "string.h" + +#include "keyboard/event_queue.h" +#include "keyboard/handler.h" - vga_init(); - vga_log_info("[", "init", "] vga"); - vga_print_at_end_c("... Ok\n", GREEN); +#define TIMER_FREQ 1000 // 1000 Hz - vga_log_info("[", "init", "] pic"); - pic_init(); - vga_print_at_end_c("... Ok\n", GREEN); +void KERNEL_INIT(const char *name, void (*init_function)(void)) { + print("[\033[34minit\033[0m] "); + vga_print(name); - vga_log_info("[", "init", "] idt"); - idt_init(); - vga_print_at_end_c("... Ok\n", GREEN); + init_function(); + + print_at_end("... Ok\n", GREEN); +} - vga_log_info("[", "init", "] pit and timer"); +void timer_setup() { pic_clear_mask(0); - timer_init(1000); // 1000 Hz - + timer_init(TIMER_FREQ); // 1000 Hz + sti(); - for (int i = 0; i < 53; i++) { + for (int i = 0; i < 33; i++) { vga_print("."); timer_sleep(0.02); } - vga_print_at_end_c("... Ok\n", GREEN); // timer +} + +void kernel_main() { + + KERNEL_INIT("VGA console", vga_init); + + KERNEL_INIT("PIC - Programmable Interrupt Controller", pic_init); + + KERNEL_INIT("IDT - Interrupt Descriptor Table", idt_init); + + KERNEL_INIT("PIT - Programmable Interval Timer", timer_setup); // 1000 Hz + + KERNEL_INIT("PS/2 controller", ps2_init); + KERNEL_INIT("Keyboard Driver", init_keyboard); + + pic_clear_mask(1); + + while (1) { + input_event_t event; + input_queue_pop(&event); + + if (event.type == INPUT_CHAR) { + print("Character: "); + print_char(event.character); + print("\n"); + event = (input_event_t){0}; + event.type = 11; + } + } for (;;) { asm volatile("hlt"); } return; -} +} \ No newline at end of file diff --git a/src/libs/stdio.c b/src/libs/stdio.c new file mode 100644 index 0000000..fa49dad --- /dev/null +++ b/src/libs/stdio.c @@ -0,0 +1,206 @@ +#include + +#include "types.h" +#include "vga.h" +#include "vga_lib.h" + +#include "string.h" + +#include "stdio.h" + +#define FORMATTER_BUFFER_SIZE 1024 +static char buffer[FORMATTER_BUFFER_SIZE]; + +void print(const char *str) { + while (*str) { + + if (*str == '\033') { + str++; + + if (*str == '[') { + str++; + + if (*str == '3') { + str++; + + switch (*str) { + case '0': + vga_set_color(BLACK, DEFUALT_B); + break; + + case '1': + vga_set_color(RED, DEFUALT_B); + break; + + case '2': + vga_set_color(GREEN, DEFUALT_B); + break; + + case '3': + vga_set_color(YELLOW, DEFUALT_B); + break; + + case '4': + vga_set_color(BLUE, DEFUALT_B); + break; + + case '5': + vga_set_color(MAGENTA, DEFUALT_B); + break; + + case '6': + vga_set_color(CYAN, DEFUALT_B); + break; + + case '7': + vga_set_color(WHITE, DEFUALT_B); + break; + } + + if (*str) + str++; + + if (*str == 'm') + str++; + } else if (*str == '0') { + str++; + + if (*str == 'm') { + vga_set_color(DEFUALT_F, DEFUALT_B); + str++; + } + } + } + + continue; + } + + vga_print_char(*str); + str++; + } +} + +void println(const char *str) { + vga_print("\n"); + vga_print(str); +} + +void print_char(char c) { vga_print_char(c); } + +void print_hex(uint32_t value) { vga_print_hex(value); } + +void print_at_end(const char *str, uint8_t color) { vga_print_at_end_c(str, color); } + +void printf(const char *format, ...) { + va_list args; + + va_start(args, format); + + char *result = vformatter(format, args); + + va_end(args); + + print(result); +} + +void snprintf(char *buffer, size_t buffer_size, const char *format, ...) { + va_list args; + + va_start(args, format); + + char *result = vformatter(format, args); + + va_end(args); + + size_t i; + for (i = 0; i < buffer_size - 1 && result[i] != '\0'; i++) { + buffer[i] = result[i]; + } + buffer[i] = '\0'; +} + +char *formatter(const char *format, ...) { + va_list args; + + va_start(args, format); + + char *result = vformatter(format, args); + + va_end(args); + + return result; +} + +char *vformatter(const char *format, va_list args) { + buffer[0] = '\0'; + + while (*format) { + + if (*format != '%') { + char temp[2] = {*format, '\0'}; + strcat(buffer, temp); + + format++; + continue; + } + + format++; + + switch (*format) { + + case 's': { + const char *str = va_arg(args, const char *); + strcat(buffer, str); + break; + } + + case 'd': { + int number = va_arg(args, int); + strcat(buffer, int2str(number)); + break; + } + + case 'x': { + uint32_t number = va_arg(args, uint32_t); + strcat(buffer, uint2str(number, 16, false)); + break; + } + + case 'h': { + uint32_t number = va_arg(args, uint32_t); + strcat(buffer, uint2str(number, 16, true)); + break; + } + + case 'b': { + uint32_t number = va_arg(args, uint32_t); + strcat(buffer, uint2str(number, 2, false)); + break; + } + + case 'c': { + char temp[2]; + + temp[0] = (char)va_arg(args, int); + temp[1] = '\0'; + + strcat(buffer, temp); + break; + } + + case '%': { + strcat(buffer, "%"); + break; + } + + default: { + strcat(buffer, "%"); + break; + } + } + + format++; + } + + return buffer; +} diff --git a/src/libs/string.c b/src/libs/string.c new file mode 100644 index 0000000..4911539 --- /dev/null +++ b/src/libs/string.c @@ -0,0 +1,121 @@ +#include "string.h" +#include "types.h" +#include + +int strlen(char *str) { + int len = 0; + while (*str++) { + len++; + } + return len; +} + +char *int2str(int num) { + static char str[33]; + + char *p = str + 32; + + *p = '\0'; + + if (num == 0) { + *(--p) = '0'; + } else { + bool negative = num < 0; + + if (negative) + num = -num; + + while (num > 0) { + *(--p) = (num % 10) + '0'; + num /= 10; + } + + if (negative) + *(--p) = '-'; + } + + return p; +} + +char *uint2str(uint32_t number, uint8_t base, bool uppercase) { + static char buffer[33]; + + const char *digits_lower = "0123456789abcdef"; + const char *digits_upper = "0123456789ABCDEF"; + const char *digits = uppercase ? digits_upper : digits_lower; + + if (base < 2 || base > 16) { + buffer[0] = '\0'; + return buffer; + } + + char *ptr = &buffer[32]; + *ptr = '\0'; + + if (number == 0) { + *--ptr = '0'; + return ptr; + } + + while (number > 0) { + uint32_t remainder = number % base; + *--ptr = digits[remainder]; + number /= base; + } + + return ptr; +} + +void strcpy(char *dest, char *src) { + while (*src) { + *dest++ = *src++; + } + *dest = '\0'; +} + +void strcat(char *dest, const char *src) { + while (*dest) { + dest++; + } + while (*src) { + *dest++ = *src++; + } + *dest = '\0'; +} + +int strcmp(const char *str1, const char *str2) { + while (*str1 && (*str1 == *str2)) { + str1++; + str2++; + } + return *(const unsigned char *)str1 - *(const unsigned char *)str2; +} + +char *strchr(const char *str, int c) { + while (*str != '\0') { + if (*str == (char)c) { + return (char *)str; + } + + str++; + } + + return (c == '\0') ? (char *)str : NULL; +} + +char *strstr(const char *str, const char *substr) { + if (!*substr) { + return (char *)str; + } + for (; *str; str++) { + if (*str == *substr) { + const char *h, *n; + for (h = str, n = substr; *h && *n && *h == *n; ++h, ++n) + ; + if (!*n) { + return (char *)str; + } + } + } + return NULL; +} \ No newline at end of file