377 lines
9.8 KiB
C
377 lines
9.8 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"
|
|
#include "csi.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
|
|
*****************************************************************************/
|
|
|
|
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;
|
|
vga->Is2param = false;
|
|
vga->IsColorReverse = false;
|
|
vga->IsHide = false;
|
|
vga->color = DEFAULT_CHAR_COLOR;
|
|
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)
|
|
|
|
static void newline(vga_buf *vga)
|
|
{
|
|
u16 *buf = vga->buf;
|
|
vga->cur_col = 0;
|
|
vga->scr_cur_line = NEXTLINE(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)
|
|
{
|
|
// 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
|
|
}
|
|
}
|
|
}
|
|
|
|
static void nextcol(vga_buf *vgabuf)
|
|
{
|
|
vgabuf->cur_col++;
|
|
if (vgabuf->cur_col == SCR_WIDTH)
|
|
{
|
|
newline(vgabuf);
|
|
}
|
|
}
|
|
|
|
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;
|
|
vga->Is2param = false;
|
|
break;
|
|
default:
|
|
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 ';':
|
|
if (vga->CSI == CSI_PARAM1)
|
|
{
|
|
vga->CSI = CSI_PARAM2;
|
|
vga->Is2param = true;
|
|
}
|
|
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);
|
|
} |