Port back CSI handling and cursor blink

This commit is contained in:
Mark
2020-06-19 16:40:50 +03:00
parent dd36f0decf
commit 55b2e665fd
6 changed files with 260 additions and 45 deletions
+8 -12
View File
@@ -7,6 +7,8 @@
#include "arch/amd64/hw/idt.h"
#include "arch/amd64/hw/io.h"
#include "arch/amd64/cpu.h"
#include "sys/display.h"
#include "sys/console.h"
#include "user/time.h"
#include "sys/assert.h"
#include "sys/thread.h"
@@ -58,18 +60,12 @@ void timer_remove_sleep(struct thread *thr) {
static uint32_t timer_tick(void *arg) {
switch ((uint64_t) arg) {
case TIMER_PIT:
// #if defined(VESA_ENABLE)
// ++int_timer_ticks;
// if (int_timer_ticks >= 300) {
// con_blink();
// int_timer_ticks = 0;
// }
// if (!vesa_available) {
//#else
// {
//#endif
// amd64_con_sync_cursor();
// }
++int_timer_ticks;
if (int_timer_ticks >= 300) {
g_display_blink_state ^= 1;
int_timer_ticks = 0;
}
console_update_cursor();
// Each tick is approx. 1ms, so add 1ms to system time
system_time += 1000000;
break;
+2
View File
@@ -24,7 +24,9 @@ struct console {
// Enslave a TTY to a physical console
void console_attach(struct console *con, struct chrdev *tty);
uint16_t console_buffer_at(uint16_t y, uint16_t x);
void console_resize(struct console *con, uint16_t new_width, uint16_t new_height);
void console_update_cursor(void);
void console_putc(struct console *con, struct chrdev *tty, int c);
void console_type(struct console *con, int c);
+2
View File
@@ -28,6 +28,8 @@ struct display {
struct list_head list;
};
extern int g_display_blink_state;
void display_add(struct display *d);
struct display *display_create(void);
+20 -21
View File
@@ -27,26 +27,26 @@ 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_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);
@@ -54,7 +54,6 @@ void tty_data_write(struct chrdev *tty, char c) {
switch (c) {
case '\n':
// TODO: this should also check ICANON
if (tty->tc.c_lflag & ECHONL) {
tty_putc(tty, c);
}
+225 -10
View File
@@ -10,13 +10,29 @@
#define ATTR_DEFAULT 0x1700
#define ESC_ESC 1
#define ESC_CSI 2
#define ATTR_BOLD 1
static void console_flush(struct console *con, struct console_buffer *buf);
static LIST_HEAD(g_consoles);
struct console_buffer {
// Current attribute
uint16_t attr;
// Extended attributes
uint16_t xattrs;
// Escape code processing
uint32_t esc_argv[8];
char esc_letter;
size_t esc_argc;
int esc_mode;
// Cursor
uint16_t y, x;
// Blink
uint16_t last_blink_y, last_blink_x;
uint16_t data[0];
};
@@ -26,7 +42,11 @@ static struct console_buffer *console_buffer_create(uint16_t rows, uint16_t cols
memsetw(buf->data, ATTR_DEFAULT, rows * cols);
buf->y = 0;
buf->x = 0;
buf->last_blink_x = 0;
buf->last_blink_y = 0;
buf->attr = ATTR_DEFAULT;
buf->xattrs = 0;
buf->esc_mode = 0;
return buf;
}
@@ -75,28 +95,223 @@ static void console_scroll_check(struct console *con, struct console_buffer *buf
}
}
static uint8_t color_map[8] = { 0, 4, 2, 6, 1, 5, 3, 7 };
// I guess I could've implemented VT100 escape handling better, but
// this is all I invented so far
static void process_csi(struct console *con, struct console_buffer *buf) {
switch (buf->esc_letter) {
case 'm':
for (size_t i = 0; i < buf->esc_argc; ++i) {
uint32_t v = buf->esc_argv[i];
switch (v / 10) {
case 0:
switch (v % 10) {
case 0:
// Reset
buf->attr = ATTR_DEFAULT;
buf->xattrs = 0;
break;
case 1:
// Bright
buf->xattrs |= ATTR_BOLD;
break;
case 2:
// Dim
buf->xattrs &= ~ATTR_BOLD;
break;
case 7:
// Reverse
buf->attr >>= 4;
buf->attr |= (buf->attr & 0xF0) << 8;
buf->attr &= 0xFF00;
break;
}
break;
case 3:
// Foreground
buf->attr &= ~0x0F00;
buf->attr |= (uint16_t) color_map[v % 10] << 8;
break;
case 4:
// Background
buf->attr &= ~0xF000;
buf->attr |= (uint16_t) color_map[v % 10] << 12;
break;
}
}
break;
case 'J':
switch (buf->esc_argv[0]) {
case 0:
// Erase lines down
//memsetw(con_buffer, attr, con_width * y);
break;
case 1:
// Erase lines up
//memsetw(&con_buffer[y * con_width], attr, con_width * (con_height - y));
break;
case 2:
// Erase all
memsetw(buf->data, buf->attr, con->width_chars * con->height_chars);
console_flush(con, buf);
break;
}
break;
case 'f':
// Set cursor position
buf->y = (buf->esc_argv[0] - 1) % con->height_chars;
buf->x = (buf->esc_argv[1] - 1) % (con->width_chars - 1);
break;
default:
kdebug("\033[31mUnknown CSI sequence: %c\033[0m\n", buf->esc_letter);
break;
//case 'A':
// // Cursor up
// if (!esc_argv[0]) {
// esc_argv[0] = 1;
// }
// if (esc_argv[0] >= y) {
// y = 0;
// } else {
// y -= esc_argv[0];
// }
// break;
//case 'B':
// // Cursor down
// if (!esc_argv[0]) {
// esc_argv[0] = 1;
// }
// if (esc_argv[0] + y >= (uint32_t) (con_height - 1)) {
// y = 22;
// } else {
// y += esc_argv[0];
// }
// break;
//case 'C':
// // Forward
// if (!esc_argv[0]) {
// esc_argv[0] = 1;
// }
// if (esc_argv[0] + x >= con_width) {
// x = 79;
// } else {
// x += esc_argv[0];
// }
// break;
//case 'D':
// // Backward
// if (!esc_argv[0]) {
// esc_argv[0] = 1;
// }
// if (esc_argv[0] >= x) {
// x = 0;
// } else {
// x -= esc_argv[0];
// }
// break;
//case 'K':
// // Erase end of line
// memsetw(&con_buffer[y * con_width + x], attr, con_width - x);
// break;
}
}
static void _console_putc(struct console *con, struct console_buffer *buf, int c) {
int act = buf == con->buf_active;
if (c == '\n') {
++buf->y;
buf->x = 0;
console_scroll_check(con, buf);
} else if (c >= ' ') {
buf->data[buf->y * con->width_chars + buf->x] = c | buf->attr;
if (act) {
display_setc(con->display, buf->y, buf->x, c | buf->attr);
switch (buf->esc_mode) {
case ESC_CSI:
if (c >= '0' && c <= '9') {
buf->esc_argv[buf->esc_argc] *= 10;
buf->esc_argv[buf->esc_argc] += c - '0';
} else if (c == ';') {
buf->esc_argv[++buf->esc_argc] = 0;
} else {
++buf->esc_argc;
buf->esc_letter = c;
process_csi(con, buf);
buf->esc_mode = 0;
}
break;
case ESC_ESC:
if (c == '[') {
buf->esc_mode = ESC_CSI;
break;
} else {
buf->esc_mode = 0;
}
__attribute__((fallthrough));
case 0:
if (c == '\033') {
buf->esc_mode = ESC_ESC;
buf->esc_argv[0] = 0;
buf->esc_argc = 0;
return;
}
++buf->x;
if (buf->x >= con->width_chars) {
if (c == '\n') {
++buf->y;
buf->x = 0;
console_scroll_check(con, buf);
} else if (c >= ' ') {
buf->data[buf->y * con->width_chars + buf->x] = c | buf->attr;
if (act) {
uint16_t a = buf->attr;
if (buf->xattrs & ATTR_BOLD) {
a |= 0x8000;
}
display_setc(con->display, buf->y, buf->x, c | a);
}
++buf->x;
if (buf->x >= con->width_chars) {
++buf->y;
buf->x = 0;
console_scroll_check(con, buf);
}
}
}
}
void console_update_cursor(void) {
struct console *con;
static int prev_blink = 0;
if (g_display_blink_state != prev_blink) {
list_for_each_entry(con, &g_consoles, list) {
if (con->display && con->buf_active) {
struct console_buffer *buf = con->buf_active;
uint16_t c = buf->data[buf->y * con->width_chars + buf->x];
if (g_display_blink_state) {
// Swap attributes
c = ((c >> 4) & 0xF00) |
((c & 0xF00) << 4) |
(c & 0xFF);
}
display_setc(con->display, buf->y, buf->x, c);
if (buf->last_blink_x != buf->x || buf->last_blink_y != buf->y) {
// Also redraw character at last blink position
display_setc(con->display,
buf->last_blink_y,
buf->last_blink_x,
buf->data[buf->last_blink_y * con->width_chars +
buf->last_blink_x]);
buf->last_blink_x = buf->x;
buf->last_blink_y = buf->y;
}
}
}
prev_blink = g_display_blink_state;
}
}
void console_putc(struct console *con, struct chrdev *tty, int c) {
struct tty_data *data = tty->dev_data;
_assert(data);
+3 -2
View File
@@ -1,11 +1,13 @@
#include "sys/font/psf.h"
#include "sys/display.h"
#include "sys/console.h"
#include "sys/debug.h"
#include <stddef.h>
int g_display_blink_state = 0;
static LIST_HEAD(displays);
static uint8_t color_map[8] = { 0, 4, 2, 6, 1, 5, 3, 7 };
static uint32_t rgb_map[16] = {
0x000000,
0x0000AA,
@@ -44,7 +46,6 @@ void display_add(struct display *disp) {
void display_setc(struct display *disp, uint16_t y, uint16_t x, uint16_t ch) {
if (disp->flags & DISP_GRAPHIC) {
// TODO: attr conversion
psf_draw(disp, y, x, ch & 0xFF, rgb_map[(ch >> 8) & 0xF], rgb_map[(ch >> 12) & 0xF]);
}
}