X-Git-Url: https://scm.lunaixsky.com/lunaix-os.git/blobdiff_plain/78cd005fac540973751b5a108c37a715bc64b5a2..59ecf21e36b2332f6adf2a568ef555283d8c119a:/lunaix-os/hal/term/term.c diff --git a/lunaix-os/hal/term/term.c b/lunaix-os/hal/term/term.c index 2130105..b566c55 100644 --- a/lunaix-os/hal/term/term.c +++ b/lunaix-os/hal/term/term.c @@ -2,91 +2,119 @@ #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); switch (req) { - case TIOCSPGRP: { - pid_t pgid = va_arg(args, pid_t); - if (pgid < 0) { - err = EINVAL; - goto done; - } - term->fggrp = pgid; - break; + case TIOCSPGRP: { + pid_t pgid = va_arg(args, pid_t); + if (pgid < 0) { + err = EINVAL; + goto done; } - 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->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); - term_push_lcntl(term, lcntl); - break; + if (!lcntl) { + err = EINVAL; + goto done; } - case TIOCPOP: - term_pop_lcntl(term); - break; - case TIOCSCDEV: { - int fd = va_arg(args, int); - struct v_fd* vfd; - - if (vfs_getfd(fd, &vfd)) { - err = EINVAL; - goto done; - } - 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; - } + 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; + } + + 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; + } + + term_bind(term, cdev); + break; + } + case TDEV_TCGETCHDEV: { + struct dev_info* devinfo = va_arg(args, struct dev_info*); - term_bind(term, cdev); - break; + if (!term->chdev) { + err = ENODEV; + goto done; } - case TIOCGCDEV: { - struct dev_info* devinfo = va_arg(args, struct dev_info*); - if (!term->chdev) { - err = ENODEV; + 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; } - if (devinfo) { - device_populate_info(term->chdev, devinfo); - } - break; + term->chdev_ops.set_speed(term->chdev, tios->c_baud); } - default: - err = EINVAL; - goto done; + } break; + default: + err = EINVAL; + goto done; } done: @@ -95,81 +123,73 @@ 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', 8, 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; + terminal->dev->ops.read = tdev_do_read; + terminal->dev->ops.write = tdev_do_write; llist_init_head(&terminal->lcntl_stack); - line_alloc(&terminal->line, 1024); + line_alloc(&terminal->line_in, 1024); + line_alloc(&terminal->line_out, 1024); + + 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++); + } + + terminal->lflags = _ICANON | _IEXTEN | _ISIG | _ECHO; + terminal->iflags = _ICRNL; + memcpy(terminal->cc, default_cc, _NCCS * sizeof(cc_t)); return terminal; } @@ -200,7 +220,7 @@ term_get_lcntl(u32_t lcntl_index) return NULL; } - lcntl_instance->apply = lcntl_template->apply; + lcntl_instance->process_and_put = lcntl_template->process_and_put; return lcntl_instance; } @@ -227,7 +247,7 @@ term_pop_lcntl(struct term* term) device_lock(term->dev); struct term_lcntl* lcntl = - list_entry(term->lcntl_stack.prev, struct term_lcntl, lcntls); + list_entry(term->lcntl_stack.prev, struct term_lcntl, lcntls); llist_delete(term->lcntl_stack.prev); vfree(lcntl); @@ -237,76 +257,28 @@ term_pop_lcntl(struct term* term) 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