X-Git-Url: https://scm.lunaixsky.com/lunaix-os.git/blobdiff_plain/8b8f49b713d64065775fe538232f8639083601bd..64e5fa9a495e388c922157b9a616204c299f5e05:/lunaix-os/hal/term/term.c diff --git a/lunaix-os/hal/term/term.c b/lunaix-os/hal/term/term.c index 2130105..0c404a5 100644 --- a/lunaix-os/hal/term/term.c +++ b/lunaix-os/hal/term/term.c @@ -2,22 +2,26 @@ #include #include #include +#include #include #include #include #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 }; +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 int term_exec_cmd(struct device* dev, u32_t req, va_list args) { - struct term* term = (struct term*)dev->underlay; + struct term* term = termdev(dev); int err = 0; device_lock(dev); @@ -34,22 +38,7 @@ term_exec_cmd(struct device* dev, u32_t req, va_list args) } case TIOCGPGRP: return term->fggrp; - case TIOCPUSH: { - u32_t lcntl_idx = va_arg(args, u32_t); - struct term_lcntl* lcntl = term_get_lcntl(lcntl_idx); - - if (!lcntl) { - err = EINVAL; - goto done; - } - - term_push_lcntl(term, lcntl); - break; - } - case TIOCPOP: - term_pop_lcntl(term); - break; - case TIOCSCDEV: { + case TDEV_TCSETCHDEV: { int fd = va_arg(args, int); struct v_fd* vfd; @@ -71,7 +60,7 @@ term_exec_cmd(struct device* dev, u32_t req, va_list args) term_bind(term, cdev); break; } - case TIOCGCDEV: { + case TDEV_TCGETCHDEV: { struct dev_info* devinfo = va_arg(args, struct dev_info*); if (!term->chdev) { @@ -84,6 +73,30 @@ 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, + .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; + } + + term->chdev_ops.set_speed(term->chdev, tios->c_baud); + } + } break; default: err = EINVAL; goto done; @@ -95,218 +108,115 @@ done: } static int -term_write(struct device* dev, void* buf, size_t offset, size_t len) +tdev_do_write(struct device* dev, void* buf, size_t offset, size_t len) { - struct term* term = (struct term*)dev->underlay; - size_t sz = MIN(len, term->line.sz_hlf); - - if (!term->chdev) { - return ENODEV; - } - - device_lock(term->dev); - - memcpy(term->line.current, &((char*)buf)[offset], sz); - - struct term_lcntl *lcntl, *n; - llist_for_each(lcntl, n, &term->lcntl_stack, lcntls) - { - sz = lcntl->apply(term, term->line.current, sz); - line_flip(&term->line); + 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); + + if (rbuffer_full(deref(current))) { + term_flush(tdev); + } } - int errcode = term_sendline(term, sz); - - device_unlock(term->dev); - - return errcode; + return 0; } static int -term_read(struct device* dev, void* buf, size_t offset, size_t len) +tdev_do_read(struct device* dev, void* buf, size_t offset, size_t len) { - struct term* term = (struct term*)dev->underlay; - size_t sz = MIN(len, term->line.sz_hlf); - - if (!term->chdev) { - return ENODEV; - } - - device_lock(term->dev); - - sz = term_readline(term, sz); - if (!sz) { - device_unlock(term->dev); - return 0; - } + 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); + } - struct term_lcntl *pos, *n; - llist_for_each(pos, n, &term->lcntl_stack, lcntls) - { - sz = pos->apply(term, term->line.current, sz); - line_flip(&term->line); + rdsz += rbuffer_gets( + deref(current), &((char*)buf)[offset + rdsz], len - rdsz); } - memcpy(&((char*)buf)[offset], term->line.current, sz); - - device_unlock(term->dev); - - return sz; + return rdsz; } +static cc_t default_cc[_NCCS] = {4, '\n', 0x7f, 3, 1, 24, 22, 0, 0, 1, 1}; + struct term* -term_create() +term_create(struct device* chardev, char* suffix) { - struct term* terminal = valloc(sizeof(struct term)); + struct term* terminal = vzalloc(sizeof(struct term)); if (!terminal) { return NULL; } terminal->dev = device_allocseq(NULL, terminal); + terminal->chdev = chardev; - terminal->dev->ops.read = term_read; - terminal->dev->ops.write = term_write; - - llist_init_head(&terminal->lcntl_stack); - line_alloc(&terminal->line, 1024); - - return terminal; -} - -int -term_bind(struct term* term, struct device* chdev) -{ - device_lock(term->dev); - - term->chdev = chdev; + terminal->dev->ops.read = tdev_do_read; + terminal->dev->ops.write = tdev_do_write; - device_unlock(term->dev); + // TODO choice of lcntl can be flexible + terminal->lcntl = line_controls[ANSI_LCNTL]; - return 0; -} + line_alloc(&terminal->line_in, 1024); + line_alloc(&terminal->line_out, 1024); -struct term_lcntl* -term_get_lcntl(u32_t lcntl_index) -{ - if (lcntl_index >= LCNTL_TABLE_LEN) { - return NULL; + if (chardev) { + int cdev_var = DEV_VAR_FROM(chardev->ident.unique); + device_register(terminal->dev, &termdev, "tty%s%d", suffix, cdev_var); + } else { + device_register(terminal->dev, &termdev, "tty%d", termdev.variant++); } - struct term_lcntl* lcntl_template = line_controls[lcntl_index]; - struct term_lcntl* lcntl_instance = valloc(sizeof(struct term_lcntl)); + 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)); - if (!lcntl_instance) { - return NULL; - } - - lcntl_instance->apply = lcntl_template->apply; - - return lcntl_instance; + return terminal; } 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_flip(struct linebuffer* lbf) -{ - char* tmp = lbf->current; - lbf->current = lbf->next; - lbf->next = tmp; -} - void line_alloc(struct linebuffer* lbf, size_t sz_hlf) { char* buffer = valloc(sz_hlf * 2); - lbf->current = buffer; - lbf->next = &buffer[sz_hlf]; + memset(lbf, 0, sizeof(*lbf)); + lbf->current = rbuffer_create(buffer, sz_hlf); + lbf->next = rbuffer_create(&buffer[sz_hlf], sz_hlf); lbf->sz_hlf = sz_hlf; } void line_free(struct linebuffer* lbf, size_t sz_hlf) { - void* ptr = (void*)MIN((ptr_t)lbf->current, (ptr_t)lbf->next); + void* ptr = + (void*)MIN((ptr_t)lbf->current->buffer, (ptr_t)lbf->next->buffer); vfree(ptr); } -int -term_sendline(struct term* tdev, size_t len) -{ - struct device* chdev = tdev->chdev; - - device_lock(chdev); - - int code = chdev->ops.write(chdev, tdev->line.current, 0, len); - - device_unlock(chdev); - - return code; -} - -int -term_readline(struct term* tdev, size_t len) -{ - struct device* chdev = tdev->chdev; - - device_lock(chdev); - - int code = chdev->ops.read(chdev, tdev->line.current, 0, len); - - device_unlock(chdev); - - return code; -} - -int -term_init(struct device_def* devdef) +void +term_sendsig(struct term* tdev, int signal) { - struct term* terminal = term_create(); - struct device* tdev = device_allocseq(NULL, terminal); - tdev->ops.read = term_read; - tdev->ops.write = term_write; - tdev->ops.exec_cmd = term_exec_cmd; - - devdef->class.variant++; - device_register(tdev, &devdef->class, "tty%d", devdef->class.variant); - - return 0; -} - -static struct device_def vterm_def = { - .class = DEVCLASS(DEVIF_NON, DEVFN_TTY, DEV_VTERM), - .name = "virtual terminal", - .init = term_init -}; -EXPORT_DEVICE(vterm, &vterm_def, load_on_demand); \ No newline at end of file + if ((tdev->lflags & _ISIG)) { + proc_setsignal(get_process(tdev->fggrp), signal); + } +} \ No newline at end of file