feat: better rtc framework which aims to remove single rtc restrictions.
[lunaix-os.git] / lunaix-os / kernel / tty / lxconsole.c
index a226e4221e8253336eb477c97ef114597d4c0460..8d0747dda601c905c67a8ff4c863705ddd22a944 100644 (file)
@@ -1,12 +1,25 @@
+/**
+ * @file lxconsole.c
+ * @author Lunaixsky (lunaxisky@qq.com)
+ * @brief Provides simple terminal support
+ * @version 0.1
+ * @date 2023-06-18
+ *
+ * @copyright Copyright (c) 2023
+ *
+ */
+
 #include <klibc/string.h>
 #include <lunaix/device.h>
 #include <lunaix/input.h>
+#include <lunaix/ioctl.h>
 #include <lunaix/keyboard.h>
 #include <lunaix/lxconsole.h>
 #include <lunaix/mm/pmm.h>
 #include <lunaix/mm/valloc.h>
 #include <lunaix/mm/vmm.h>
 #include <lunaix/sched.h>
+#include <lunaix/signal.h>
 #include <lunaix/tty/console.h>
 #include <lunaix/tty/tty.h>
 
@@ -18,34 +31,99 @@ __tty_write(struct device* dev, void* buf, size_t offset, size_t len);
 int
 __tty_read(struct device* dev, void* buf, size_t offset, size_t len);
 
+void
+console_write(struct console* console, u8_t* data, size_t size);
+
+void
+console_flush();
+
 static waitq_t lx_reader;
