X-Git-Url: https://scm.lunaixsky.com/lunaix-os.git/blobdiff_plain/8b8f49b713d64065775fe538232f8639083601bd..bffa3430fbbaaad29bec0b5bee9c1f0bfc7fd068:/lunaix-os/hal/term/term.c diff --git a/lunaix-os/hal/term/term.c b/lunaix-os/hal/term/term.c index 2130105..4353265 100644 --- a/lunaix-os/hal/term/term.c +++ b/lunaix-os/hal/term/term.c @@ -2,22 +2,24 @@ #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 }; #define LCNTL_TABLE_LEN (sizeof(line_controls) / sizeof(struct term_lcntl*)) +static struct devclass termdev_class = 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) { - struct term* term = (struct term*)dev->underlay; + struct term* term = termdev(dev); int err = 0; device_lock(dev); @@ -34,22 +36,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 +45,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 +58,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 +71,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_cap_ops* cap_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; + } + + cap_ops = term->tp_cap->cap_ops; + + if (tios->c_baud != term->iospeed) { + term->iospeed = tios->c_baud; + + cap_ops->set_speed(term->chdev, tios->c_baud); + } + + if (old_cf != tios->c_cflag) { + cap_ops->set_cntrl_mode(term->chdev, tios->c_cflag); + } + } break; default: err = EINVAL; goto done; @@ -95,218 +119,148 @@ 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() +term_create(struct device* chardev, char* suffix) { - struct term* terminal = valloc(sizeof(struct term)); + struct term* terminal; + struct device* tdev; + struct capability_meta* termport_cap; + struct capability_meta* tios_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; + tdev = device_allocseq(NULL, terminal); + terminal->dev = tdev; + terminal->chdev = chardev; - 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; + 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(tdev, &termdev_class, "tty%d", termdev_class.variant++); } - struct term_lcntl* lcntl_template = line_controls[lcntl_index]; - struct term_lcntl* lcntl_instance = valloc(sizeof(struct term_lcntl)); - - if (!lcntl_instance) { - return NULL; + termport_cap = device_get_capability(chardev, TERMPORT_CAP); + if (termport_cap) { + terminal->tp_cap = + get_capability(termport_cap, struct termport_capability); + + assert(terminal->tp_cap->cap_ops); + terminal->tp_cap->term = terminal; } - lcntl_instance->apply = lcntl_template->apply; - - return lcntl_instance; -} - -int -term_push_lcntl(struct term* term, struct term_lcntl* lcntl) -{ - device_lock(term->dev); - - llist_append(&term->lcntl_stack, &lcntl->lcntls); + tios_cap = new_capability_marker(TERMIOS_CAP); + device_grant_capability(tdev, tios_cap); - device_unlock(term->dev); + load_default_setting(terminal); - return 0; + return terminal; } 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