#include <lunaix/process.h>
#include <lunaix/spike.h>
#include <lunaix/status.h>
+#include <lunaix/syslog.h>
-#include <usr/lunaix/ioctl_defs.h>
+#include <usr/lunaix/ioctl.h>
+
+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)
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;
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:
}
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
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