renamed and cleaned up export header files to match linux convention
[lunaix-os.git] / lunaix-os / hal / term / term.c
index b566c555a1ca4c5a53d2beb9a8a94e4c1642eddd..59b7ebe81de1e5c96c53ec03aadfa17591cbd650 100644 (file)
@@ -5,18 +5,21 @@
 #include <lunaix/process.h>
 #include <lunaix/spike.h>
 #include <lunaix/status.h>
+#include <lunaix/syslog.h>
 
-#include <usr/lunaix/ioctl_defs.h>
+#include <usr/lunaix/ioctl.h>
+
+LOG_MODULE("term");
 
-#define ANSI_LCNTL 0
 #define termdev(dev) ((struct term*)(dev)->underlay)
 
-extern struct term_lcntl ansi_line_controller;
-static struct term_lcntl* line_controls[] = {[ANSI_LCNTL] =
-                                                 &ansi_line_controller};
 #define LCNTL_TABLE_LEN (sizeof(line_controls) / sizeof(struct term_lcntl*))
 
-static struct devclass termdev = DEVCLASS(DEVIF_NON, DEVFN_TTY, DEV_VTERM);
+static struct devclass termdev_class = DEVCLASS(LUNAIX, TTY, VTERM);
+
+struct device* sysconsole = NULL;
+
+extern struct termport_pot_ops default_termport_pot_ops;
 
 static int
 term_exec_cmd(struct device* dev, u32_t req, va_list args)
@@ -27,94 +30,92 @@ term_exec_cmd(struct device* dev, u32_t req, va_list args)
     device_lock(dev);
 
     switch (req) {
-    case TIOCSPGRP: {
-        pid_t pgid = va_arg(args, pid_t);
-        if (pgid < 0) {
-            err = EINVAL;
-            goto done;
+        case TIOCSPGRP: {
+            pid_t pgid = va_arg(args, pid_t);
+            if (pgid < 0) {
+                err = EINVAL;
+                goto done;
+            }
+            term->fggrp = pgid;
+            break;
         }
-        term->fggrp = pgid;
-        break;
-    }
-    case TIOCGPGRP:
-        return term->fggrp;
-    case TDEV_TCPUSHLC: {
-        u32_t lcntl_idx = va_arg(args, u32_t);
-        struct term_lcntl* lcntl = term_get_lcntl(lcntl_idx);
+        case TIOCGPGRP:
+            return term->fggrp;
+        case TDEV_TCSETCHDEV: {
+            int fd = va_arg(args, int);
+            struct v_fd* vfd;
+
+            if (vfs_getfd(fd, &vfd)) {
+                err = EINVAL;
+                goto done;
+            }
 
-        if (!lcntl) {
-            err = EINVAL;
-            goto done;
-        }
+            struct device* cdev = resolve_device(vfd->file->inode->data);
+            if (!cdev) {
+                err = ENOTDEV;
+                goto done;
+            }
+            if (cdev->dev_type != DEV_IFSEQ) {
+                err = EINVAL;
+                goto done;
+            }
 
-        term_push_lcntl(term, lcntl);
-        break;
-    }
-    case TDEV_TCPOPLC:
-        term_pop_lcntl(term);
-        break;
-    case TDEV_TCSETCHDEV: {
-        int fd = va_arg(args, int);
-        struct v_fd* vfd;
-
-        if (vfs_getfd(fd, &vfd)) {
-            err = EINVAL;
-            goto done;
+            term_bind(term, cdev);
+            break;
         }
+        case TDEV_TCGETCHDEV: {
+            struct dev_info* devinfo = va_arg(args, struct dev_info*);
 
-        struct device* cdev = device_cast(vfd->file->inode->data);
-        if (!cdev) {
-            err = ENOTDEV;
-            goto done;
-        }
-        if (cdev->dev_type != DEV_IFSEQ) {
-            err = EINVAL;
-            goto done;
+            if (!term->chdev) {
+                err = ENODEV;
+                goto done;
+            }
+
+            if (devinfo) {
+                device_populate_info(term->chdev, devinfo);
+            }
+            break;
         }
+        case TDEV_TCGETATTR: {
+            struct termios* tios = va_arg(args, struct termios*);
+            *tios = (struct termios){.c_oflag = term->oflags,
+                                      .c_iflag = term->iflags,
+                                      .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 termport_pot_ops* pot_ops;
+            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;
+            }
 
-        term_bind(term, cdev);
-        break;
-    }
-    case TDEV_TCGETCHDEV: {
-        struct dev_info* devinfo = va_arg(args, struct dev_info*);
+            pot_ops = term->tp_cap->ops;
 
-        if (!term->chdev) {
-            err = ENODEV;
-            goto done;
-        }
+            if (tios->c_baud != term->iospeed) {
+                term->iospeed = tios->c_baud;
 
-        if (devinfo) {
-            device_populate_info(term->chdev, devinfo);
-        }
-        break;
-    }
-    case TDEV_TCGETATTR: {
-        struct _termios* tios = va_arg(args, struct _termios*);
-        *tios = (struct _termios){.c_oflag = term->oflags,
-                                  .c_iflag = term->iflags,
-                                  .c_lflag = term->lflags};
-        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*);
-        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));
-
-        if (tios->c_baud != term->iospeed) {
-            term->iospeed = tios->c_baud;
-            if (!term->chdev_ops.set_speed) {
-                goto done;
+                pot_ops->set_speed(term->chdev, tios->c_baud);
             }
 
-            term->chdev_ops.set_speed(term->chdev, tios->c_baud);
-        }
-    } break;
-    default:
-        err = EINVAL;
-        goto done;
+            if (old_cf != tios->c_cflag) {
+                pot_ops->set_cntrl_mode(term->chdev, tios->c_cflag);
+            }
+        } break;
+        default:
+            err = EINVAL;
+            goto done;
     }
 
 done:
@@ -123,140 +124,123 @@ 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);
+        wrsz += rbuffer_puts(
+            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);
     bool cont = true;
     size_t rdsz = 0;
