fix: corner cases when printing large content through term interface
[lunaix-os.git] / lunaix-os / hal / term / term.c
index 0c404a51208d035111b54a936e5c8db55ff494ae..3db875903761375fd575a265662659279fd9d4df 100644 (file)
@@ -18,6 +18,8 @@ static struct term_lcntl* line_controls[] = {[ANSI_LCNTL] =
 
 static struct devclass termdev = DEVCLASS(DEVIF_NON, DEVFN_TTY, DEV_VTERM);
 
+struct device* sysconsole = NULL;
+
 static int
 term_exec_cmd(struct device* dev, u32_t req, va_list args)
 {
@@ -47,7 +49,7 @@ term_exec_cmd(struct device* dev, u32_t req, va_list args)
                 goto done;
             }
 
-            struct device* cdev = device_cast(vfd->file->inode->data);
+            struct device* cdev = resolve_device(vfd->file->inode->data);
             if (!cdev) {
                 err = ENOTDEV;
                 goto done;
@@ -74,27 +76,36 @@ term_exec_cmd(struct device* dev, u32_t req, va_list args)
             break;
         }
         case TDEV_TCGETATTR: {
-            struct _termios* tios = va_arg(args, struct _termios*);
-            *tios = (struct _termios){.c_oflag = term->oflags,
+            struct termios* tios = va_arg(args, struct termios*);
+            *tios = (struct termios){.c_oflag = term->oflags,
                                       .c_iflag = term->iflags,
-                                      .c_lflag = term->lflags};
+                                      .c_lflag = term->lflags,
+                                      .c_cflag = term->cflags};
             memcpy(tios->c_cc, term->cc, _NCCS * sizeof(cc_t));
             tios->c_baud = term->iospeed;
         } break;
         case TDEV_TCSETATTR: {
-            struct _termios* tios = va_arg(args, struct _termios*);
+            struct termios* tios = va_arg(args, struct termios*);
             term->iflags = tios->c_iflag;
             term->oflags = tios->c_oflag;
             term->lflags = tios->c_lflag;
             memcpy(term->cc, tios->c_cc, _NCCS * sizeof(cc_t));
 
+            tcflag_t old_cf = term->cflags;
+            term->cflags = tios->c_cflag;
+
+            if (!term->tp_cap) {
+                goto done;
+            }
+
             if (tios->c_baud != term->iospeed) {
                 term->iospeed = tios->c_baud;
-                if (!term->chdev_ops.set_speed) {
-                    goto done;
-                }
 
-                term->chdev_ops.set_speed(term->chdev, tios->c_baud);
+                term->tp_cap->set_speed(term->chdev, tios->c_baud);
+            }
+
+            if (old_cf != tios->c_cflag) {
+                term->tp_cap->set_cntrl_mode(term->chdev, tios->c_cflag);
             }
         } break;
         default:
@@ -108,25 +119,28 @@ done:
 }
 
 static int
-tdev_do_write(struct device* dev, void* buf, size_t offset, size_t len)
+tdev_do_write(struct device* dev, void* buf, off_t fpos, size_t len)
 {
     struct term* tdev = termdev(dev);
     lbuf_ref_t current = ref_current(&tdev->line_out);
     size_t wrsz = 0;
     while (wrsz < len) {
         wrsz += rbuffer_puts(
-            deref(current), &((char*)buf)[offset + wrsz], len - wrsz);
+            deref(current), &((char*)buf)[wrsz], len - wrsz);
 
         if (rbuffer_full(deref(current))) {
             term_flush(tdev);
         }
     }
-
-    return 0;
+    
+    if (!rbuffer_empty(deref(current))) {
+        term_flush(tdev);
+    }
+    return wrsz;
 }
 
 static int
-tdev_do_read(struct device* dev, void* buf, size_t offset, size_t len)
+tdev_do_read(struct device* dev, void* buf, off_t fpos, size_t len)
 {
     struct term* tdev = termdev(dev);
     lbuf_ref_t current = ref_current(&tdev->line_in);
@@ -139,7 +153,7 @@ tdev_do_read(struct device* dev, void* buf, size_t offset, size_t len)
         }
 
         rdsz += rbuffer_gets(
-            deref(current), &((char*)buf)[offset + rdsz], len - rdsz);
+            deref(current), &((char*)buf)[rdsz], len - rdsz);
     }
 
     return rdsz;
@@ -147,6 +161,23 @@ tdev_do_read(struct device* dev, void* buf, size_t offset, size_t len)
 
 static cc_t default_cc[_NCCS] = {4, '\n', 0x7f, 3, 1, 24, 22, 0, 0, 1, 1};
 
+static void 
+load_default_setting(struct term* tdev) 
+{
+    tdev->lflags = _ICANON | _IEXTEN | _ISIG | _ECHO | _ECHOE | _ECHONL;
+    tdev->iflags = _ICRNL | _IGNBRK;
+    tdev->oflags = _ONLCR | _OPOST;
+    memcpy(tdev->cc, default_cc, _NCCS * sizeof(cc_t));
+}
+
+static void
+alloc_term_buffer(struct term* terminal, size_t sz_hlf) 
+{
+    line_alloc(&terminal->line_in, sz_hlf);
+    line_alloc(&terminal->line_out, sz_hlf);
+    terminal->scratch_pad = valloc(sz_hlf);
+}
+
 struct term*
 term_create(struct device* chardev, char* suffix)
 {
@@ -161,24 +192,29 @@ term_create(struct device* chardev, char* suffix)
 
     terminal->dev->ops.read = tdev_do_read;
     terminal->dev->ops.write = tdev_do_write;
+    terminal->dev->ops.exec_cmd = term_exec_cmd;
 
     // TODO choice of lcntl can be flexible
     terminal->lcntl = line_controls[ANSI_LCNTL];
 
-    line_alloc(&terminal->line_in, 1024);
-    line_alloc(&terminal->line_out, 1024);
+    alloc_term_buffer(terminal, 1024);
 
     if (chardev) {
         int cdev_var = DEV_VAR_FROM(chardev->ident.unique);
-        device_register(terminal->dev, &termdev, "tty%s%d", suffix, cdev_var);
+        register_device(terminal->dev, &termdev, "tty%s%d", suffix, cdev_var);
     } else {
-        device_register(terminal->dev, &termdev, "tty%d", termdev.variant++);
+        register_device(terminal->dev, &termdev, "tty%d", termdev.variant++);
+    }
+
+    struct capability_meta* termport_cap = device_get_capability(chardev, TERMPORT_CAP);
+    if (termport_cap) {
+        terminal->tp_cap = get_capability(termport_cap, struct termport_capability);
     }
 
-    terminal->lflags = _ICANON | _IEXTEN | _ISIG | _ECHO | _ECHOE | _ECHONL;
-    terminal->iflags = _ICRNL | _IGNBRK;
-    terminal->oflags = _ONLCR | _OPOST;
-    memcpy(terminal->cc, default_cc, _NCCS * sizeof(cc_t));
+    struct capability_meta* term_cap = new_capability_marker(TERMIOS_CAP);
+    device_grant_capability(terminal->dev, term_cap);
+
+    load_default_setting(terminal);
 
     return terminal;
 }