BigOS/kernel/vga.c
2023-01-01 22:40:12 +08:00

726 lines
20 KiB
C

#include "type.h"
#include "stdio.h"
#include "const.h"
#include "protect.h"
#include "string.h"
#include "proc.h"
#include "tty.h"
#include "console.h"
#include "global.h"
#include "keyboard.h"
#include "proto.h"
#include "x86.h"
#include "memman.h"
#include "assert.h"
/*****************************************************************************
* Low level vga driver
*****************************************************************************/
/*****************************************************************************
* Display the cursor by setting CRTC (6845 compatible) registers.
*
* @param position Position of the cursor based on the beginning of the video
* memory. Note that it counts in WORDs, not in BYTEs.
*****************************************************************************/
static inline void vga_set_cursor(unsigned int position)
{
disable_int();
outb(CRTC_ADDR_REG, CURSOR_H);
outb(CRTC_DATA_REG, (position >> 8) & 0xFF);
outb(CRTC_ADDR_REG, CURSOR_L);
outb(CRTC_DATA_REG, position & 0xFF);
enable_int();
}
static inline void vga_disable_cursor()
{
outb(CRTC_ADDR_REG, 0x0A);
outb(CRTC_DATA_REG, 0x20);
}
static inline void vga_enable_cursor(u8 cursor_start, u8 cursor_end)
{
outb(0x3D4, 0x0A);
outb(0x3D5, (inb(0x3D5) & 0xC0) | cursor_start);
outb(0x3D4, 0x0B);
outb(0x3D5, (inb(0x3D5) & 0xE0) | cursor_end);
}
/*****************************************************************************
* Routine for hardware screen scrolling.
*
* @param addr Offset in the video memory.
*****************************************************************************/
static inline void vga_set_video_start_addr(u32 addr)
{
disable_int();
outb(CRTC_ADDR_REG, START_ADDR_H);
outb(CRTC_DATA_REG, (addr >> 8) & 0xFF);
outb(CRTC_ADDR_REG, START_ADDR_L);
outb(CRTC_DATA_REG, addr & 0xFF);
enable_int();
}
/*****************************************************************************
* Write data directly to Video Memory cell
*
* @param pos text mode position(pos*2 yourself)
* @param dat data to be written, with format [ BG | FG | ASCII ]
*****************************************************************************/
static inline void vga_put_raw(u32 pos, u16 dat)
{
u16 *pch = (u16 *)K_PHY2LIN(V_MEM_BASE + pos);
*pch = dat;
}
/*****************************************************************************
* copy a whole screen of text mode data into video memory, assume that screen
* width is 80 or 40
*
* @param src memory block with the same size as text mode video memory()
*****************************************************************************/
static inline void vga_flush_screen(void *src)
{
u32 *_src = src;
u32 *dst = (u32 *)K_PHY2LIN(V_MEM_BASE);
for (int i = 0; i < SCR_SIZE * sizeof(u16) / sizeof(u32); ++i)
{
*dst++ = *_src++;
}
}
/*****************************************************************************
* copy a whole screen of text mode data into video memory, assume that screen
* width is 80 or 40
*
* @param src memory block with the same size as text mode video memory()
*****************************************************************************/
static inline void vga_flush_line(void *src, int line_no)
{
u32 *_src = src;
u32 *dst = (u32 *)K_PHY2LIN(V_MEM_BASE + line_no * SCR_WIDTH * 2);
for (int i = 0; i < SCR_WIDTH * sizeof(u16) / sizeof(u32); ++i)
{
*dst++ = *_src++;
}
}
static inline void vga_flush_blankline(int line_no)
{
u32 *dst = (u32 *)K_PHY2LIN(V_MEM_BASE + line_no * SCR_WIDTH * 2);
for (int i = 0; i < SCR_WIDTH * sizeof(u16) / sizeof(u32); ++i)
{
*dst++ = (BLANK << 16) | BLANK;
}
}
/*****************************************************************************
* tty - vga driver
*****************************************************************************/
static u16 pagebuf[3][SCR_BUFSIZE];
void vga_tty_init(NTTY *tty)
{
static int _cnt = 0;
assert(tty->driver_type == 1);
assert(tty->output_buf);
vga_buf *vga = tty->output_buf;
vga->buf = (void*)K_PHY2LIN(do_kmalloc(sizeof(u16) * SCR_BUFSIZE));
// vga->buf = (void *)pagebuf[_cnt++];
// kprintf("malloced %p %p %p\n", vga->buf, &vga->buf, &vga->scr_top_line);
vga->cur_col = vga->cur_row = 0;
// buf->max_line = SCR_BUFSIZE / SCR_WIDTH;
vga->scr_top_line = vga->scr_cur_line = vga->scr_bot_line = 0;
vga->head_line = 0;
u32 *ptr_buf = (u32 *)vga->buf;
for (int i = 0; i < SCR_BUFSIZE * sizeof(u16) / sizeof(u32); ++i)
{
ptr_buf[i] = (BLANK << 16) | BLANK; // bg-black, fg-white, ascii-space
}
// kprintf("%p 0x%x %d\n", vga->buf, ((u32 *)vga->buf)[20], vga->scr_cur_line);
}
#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)
// called by csi
static 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; // bg-black, fg-white, ascii-space
}
}
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
}
}
}
static void newline(vga_buf *vga)
{
u16 *buf = vga->buf;
vga->cur_col = 0;
// kprintf("bf %x\n", vgabuf->scr_cur_line);
vga->scr_cur_line = NEXTLINE(vga->scr_cur_line);
// kprintf("af %x\n", vgabuf->scr_cur_line);
vga->cur_row = CYCLE_SUB(vga->scr_top_line, vga->scr_cur_line, SCR_MAXLINE);
if (vga->cur_row == SCR_HEIGHT)
{
// auto scroll
vga->scr_top_line = NEXTLINE(vga->scr_top_line);
}
if (vga->scr_cur_line == vga->head_line)
{
vga->head_line = NEXTLINE(vga->head_line);
// remember to fill blank the old line
u32 *ptr_buf = (u32 *)(vga->buf + sizeof(u16) * vga->scr_cur_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
}
// for (int i = 0; i < SCR_WIDTH; ++ i) {
// buf[INDEX(vga->scr_cur_line, i)] = BLANK;
// }
}
}
static void nextcol(vga_buf *vgabuf)
{
vgabuf->cur_col++;
if (vgabuf->cur_col == SCR_WIDTH)
{
newline(vgabuf);
}
}
static 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;
}
}
static 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++;
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;
}
inline static void
param12vga_color(i16 *param)
{
u8 tmp = *param & 1;
*param &= 0b0110;
*param |= *param >> 2;
*param &= 0b0011;
*param |= tmp << 2;
}
static 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;
}
}
static void set_color(vga_buf *vgabuf)
{
if (vgabuf->param1 == 0)
{
vgabuf->color = DEFAULT_CHAR_COLOR;
}
else if (vgabuf->param1 == 1)
{
vgabuf->color |= 0x8800;
}
else if (vgabuf->param1 == 2)
{
vgabuf->color &= 0x7700;
}
else if (30 <= vgabuf->param1 && vgabuf->param1 <= 37)
{
vgabuf->param1 -= 30;
param12vga_color(&(vgabuf->param1));
vgabuf->color = (vgabuf->color & 0xf8ff) | FOREGROUND(vgabuf->param1);
}
else if (40 <= vgabuf->param1 && vgabuf->param1 <= 47)
{
vgabuf->param1 -= 40;
param12vga_color(&(vgabuf->param1));
vgabuf->color = (vgabuf->color & 0x8fff) | BACKGROUND(vgabuf->param1);
}
else if (90 <= vgabuf->param1 && vgabuf->param1 <= 97)
{
vgabuf->param1 -= 90;
param12vga_color(&(vgabuf->param1));
vgabuf->param1 |= 0x8;
vgabuf->color = (vgabuf->color & 0xf0ff) | FOREGROUND(vgabuf->param1);
}
else if (100 <= vgabuf->param1 && vgabuf->param1 <= 107)
{
vgabuf->param1 -= 100;
param12vga_color(&(vgabuf->param1));
vgabuf->param1 |= 0x8;
vgabuf->color = (vgabuf->color & 0x0fff) | BACKGROUND(vgabuf->param1);
}
else
{
warn("unsupport CSI: color");
}
if (vgabuf->CSI == CSI_PARAM2)
{
if (vgabuf->param2 == 0 && vgabuf->param1 == 0)
{
vgabuf->color = DEFAULT_CHAR_COLOR;
}
else if (vgabuf->param2 == 1)
{
vgabuf->color |= 0x8800;
}
else if (vgabuf->param2 == 2)
{
vgabuf->color &= 0x7700;
}
else if (30 <= vgabuf->param2 && vgabuf->param2 <= 37)
{
vgabuf->param2 -= 30;
param12vga_color(&(vgabuf->param2));
vgabuf->color = (vgabuf->color & 0xf8ff) | FOREGROUND(vgabuf->param2);
}
else if (40 <= vgabuf->param2 && vgabuf->param2 <= 47)
{
vgabuf->param2 -= 40;
param12vga_color(&(vgabuf->param2));
vgabuf->color = (vgabuf->color & 0x8fff) | BACKGROUND(vgabuf->param2);
}
else if (90 <= vgabuf->param2 && vgabuf->param2 <= 97)
{
vgabuf->param2 -= 90;
param12vga_color(&(vgabuf->param2));
vgabuf->param2 |= 0x8;
vgabuf->color = (vgabuf->color & 0xf0ff) | FOREGROUND(vgabuf->param2);
}
else if (100 <= vgabuf->param2 && vgabuf->param2 <= 107)
{
vgabuf->param2 -= 100;
param12vga_color(&(vgabuf->param2));
vgabuf->param2 |= 0x8;
vgabuf->color = (vgabuf->color & 0x0fff) | BACKGROUND(vgabuf->param2);
}
else
{
warn("unsupport CSI: color");
}
}
}
static 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;
}
}
static void CSI_handler(u8 terminator, vga_buf *vgabuf)
{
vgabuf->CSI = CSI_ESC;
switch (terminator)
{
case 'A':
if (vgabuf->param1 == 0)
vgabuf->param1 == 1;
cursor_move(-vgabuf->param1, 0, vgabuf);
break;
case 'B':
if (vgabuf->param1 == 0)
vgabuf->param1 == 1;
cursor_move(+vgabuf->param1, 0, vgabuf);
break;
case 'C':
if (vgabuf->param1 == 0)
vgabuf->param1 == 1;
cursor_move(0, +vgabuf->param1, vgabuf);
break;
case 'D':
if (vgabuf->param1 == 0)
vgabuf->param1 == 1;
cursor_move(0, -vgabuf->param1, vgabuf); // nothing
break;
case 'E':
if (vgabuf->param1 == 0)
vgabuf->param1 == 1;
cursor_move(+vgabuf->param1, -vgabuf->cur_col, vgabuf);
break;
case 'F':
if (vgabuf->param1 == 0)
vgabuf->param1 == 1;
cursor_move(-vgabuf->param1, -vgabuf->cur_col, vgabuf);
break;
case 'G': // added
if (vgabuf->param1 == 0)
vgabuf->param1 == 1;
cursor_locate(CYCLE_SUB(vgabuf->scr_top_line, vgabuf->scr_cur_line, SCR_MAXLINE), vgabuf->param1 - 1, vgabuf);
break;
case 'H':
case 'f':
if (vgabuf->param1 == 0)
vgabuf->param1 == 1;
if (vgabuf->param2 == 0)
vgabuf->param2 == 1;
cursor_locate(vgabuf->param1 - 1, vgabuf->param2 - 1, vgabuf);
break;
case 'J':
if (vgabuf->param1 == 0)
clear_screen(vgabuf, vgabuf->scr_cur_line, vgabuf->cur_col, ADDLINE(vgabuf->scr_top_line, SCR_HEIGHT - 1), SCR_WIDTH - 1);
else if (vgabuf->param1 == 1)
clear_screen(vgabuf, vgabuf->scr_top_line, 0, vgabuf->scr_cur_line, vgabuf->cur_col);
else if (vgabuf->param1 == 2)
CSI_Erase_handler(vgabuf, 2);
else if (vgabuf->param1 == 3)
CSI_Erase_handler(vgabuf, 3);
break;
case 'K':
if (vgabuf->param1 == 0)
clear_screen(vgabuf, vgabuf->scr_cur_line, vgabuf->cur_col, vgabuf->scr_cur_line, SCR_WIDTH - 1);
else if (vgabuf->param1 == 1)
clear_screen(vgabuf, vgabuf->scr_cur_line, 0, vgabuf->scr_cur_line, vgabuf->cur_col);
else if (vgabuf->param1 == 2)
clear_screen(vgabuf, vgabuf->scr_cur_line, 0, vgabuf->scr_cur_line, SCR_WIDTH - 1);
break;
case 'S': // Scroll Up
if (vgabuf->param1 == 0)
vgabuf->param1 = 1;
csi_scroll(vgabuf, -vgabuf->param1);
break;
case 'T': // Scroll Down
if (vgabuf->param1 == 0)
vgabuf->param1 = 1;
csi_scroll(vgabuf, +vgabuf->param1);
break;
case 'm':
set_color(vgabuf);
break;
}
}
void vga_tty_write(NTTY *tty, char ch)
{
// assert(tty->driver_type == 1);
// assert(tty->output_buf);
vga_buf *vga = tty->output_buf;
u16 *buf = vga->buf;
// kprintf("vga_tty_write %c to %d %d\n", ch, vga->scr_cur_line, vga->cur_col);
if (vga->CSI == CSI_ESC)
{
switch (ch)
{
case '\t':
if (INDEX(vga->scr_cur_line, vga->cur_col) == SCR_BUFSIZE - 1)
break;
while (vga->cur_col % 4 != 1)
{
nextcol(vga);
}
break;
case '\n':
newline(vga);
break;
case '\r':
vga->cur_col = 0;
break;
case '\b':
// this implementation is mimic to usual linux shell
// it moves cursor left but neither crosses line nor delete character
if (vga->cur_col > 0)
{
vga->cur_col--;
}
break;
case '\x1b':
vga->CSI = CSI_BRACKET;
break;
default:
if (vga->color == 0)
{
buf[INDEX(vga->scr_cur_line, vga->cur_col)] = MAKE_CELL(DEFAULT_CHAR_COLOR, ch);
}
else
{
buf[INDEX(vga->scr_cur_line, vga->cur_col)] = MAKE_CELL(vga->color, ch);
}
// buf[INDEX(vga->scr_cur_line, vga->cur_col)] = MAKE_CELL(DEFAULT_CHAR_COLOR, ch);
nextcol(vga);
break;
}
}
else if (vga->CSI == CSI_BRACKET)
{
switch (ch)
{
case '[':
vga->CSI = CSI_PARAM1;
vga->param1 = vga->param2 = 0;
break;
default:
vga->CSI = CSI_ESC;
break;
}
}
else
{
switch (ch)
{
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
if (vga->CSI == CSI_PARAM1)
vga->param1 = vga->param1 * 10 + ch - '0';
else if (vga->CSI == CSI_PARAM2)
vga->param2 = vga->param2 * 10 + ch - '0';
else
; // do nothing
break;
case ';':
vga->CSI = CSI_PARAM2;
break;
default:
if (!(0x20 <= ch && ch <= 0x7e))
vga->CSI = CSI_ESC;
if (0x40 <= ch && ch <= 0x7e)
CSI_handler(ch, vga);
break;
}
}
vga->cur_row = CYCLE_SUB(vga->scr_top_line, vga->scr_cur_line, SCR_MAXLINE);
if (CYCLE_SUB(vga->head_line, vga->scr_cur_line, SCR_MAXLINE) >= CYCLE_SUB(vga->head_line, vga->scr_bot_line, SCR_MAXLINE))
{
vga->scr_bot_line = vga->scr_cur_line;
}
// kprintf("row: %d; ", vga->cur_row);
}
void vga_tty_backspace(NTTY *tty)
{
vga_buf *vga = tty->output_buf;
u16 *buf = vga->buf;
if (vga->cur_col == 0)
{
vga->cur_col = SCR_WIDTH - 1;
vga->scr_cur_line = LASTLINE(vga->scr_cur_line);
}
else
{
vga->cur_col--;
}
buf[INDEX(vga->scr_cur_line, vga->cur_col)] = BLANK;
vga->cur_row = CYCLE_SUB(vga->scr_top_line, vga->scr_cur_line, SCR_MAXLINE);
}
void vga_tty_flush(NTTY *tty)
{
vga_buf *vga = tty->output_buf;
u16 *buf = vga->buf;
int i, cur_line;
vga_set_cursor(INDEX(vga->cur_row, vga->cur_col));
vga->cur_row = CYCLE_SUB(vga->scr_top_line, vga->scr_cur_line, SCR_MAXLINE);
int bottom = min(max(vga->cur_row, CYCLE_SUB(vga->scr_top_line, vga->scr_bot_line, SCR_MAXLINE)), SCR_HEIGHT);
// if (vga->cur_row == SCR_HEIGHT - 1)
// {
// vga_flush_screen(&buf[INDEX(vga->scr_top_line, 0)]);
// }
// else
// {
cur_line = vga->scr_top_line;
for (i = 0; i <= bottom; ++i)
{
vga_flush_line(&buf[INDEX(cur_line, 0)], i);
cur_line = NEXTLINE(cur_line);
}
for (; i < SCR_HEIGHT; ++i)
{
vga_flush_blankline(i);
}
// }
// kprintf("flush: row=%d, top=%d, cur=%d\n", vga->cur_row, vga->scr_top_line, vga->scr_cur_line);
}
void vga_tty_scroll(NTTY *tty, int direction)
{
vga_buf *vga = tty->output_buf;
u16 *buf = vga->buf;
if (direction == MOUSESCR_DOWN)
{
// down
if (vga->scr_top_line == vga->scr_cur_line)
return;
vga->scr_top_line = NEXTLINE(vga->scr_top_line);
}
else if (direction == MOUSESCR_UP)
{
if (vga->scr_top_line == vga->head_line)
return;
vga->scr_top_line = LASTLINE(vga->scr_top_line);
}
else
{
if (CYCLE_SUB(vga->scr_top_line, vga->scr_cur_line, SCR_MAXLINE) >= SCR_HEIGHT)
{
vga->scr_top_line = CYCLE_SUB(SCR_HEIGHT / 2, vga->scr_cur_line, SCR_MAXLINE);
}
// kprintf("scroll to cur top-%d, cur-%d\n", vga->scr_top_line, vga->scr_cur_line);
}
vga->cur_row = CYCLE_SUB(vga->scr_top_line, vga->scr_cur_line, SCR_MAXLINE);
if (vga->cur_row >= SCR_HEIGHT)
{
vga_disable_cursor();
// kprintf("disable cursor: %d\n", vga->cur_row);
}
else
{
vga_enable_cursor(14, 15);
}
vga_tty_flush(tty);
}
void vga_tty_select(NTTY *tty)
{
disable_int();
cur_ntty = tty;
enable_int();
vga_tty_flush(cur_ntty);
}