X-Git-Url: https://scm.lunaixsky.com/lunaix-os.git/blobdiff_plain/59ecf21e36b2332f6adf2a568ef555283d8c119a..bdc143a7aa3f51a46eceec62b0b364599533fa21:/lunaix-os/hal/term/term.c diff --git a/lunaix-os/hal/term/term.c b/lunaix-os/hal/term/term.c index b566c55..9f65d38 100644 --- a/lunaix-os/hal/term/term.c +++ b/lunaix-os/hal/term/term.c @@ -8,15 +8,13 @@ #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 = DEVCLASS(DEVIF_NON, DEVFN_TTY, DEV_VTERM); +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) @@ -27,94 +25,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_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; + } - term_bind(term, cdev); - break; - } - case TDEV_TCGETCHDEV: { - struct dev_info* devinfo = va_arg(args, struct dev_info*); + cap_ops = term->tp_cap->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; + cap_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) { + cap_ops->set_cntrl_mode(term->chdev, tios->c_cflag); + } + } break; + default: + err = EINVAL; + goto done; } done: @@ -123,140 +119,125 @@ 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}; + +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)); +} + +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 device* chardev, char* suffix) { - struct term* terminal = vzalloc(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); + 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(tdev, &termdev_class, "tty%d", termdev_class.variant++); } - 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; -} - -struct term_lcntl* -term_get_lcntl(u32_t lcntl_index) -{ - if (lcntl_index >= LCNTL_TABLE_LEN) { - 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; } - struct term_lcntl* lcntl_template = line_controls[lcntl_index]; - struct term_lcntl* lcntl_instance = valloc(sizeof(struct term_lcntl)); + tios_cap = new_capability_marker(TERMIOS_CAP); + device_grant_capability(tdev, tios_cap); - if (!lcntl_instance) { - return NULL; - } + load_default_setting(terminal); - lcntl_instance->process_and_put = lcntl_template->process_and_put; - - 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_alloc(struct linebuffer* lbf, size_t sz_hlf) { @@ -279,6 +260,6 @@ void term_sendsig(struct term* tdev, int signal) { if ((tdev->lflags & _ISIG)) { - proc_setsignal(get_process(tdev->fggrp), signal); + signal_send(-tdev->fggrp, signal); } } \ No newline at end of file