From df1c5352c4a1c9e60adecc03f2a8e1d039bac9b0 Mon Sep 17 00:00:00 2001 From: "Enrico Fraccaroli (Galfurian)" Date: Fri, 14 Jan 2022 09:13:00 -0500 Subject: [PATCH] Correctly implement main termios commands. --- mentos/inc/drivers/keyboard/keyboard.h | 15 ++- mentos/inc/process/process.h | 3 + mentos/src/drivers/keyboard/keyboard.c | 122 ++++++++++++++++--------- mentos/src/io/proc_video.c | 102 +++++++++++++++++++-- mentos/src/process/process.c | 2 + 5 files changed, 187 insertions(+), 57 deletions(-) diff --git a/mentos/inc/drivers/keyboard/keyboard.h b/mentos/inc/drivers/keyboard/keyboard.h index 4835208..aeabe79 100644 --- a/mentos/inc/drivers/keyboard/keyboard.h +++ b/mentos/inc/drivers/keyboard/keyboard.h @@ -28,10 +28,17 @@ void keyboard_disable(); /// @brief Leds handler. void keyboard_update_leds(); -/// @brief Get a char from the buffer. -/// @details It loops until there is something new to read. -/// @return The read character. -int keyboard_getc(); +/// @brief Gets and removes a char from the back of the buffer. +/// @return The extracted character. +int keyboard_pop_back(); + +/// @brief Gets a char from the back of the buffer. +/// @return The read character. +int keyboard_back(); + +/// @brief Gets a char from the front of the buffer. +/// @return The read character. +int keyboard_front(); /// @brief Initializes the keyboard drivers. /// @return 0 on success, 1 on error. diff --git a/mentos/inc/process/process.h b/mentos/inc/process/process.h index 7dabbba..bcc8e45 100644 --- a/mentos/inc/process/process.h +++ b/mentos/inc/process/process.h @@ -5,6 +5,7 @@ #pragma once +#include "drivers/keyboard/keyboard.h" #include "bits/termios-struct.h" #include "system/signal.h" #include "devices/fpu.h" @@ -150,6 +151,8 @@ typedef struct task_struct { /// Process-wise terminal options. termios_t termios; + /// Buffer for managing inputs from keyboard. + fs_rb_scancode_t keyboard_rb; //==== Future work ========================================================= // - task's attributes: diff --git a/mentos/src/drivers/keyboard/keyboard.c b/mentos/src/drivers/keyboard/keyboard.c index 9b7f5d8..5c649d5 100644 --- a/mentos/src/drivers/keyboard/keyboard.c +++ b/mentos/src/drivers/keyboard/keyboard.c @@ -33,6 +33,8 @@ static uint8_t ledstate = 0; static uint32_t kflags = 0; /// Where we store the keypress. fs_rb_scancode_t scancodes; +/// Spinlock to protect access to the scancode buffer. +spinlock_t scancodes_lock; #define KBD_LEFT_SHIFT (1 << 0) ///< Flag which identifies the left shift. #define KBD_RIGHT_SHIFT (1 << 1) ///< Flag which identifies the right shift. @@ -69,6 +71,51 @@ static inline bool_t get_keypad_number(int scancode) return -1; } +static inline void keyboard_push_front(int c) +{ + if (c >= 0) { + spinlock_lock(&scancodes_lock); + fs_rb_scancode_push_front(&scancodes, c); + spinlock_unlock(&scancodes_lock); + } +} + +int keyboard_pop_back() +{ + int c; + spinlock_lock(&scancodes_lock); + if (!fs_rb_scancode_empty(&scancodes)) + c = fs_rb_scancode_pop_back(&scancodes); + else + c = -1; + spinlock_unlock(&scancodes_lock); + return c; +} + +int keyboard_back() +{ + int c; + spinlock_lock(&scancodes_lock); + if (!fs_rb_scancode_empty(&scancodes)) + c = fs_rb_scancode_back(&scancodes); + else + c = -1; + spinlock_unlock(&scancodes_lock); + return c; +} + +int keyboard_front() +{ + int c = -1; + spinlock_lock(&scancodes_lock); + if (!fs_rb_scancode_empty(&scancodes)) + c = fs_rb_scancode_front(&scancodes); + else + c = -1; + spinlock_unlock(&scancodes_lock); + return c; +} + void keyboard_isr(pt_regs *f) { unsigned int scancode; @@ -102,11 +149,11 @@ void keyboard_isr(pt_regs *f) pr_debug("Press(KBD_RIGHT_CONTROL)\n"); } else if (scancode == KEY_LEFT_ALT) { bitmask_set_assign(kflags, KBD_LEFT_ALT); - fs_rb_scancode_push(&scancodes, scancode << 16u); + keyboard_push_front(scancode << 16u); pr_debug("Press(KBD_LEFT_ALT)\n"); } else if (scancode == KEY_RIGHT_ALT) { bitmask_set_assign(kflags, KBD_RIGHT_ALT); - fs_rb_scancode_push(&scancodes, scancode << 16u); + keyboard_push_front(scancode << 16u); pr_debug("Press(KBD_RIGHT_ALT)\n"); } else if (scancode == (KEY_LEFT_SHIFT | CODE_BREAK)) { bitmask_clear_assign(kflags, KBD_LEFT_SHIFT); @@ -139,50 +186,50 @@ void keyboard_isr(pt_regs *f) keyboard_update_leds(); pr_debug("Toggle(KBD_SCROLL_LOCK)\n"); } else if (scancode == KEY_BACKSPACE) { - fs_rb_scancode_push(&scancodes, '\b'); + keyboard_push_front('\b'); pr_debug("Press(KEY_BACKSPACE)\n"); } else if (scancode == KEY_DELETE) { - fs_rb_scancode_push(&scancodes, 127); + keyboard_push_front(127); pr_debug("Press(KEY_DELETE)\n"); } else if ((scancode == KEY_ENTER) || (scancode == KEY_KP_RETURN)) { - fs_rb_scancode_push(&scancodes, '\n'); + keyboard_push_front('\n'); pr_debug("Press(KEY_ENTER)\n"); } else if ((scancode == KEY_PAGE_UP) || (keypad_fun_number == 9)) { - fs_rb_scancode_push(&scancodes, scancode); + keyboard_push_front(scancode); pr_debug("Press(KEY_PAGE_UP)\n"); } else if ((scancode == KEY_PAGE_DOWN) || (keypad_fun_number == 2)) { - fs_rb_scancode_push(&scancodes, scancode); + keyboard_push_front(scancode); pr_debug("Press(KEY_PAGE_DOWN)\n"); } else if ((scancode == KEY_UP_ARROW) || (keypad_fun_number == 8)) { pr_debug("Press(KEY_UP_ARROW)\n"); - fs_rb_scancode_push(&scancodes, '\033'); - fs_rb_scancode_push(&scancodes, '['); - fs_rb_scancode_push(&scancodes, 'A'); + keyboard_push_front('\033'); + keyboard_push_front('['); + keyboard_push_front('A'); } else if ((scancode == KEY_DOWN_ARROW) || (keypad_fun_number == 2)) { pr_debug("Press(KEY_DOWN_ARROW)\n"); - fs_rb_scancode_push(&scancodes, '\033'); - fs_rb_scancode_push(&scancodes, '['); - fs_rb_scancode_push(&scancodes, 'B'); + keyboard_push_front('\033'); + keyboard_push_front('['); + keyboard_push_front('B'); } else if ((scancode == KEY_RIGHT_ARROW) || (keypad_fun_number == 6)) { pr_debug("Press(KEY_RIGHT_ARROW)\n"); - fs_rb_scancode_push(&scancodes, '\033'); - fs_rb_scancode_push(&scancodes, '['); - fs_rb_scancode_push(&scancodes, 'C'); + keyboard_push_front('\033'); + keyboard_push_front('['); + keyboard_push_front('C'); } else if ((scancode == KEY_LEFT_ARROW) || (keypad_fun_number == 4)) { pr_debug("Press(KEY_LEFT_ARROW)\n"); - fs_rb_scancode_push(&scancodes, '\033'); - fs_rb_scancode_push(&scancodes, '['); - fs_rb_scancode_push(&scancodes, 'D'); + keyboard_push_front('\033'); + keyboard_push_front('['); + keyboard_push_front('D'); } else if ((scancode == KEY_HOME) || (keypad_fun_number == 7)) { pr_debug("Press(KEY_HOME)\n"); - fs_rb_scancode_push(&scancodes, '\033'); - fs_rb_scancode_push(&scancodes, '['); - fs_rb_scancode_push(&scancodes, 'H'); + keyboard_push_front('\033'); + keyboard_push_front('['); + keyboard_push_front('H'); } else if ((scancode == KEY_END) || (keypad_fun_number == 1)) { pr_debug("Press(KEY_END)\n"); - fs_rb_scancode_push(&scancodes, '\033'); - fs_rb_scancode_push(&scancodes, '['); - fs_rb_scancode_push(&scancodes, 'F'); + keyboard_push_front('\033'); + keyboard_push_front('['); + keyboard_push_front('F'); } else if (scancode == KEY_ESCAPE) { // Nothing to do. } else if (keypad_fun_number == 5) { @@ -191,25 +238,17 @@ void keyboard_isr(pt_regs *f) // Get the current keymap. const keymap_t *keymap = get_keymap(scancode); // Get the specific keymap. -#if 0 - pr_debug("%04x '%c' (%04x) '%c' (%04x) '%c' (%04x) '%c' (%04x))\n", - scancode, - ((0x00ff & keymap->normal) >= 32) ? keymap->normal : ' ', keymap->normal, - ((0x00ff & keymap->shift) >= 32) ? keymap->shift : ' ', keymap->shift, - ((0x00ff & keymap->ctrl) >= 32) ? keymap->ctrl : ' ', keymap->ctrl, - ((0x00ff & keymap->alt) >= 32) ? keymap->alt : ' ', keymap->alt); -#endif int character = 0; if (!bitmask_check(kflags, KBD_LEFT_SHIFT | KBD_RIGHT_SHIFT) != !bitmask_check(kflags, KBD_CAPS_LOCK)) { - fs_rb_scancode_push(&scancodes, keymap->shift); + keyboard_push_front(keymap->shift); } else if ((get_keymap_type() == KEYMAP_IT) && bitmask_check(kflags, KBD_RIGHT_ALT) && (bitmask_check(kflags, KBD_LEFT_SHIFT | KBD_RIGHT_SHIFT))) { - fs_rb_scancode_push(&scancodes, keymap->alt); + keyboard_push_front(keymap->alt); } else if (bitmask_check(kflags, KBD_RIGHT_ALT)) { - fs_rb_scancode_push(&scancodes, keymap->alt); + keyboard_push_front(keymap->alt); } else if (bitmask_check(kflags, KBD_LEFT_CONTROL | KBD_RIGHT_CONTROL)) { - fs_rb_scancode_push(&scancodes, keymap->ctrl); + keyboard_push_front(keymap->ctrl); } else { - fs_rb_scancode_push(&scancodes, keymap->normal); + keyboard_push_front(keymap->normal); } } pic8259_send_eoi(IRQ_KEYBOARD); @@ -237,15 +276,12 @@ void keyboard_disable() outportb(0x60, 0xF5); } -int keyboard_getc() -{ - return fs_rb_scancode_pop(&scancodes); -} - int keyboard_initialize() { // Initialize the ring-buffer for the scancodes. fs_rb_scancode_init(&scancodes); + // Initialize the spinlock. + spinlock_init(&scancodes_lock); // Initialize the keymaps. init_keymaps(); // Install the IRQ. diff --git a/mentos/src/io/proc_video.c b/mentos/src/io/proc_video.c index 6122d5b..b9a583e 100644 --- a/mentos/src/io/proc_video.c +++ b/mentos/src/io/proc_video.c @@ -24,13 +24,101 @@ #include "ctype.h" #include "process/scheduler.h" +void print_rb(fs_rb_scancode_t *rb) +{ + if (!fs_rb_scancode_empty(rb)) { + for (unsigned i = rb->read; (i < rb->write) && (i < rb->size); ++i) { + pr_debug("%c", rb->buffer[i]); + } + pr_debug("\n"); + } +} + static ssize_t procv_read(vfs_file_t *file, char *buf, off_t offset, size_t nbyte) { - if (buf == NULL) { + // Stop if the buffer is invalid. + if (buf == NULL) return -1; + + // Get the currently running process. + task_struct *process = scheduler_get_current_process(); + // Get a pointer to its ketboard ring-buffer. + fs_rb_scancode_t *rb = &process->keyboard_rb; + + // If we are in canonical mode, and the last inserted element is a newline, + // we pop the buffer until it's empty. + if (bitmask_check(process->termios.c_lflag, ICANON) && (fs_rb_scancode_front(rb) == '\n')) { + *((char *)buf) = fs_rb_scancode_pop_back(rb) & 0x00FF; + return 1; } + + // Once we have dealt with the canonical mode, get the characgter. + int c = keyboard_pop_back(); + // Check that it's a valid caracter. + if (c < 0) + return 0; + c &= 0x00FF; + // Add the character to the buffer. + fs_rb_scancode_push_front(rb, c); + // If echo is activated, output the character to video. + if (bitmask_check(process->termios.c_lflag, ECHO)) { + if (iscntrl(c)) { + if (isalpha('A' + (c - 1)) && (c != '\n')) { + video_putc('^'); + video_putc('A' + (c - 1)); + } + } else { + video_putc(c); + } + } + + if (bitmask_check(process->termios.c_lflag, ISIG)) { + if (iscntrl(c)) { + if (c == 0x03) { + sys_kill(process->pid, SIGTERM); + } else if (c == 0x1A) { + sys_kill(process->pid, SIGSTOP); + } + } + } + + // If we are NOT in canonical mode, we can send the character back to user + // right away. + if (!bitmask_check(process->termios.c_lflag, ICANON)) { + *((char *)buf) = fs_rb_scancode_pop_back(rb) & 0x00FF; + return 1; + } + +#if 0 + + // The last inserted character. + int back_c = keyboard_back(); + + if (back_c < 0) + return 0; + + // The first inserted character. + int front_c = keyboard_front(); + + pr_debug("'%c' (%3d %04x) [F: '%c' (%04x)]\n", back_c, back_c, back_c, front_c, front_c); + + // Echo the character to video. + if (bitmask_check(process->termios.c_lflag, ECHO)) { + video_putc(back_c & 0x00FF); + } + + // If we have the canonical input active, we should not return characters, + // until we receive a newline. + if ((bitmask_check(process->termios.c_lflag, ICANON) && (front_c == '\n')) || + !bitmask_check(process->termios.c_lflag, ICANON)) { + *((char *)buf) = keyboard_pop_back() & 0x00FF; + return 1; + } +#endif + +#if 0 // Read the character from the keyboard. - int c = keyboard_getc(); + int c = keyboard_getc(false) & 0x00FF; if (c < 0) return 0; if (c == KEY_PAGE_UP) { @@ -40,19 +128,13 @@ static ssize_t procv_read(vfs_file_t *file, char *buf, off_t offset, size_t nbyt video_shift_one_page_up(); return 0; } else { - pr_debug("'%c' (0x%04x)\n", c, c); - // Get the currently running process. - task_struct *process = scheduler_get_current_process(); // Echo the character to video. if (bitmask_check(process->termios.c_lflag, ECHO)) { video_putc(c & 0x00FF); } - // Return the character. - //if (!bitmask_check(process->termios.c_lflag, ICANON)) { - *((char *)buf) = c & 0x00FF; - //} } - return 1; +#endif + return 0; } static ssize_t procv_write(vfs_file_t *file, const void *buf, off_t offset, size_t nbyte) diff --git a/mentos/src/process/process.c b/mentos/src/process/process.c index 5cf61ca..874b478 100644 --- a/mentos/src/process/process.c +++ b/mentos/src/process/process.c @@ -236,6 +236,8 @@ static inline task_struct *__alloc_task(task_struct *source, task_struct *parent .c_oflag = 0, .c_iflag = 0 }; + // Initialize the ringbuffer. + fs_rb_scancode_init(&proc->keyboard_rb); return proc; }