Files
kernel/sys/char/tty.c
T
2020-06-19 16:40:50 +03:00

180 lines
4.5 KiB
C

#include "arch/amd64/hw/rs232.h"
#include "arch/amd64/hw/con.h"
#include "arch/amd64/hw/ps2.h"
#include "user/termios.h"
#include "user/signum.h"
#include "sys/char/input.h"
#include "user/errno.h"
#include "sys/char/line.h"
#include "sys/char/ring.h"
#include "arch/amd64/cpu.h"
#include "sys/char/tty.h"
#include "sys/char/chr.h"
#include "sys/console.h"
#include "sys/string.h"
#include "sys/thread.h"
#include "sys/assert.h"
#include "sys/ctype.h"
#include "sys/debug.h"
#include "sys/sched.h"
#include "sys/panic.h"
#include "sys/heap.h"
#include "sys/dev.h"
#include "sys/mm.h"
static ssize_t tty_write(struct chrdev *tty, const void *buf, size_t pos, size_t lim);
static int tty_ioctl(struct chrdev *tty, unsigned int cmd, void *arg);
static const struct termios default_termios = TERMIOS_DEFAULT;
//void tty_control_write(struct chrdev *tty, char c) {
// struct tty_data *data = tty->dev_data;
// _assert(data);
//
// switch (c) {
// case 'd':
// ring_signal(&tty->buffer, RING_SIGNAL_EOF);
// break;
// case '.':
// //ring_signal(&tty->buffer, RING_SIGNAL_BRK);
// thread_signal_pgid(data->fg_pgid, SIGUSR1);
// break;
// case 'c':
// //ring_signal(&tty->buffer, RING_SIGNAL_BRK);
// thread_signal_pgid(data->fg_pgid, SIGINT);
// break;
// default:
// panic("Unhandled control to TTY: ^%c\n", c);
// }
//}
void tty_data_write(struct chrdev *tty, char c) {
_assert(tty && tty->type == CHRDEV_TTY);
ring_putc(NULL, &tty->buffer, c, 0);
switch (c) {
case '\n':
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':
ring_signal(&tty->buffer, 0);
break;
case '\033':
if ((tty->tc.c_lflag & ECHO) || (tty->tc.c_iflag & ICANON)) {
tty_puts(tty, "^[");
}
break;
default:
// This ignores ICANON
if (tty->tc.c_lflag & ECHO) {
tty_putc(tty, c);
}
}
}
void tty_puts(struct chrdev *tty, const char *s) {
for (; *s; ++s) {
tty_putc(tty, *s);
}
}
int tty_create(struct console *master) {
struct chrdev *tty = kmalloc(sizeof(struct chrdev));
_assert(tty);
struct tty_data *data = kmalloc(sizeof(struct tty_data));
_assert(data);
data->fg_pgid = 1;
data->master = NULL;
data->buffer = NULL;
list_head_init(&data->list);
tty->type = CHRDEV_TTY;
memcpy(&tty->tc, &default_termios, sizeof(struct termios));
tty->write = tty_write;
tty->ioctl = tty_ioctl;
tty->read = line_read;
tty->dev_data = data;
ring_init(&tty->buffer, 16);
console_attach(master, tty);
dev_add(DEV_CLASS_CHAR, DEV_CHAR_TTY, tty, "tty0");
return 0;
}
void tty_putc(struct chrdev *tty, char c) {
struct tty_data *data = tty->dev_data;
_assert(data);
_assert(data->master);
console_putc(data->master, tty, c);
}
void tty_init(void) {
// tty0
// ring_init(&_dev_tty0.buffer, 16);
// g_keyboard_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) {
struct tty_data *data = tty->dev_data;
_assert(data);
for (size_t i = 0; i < lim; ++i) {
console_putc(data->master, tty, ((const char *) buf)[i]);
}
return lim;
}
static int tty_ioctl(struct chrdev *tty, unsigned int cmd, void *arg) {
struct tty_data *data = tty->dev_data;
_assert(data);
switch (cmd) {
case TIOCGWINSZ:
{
_assert(arg);
struct winsize *winsz = arg;
_assert(data->master);
winsz->ws_col = data->master->width_chars;
winsz->ws_row = data->master->height_chars;
}
return 0;
case TCGETS:
memcpy(arg, &tty->tc, sizeof(struct termios));
return 0;
case TCSETS:
memcpy(&tty->tc, arg, sizeof(struct termios));
if (tty->tc.c_iflag & ICANON) {
tty->buffer.flags &= ~RING_RAW;
} else {
tty->buffer.flags |= RING_RAW;
}
return 0;
case TIOCSPGRP:
// Clear interrupts and stuff
tty->buffer.flags = 0;
data->fg_pgid = *(pid_t *) arg;
return 0;
}
return -EINVAL;
}