X-Git-Url: https://scm.lunaixsky.com/lunaix-os.git/blobdiff_plain/8b8f49b713d64065775fe538232f8639083601bd..a8e9a00d034efa9e6b483c4a3decddf9f9686db2:/lunaix-os/hal/term/term.c diff --git a/lunaix-os/hal/term/term.c b/lunaix-os/hal/term/term.c index 2130105..59b7ebe 100644 --- a/lunaix-os/hal/term/term.c +++ b/lunaix-os/hal/term/term.c @@ -2,22 +2,29 @@ #include #include #include +#include #include #include +#include -#include +#include -#define ANSI_LCNTL 0 +LOG_MODULE("term"); + +#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_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) { - struct term* term = (struct term*)dev->underlay; + struct term* term = termdev(dev); int err = 0; device_lock(dev); @@ -34,22 +41,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; @@ -58,7 +50,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; @@ -71,7 +63,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 +76,43 @@ 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, + .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; + } + + pot_ops = term->tp_cap->ops; + + if (tios->c_baud != term->iospeed) { + term->iospeed = tios->c_baud; + + pot_ops->set_speed(term->chdev, tios->c_baud); + } + + if (old_cf != tios->c_cflag) { + pot_ops->set_cntrl_mode(term->chdev, tios->c_cflag); + } + } break; default: err = EINVAL; goto done; @@ -95,218 +124,146 @@ done: } static int -term_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* term = (struct term*)dev->underlay; - size_t sz = MIN(len, term->line.sz_hlf); - - if (!term->chdev) { - return ENODEV; + 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)[wrsz], len - wrsz); + + if (rbuffer_full(deref(current))) { + term_flush(tdev); + } } - - 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); + + if (!rbuffer_empty(deref(current))) { + term_flush(tdev); } - - int errcode = term_sendline(term, sz); - - device_unlock(term->dev); - - return errcode; + return wrsz; } static int -term_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* 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_lcntl *pos, *n; - llist_for_each(pos, n, &term->lcntl_stack, lcntls) - { - sz = pos->apply(term, term->line.current, sz); - line_flip(&term->line); + 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) { + cont = term_read(tdev); + rdsz += rbuffer_gets( + deref(current), &((char*)buf)[rdsz], len - rdsz); } + + tdev->line_in.sflags = 0; + return rdsz; +} - memcpy(&((char*)buf)[offset], term->line.current, sz); +static cc_t default_cc[_NCCS] = {4, '\n', 0x7f, 3, 1, 24, 22, 0, 0, 1, 1}; - device_unlock(term->dev); +static void +load_default_setting(struct term* tdev) +{ + 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)); +} - return sz; +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 termport_potens* +term_attach_potens(struct device* chardev, + struct termport_pot_ops* ops, char* suffix) { - struct term* terminal = valloc(sizeof(struct term)); + 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); - - 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; -} + tdev = device_allocseq(NULL, terminal); + terminal->dev = tdev; + terminal->chdev = chardev; -int -term_bind(struct term* term, struct device* chdev) -{ - device_lock(term->dev); - - term->chdev = chdev; + tdev->ops.read = tdev_do_read; + tdev->ops.write = tdev_do_write; + tdev->ops.exec_cmd = term_exec_cmd; - device_unlock(term->dev); + waitq_init(&terminal->line_in_event); - return 0; -} + alloc_term_buffer(terminal, 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); + register_device(tdev, &termdev_class, "tty%s%d", suffix, cdev_var); + } else { + register_device_var(tdev, &termdev_class, "tty"); } - struct term_lcntl* lcntl_template = line_controls[lcntl_index]; - struct term_lcntl* lcntl_instance = valloc(sizeof(struct term_lcntl)); + INFO("spawned: %s", tdev->name_val); - if (!lcntl_instance) { - return NULL; - } - - lcntl_instance->apply = lcntl_template->apply; - - return lcntl_instance; -} + tp_cap = new_potens(potens(TERMPORT), struct termport_potens); + tp_cap->ops = ops ?: &default_termport_pot_ops; -int -term_push_lcntl(struct term* term, struct term_lcntl* lcntl) -{ - device_lock(term->dev); + terminal->tp_cap = tp_cap; + tp_cap->term = terminal; - llist_append(&term->lcntl_stack, &lcntl->lcntls); + device_grant_potens(tdev, potens_meta(tp_cap)); - device_unlock(term->dev); + load_default_setting(terminal); - return 0; + return tp_cap; } int -term_pop_lcntl(struct term* term) +term_bind(struct term* term, struct device* chdev) { - 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); + term->chdev = chdev; device_unlock(term->dev); - return 1; -} - -void -line_flip(struct linebuffer* lbf) -{ - char* tmp = lbf->current; - lbf->current = lbf->next; - lbf->next = tmp; + return 0; } 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)) { + signal_send(-tdev->fggrp, signal); + pwake_all(&tdev->line_in_event); + } +} \ No newline at end of file