Add ttyS0
This commit is contained in:
@@ -2,6 +2,10 @@
|
||||
#include <stdint.h>
|
||||
|
||||
#define RS232_COM1 0x3F8
|
||||
struct chrdev;
|
||||
|
||||
int rs232_putc(void *dev, char c);
|
||||
void rs232_set_tty(uint16_t com, struct chrdev *tty);
|
||||
|
||||
void rs232_init(uint16_t port);
|
||||
void rs232_send(uint16_t port, char c);
|
||||
|
||||
@@ -5,6 +5,7 @@ enum {
|
||||
CFG_ROOT = 1,
|
||||
CFG_INIT,
|
||||
CFG_RDINIT,
|
||||
CFG_CONSOLE,
|
||||
|
||||
__CFG_SIZE
|
||||
};
|
||||
|
||||
@@ -6,6 +6,7 @@ struct thread;
|
||||
|
||||
#define RING_SIGNAL_BRK (1 << 0)
|
||||
#define RING_SIGNAL_EOF (1 << 1)
|
||||
#define RING_SIGNAL_RET (1 << 2)
|
||||
|
||||
// Ring buffer
|
||||
struct ring {
|
||||
|
||||
@@ -5,6 +5,9 @@
|
||||
#define TIOCSPGRP 0x5410
|
||||
#define TIOCGWINSZ 0x5413
|
||||
|
||||
// Input flags
|
||||
#define ICANON (1 << 1)
|
||||
|
||||
// Output flags
|
||||
#define OPOST (1 << 0)
|
||||
#define ONLCR (1 << 2)
|
||||
@@ -20,7 +23,7 @@
|
||||
|
||||
#define TERMIOS_DEFAULT \
|
||||
{ \
|
||||
.c_iflag = 0, \
|
||||
.c_iflag = ICANON, \
|
||||
.c_oflag = OPOST, \
|
||||
.c_cflag = 0, \
|
||||
.c_lflag = ECHO | ECHONL | ECHOE | ECHOK, \
|
||||
|
||||
+40
-3
@@ -29,12 +29,27 @@
|
||||
#define RS232_LSR_TEMT 64
|
||||
#define RS232_LSR_ERR 128
|
||||
|
||||
static struct chrdev *_rs232_tty[4] = {NULL};
|
||||
|
||||
void rs232_send(uint16_t port, char c) {
|
||||
while (!(inb(port + RS232_LSR) & RS232_LSR_THRE)) {
|
||||
}
|
||||
outb(port, c);
|
||||
}
|
||||
|
||||
int rs232_putc(void *dev, char c) {
|
||||
rs232_send(((uintptr_t) dev) & 0xFFFF, c);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void rs232_set_tty(uint16_t com, struct chrdev *tty) {
|
||||
switch (com) {
|
||||
case RS232_COM1:
|
||||
_rs232_tty[0] = tty;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t rs232_irq(void *ctx) {
|
||||
uint16_t port = (uint16_t) (uintptr_t) ctx;
|
||||
int has_data = 0;
|
||||
@@ -44,11 +59,33 @@ static uint32_t rs232_irq(void *ctx) {
|
||||
has_data = 1;
|
||||
uint8_t c = inb(port);
|
||||
|
||||
if (c == '\r') {
|
||||
c = '\n';
|
||||
if (c < ' ') {
|
||||
kdebug("Special character in serial input: 0x%02x\n", c);
|
||||
}
|
||||
|
||||
// TODO: send data to bound TTY
|
||||
// Translate serial codes to proper values recognized by kernel
|
||||
// line discipline. TODO: make c_cc in termios handle special characters
|
||||
int control = 0;
|
||||
|
||||
switch (c) {
|
||||
case 0x0D:
|
||||
c = '\n';
|
||||
break;
|
||||
case 0x7F:
|
||||
c = '\b';
|
||||
break;
|
||||
case 0x04:
|
||||
control = 'd';
|
||||
break;
|
||||
}
|
||||
|
||||
if (_rs232_tty[0]) {
|
||||
if (!control) {
|
||||
tty_data_write(_rs232_tty[0], c);
|
||||
} else {
|
||||
tty_control_write(_rs232_tty[0], control);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return has_data ? IRQ_HANDLED : IRQ_UNHANDLED;
|
||||
|
||||
+14
-2
@@ -256,7 +256,10 @@ int sys_select(int nfds, fd_set *rd, fd_set *wr, fd_set *exc, struct timeval *tv
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t deadline = tv->tv_sec * 1000000000ULL + tv->tv_usec * 1000ULL + system_time;
|
||||
uint64_t deadline = (uint64_t) -1;
|
||||
if (tv) {
|
||||
deadline = tv->tv_sec * 1000000000ULL + tv->tv_usec * 1000ULL + system_time;
|
||||
}
|
||||
int res;
|
||||
|
||||
while (1) {
|
||||
@@ -269,11 +272,20 @@ int sys_select(int nfds, fd_set *rd, fd_set *wr, fd_set *exc, struct timeval *tv
|
||||
struct chrdev *chr = fd->vnode->dev;
|
||||
_assert(chr);
|
||||
|
||||
if (ring_readable(&chr->buffer) > 0) {
|
||||
if (chr->buffer.flags & (RING_SIGNAL_EOF | RING_SIGNAL_BRK | RING_SIGNAL_RET)) {
|
||||
FD_SET(i, rd);
|
||||
res = 0;
|
||||
goto done;
|
||||
}
|
||||
|
||||
// Report data available for non-canonical devices
|
||||
if (chr->type == CHRDEV_TTY && !(chr->tc.c_iflag & ICANON)) {
|
||||
if (ring_readable(&chr->buffer) > 0) {
|
||||
FD_SET(i, rd);
|
||||
res = 0;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@ static const struct __kernel_cmdline_pair {
|
||||
{ "root", CFG_ROOT, VALUE_STRING },
|
||||
{ "init", CFG_INIT, VALUE_STRING },
|
||||
{ "rdinit", CFG_RDINIT, VALUE_STRING },
|
||||
{ "console", CFG_CONSOLE, VALUE_STRING },
|
||||
};
|
||||
|
||||
// Default config
|
||||
@@ -24,6 +25,7 @@ uintptr_t kernel_config[__CFG_SIZE] = {
|
||||
[CFG_ROOT] = (uintptr_t) "ram0",
|
||||
[CFG_INIT] = (uintptr_t) "/init",
|
||||
[CFG_RDINIT] = (uintptr_t) "/init",
|
||||
[CFG_CONSOLE] = (uintptr_t) "tty0",
|
||||
};
|
||||
|
||||
static int parse_number(const char *s, intptr_t *res) {
|
||||
|
||||
+3
-2
@@ -22,6 +22,7 @@
|
||||
extern uintptr_t argp_copy(struct thread *thr, const char *const argv[], size_t *arg_count);
|
||||
|
||||
static int user_init_start(const char *init_filename) {
|
||||
const char *init_console = (const char *) kernel_config[CFG_CONSOLE];
|
||||
struct ofile fd;
|
||||
struct stat st;
|
||||
struct thread *user_init;
|
||||
@@ -100,8 +101,8 @@ static int user_init_start(const char *init_filename) {
|
||||
stderr = stdout;
|
||||
|
||||
struct vnode *stdout_device;
|
||||
if ((res = dev_find(DEV_CLASS_CHAR, "tty0", &stdout_device)) != 0) {
|
||||
panic("%s: %s\n", "tty0", kstrerror(res));
|
||||
if ((res = dev_find(DEV_CLASS_CHAR, init_console, &stdout_device)) != 0) {
|
||||
panic("%s: %s\n", init_console, kstrerror(res));
|
||||
}
|
||||
|
||||
if ((res = vfs_open_vnode(&user_init->ioctx, stdin, stdout_device, O_RDONLY)) != 0) {
|
||||
|
||||
+11
-1
@@ -4,6 +4,7 @@
|
||||
#include "sys/chr.h"
|
||||
#include "sys/tty.h"
|
||||
#include "sys/amd64/cpu.h"
|
||||
#include "sys/line.h"
|
||||
|
||||
ssize_t line_read(struct chrdev *chr, void *buf, size_t pos, size_t lim) {
|
||||
struct thread *thr = get_cpu()->thread;
|
||||
@@ -15,8 +16,16 @@ ssize_t line_read(struct chrdev *chr, void *buf, size_t pos, size_t lim) {
|
||||
char *wr = buf;
|
||||
char c;
|
||||
|
||||
// Only needed for stuff like select(), which is called before read()
|
||||
chr->buffer.flags &= ~RING_SIGNAL_RET;
|
||||
|
||||
if (r->flags & RING_SIGNAL_EOF) {
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(chr->tc.c_iflag & ICANON)) {
|
||||
// Just spit out data as soon as it's available
|
||||
return simple_line_read(chr, buf, pos, lim);
|
||||
}
|
||||
|
||||
// NO ICANON YET
|
||||
@@ -68,6 +77,7 @@ ssize_t line_read(struct chrdev *chr, void *buf, size_t pos, size_t lim) {
|
||||
}
|
||||
}
|
||||
|
||||
chr->buffer.flags &= ~RING_SIGNAL_RET;
|
||||
return rd;
|
||||
}
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include "sys/string.h"
|
||||
#include "sys/assert.h"
|
||||
#include "sys/termios.h"
|
||||
#include "sys/amd64/hw/rs232.h"
|
||||
#include "sys/ring.h"
|
||||
#include "sys/mm.h"
|
||||
#include "sys/amd64/cpu.h"
|
||||
@@ -45,6 +46,23 @@ static struct chrdev _dev_tty0 = {
|
||||
.ioctl = tty_ioctl
|
||||
};
|
||||
|
||||
// Serial console
|
||||
static struct tty_data _dev_ttyS0_data = {
|
||||
.fg_pgid = 1,
|
||||
.out_dev = (void *) RS232_COM1,
|
||||
.out_putc = rs232_putc
|
||||
};
|
||||
|
||||
static struct chrdev _dev_ttyS0 = {
|
||||
.type = CHRDEV_TTY,
|
||||
.dev_data = &_dev_ttyS0_data,
|
||||
.tc = TERMIOS_DEFAULT,
|
||||
.write = tty_write,
|
||||
// Line discipline
|
||||
.read = line_read,
|
||||
.ioctl = tty_ioctl
|
||||
};
|
||||
|
||||
void tty_control_write(struct chrdev *tty, char c) {
|
||||
struct tty_data *data = tty->dev_data;
|
||||
_assert(data);
|
||||
@@ -72,6 +90,10 @@ void tty_data_write(struct chrdev *tty, char c) {
|
||||
if (tty->tc.c_lflag & ECHONL) {
|
||||
tty_putc(tty, c);
|
||||
}
|
||||
if (tty->tc.c_iflag & ICANON) {
|
||||
// Trigger line flush
|
||||
ring_signal(&tty->buffer, RING_SIGNAL_RET);
|
||||
}
|
||||
break;
|
||||
case '\b':
|
||||
break;
|
||||
@@ -101,12 +123,15 @@ void tty_putc(struct chrdev *tty, char c) {
|
||||
}
|
||||
|
||||
void tty_init(void) {
|
||||
// tty0
|
||||
ring_init(&_dev_tty0.buffer, 16);
|
||||
|
||||
// Bind tty0 to keyboard
|
||||
ps2_kbd_set_tty(&_dev_tty0);
|
||||
|
||||
dev_add(DEV_CLASS_CHAR, DEV_CHAR_TTY, &_dev_tty0, "tty0");
|
||||
|
||||
// ttyS0
|
||||
ring_init(&_dev_ttyS0.buffer, 16);
|
||||
rs232_set_tty(RS232_COM1, &_dev_ttyS0);
|
||||
dev_add(DEV_CLASS_CHAR, DEV_CHAR_TTY, &_dev_ttyS0, "ttyS0");
|
||||
}
|
||||
|
||||
static ssize_t tty_write(struct chrdev *tty, const void *buf, size_t pos, size_t lim) {
|
||||
|
||||
Reference in New Issue
Block a user