430 lines
13 KiB
C
430 lines
13 KiB
C
#include "tty.h"
|
|
#include "x86.h"
|
|
#include "console.h"
|
|
#include "const.h"
|
|
#include "assert.h"
|
|
|
|
#define INDEX(row, col) ((row)*SCR_WIDTH + (col))
|
|
#define NEXTLINE(row) NEXT(row, SCR_MAXLINE)
|
|
#define LASTLINE(row) LAST(row, SCR_MAXLINE)
|
|
#define ADDLINE(row, add_num) (((row) + add_num) % SCR_MAXLINE)
|
|
|
|
void enable_blink()
|
|
{
|
|
disable_int();
|
|
inb(0x3DA);
|
|
outb(0x3C0, 0x30);
|
|
u8 temp = inb(0x3C1);
|
|
outb(0x3C0, temp | 0x08);
|
|
enable_int();
|
|
}
|
|
|
|
void disable_blink()
|
|
{
|
|
disable_int();
|
|
inb(0x3DA);
|
|
outb(0x3C0, 0x30);
|
|
u8 temp = inb(0x3C1);
|
|
outb(0x3C0, temp & 0xF7);
|
|
enable_int();
|
|
}
|
|
|
|
void set_underline(u32 addr)
|
|
{
|
|
disable_int();
|
|
inb(0x3DA);
|
|
outb(0x3C0, 0x30);
|
|
u8 temp = inb(0x3C1);
|
|
outb(0x3C0, temp | 0x01);
|
|
outb(CRTC_ADDR_REG, UNDERLINE_REG);
|
|
outb(CRTC_DATA_REG, addr & 0xFF);
|
|
enable_int();
|
|
}
|
|
|
|
// called by csi
|
|
void csi_scroll(vga_buf *vgabuf, i16 scroll_num)
|
|
{
|
|
while (scroll_num > 0) // down
|
|
{
|
|
scroll_num--;
|
|
for (int i = SCR_HEIGHT - 1; i > 0; i--)
|
|
{
|
|
int line_dst = ADDLINE(vgabuf->scr_top_line, i);
|
|
int line_src = ADDLINE(vgabuf->scr_top_line, i - 1);
|
|
u32 *ptr_buf_dst = (u32 *)(vgabuf->buf + sizeof(u16) * line_dst * SCR_WIDTH);
|
|
u32 *ptr_buf_src = (u32 *)(vgabuf->buf + sizeof(u16) * line_src * SCR_WIDTH);
|
|
for (int p = 0; p < SCR_WIDTH * sizeof(u16) / sizeof(u32); ++p)
|
|
{
|
|
*ptr_buf_dst++ = *ptr_buf_src++;
|
|
}
|
|
}
|
|
u32 *ptr_buf_start = (u32 *)(vgabuf->buf + sizeof(u16) * (vgabuf->scr_top_line) * SCR_WIDTH);
|
|
for (int i = 0; i < SCR_WIDTH * sizeof(u16) / sizeof(u32); ++i)
|
|
{
|
|
*ptr_buf_start++ = (BLANK << 16) | BLANK;
|
|
}
|
|
}
|
|
while (scroll_num < 0) // up
|
|
{
|
|
scroll_num++;
|
|
|
|
for (int i = 0; i < SCR_HEIGHT - 1; i++)
|
|
{
|
|
int line_dst = ADDLINE(vgabuf->scr_top_line, i);
|
|
int line_src = ADDLINE(vgabuf->scr_top_line, i + 1);
|
|
u32 *ptr_buf_dst = (u32 *)(vgabuf->buf + sizeof(u16) * line_dst * SCR_WIDTH);
|
|
u32 *ptr_buf_src = (u32 *)(vgabuf->buf + sizeof(u16) * line_src * SCR_WIDTH);
|
|
for (int p = 0; p < SCR_WIDTH * sizeof(u16) / sizeof(u32); ++p)
|
|
{
|
|
*ptr_buf_dst++ = *ptr_buf_src++;
|
|
}
|
|
}
|
|
int line_end = ADDLINE(vgabuf->scr_top_line, SCR_HEIGHT - 1);
|
|
u32 *ptr_buf_end = (u32 *)(vgabuf->buf + sizeof(u16) * line_end * SCR_WIDTH);
|
|
for (int i = 0; i < SCR_WIDTH * sizeof(u16) / sizeof(u32); ++i)
|
|
{
|
|
*ptr_buf_end++ = (BLANK << 16) | BLANK; // bg-black, fg-white, ascii-space
|
|
}
|
|
}
|
|
}
|
|
|
|
void cursor_locate(i16 row, i16 col, vga_buf *vgabuf)
|
|
{
|
|
|
|
vgabuf->scr_cur_line = vgabuf->scr_top_line;
|
|
while (row > 0 && row < SCR_HEIGHT)
|
|
{
|
|
row--;
|
|
vgabuf->scr_cur_line = NEXTLINE(vgabuf->scr_cur_line);
|
|
if (vgabuf->scr_cur_line == vgabuf->scr_bot_line)
|
|
break;
|
|
}
|
|
if (col >= 0 && col <= SCR_WIDTH - 1)
|
|
{
|
|
vgabuf->cur_col = col;
|
|
}
|
|
}
|
|
|
|
void cursor_move(i16 move_row, i16 move_col, vga_buf *vgabuf)
|
|
{
|
|
// kprintf("%d,%d", move_row, move_col);
|
|
while (move_row > 0) // down
|
|
{
|
|
move_row--;
|
|
if (vgabuf->scr_cur_line == vgabuf->scr_bot_line)
|
|
break;
|
|
vgabuf->scr_cur_line = NEXTLINE(vgabuf->scr_cur_line);
|
|
vgabuf->cur_row = CYCLE_SUB(vgabuf->scr_top_line, vgabuf->scr_cur_line, SCR_MAXLINE);
|
|
if (vgabuf->cur_row == SCR_HEIGHT)
|
|
{
|
|
// auto scroll
|
|
vgabuf->scr_top_line = NEXTLINE(vgabuf->scr_top_line);
|
|
}
|
|
}
|
|
while (move_row < 0) // up
|
|
{
|
|
move_row++;
|
|
if (vgabuf->scr_cur_line == vgabuf->scr_top_line)
|
|
break;
|
|
vgabuf->scr_cur_line = LASTLINE(vgabuf->scr_cur_line);
|
|
// if (vgabuf->scr_cur_line == vgabuf->scr_top_line)
|
|
// {
|
|
// if (vgabuf->scr_top_line == vgabuf->head_line)
|
|
// break;
|
|
// // vgabuf->scr_cur_line = LASTLINE(vgabuf->scr_cur_line);
|
|
// vgabuf->scr_top_line = LASTLINE(vgabuf->scr_top_line);
|
|
// vgabuf->scr_bot_line = LASTLINE(vgabuf->scr_bot_line);
|
|
// }
|
|
}
|
|
vgabuf->cur_row = CYCLE_SUB(vgabuf->scr_top_line, vgabuf->scr_cur_line, SCR_MAXLINE);
|
|
vgabuf->cur_col += move_col;
|
|
if (vgabuf->cur_col < 0)
|
|
vgabuf->cur_col = 0;
|
|
else if (vgabuf->cur_col >= SCR_WIDTH)
|
|
vgabuf->cur_col = SCR_WIDTH - 1;
|
|
}
|
|
|
|
void clear_screen(vga_buf *vgabuf, i16 src_row, i16 src_col, i16 dst_row, i16 dst_col)
|
|
{
|
|
u16 *buf = vgabuf->buf;
|
|
int src_index = INDEX(src_row, src_col);
|
|
int dst_index = INDEX(dst_row, dst_col);
|
|
if (src_index <= dst_index)
|
|
for (int i = src_index; i <= dst_index; i++)
|
|
{
|
|
buf[i] = BLANK;
|
|
}
|
|
else // scr>dst
|
|
{
|
|
for (int i = 0; i <= dst_index; i++)
|
|
buf[i] = BLANK;
|
|
int index_end = INDEX(SCR_MAXLINE - 1, SCR_WIDTH - 1);
|
|
for (int i = 0; i <= index_end; i++)
|
|
buf[i] = BLANK;
|
|
}
|
|
}
|
|
|
|
inline static void
|
|
param12vga_color(i16 *param)
|
|
{
|
|
u8 tmp = *param & 1;
|
|
*param &= 0b0110;
|
|
*param |= *param >> 2;
|
|
*param &= 0b0011;
|
|
*param |= tmp << 2;
|
|
}
|
|
|
|
inline static void
|
|
enable_reverse(vga_buf *vgabuf)
|
|
{
|
|
vgabuf->last_color = vgabuf->color;
|
|
vgabuf->color = ((vgabuf->color & 0xf000) >> 4) | ((vgabuf->color & 0x0f00) << 4);
|
|
vgabuf->IsColorReverse = true;
|
|
}
|
|
|
|
inline static void
|
|
disable_reverse(vga_buf *vgabuf)
|
|
{
|
|
if (vgabuf->IsColorReverse == true)
|
|
{
|
|
vgabuf->color = vgabuf->last_color;
|
|
vgabuf->IsColorReverse = false;
|
|
}
|
|
}
|
|
|
|
inline static void
|
|
enable_hide(vga_buf *vgabuf)
|
|
{
|
|
vgabuf->last_color = vgabuf->color;
|
|
u16 back_clolor = ((vgabuf->color & 0xF000) >> 4);
|
|
vgabuf->color &= 0xf000;
|
|
vgabuf->color |= back_clolor;
|
|
vgabuf->IsHide = true;
|
|
}
|
|
|
|
inline static void
|
|
disable_hide(vga_buf *vgabuf)
|
|
{
|
|
if (vgabuf->IsHide == true)
|
|
{
|
|
vgabuf->color = vgabuf->last_color;
|
|
vgabuf->IsHide = false;
|
|
}
|
|
}
|
|
|
|
void set_color(i16 param_cnt, i16 param[], vga_buf *vgabuf)
|
|
{
|
|
for (int i = 0; i <= param_cnt; i++)
|
|
{
|
|
if (param[i] == 0)
|
|
{
|
|
disable_reverse(vgabuf);
|
|
disable_hide(vgabuf);
|
|
vgabuf->color = DEFAULT_CHAR_COLOR;
|
|
}
|
|
else if (param[i] == 7)
|
|
{
|
|
enable_reverse(vgabuf);
|
|
}
|
|
else if (param[i] == 8)
|
|
{
|
|
enable_hide(vgabuf);
|
|
}
|
|
else if (param[i] == 27)
|
|
{
|
|
disable_reverse(vgabuf);
|
|
}
|
|
else if (param[i] == 28)
|
|
{
|
|
disable_hide(vgabuf);
|
|
}
|
|
else if (30 <= param[i] && param[i] <= 37)
|
|
{
|
|
param[i] -= 30;
|
|
param12vga_color(&(param[i]));
|
|
vgabuf->color = (vgabuf->color & 0xf8ff) | FOREGROUND(param[i]);
|
|
}
|
|
else if (param[i] == 39)
|
|
{
|
|
u16 default_foreground = DEFAULT_CHAR_COLOR & 0x0f00;
|
|
vgabuf->color = (vgabuf->color & 0xf0ff) | default_foreground;
|
|
}
|
|
else if (40 <= param[i] && param[i] <= 47)
|
|
{
|
|
param[i] -= 40;
|
|
param12vga_color(&(param[i]));
|
|
vgabuf->color = (vgabuf->color & 0x8fff) | BACKGROUND(param[i]);
|
|
}
|
|
else if (param[i] == 49)
|
|
{
|
|
u16 default_background = DEFAULT_CHAR_COLOR & 0xf000;
|
|
vgabuf->color = (vgabuf->color & 0x0fff) | default_background;
|
|
}
|
|
else if (90 <= param[i] && param[i] <= 97)
|
|
{
|
|
param[i] -= 90;
|
|
param12vga_color(&(param[i]));
|
|
param[i] |= 0x8;
|
|
vgabuf->color = (vgabuf->color & 0xf0ff) | FOREGROUND(param[i]);
|
|
}
|
|
else if (100 <= param[i] && param[i] <= 107)
|
|
{
|
|
param[i] -= 100;
|
|
param12vga_color(&(param[i]));
|
|
param[i] |= 0x8;
|
|
vgabuf->color = (vgabuf->color & 0x0fff) | BACKGROUND(param[i]);
|
|
}
|
|
else
|
|
{
|
|
warn("\x1b[47;93munsupport CSI: sgr param[%d]:%d\x1b[m\n", i, param[i]);
|
|
}
|
|
}
|
|
}
|
|
|
|
void CSI_Erase_handler(vga_buf *vgabuf, int n)
|
|
{
|
|
if (n == 2)
|
|
{
|
|
vgabuf->scr_bot_line = ADDLINE(vgabuf->scr_top_line, SCR_HEIGHT - 1);
|
|
for (int i = 0; i < SCR_HEIGHT; i++)
|
|
{
|
|
vgabuf->scr_cur_line = NEXTLINE(vgabuf->scr_cur_line);
|
|
vgabuf->scr_bot_line = NEXTLINE(vgabuf->scr_bot_line);
|
|
// kprintf("af %x\n", vgabuf->scr_cur_line);
|
|
vgabuf->cur_row = CYCLE_SUB(vgabuf->scr_top_line, vgabuf->scr_bot_line, SCR_MAXLINE);
|
|
if (vgabuf->cur_row == SCR_HEIGHT)
|
|
{
|
|
// auto scroll
|
|
vgabuf->scr_top_line = NEXTLINE(vgabuf->scr_top_line);
|
|
}
|
|
if (vgabuf->scr_bot_line == vgabuf->head_line)
|
|
{
|
|
vgabuf->head_line = NEXTLINE(vgabuf->head_line);
|
|
// remember to fill blank the old line
|
|
u32 *ptr_buf = (u32 *)(vgabuf->buf + sizeof(u16) * vgabuf->scr_bot_line * SCR_WIDTH);
|
|
for (int i = 0; i < SCR_WIDTH * sizeof(u16) / sizeof(u32); ++i)
|
|
{
|
|
*ptr_buf++ = (BLANK << 16) | BLANK; // bg-black, fg-white, ascii-space
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (n == 3)
|
|
{
|
|
int line = vgabuf->head_line;
|
|
while (line != vgabuf->scr_top_line)
|
|
{
|
|
u32 *ptr_buf = (u32 *)(vgabuf->buf + sizeof(u16) * line * SCR_WIDTH);
|
|
for (int i = 0; i < SCR_WIDTH * sizeof(u16) / sizeof(u32); ++i)
|
|
{
|
|
*ptr_buf++ = (BLANK << 16) | BLANK; // bg-black, fg-white, ascii-space
|
|
}
|
|
line = NEXTLINE(line);
|
|
}
|
|
vgabuf->head_line = vgabuf->scr_top_line;
|
|
}
|
|
}
|
|
|
|
void CSI_handler(u8 terminator, vga_buf *vgabuf)
|
|
{
|
|
vgabuf->CSI = CSI_ESC;
|
|
i16 param[MAXNUM_PARAM] = {0};
|
|
i16 param_cnt = 0;
|
|
for (int i = 0; i < vgabuf->param_num && param_cnt < MAXNUM_PARAM; i++)
|
|
{
|
|
u8 ch = vgabuf->param_c[i];
|
|
if (ch != ';')
|
|
{
|
|
param[param_cnt] = param[param_cnt] * 10 + ch - '0';
|
|
}
|
|
else
|
|
{
|
|
param_cnt++;
|
|
continue;
|
|
}
|
|
}
|
|
switch (terminator)
|
|
{
|
|
case 'A': // Cursor Up
|
|
if (param[0] == 0)
|
|
param[0] = 1;
|
|
cursor_move(-param[0], 0, vgabuf);
|
|
break;
|
|
case 'B': // Cursor Down
|
|
if (param[0] == 0)
|
|
param[0] = 1;
|
|
cursor_move(+param[0], 0, vgabuf);
|
|
break;
|
|
case 'C': // Cursor Forward
|
|
if (param[0] == 0)
|
|
param[0] = 1;
|
|
cursor_move(0, +param[0], vgabuf);
|
|
break;
|
|
case 'D': // Cursor Back
|
|
if (param[0] == 0)
|
|
param[0] = 1;
|
|
cursor_move(0, -param[0], vgabuf); // nothing
|
|
break;
|
|
case 'E': // Cursor Next Line
|
|
if (param[0] == 0)
|
|
param[0] = 1;
|
|
cursor_move(+param[0], -vgabuf->cur_col, vgabuf);
|
|
break;
|
|
case 'F': // Cursor Previous Line
|
|
if (param[0] == 0)
|
|
param[0] = 1;
|
|
cursor_move(-param[0], -vgabuf->cur_col, vgabuf);
|
|
break;
|
|
case 'G': // Cursor Horizontal Absolute
|
|
if (param[0] == 0)
|
|
param[0] = 1;
|
|
cursor_locate(CYCLE_SUB(vgabuf->scr_top_line, vgabuf->scr_cur_line, SCR_MAXLINE), param[0] - 1, vgabuf);
|
|
break;
|
|
case 'H': // Cursor Position
|
|
case 'f':
|
|
if (param[0] == 0)
|
|
param[0] = 1;
|
|
if (param[1] == 0)
|
|
param[1] = 1;
|
|
cursor_locate(param[0] - 1, param[1] - 1, vgabuf);
|
|
break;
|
|
case 'J': // Erase in Display
|
|
if (param[0] == 0)
|
|
// from Cursor Position to the end of the screen
|
|
clear_screen(vgabuf, vgabuf->scr_cur_line, vgabuf->cur_col, ADDLINE(vgabuf->scr_top_line, SCR_HEIGHT - 1), SCR_WIDTH - 1);
|
|
else if (param[0] == 1)
|
|
// from Cursor Position to the start of the screen
|
|
clear_screen(vgabuf, vgabuf->scr_top_line, 0, vgabuf->scr_cur_line, vgabuf->cur_col);
|
|
else if (param[0] == 2)
|
|
// The whole screen
|
|
CSI_Erase_handler(vgabuf, 2);
|
|
else if (param[0] == 3)
|
|
// The whole screen and the buffer
|
|
CSI_Erase_handler(vgabuf, 3);
|
|
break;
|
|
case 'K': // Erase in Line
|
|
if (param[0] == 0)
|
|
// from Cursor Position to the end of the line
|
|
clear_screen(vgabuf, vgabuf->scr_cur_line, vgabuf->cur_col, vgabuf->scr_cur_line, SCR_WIDTH - 1);
|
|
else if (param[0] == 1)
|
|
// from Cursor Position to the start of the line
|
|
clear_screen(vgabuf, vgabuf->scr_cur_line, 0, vgabuf->scr_cur_line, vgabuf->cur_col);
|
|
else if (param[0] == 2)
|
|
// The whole line
|
|
clear_screen(vgabuf, vgabuf->scr_cur_line, 0, vgabuf->scr_cur_line, SCR_WIDTH - 1);
|
|
break;
|
|
case 'S': // Scroll Up
|
|
if (param[0] == 0)
|
|
param[0] = 1;
|
|
csi_scroll(vgabuf, -param[0]);
|
|
break;
|
|
case 'T': // Scroll Down
|
|
if (param[0] == 0)
|
|
param[0] = 1;
|
|
csi_scroll(vgabuf, +param[0]);
|
|
break;
|
|
case 'm': // Select Graphic Rendition
|
|
set_color(param_cnt, param, vgabuf);
|
|
break;
|
|
}
|
|
} |