-static volatile char key;
+static volatile char ttychr;
+
+static volatile pid_t fg_pgid = 0;
+
+static inline void
+print_control_code(const char cntrl)
+{
+    console_write_char('^');
+    console_write_char(cntrl + 64);
+}
 
 int
 __lxconsole_listener(struct input_device* dev)
 {
-    uint32_t keycode = dev->current_pkt.sys_code;
-    uint32_t type = dev->current_pkt.pkt_type;
-    if (type == PKT_PRESS) {
-        if (keycode == KEY_PG_UP) {
-            console_view_up();
-        } else if (keycode == KEY_PG_DOWN) {
-            console_view_down();
-        }
+    u32_t key = dev->current_pkt.sys_code;
+    u32_t type = dev->current_pkt.pkt_type;
+    kbd_kstate_t state = key >> 16;
+    ttychr = key & 0xff;
+    key = key & 0xffff;
+
+    if (type == PKT_RELEASE) {
         goto done;
     }
-    if ((keycode & 0xff00) > KEYPAD) {
+
+    if ((state & KBD_KEY_FLCTRL_HELD)) {
+        char cntrl = (char)(ttychr | 0x20);
+        if ('a' > cntrl || cntrl > 'z') {
+            goto done;
+        }
+        ttychr = cntrl - 'a' + 1;
+        switch (ttychr) {
+            case TCINTR:
+                signal_send(-fg_pgid, _SIGINT);
+                print_control_code(ttychr);
+                break;
+            case TCSTOP:
+                signal_send(-fg_pgid, _SIGSTOP);
+                print_control_code(ttychr);
+                break;
+            default:
+                break;
+        }
+    } else if (key == KEY_PG_UP) {
+        console_view_up();
+        goto done;
+    } else if (key == KEY_PG_DOWN) {
+        console_view_down();
+        goto done;
+    } else if ((key & 0xff00) <= KEYPAD) {
+        ttychr = key;
+    } else {
         goto done;
     }
 
-    key = (char)(keycode & 0x00ff);
-
     pwake_all(&lx_reader);
 
 done:
     return INPUT_EVT_NEXT;
 }
 
+int
+__tty_exec_cmd(struct device* dev, u32_t req, va_list args)
+{
+    switch (req) {
+        case TIOCGPGRP:
+            return fg_pgid;
+        case TIOCSPGRP:
+            fg_pgid = va_arg(args, pid_t);
+            break;
+        case TIOCCLSBUF:
+            fifo_clear(&lx_console.output);
+            fifo_clear(&lx_console.input);
+            lx_console.wnd_start = 0;
+            lx_console.lines = 0;
+            lx_console.output.flags |= FIFO_DIRTY;
+            break;
+        case TIOCFLUSH:
+            lx_console.output.flags |= FIFO_DIRTY;
+            console_flush();
+            break;
+        default:
+            return EINVAL;
+    }
+    return 0;
+}
+
 void
 lxconsole_init()
 {
@@ -54,10 +132,29 @@ lxconsole_init()
     fifo_init(&lx_console.input, valloc(4096), 4096, 0);
 
     lx_console.flush_timer = NULL;
+}
+
+int
+__tty_write_pg(struct device* dev, void* buf, size_t offset)
+{
+    return __tty_write(dev, buf, offset, PG_SIZE);
+}
+
+int
+__tty_read_pg(struct device* dev, void* buf, size_t offset)
+{
+    return __tty_read(dev, buf, offset, PG_SIZE);
+}
 
+void
+lxconsole_spawn_ttydev()
+{
     struct device* tty_dev = device_addseq(NULL, &lx_console, "tty");
-    tty_dev->write = __tty_write;
-    tty_dev->read = __tty_read;
+    tty_dev->ops.write = __tty_write;
+    tty_dev->ops.write_page = __tty_write_pg;
+    tty_dev->ops.read = __tty_read;
+    tty_dev->ops.read_page = __tty_read_pg;
+    tty_dev->ops.exec_cmd = __tty_exec_cmd;
 
     waitq_init(&lx_reader);
     input_add_listener(__lxconsole_listener);
@@ -68,6 +165,8 @@ __tty_write(struct device* dev, void* buf, size_t offset, size_t len)
 {
     struct console* console = (struct console*)dev->underlay;
     console_write(console, buf, len);
+
+    return len;
 }
 
 int
@@ -83,17 +182,34 @@ __tty_read(struct device* dev, void* buf, size_t offset, size_t len)
     while (count < len) {
         pwait(&lx_reader);
 
-        if (key == 0x08) {
-            if (fifo_backone(&console->input)) {
-                console_write_char(key);
+        if (ttychr < 0x1B) {
+            // ASCII control codes
+            switch (ttychr) {
+                case TCINTR:
+                    fifo_clear(&console->input);
+                    return 0;
+                case TCBS:
+                    if (fifo_backone(&console->input)) {
+                        console_write_char(ttychr);
+                    }
+                    continue;
+                case TCLF:
+                case TCCR:
+                    goto proceed;
+                default:
+                    break;
             }
+            print_control_code(ttychr);
             continue;
         }
-        console_write_char(key);
-        if (!fifo_putone(&console->input, key) || key == '\n') {
+
+    proceed:
+        console_write_char(ttychr);
+        if (!fifo_putone(&console->input, ttychr) || ttychr == '\n') {
             break;
         }
     }
+
     return count + fifo_read(&console->input, buf + count, len - count);
 }
 
@@ -175,15 +291,15 @@ console_flush()
 }
 
 void
-console_write(struct console* console, uint8_t* data, size_t size)
+console_write(struct console* console, u8_t* data, size_t size)
 {
     struct fifo_buf* fbuf = &console->output;
     mutex_lock(&console->output.lock);
     fifo_set_rdptr(fbuf, console->wnd_start);
 
-    uint8_t* buffer = fbuf->data;
-    uintptr_t ptr = fbuf->wr_pos;
-    uintptr_t rd_ptr = fbuf->rd_pos;
+    u8_t* buffer = fbuf->data;
+    ptr_t ptr = fbuf->wr_pos;
+    ptr_t rd_ptr = fbuf->rd_pos;
 
     char c;
     for (size_t i = 0; i < size; i++) {
@@ -212,18 +328,22 @@ console_write(struct console* console, uint8_t* data, size_t size)
     console->wnd_start = rd_ptr;
     fbuf->flags |= FIFO_DIRTY;
     mutex_unlock(&fbuf->lock);
+
+    if (!lx_console.flush_timer) {
+        console_flush();
+    }
 }
 
 void
 console_write_str(char* str)
 {
-    console_write(&lx_console, str, strlen(str));
+    console_write(&lx_console, (u8_t*)str, strlen(str));
 }
 
 void
 console_write_char(char str)
 {
-    console_write(&lx_console, &str, 1);
+    console_write(&lx_console, (u8_t*)&str, 1);
 }
 
 void