"devnull.c",
"serial.c",
"devzero.c",
- "lxconsole.c",
-])
\ No newline at end of file
+])
+
+if config("vga_console"):
+ sources("lxconsole.c")
\ No newline at end of file
""" Controlling support of character devices """
add_to_collection(hal)
+
+ @Term
+ def vga_console():
+ """ Enable VGA console device (text mode only) """
+
+ type(bool)
+ default(True)
static int
__zero_rd_pg(struct device* dev, void* buf, size_t offset)
{
- memset(&((u8_t*)buf)[offset], 0, PAGE_SIZE);
+ memset(buf, 0, PAGE_SIZE);
return PAGE_SIZE;
}
static int
__zero_rd(struct device* dev, void* buf, size_t offset, size_t len)
{
- memset(&((u8_t*)buf)[offset], 0, len);
+ memset(buf, 0, len);
return len;
}
struct console
{
+ struct capability_meta* tp_cap;
struct lx_timer* flush_timer;
struct fifo_buf output;
struct fifo_buf input;
}
fifo_putone(&lx_console.input, ttychr);
- pwake_all(&lx_reader);
+ struct termport_capability* tpcap;
+ tpcap = get_capability(lx_console.tp_cap, typeof(*tpcap));
+ term_notify_data_avaliable(tpcap);
+
+ pwake_all(&lx_reader);
done:
return INPUT_EVT_NEXT;
}
return count + fifo_read(&console->input, buf + count, len - count);
}
+int
+__tty_read_async(struct device* dev, void* buf, size_t offset, size_t len)
+{
+ struct console* console = (struct console*)dev->underlay;
+
+ return fifo_read(&console->input, buf, len);
+}
+
size_t
__find_next_line(size_t start)
{
tty_dev->ops.write_page = __tty_write_pg;
tty_dev->ops.read = __tty_read;
tty_dev->ops.read_page = __tty_read_pg;
+ tty_dev->ops.write_async = __tty_write;
+ tty_dev->ops.read_async = __tty_read_async;
waitq_init(&lx_reader);
input_add_listener(__lxconsole_listener);
+ struct termport_capability* tp_cap;
+
+ tp_cap = new_capability(TERMPORT_CAP, struct termport_capability);
+ term_cap_set_operations(tp_cap, termport_default_ops);
+
+ lx_console.tp_cap = cap_meta(tp_cap);
+ device_grant_capability(tty_dev, lx_console.tp_cap);
+
register_device(tty_dev, &devdef->class, "vcon");
- term_create(tty_dev, "FB");
+ term_create(tty_dev, "VCON");
return 0;
}
.class = DEVCLASS(DEVIF_NON, DEVFN_TTY, DEV_BUILTIN),
.init = lxconsole_spawn_ttydev
};
-// FIXME
EXPORT_DEVICE(lxconsole, &lxconsole_def, load_onboot);
\ No newline at end of file
mark_device_done_read(sdev->dev);
pwake_one(&sdev->wq_rxdone);
+
+ struct termport_capability* tpcap;
+ tpcap = get_capability(sdev->tp_cap, typeof(*tpcap));
+ term_notify_data_avaliable(tpcap);
}
void
struct serial_dev* sdev = serial_device(dev);
lock_sdev(sdev);
- sdev_execmd(sdev, SERIO_SETBRDIV, speed);
+ sdev_execmd(sdev, SERIO_SETBRDRATE, speed);
+
+ unlock_sdev(sdev);
+}
+
+static void
+__serial_set_baseclk(struct device* dev, unsigned int base)
+{
+ struct serial_dev* sdev = serial_device(dev);
+ lock_sdev(sdev);
+
+ sdev_execmd(sdev, SERIO_SETBRDBASE, base);
unlock_sdev(sdev);
}
#define RXBUF_SIZE 512
+static struct termport_cap_ops tpcap_ops = {
+ .set_cntrl_mode = __serial_set_cntrl_mode,
+ .set_clkbase = __serial_set_baseclk,
+ .set_speed = __serial_set_speed
+};
+
struct serial_dev*
serial_create(struct devclass* class, char* if_ident)
{
- struct serial_dev* sdev = valloc(sizeof(struct serial_dev));
+ struct serial_dev* sdev = vzalloc(sizeof(struct serial_dev));
struct device* dev = device_allocseq(dev_meta(serial_cat), sdev);
dev->ops.read = __serial_read;
dev->ops.read_page = __serial_read_page;
struct termport_capability* tp_cap =
new_capability(TERMPORT_CAP, struct termport_capability);
- tp_cap->set_speed = __serial_set_speed;
- tp_cap->set_cntrl_mode = __serial_set_cntrl_mode;
+
+ term_cap_set_operations(tp_cap, &tpcap_ops);
+ sdev->tp_cap = cap_meta(tp_cap);
waitq_init(&sdev->wq_rxdone);
waitq_init(&sdev->wq_txdone);
struct llist_header local_ports;
struct serial_dev* sdev;
ptr_t base_addr;
+ unsigned int base_clk;
int iv;
struct
uart_free(struct uart16550*);
static inline int
-uart_baud_divisor(struct uart16550* uart, int div)
+uart_baud_divisor(struct uart16550* uart, unsigned int div)
{
u32_t rlc = uart->read_reg(uart, UART_rLC);
uart->write_reg(uart, UART_rLC, UART_rLC_DLAB | rlc);
- u8_t ls = (div & 0xff), ms = (div & 0xff00) >> 8;
+ u8_t ls = (div & 0x00ff), ms = (div & 0xff00) >> 8;
uart->write_reg(uart, UART_rLS, ls);
uart->write_reg(uart, UART_rMS, ms);
uart->cntl_save.rie = 0;
uart->base_addr = base_addr;
+ uart->base_clk = 115200U;
return uart;
}
case SERIO_RXDA:
uart_clrie(uart);
break;
- case SERIO_SETBRDIV:
- // TODO
- break;
+ case SERIO_SETBRDRATE:
+ {
+ unsigned int div, rate;
+
+ rate = va_arg(args, speed_t);
+ if (!rate) {
+ return EINVAL;
+ }
+
+ div = uart->base_clk / va_arg(args, speed_t);
+ uart_baud_divisor(uart, div);
+ break;
+ }
+ case SERIO_SETBRDBASE:
+ {
+ int clk = va_arg(args, unsigned int);
+ if (!clk) {
+ return EINVAL;
+ }
+
+ uart->base_clk = clk;
+ break;
+ }
case SERIO_SETCNTRLMODE:
uart_set_control_mode(uart, va_arg(args, tcflag_t));
break;
"vga_gfxm_ops.c",
"vga.c",
"vga_mmio_ops.c",
- "vga_pci.c"
+ "vga_pci.c",
+ "vga_rawtty.c",
])
\ No newline at end of file
#include <lunaix/spike.h>
#include <lunaix/tty/tty.h>
#include <stdint.h>
+#include <lunaix/owloysius.h>
+#include <lunaix/mm/pagetable.h>
+#include <lunaix/mm/mmio.h>
#include <sys/port_io.h>
}
str++;
}
-}
\ No newline at end of file
+}
+
+static void
+vga_rawtty_init()
+{
+ // FIXME we should get rid of it at some point
+ tty_init((void*)ioremap(0xB8000, PAGE_SIZE));
+ tty_set_theme(VGA_COLOR_WHITE, VGA_COLOR_BLACK);
+}
+owloysius_fetch_init(vga_rawtty_init, on_earlyboot);
\ No newline at end of file
"term.c",
"console.c",
"term_io.c",
+ "default_ops.c",
"lcntls/ansi_cntl.c",
"lcntls/lcntl.c",
])
\ No newline at end of file
--- /dev/null
+#include <hal/term.h>
+
+static void
+__tpcap_default_set_speed(struct device* dev, speed_t speed)
+{
+
+}
+
+static void
+__tpcap_default_set_baseclk(struct device* dev, unsigned int base)
+{
+
+}
+
+static void
+__tpcap_default_set_cntrl_mode(struct device* dev, tcflag_t cflag)
+{
+
+}
+
+struct termport_cap_ops default_termport_cap_ops = {
+ .set_cntrl_mode = __tpcap_default_set_cntrl_mode,
+ .set_clkbase = __tpcap_default_set_baseclk,
+ .set_speed = __tpcap_default_set_speed
+};
\ No newline at end of file
* @copyright Copyright (c) 2023
*
*/
-#include <hal/term.h>
+#include "lcntl.h"
#include <usr/lunaix/term.h>
#define CTRL_MNEMO(chr) (chr - 'A' + 1)
-static inline int
-__ansi_actcontrol(struct term* termdev, struct linebuffer* lbuf, char chr)
+int
+__ansi_actcontrol(struct lcntl_state* state, char chr)
{
- struct rbuffer* cooked = lbuf->next;
- switch (chr) {
- default:
- if ((int)chr < 32) {
- rbuffer_put(cooked, '^');
- return rbuffer_put(cooked, chr += 64);
- }
- break;
+ if (chr < 32 && chr != '\n') {
+ lcntl_put_char(state, '^');
+ return lcntl_put_char(state, chr += 64);
}
- return rbuffer_put_nof(cooked, chr);
+ return lcntl_put_char(state, chr);
}
-
-struct term_lcntl ansi_line_controller = {.process_and_put = __ansi_actcontrol};
\ No newline at end of file
#include <hal/term.h>
#include <usr/lunaix/term.h>
+#include "lcntl.h"
+
#include <lunaix/process.h>
#include <lunaix/spike.h>
static inline void
-raise_sig(struct term* at_term, struct linebuffer* lbuf, int sig)
+init_lcntl_state(struct lcntl_state* state,
+ struct term* tdev, enum lcntl_dir direction)
{
- term_sendsig(at_term, sig);
- lbuf->sflags |= LSTATE_SIGRAISE;
+ *state = (struct lcntl_state) {
+ .tdev = tdev,
+ ._lf = tdev->lflags,
+ ._cf = tdev->cflags,
+ .direction = direction,
+ .echobuf = tdev->line_out.current,
+ };
+
+ struct linebuffer* lb;
+ if (direction == INBOUND) {
+ state->_if = tdev->iflags;
+ lb = &tdev->line_in;
+ }
+ else {
+ state->_of = tdev->oflags;
+ lb = &tdev->line_out;
+ }
+
+ state->inbuf = lb->current;
+ state->outbuf = lb->next;
+ state->active_line = lb;
}
-static inline int must_inline optimize("-fipa-cp-clone")
-lcntl_transform_seq(struct term* tdev, struct linebuffer* lbuf, bool out)
+static inline void
+raise_sig(struct lcntl_state* state, int sig)
{
- struct rbuffer* raw = lbuf->current;
- struct rbuffer* cooked = lbuf->next;
- struct rbuffer* output = tdev->line_out.current;
+ term_sendsig(state->tdev, sig);
+ lcntl_raise_line_event(state, LEVT_SIGRAISE);
+}
- int i = 0, _if = tdev->iflags & -!out, _of = tdev->oflags & -!!out,
- _lf = tdev->lflags;
- int allow_more = 1, latest_eol = cooked->ptr;
- char c;
+static inline char
+__remap_character(struct lcntl_state* state, char c)
+{
+ if (c == '\r') {
+ if ((state->_if & _ICRNL) || (state->_of & _OCRNL)) {
+ return '\n';
+ }
+ }
+ else if (c == '\n') {
+ if ((state->_if & _INLCR) || (state->_of & (_ONLRET))) {
+ return '\r';
+ }
+ }
+ else if ('a' <= c && c <= 'z') {
+ if ((state->_if & _IUCLC)) {
+ return c | 0b100000;
+ } else if ((state->_of & _OLCUC)) {
+ return c & ~0b100000;
+ }
+ }
+
+ return c;
+}
- int (*lcntl_slave_put)(struct term*, struct linebuffer*, char) =
- tdev->lcntl->process_and_put;
+static inline void
+lcntl_echo_char(struct lcntl_state* state, char c)
+{
+ rbuffer_put(state->echobuf, c);
+}
+
+int
+__ansi_actcontrol(struct lcntl_state* state, char chr);
+
+static inline int must_inline
+lcntl_transform_seq(struct lcntl_state* state)
+{
+ struct term* tdev = state->tdev;
+ char c;
+ int i = 0;
+ bool full = false;
#define EOL tdev->cc[_VEOL]
#define EOF tdev->cc[_VEOF]
#define QUIT tdev->cc[_VQUIT]
#define SUSP tdev->cc[_VSUSP]
-#define putc_safe(rb, chr) \
- ({ \
- if (!rbuffer_put_nof(rb, chr)) { \
- break; \
- } \
- })
+ while (!lcntl_test_flag(state, LCNTLF_STOP))
+ {
+ lcntl_unset_flag(state, LCNTLF_SPECIAL_CHAR);
- if (!out) {
- // Keep all cc's (except VMIN & VTIME) up to L2 cache.
- for (size_t i = 0; i < _VMIN; i++) {
- prefetch_rd(&tdev->cc[i], 2);
+ if (!rbuffer_get(state->inbuf, &c)) {
+ break;
}
- }
- while (allow_more && rbuffer_get(raw, &c)) {
-
- if (c == '\r' && ((_if & _ICRNL) || (_of & _OCRNL))) {
- c = '\n';
- } else if (c == '\n') {
- if ((_if & _INLCR) || (_of & (_ONLRET))) {
- c = '\r';
- }
- }
+ c = __remap_character(state, c);
if (c == '\0') {
- if ((_if & _IGNBRK)) {
+ if ((state->_if & _IGNBRK)) {
continue;
}
- if ((_if & _BRKINT)) {
- raise_sig(tdev, lbuf, SIGINT);
+ if ((state->_if & _BRKINT)) {
+ raise_sig(state, SIGINT);
break;
}
}
- if ('a' <= c && c <= 'z') {
- if ((_if & _IUCLC)) {
- c = c | 0b100000;
- } else if ((_of & _OLCUC)) {
- c = c & ~0b100000;
- }
- }
-
- if (out) {
+ if (lcntl_outbound(state)) {
goto do_out;
}
if (c == '\n') {
- latest_eol = cooked->ptr + 1;
- if ((_lf & _ECHONL)) {
- rbuffer_put(output, c);
+ if (lcntl_check_echo(state, _ECHONL)) {
+ lcntl_echo_char(state, c);
}
}
// For input procesing
+ lcntl_set_flag(state, LCNTLF_SPECIAL_CHAR);
+
if (c == '\n' || c == EOL) {
- lbuf->sflags |= LSTATE_EOL;
- } else if (c == EOF) {
- lbuf->sflags |= LSTATE_EOF;
- rbuffer_clear(raw);
- break;
- } else if (c == INTR) {
- raise_sig(tdev, lbuf, SIGINT);
- } else if (c == QUIT) {
- raise_sig(tdev, lbuf, SIGKILL);
- break;
- } else if (c == SUSP) {
- raise_sig(tdev, lbuf, SIGSTOP);
- } else if (c == ERASE) {
- if (!rbuffer_erase(cooked))
- continue;
- } else if (c == KILL) {
- // TODO shrink the rbuffer
- } else {
- goto keep;
+ lcntl_raise_line_event(state, LEVT_EOL);
}
-
- if ((_lf & _ECHOE) && c == ERASE) {
- rbuffer_put(output, '\x8');
- rbuffer_put(output, ' ');
- rbuffer_put(output, '\x8');
+ else if (c == EOF) {
+ lcntl_raise_line_event(state, LEVT_EOF);
+ lcntl_set_flag(state, LCNTLF_CLEAR_INBUF);
+ lcntl_set_flag(state, LCNTLF_STOP);
}
- if ((_lf & _ECHOK) && c == KILL) {
- rbuffer_put(output, c);
- rbuffer_put(output, '\n');
+ else if (c == INTR) {
+ raise_sig(state, SIGINT);
+ lcntl_set_flag(state, LCNTLF_CLEAR_OUTBUF);
}
-
- continue;
-
- keep:
- if ((_lf & _ECHO)) {
- rbuffer_put(output, c);
+ else if (c == QUIT) {
+ raise_sig(state, SIGKILL);
+ lcntl_set_flag(state, LCNTLF_CLEAR_OUTBUF);
+ lcntl_set_flag(state, LCNTLF_STOP);
+ }
+ else if (c == SUSP) {
+ raise_sig(state, SIGSTOP);
+ }
+ else if (c == ERASE) {
+ if (rbuffer_erase(state->outbuf) &&
+ lcntl_check_echo(state, _ECHOE))
+ {
+ lcntl_echo_char(state, '\x8');
+ lcntl_echo_char(state, ' ');
+ lcntl_echo_char(state, '\x8');
+ }
+ continue;
+ }
+ else if (c == KILL) {
+ lcntl_set_flag(state, LCNTLF_CLEAR_OUTBUF);
+ }
+ else {
+ lcntl_unset_flag(state, LCNTLF_SPECIAL_CHAR);
}
- goto put_char;
+ if (lcntl_check_echo(state, _ECHOK) && c == KILL) {
+ lcntl_echo_char(state, c);
+ lcntl_echo_char(state, '\n');
+ }
do_out:
- if (c == '\n' && (_of & _ONLCR)) {
- putc_safe(cooked, '\r');
+ if (c == '\n' && (state->_of & _ONLCR)) {
+ full = !rbuffer_put_nof(state->outbuf, '\r');
}
- put_char:
- if (!out && (_lf & _IEXTEN) && lcntl_slave_put) {
- allow_more = lcntl_slave_put(tdev, lbuf, c);
- } else {
- allow_more = rbuffer_put_nof(cooked, c);
+ if (!full) {
+ if (lcntl_inbound(state) && (state->_lf & _IEXTEN)) {
+ full = !__ansi_actcontrol(state, c);
+ }
+ else {
+ full = !lcntl_put_char(state, c);
+ }
+ }
+
+ if (lcntl_test_flag(state, LCNTLF_CLEAR_INBUF)) {
+ rbuffer_clear(state->inbuf);
+ lcntl_unset_flag(state, LCNTLF_CLEAR_INBUF);
+ }
+
+ if (lcntl_test_flag(state, LCNTLF_CLEAR_OUTBUF)) {
+ rbuffer_clear(state->outbuf);
+ lcntl_unset_flag(state, LCNTLF_CLEAR_OUTBUF);
}
+
+ i++;
}
- if (!out && !rbuffer_empty(output) && !(_lf & _NOFLSH)) {
+ if (state->direction != OUTBOUND && !(state->_lf & _NOFLSH)) {
term_flush(tdev);
}
- line_flip(lbuf);
+ line_flip(state->active_line);
return i;
}
int
lcntl_transform_inseq(struct term* tdev)
{
- return lcntl_transform_seq(tdev, &tdev->line_in, false);
+ struct lcntl_state state;
+
+ init_lcntl_state(&state, tdev, INBOUND);
+ return lcntl_transform_seq(&state);
}
int
lcntl_transform_outseq(struct term* tdev)
{
- return lcntl_transform_seq(tdev, &tdev->line_out, true);
+ struct lcntl_state state;
+
+ init_lcntl_state(&state, tdev, OUTBOUND);
+ return lcntl_transform_seq(&state);
+}
+
+int
+lcntl_put_char(struct lcntl_state* state, char c)
+{
+ if (lcntl_check_echo(state, _ECHO)) {
+ lcntl_echo_char(state, c);
+ }
+
+ if (!lcntl_test_flag(state, LCNTLF_SPECIAL_CHAR)) {
+ return rbuffer_put_nof(state->outbuf, c);
+ }
+
+ return 1;
}
\ No newline at end of file
--- /dev/null
+#ifndef __LUNAIX_LCNTL_H
+#define __LUNAIX_LCNTL_H
+
+#include <hal/term.h>
+
+#define LCNTLF_SPECIAL_CHAR 0b000001
+#define LCNTLF_CLEAR_INBUF 0b000010
+#define LCNTLF_CLEAR_OUTBUF 0b000100
+#define LCNTLF_STOP 0b001000
+
+enum lcntl_dir {
+ INBOUND,
+ OUTBOUND
+};
+
+struct lcntl_state {
+ struct term* tdev;
+ tcflag_t _if; // iflags
+ tcflag_t _of; // oflags
+ tcflag_t _lf; // local flags
+ tcflag_t _cf; // control flags
+ tcflag_t _sf; // state flags
+ enum lcntl_dir direction;
+
+ struct linebuffer* active_line;
+ struct rbuffer* inbuf;
+ struct rbuffer* outbuf;
+ struct rbuffer* echobuf;
+};
+
+int
+lcntl_put_char(struct lcntl_state* state, char c);
+
+static inline void
+lcntl_set_flag(struct lcntl_state* state, int flags)
+{
+ state->_sf |= flags;
+}
+
+static inline void
+lcntl_raise_line_event(struct lcntl_state* state, int event)
+{
+ state->active_line->sflags |= event;
+}
+
+static inline void
+lcntl_unset_flag(struct lcntl_state* state, int flags)
+{
+ state->_sf &= ~flags;
+}
+
+static inline bool
+lcntl_test_flag(struct lcntl_state* state, int flags)
+{
+ return !!(state->_sf & flags);
+}
+
+static inline bool
+lcntl_outbound(struct lcntl_state* state)
+{
+ return (state->direction == OUTBOUND);
+}
+
+static inline bool
+lcntl_inbound(struct lcntl_state* state)
+{
+ return (state->direction == INBOUND);
+}
+
+static inline bool
+lcntl_check_echo(struct lcntl_state* state, int echo_type)
+{
+ return lcntl_inbound(state) && (state->_lf & echo_type);
+}
+
+
+#endif /* __LUNAIX_LCNTL_H */
#include <usr/lunaix/ioctl_defs.h>
-#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;
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;
goto done;
}
+ cap_ops = term->tp_cap->cap_ops;
+
if (tios->c_baud != term->iospeed) {
term->iospeed = tios->c_baud;
- term->tp_cap->set_speed(term->chdev, tios->c_baud);
+ cap_ops->set_speed(term->chdev, tios->c_baud);
}
if (old_cf != tios->c_cflag) {
- term->tp_cap->set_cntrl_mode(term->chdev, tios->c_cflag);
+ cap_ops->set_cntrl_mode(term->chdev, tios->c_cflag);
}
} break;
default:
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)[rdsz], len - rdsz);
}
-
+
+ tdev->line_in.sflags = 0;
return rdsz;
}
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));
}
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;
- terminal->dev->ops.exec_cmd = term_exec_cmd;
+ 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);
alloc_term_buffer(terminal, 1024);
if (chardev) {
int cdev_var = DEV_VAR_FROM(chardev->ident.unique);
- register_device(terminal->dev, &termdev, "tty%s%d", suffix, cdev_var);
+ register_device(tdev, &termdev_class, "tty%s%d", suffix, cdev_var);
} else {
- register_device(terminal->dev, &termdev, "tty%d", termdev.variant++);
+ register_device(tdev, &termdev_class, "tty%d", termdev_class.variant++);
}
- struct capability_meta* termport_cap = device_get_capability(chardev, TERMPORT_CAP);
+ termport_cap = device_get_capability(chardev, TERMPORT_CAP);
if (termport_cap) {
- terminal->tp_cap = get_capability(termport_cap, struct termport_capability);
+ terminal->tp_cap =
+ get_capability(termport_cap, struct termport_capability);
+
+ assert(terminal->tp_cap->cap_ops);
+ terminal->tp_cap->term = terminal;
}
- struct capability_meta* term_cap = new_capability_marker(TERMIOS_CAP);
- device_grant_capability(terminal->dev, term_cap);
+ tios_cap = new_capability_marker(TERMIOS_CAP);
+ device_grant_capability(tdev, tios_cap);
load_default_setting(terminal);
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
#include <usr/lunaix/term.h>
-#define ONBREAK (LSTATE_EOF | LSTATE_SIGRAISE)
-#define ONSTOP (LSTATE_SIGRAISE | LSTATE_EOL | LSTATE_EOF)
+#define ONBREAK (LEVT_EOF | LEVT_SIGRAISE)
+#define ONSTOP (LEVT_SIGRAISE | LEVT_EOL | LEVT_EOF)
static int
do_read_raw(struct term* tdev)
{
- struct device* chdev = tdev->chdev;
-
- struct linebuffer* line_in = &tdev->line_in;
- size_t max_lb_sz = line_in->sz_hlf;
-
- line_flip(line_in);
-
- char* inbuffer = line_in->current->buffer;
- size_t min = tdev->cc[_VMIN] - 1;
- size_t sz = chdev->ops.read_async(chdev, inbuffer, 0, max_lb_sz);
- time_t t = clock_systime(), dt = 0;
- time_t expr = (tdev->cc[_VTIME] * 100) - 1;
-
+ struct linebuffer* line_in;
+ lbuf_ref_t current_buf;
+ size_t min, sz = 0;
+ time_t t, expr, dt = 0;
+
+ line_in = &tdev->line_in;
+ current_buf = ref_current(line_in);
+
+ min = tdev->cc[_VMIN] - 1;
+ t = clock_systime();
+ expr = (tdev->cc[_VTIME] * 100) - 1;
+
+ min = MIN(min, (size_t)line_in->sz_hlf);
while (sz <= min && dt <= expr) {
// XXX should we held the device lock while we are waiting?
sched_pass();
dt = clock_systime() - t;
t += dt;
- max_lb_sz -= sz;
-
- // TODO pass a flags to read to indicate it is non blocking ops
- sz += chdev->ops.read_async(chdev, &inbuffer[sz], 0, max_lb_sz);
+ sz = deref(current_buf)->len;
}
- rbuffer_puts(line_in->next, inbuffer, sz);
- line_flip(line_in);
-
return 0;
}
-static int
-do_read_raw_canno(struct term* tdev)
-{
- struct device* chdev = tdev->chdev;
- struct linebuffer* line_in = &tdev->line_in;
- struct rbuffer* current_buf = line_in->current;
- int sz = chdev->ops.read(chdev, current_buf->buffer, 0, line_in->sz_hlf);
-
- current_buf->ptr = sz;
- current_buf->len = sz;
-
- return sz;
-}
-
-static int
-term_read_noncano(struct term* tdev)
-{
- struct device* chdev = tdev->chdev;
- return do_read_raw(tdev);
-}
-
-static int
+static inline int
term_read_cano(struct term* tdev)
{
- struct device* chdev = tdev->chdev;
- struct linebuffer* line_in = &tdev->line_in;
- int size = 0;
+ struct linebuffer* line_in;
+ line_in = &tdev->line_in;
while (!(line_in->sflags & ONSTOP)) {
- // move all hold-out content to 'next' buffer
- line_flip(line_in);
-
- size += do_read_raw_canno(tdev);
- lcntl_transform_inseq(tdev);
+ pwait(&tdev->line_in_event);
}
return 0;
if ((tdev->lflags & _ICANON)) {
return term_read_cano(tdev);
}
- return term_read_noncano(tdev);
+
+ return do_read_raw(tdev);
}
int
term_flush(struct term* tdev)
{
+ struct device* chardev;
struct linebuffer* line_out = &tdev->line_out;
char* xmit_buf = tdev->scratch_pad;
lbuf_ref_t current_ref = ref_current(line_out);
-
+
int count = 0;
+ chardev = tdev->chdev;
+
while (!rbuffer_empty(deref(current_ref))) {
if ((tdev->oflags & _OPOST)) {
lcntl_transform_outseq(tdev);
off_t off = 0;
int ret = 0;
while (xmit_len && ret >= 0) {
- ret = tdev->chdev->ops.write(tdev->chdev, &xmit_buf[off], 0, xmit_len);
+ ret = chardev->ops.write(chardev, &xmit_buf[off], 0, xmit_len);
xmit_len -= ret;
off += ret;
count += ret;
}
return count;
+}
+
+void
+term_notify_data_avaliable(struct termport_capability* cap)
+{
+ struct term* term;
+ struct device* term_chrdev;
+ struct linebuffer* line_in;
+ lbuf_ref_t current_ref;
+ char* buf;
+ int sz;
+
+ term = cap->term;
+ term_chrdev = term->chdev;
+ line_in = &term->line_in;
+ current_ref = ref_current(line_in);
+
+ // make room for current buf
+ line_flip(line_in);
+ buf = deref(current_ref)->buffer;
+
+ sz = term_chrdev->ops.read_async(term_chrdev, buf, 0, line_in->sz_hlf);
+ rbuffer_setcontent(deref(current_ref), sz);
+
+ if ((term->lflags & _ICANON)) {
+ lcntl_transform_inseq(term);
+ // write all processed to next, and flip back to current
+ }
+
+ pwake_all(&term->line_in_event);
}
\ No newline at end of file
struct rbuffer rxbuf;
int wr_len;
+ struct capability_meta* tp_cap;
+
/**
* @brief Write buffer to TX. The return code indicate
* the transaction is either done in synced mode (TX_DONE) or will be
#include <lunaix/device.h>
#include <lunaix/ds/rbuffer.h>
+#include <lunaix/ds/waitq.h>
#include <lunaix/signal_defs.h>
#include <usr/lunaix/term.h>
short sflags;
short sz_hlf;
};
-#define LSTATE_EOL (1)
-#define LSTATE_EOF (1 << 1)
-#define LSTATE_SIGRAISE (1 << 2)
+#define LEVT_EOL (1)
+#define LEVT_EOF (1 << 1)
+#define LEVT_SIGRAISE (1 << 2)
typedef struct rbuffer** lbuf_ref_t;
#define ref_current(lbuf) (&(lbuf)->current)
#define ref_next(lbuf) (&(lbuf)->next)
#define deref(bref) (*(bref))
-struct term_lcntl
-{
- struct term* term;
- int (*process_and_put)(struct term*, struct linebuffer*, char);
-};
-
/**
* @brief Communication port capability that a device is supported natively,
* or able to emulate low level serial transmission behaviour specify
*/
#define TERMIOS_CAP 0x534f4954U
-struct termport_capability
-{
- CAPABILITY_META;
+struct term;
+struct termport_cap_ops
+{
void (*set_speed)(struct device*, speed_t);
+ void (*set_clkbase)(struct device*, unsigned int);
void (*set_cntrl_mode)(struct device*, tcflag_t);
};
+struct termport_capability
+{
+ CAPABILITY_META;
+ struct termport_cap_ops* cap_ops;
+ struct term* term;
+};
+
struct term
{
struct device* dev;
struct device* chdev;
- struct term_lcntl* lcntl;
struct linebuffer line_out;
struct linebuffer line_in;
char* scratch_pad;
pid_t fggrp;
struct termport_capability* tp_cap;
+ waitq_t line_in_event;
/* -- POSIX.1-2008 compliant fields -- */
tcflag_t iflags;
tcflag_t lflags;
tcflag_t cflags;
cc_t cc[_NCCS];
+
+ /* -- END POSIX.1-2008 compliant fields -- */
speed_t iospeed;
+ speed_t clkbase;
+ tcflag_t tflags; // temp flags
};
extern struct device* sysconsole;
int
term_bind(struct term* tdev, struct device* chdev);
-int
-term_push_lcntl(struct term* tdev, struct term_lcntl* lcntl);
-
-int
-term_pop_lcntl(struct term* tdev);
-
-struct term_lcntl*
-term_get_lcntl(u32_t lcntl_index);
-
static inline void
line_flip(struct linebuffer* lbf)
{
int
lcntl_transform_outseq(struct term* tdev);
+static inline void
+term_cap_set_operations(struct termport_capability* cap,
+ struct termport_cap_ops* ops)
+{
+ cap->cap_ops = ops;
+}
+
+void
+term_notify_data_avaliable(struct termport_capability* cap);
+
+#define termport_default_ops \
+ ({ \
+ extern struct termport_cap_ops default_termport_cap_ops;\
+ &default_termport_cap_ops; \
+ })
+
#endif /* __LUNAIX_TERM_H */
rbuffer_puts(struct rbuffer* rb, char* c, size_t len);
int
-rbuffer_gets(struct rbuffer* rb, char* buf, size_t len);
+rbuffer_gets_opt(struct rbuffer* rb, char* buf, size_t len, bool consumed);
int
rbuffer_get(struct rbuffer* rb, char* c);
+static inline int
+rbuffer_gets(struct rbuffer* rb, char* buf, size_t len)
+{
+ return rbuffer_gets_opt(rb, buf, len, true);
+}
+
+static inline int
+rbuffer_gets_no_consume(struct rbuffer* rb, char* buf, size_t len)
+{
+ return rbuffer_gets_opt(rb, buf, len, false);
+}
static inline void
rbuffer_clear(struct rbuffer* rb)
return rb->len == 0;
}
+static inline unsigned int
+rbuffer_len(struct rbuffer* rb)
+{
+ return rb->len;
+}
+
+static inline void
+rbuffer_setcontent(struct rbuffer* rb, size_t content_len)
+{
+ rb->ptr = content_len;
+ rb->len = content_len;
+}
+
static inline bool
rbuffer_full(struct rbuffer* rb)
{
#include "ioctl_defs.h"
-#define SERIO_RXEN IOREQ(1, 0)
-#define SERIO_RXDA IOREQ(2, 0)
+#define SERIO_RXEN IOREQ(1, 0)
+#define SERIO_RXDA IOREQ(2, 0)
-#define SERIO_TXEN IOREQ(3, 0)
-#define SERIO_TXDA IOREQ(4, 0)
+#define SERIO_TXEN IOREQ(3, 0)
+#define SERIO_TXDA IOREQ(4, 0)
-#define SERIO_SETBRDIV IOREQ(5, 0)
-#define SERIO_SETCNTRLMODE IOREQ(6, 0)
+#define SERIO_SETBRDRATE IOREQ(5, 0)
+#define SERIO_SETCNTRLMODE IOREQ(6, 0)
+#define SERIO_SETBRDBASE IOREQ(7, 0)
#endif /* __LUNAIX_USERIAL_H */
"kinit.c",
"lunad.c",
"spike.c",
- "tty/tty.c",
"kprint/kp_records.c",
"kprint/kprintf.c",
"time/clock.c",
}
int
-rbuffer_gets(struct rbuffer* rb, char* buf, size_t len)
+rbuffer_gets_opt(struct rbuffer* rb, char* buf, size_t len, bool consumed)
{
if (!len || !rb->len)
return 0;
memcpy(&buf[-nlen], &rb->buffer[ptr_start], nlen);
}
- rb->len -= nlen;
+ if (consumed) {
+ rb->len -= nlen;
+ }
return nlen;
}
/* Begin kernel bootstrapping sequence */
boot_begin(bhctx);
- tty_init((void*)ioremap(0xB8000, PAGE_SIZE));
-
/* Setup kernel memory layout and services */
kmem_init(bhctx);
- // FIXME this goes to hal/gfxa
- tty_set_theme(VGA_COLOR_WHITE, VGA_COLOR_BLACK);
-
boot_parse_cmdline(bhctx);
/* Prepare stack trace environment */
struct cake_pile *proc_pile ,*thread_pile;
+#define root_process (sched_ctx.procs[1])
+
LOG_MODULE("SCHED")
void
bed->alarm_time = seconds ? now + seconds : 0;
- struct proc_info* root_proc = sched_ctx.procs[0];
if (llist_empty(&bed->sleepers)) {
llist_append(&sched_ctx.sleepers, &bed->sleepers);
}
// every process is the child of first process (pid=1)
if (!process->parent) {
if (likely(!kernel_process(process))) {
- process->parent = sched_ctx.procs[1];
+ process->parent = root_process;
} else {
process->parent = process;
}
cake_release(thread_pile, thread);
}
+static void
+orphan_children(struct proc_info* proc)
+{
+ struct proc_info *root;
+ struct proc_info *pos, *n;
+
+ root = root_process;
+
+ llist_for_each(pos, n, &proc->children, siblings) {
+ pos->parent = root;
+ llist_append(&root->children, &pos->siblings);
+ }
+}
+
void
delete_process(struct proc_info* proc)
{
destory_thread(pos);
}
+ orphan_children(proc);
+
procvm_unmount_release(mm);
cake_release(proc_pile, proc);
signal_send(pid_t pid, signum_t signum)
{
if (signum >= _SIG_NUM) {
- syscall_result(EINVAL);
- return -1;
+ return EINVAL;
}
pid_t sender_pid = __current->pid;
} else {
// TODO: send to all process.
// But I don't want to support it yet.
- syscall_result(EINVAL);
- return -1;
+ return EINVAL;
}
send_grp: ;
send_single:
if (proc_terminated(proc)) {
- syscall_result(EINVAL);
- return -1;
+ return EINVAL;
}
proc_setsignal(proc, signum);
__DEFINE_LXSYSCALL2(int, kill, pid_t, pid, int, signum)
{
- return signal_send(pid, signum);
+ return syscall_result(signal_send(pid, signum));
}
__DEFINE_LXSYSCALL1(int, sigpending, sigset_t, *sigset)
term.c_oflag = ONLCR | OPOST;
term.c_cflag = CREAD | CLOCAL | CS8 | CPARENB;
term.c_cc[VERASE] = 0x7f;
+
+ cfsetispeed(&term, B9600);
+ cfsetospeed(&term, B9600);
check(tcsetattr(fd, 0, &term));
static inline int cfsetispeed(struct termios* termios, speed_t baud)
{
+ if (baud > B38400) {
+ return -1;
+ }
+
termios->c_baud = baud;
return 0;
}
static inline int cfsetospeed(struct termios* termios, speed_t baud)
{
+ if (baud > B38400) {
+ return -1;
+ }
+
termios->c_baud = baud;
return 0;
}
int tcsendbreak(int, int);
int tcsetattr(int, int, const struct termios *);
-
#endif /* __LUNAIX_TERMIOS_H */
waitpid(p, NULL, 0);
}
+static char*
+sanity_filter(char* buf)
+{
+ int off = 0, i = 0;
+ char c;
+ do {
+ c = buf[i];
+
+ if ((32 <= c && c <= 126) || !c) {
+ buf[i - off] = c;
+ }
+ else {
+ off++;
+ }
+
+ i++;
+ } while(c);
+
+ return buf;
+}
+
void
sh_loop()
{
}
buf[sz] = '\0';
+ sanity_filter(buf);
// currently, this shell only support single argument
if (!parse_cmdline(buf, argv)) {