From: Tulio A M Mendes Date: Fri, 13 Feb 2026 21:36:11 +0000 (-0300) Subject: feat: VKILL line kill, c_iflag ICRNL/IGNCR/INLCR, TCSETSW/TCSETSF X-Git-Url: https://projects.tadryanom.me/?a=commitdiff_plain;h=c1d9f9ff8d74f8817658685a07f111fa0735e359;p=AdrOS.git feat: VKILL line kill, c_iflag ICRNL/IGNCR/INLCR, TCSETSW/TCSETSF - Add VKILL (Ctrl-U) handling in canonical mode: erases entire line buffer with visual backspace feedback - Add c_iflag bits: ICRNL (default on), IGNCR, INLCR - Add tty_iflag state variable, default ICRNL enabled - c_iflag input translation runs before signal/canonical processing - Replace hardcoded CR→NL conversion with c_iflag-based translation - TCGETS now returns c_iflag; TCSETS now applies c_iflag mask - Add TCSETSW (0x5403) and TCSETSF (0x5404) ioctl commands (treated same as TCSETS — no output queue to drain/flush) 20/20 smoke tests pass. --- diff --git a/include/tty.h b/include/tty.h index 0ec5089..c8deb98 100644 --- a/include/tty.h +++ b/include/tty.h @@ -30,12 +30,20 @@ struct winsize { uint16_t ws_ypixel; }; +/* c_lflag bits */ enum { TTY_ICANON = 0x0002, TTY_ECHO = 0x0008, TTY_ISIG = 0x0001, }; +/* c_iflag bits */ +enum { + TTY_ICRNL = 0x0100, /* map CR to NL on input */ + TTY_IGNCR = 0x0080, /* ignore CR on input */ + TTY_INLCR = 0x0040, /* map NL to CR on input */ +}; + /* c_oflag bits (POSIX) */ enum { TTY_OPOST = 0x0001, diff --git a/src/kernel/tty.c b/src/kernel/tty.c index fe8d65a..fb8b0e4 100644 --- a/src/kernel/tty.c +++ b/src/kernel/tty.c @@ -26,6 +26,7 @@ static uint32_t canon_tail = 0; static waitqueue_t tty_wq; +static uint32_t tty_iflag = TTY_ICRNL; static uint32_t tty_lflag = TTY_ICANON | TTY_ECHO | TTY_ISIG; static uint32_t tty_oflag = TTY_OPOST | TTY_ONLCR; static uint8_t tty_cc[NCCS] = { @@ -205,6 +206,8 @@ static void canon_push(char c) { enum { TTY_TCGETS = 0x5401, TTY_TCSETS = 0x5402, + TTY_TCSETSW = 0x5403, + TTY_TCSETSF = 0x5404, TTY_TIOCGPGRP = 0x540F, TTY_TIOCSPGRP = 0x5410, TTY_TIOCGWINSZ = 0x5413, @@ -252,6 +255,7 @@ int tty_ioctl(uint32_t cmd, void* user_arg) { struct termios t; memset(&t, 0, sizeof(t)); uintptr_t flags = spin_lock_irqsave(&tty_lock); + t.c_iflag = tty_iflag; t.c_lflag = tty_lflag; t.c_oflag = tty_oflag; for (int i = 0; i < NCCS; i++) t.c_cc[i] = tty_cc[i]; @@ -260,10 +264,11 @@ int tty_ioctl(uint32_t cmd, void* user_arg) { return 0; } - if (cmd == TTY_TCSETS) { + if (cmd == TTY_TCSETS || cmd == TTY_TCSETSW || cmd == TTY_TCSETSF) { struct termios t; if (copy_from_user(&t, user_arg, sizeof(t)) < 0) return -EFAULT; uintptr_t flags = spin_lock_irqsave(&tty_lock); + tty_iflag = t.c_iflag & (TTY_ICRNL | TTY_IGNCR | TTY_INLCR); tty_lflag = t.c_lflag & (TTY_ICANON | TTY_ECHO | TTY_ISIG); tty_oflag = t.c_oflag & (TTY_OPOST | TTY_ONLCR); for (int i = 0; i < NCCS; i++) tty_cc[i] = t.c_cc[i]; @@ -288,8 +293,17 @@ int tty_ioctl(uint32_t cmd, void* user_arg) { void tty_input_char(char c) { uintptr_t flags = spin_lock_irqsave(&tty_lock); + uint32_t iflag = tty_iflag; uint32_t lflag = tty_lflag; + /* c_iflag input translation */ + if (c == '\r') { + if (iflag & TTY_IGNCR) { spin_unlock_irqrestore(&tty_lock, flags); return; } + if (iflag & TTY_ICRNL) c = '\n'; + } else if (c == '\n') { + if (iflag & TTY_INLCR) c = '\r'; + } + enum { SIGINT_NUM = 2, SIGQUIT_NUM = 3, SIGTSTP_NUM = 20 }; if (lflag & TTY_ISIG) { @@ -341,7 +355,6 @@ void tty_input_char(char c) { } if ((lflag & TTY_ICANON) == 0) { - if (c == '\r') c = '\n'; canon_push(c); wq_wake_one(&tty_wq); if (lflag & TTY_ECHO) { @@ -362,7 +375,17 @@ void tty_input_char(char c) { return; } - if (c == '\r') c = '\n'; + if (tty_cc[VKILL] && (uint8_t)c == tty_cc[VKILL]) { + if (lflag & TTY_ECHO) { + while (line_len > 0) { + line_len--; + kprintf("\b \b"); + } + } + line_len = 0; + spin_unlock_irqrestore(&tty_lock, flags); + return; + } if (c == '\n') { if (lflag & TTY_ECHO) {