X-Git-Url: https://scm.lunaixsky.com/lunaix-os.git/blobdiff_plain/64e5fa9a495e388c922157b9a616204c299f5e05..a8e9a00d034efa9e6b483c4a3decddf9f9686db2:/lunaix-os/hal/term/term.c diff --git a/lunaix-os/hal/term/term.c b/lunaix-os/hal/term/term.c index 0c404a5..59b7ebe 100644 --- a/lunaix-os/hal/term/term.c +++ b/lunaix-os/hal/term/term.c @@ -5,18 +5,21 @@ #include #include #include +#include -#include +#include + +LOG_MODULE("term"); -#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(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) @@ -47,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; @@ -74,27 +77,40 @@ 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, + struct termios* tios = va_arg(args, struct termios*); + *tios = (struct termios){.c_oflag = term->oflags, .c_iflag = term->iflags, - .c_lflag = term->lflags}; + .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 _termios* tios = va_arg(args, struct _termios*); + 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; - if (!term->chdev_ops.set_speed) { - goto done; - } - term->chdev_ops.set_speed(term->chdev, 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: @@ -108,79 +124,109 @@ 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); + 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); - } + while (cont && rdsz < len) { + cont = term_read(tdev); rdsz += rbuffer_gets( - deref(current), &((char*)buf)[offset + rdsz], len - rdsz); + deref(current), &((char*)buf)[rdsz], len - rdsz); } - + + tdev->line_in.sflags = 0; return rdsz; } static cc_t default_cc[_NCCS] = {4, '\n', 0x7f, 3, 1, 24, 22, 0, 0, 1, 1}; -struct term* -term_create(struct device* chardev, char* suffix) +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) { - struct term* terminal = vzalloc(sizeof(struct term)); + line_alloc(&terminal->line_in, sz_hlf); + line_alloc(&terminal->line_out, sz_hlf); + terminal->scratch_pad = valloc(sz_hlf); +} + +struct termport_potens* +term_attach_potens(struct device* chardev, + struct termport_pot_ops* ops, char* suffix) +{ + 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); + 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; - // TODO choice of lcntl can be flexible - terminal->lcntl = line_controls[ANSI_LCNTL]; + waitq_init(&terminal->line_in_event); - 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_var(tdev, &termdev_class, "tty"); } - 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)); + INFO("spawned: %s", tdev->name_val); + + tp_cap = new_potens(potens(TERMPORT), struct termport_potens); + tp_cap->ops = ops ?: &default_termport_pot_ops; + + terminal->tp_cap = tp_cap; + tp_cap->term = terminal; + + device_grant_potens(tdev, potens_meta(tp_cap)); + + load_default_setting(terminal); - return terminal; + return tp_cap; } int @@ -217,6 +263,7 @@ void term_sendsig(struct term* tdev, int signal) { if ((tdev->lflags & _ISIG)) { - proc_setsignal(get_process(tdev->fggrp), signal); + signal_send(-tdev->fggrp, signal); + pwake_all(&tdev->line_in_event); } } \ No newline at end of file