-    while (cont && rdsz < len) {
-        if (rbuffer_empty(deref(current))) {
-            tdev->line_in.sflags = 0;
-            cont = term_read(tdev);
-        }
 
-        rdsz += rbuffer_gets(deref(current), &((char*)buf)[offset + rdsz],
-                             len - rdsz);
+    while (cont && rdsz < len) {
+        cont = term_read(tdev);
+        rdsz += rbuffer_gets(
+            deref(current), &((char*)buf)[rdsz], len - rdsz);
     }
-
+    
+    tdev->line_in.sflags = 0;
     return rdsz;
 }
 
-static cc_t default_cc[_NCCS] = {4, '\n', 8, 3, 1, 24, 22, 0, 0, 1, 1};
+static cc_t default_cc[_NCCS] = {4, '\n', 0x7f, 3, 1, 24, 22, 0, 0, 1, 1};
 
-struct term*
-term_create(struct device* chardev, char* suffix)
+static void 
+load_default_setting(struct term* tdev) 
 {
-    struct term* terminal = vzalloc(sizeof(struct term));
+    tdev->lflags = _ICANON | _IEXTEN | _ISIG | _ECHO | _ECHOE | _ECHONL;
+    tdev->iflags = _ICRNL | _IGNBRK;
+    tdev->oflags = _ONLCR | _OPOST;
+    tdev->iospeed = _B9600;
+    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 termport_potens*
+term_attach_potens(struct device* chardev, 
+                   struct termport_pot_ops* ops, char* suffix)
+{
+    struct term* terminal;
+    struct device* tdev;
+    struct termport_potens* tp_cap;
+
+    terminal = vzalloc(sizeof(struct term));
     if (!terminal) {
         return NULL;
     }
 
-    terminal->dev = device_allocseq(NULL, terminal);
+    tdev = device_allocseq(NULL, terminal);
+    terminal->dev = tdev;
     terminal->chdev = chardev;
 
-    terminal->dev->ops.read = tdev_do_read;
-    terminal->dev->ops.write = tdev_do_write;
+    tdev->ops.read = tdev_do_read;
+    tdev->ops.write = tdev_do_write;
+    tdev->ops.exec_cmd = term_exec_cmd;
+
+    waitq_init(&terminal->line_in_event);
 
-    llist_init_head(&terminal->lcntl_stack);
-    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(tdev, &termdev_class, "tty%s%d", suffix, cdev_var);
     } else {
-        device_register(terminal->dev, &termdev, "tty%d", termdev.variant++);
+        register_device_var(tdev, &termdev_class, "tty");
     }
 
-    terminal->lflags = _ICANON | _IEXTEN | _ISIG | _ECHO;
-    terminal->iflags = _ICRNL;
-    memcpy(terminal->cc, default_cc, _NCCS * sizeof(cc_t));
-
-    return terminal;
-}
-
-int
-term_bind(struct term* term, struct device* chdev)
-{
-    device_lock(term->dev);
-
-    term->chdev = chdev;
-
-    device_unlock(term->dev);
-
-    return 0;
-}
+    INFO("spawned: %s", tdev->name_val);
 
-struct term_lcntl*
-term_get_lcntl(u32_t lcntl_index)
-{
-    if (lcntl_index >= LCNTL_TABLE_LEN) {
-        return NULL;
-    }
+    tp_cap = new_potens(potens(TERMPORT), struct termport_potens);
+    tp_cap->ops = ops ?: &default_termport_pot_ops;
 
-    struct term_lcntl* lcntl_template = line_controls[lcntl_index];
-    struct term_lcntl* lcntl_instance = valloc(sizeof(struct term_lcntl));
+    terminal->tp_cap = tp_cap;
+    tp_cap->term = terminal;
 
-    if (!lcntl_instance) {
-        return NULL;
-    }
+    device_grant_potens(tdev, potens_meta(tp_cap));
 
-    lcntl_instance->process_and_put = lcntl_template->process_and_put;
+    load_default_setting(terminal);
 
-    return lcntl_instance;
+    return tp_cap;
 }
 
 int
-term_push_lcntl(struct term* term, struct term_lcntl* lcntl)
+term_bind(struct term* term, struct device* chdev)
 {
     device_lock(term->dev);
 
-    llist_append(&term->lcntl_stack, &lcntl->lcntls);
+    term->chdev = chdev;
 
     device_unlock(term->dev);
 
     return 0;
 }
 
-int
-term_pop_lcntl(struct term* term)
-{
-    if (term->lcntl_stack.prev == &term->lcntl_stack) {
-        return 0;
-    }
-
-    device_lock(term->dev);
-
-    struct term_lcntl* lcntl =
-        list_entry(term->lcntl_stack.prev, struct term_lcntl, lcntls);
-    llist_delete(term->lcntl_stack.prev);
-
-    vfree(lcntl);
-
-    device_unlock(term->dev);
-
-    return 1;
-}
-
 void
 line_alloc(struct linebuffer* lbf, size_t sz_hlf)
 {
@@ -279,6 +263,7 @@ void
 term_sendsig(struct term* tdev, int signal)
 {
     if ((tdev->lflags & _ISIG)) {
-        proc_setsignal(get_process(tdev->fggrp), signal);
+        signal_send(-tdev->fggrp, signal);
+        pwake_all(&tdev->line_in_event);
     }
 }
\ No newline at end of file