📄 video.c
字号:
/*****************************************************************************
TEXT VIDEO
EXPORTS:
extern console_t _vc[MAX_VC];
extern unsigned short _num_vc;
extern volatile console_t *_curr_vc;
void blink(void);
void putch(console_t *con, unsigned char c);
void select_vc(unsigned which_con);
void init_console(void);
*****************************************************************************/
#include <string.h> /* movedata() */
#include <stdio.h> /* sprintf() */
#include <krnl.h> /* console_t */
#include <x86.h> /* inportb(), outportb(), critb(), crite() */
#define VGA_MISC_READ 0x3CC
#define VGA_GC_INDEX 0x3CE
#define VGA_GC_DATA 0x3CF
console_t _vc[MAX_VC];
unsigned short _num_vc;
volatile console_t *_curr_vc;
static unsigned _vga_fb_adr;
static unsigned short _crtc_io_adr;
static unsigned char _vc_width, _vc_height;
/*****************************************************************************
*****************************************************************************/
void blink(void)
{
pokeb(LINEAR_DATA_SEL, _vga_fb_adr,
peekb(LINEAR_DATA_SEL, _vga_fb_adr) + 1);
}
/*****************************************************************************
*****************************************************************************/
static void scroll(console_t *con)
{
unsigned short blank, temp;
blank = 0x20 | ((unsigned short)con->attrib << 8);
/* scroll up */
if(con->csr_y >= _vc_height)
{
temp = con->csr_y - _vc_height + 1;
/* use farptr access to framebuffer so it works with both
paging and segmentation */
movedata(LINEAR_DATA_SEL, con->fb_adr + temp * _vc_width * 2,
LINEAR_DATA_SEL, con->fb_adr,
(_vc_height - temp) * _vc_width * 2);
/* blank the bottom line of the screen */
fmemsetw(LINEAR_DATA_SEL,
con->fb_adr + (_vc_height - temp) * _vc_width * 2,
blank, _vc_width);
con->csr_y = _vc_height - 1;
}
}
/*****************************************************************************
*****************************************************************************/
static void set_attrib(unsigned char att, console_t *con)
{
static const char ansi_to_vga[] =
{
0, 4, 2, 6, 1, 5, 3, 7
};
unsigned char new_att;
new_att = con->attrib;
if(att == 0)
new_att &= ~0x08; /* bold off */
else if(att == 1)
new_att |= 0x08; /* bold on */
else if(att >= 30 && att <= 37)
{
att = ansi_to_vga[att - 30];
new_att = (new_att & ~0x07) | att;/* fg color */
}
else if(att >= 40 && att <= 47)
{
att = ansi_to_vga[att - 40] << 4;
new_att = (new_att & ~0x70) | att;/* bg color */
}
con->attrib = new_att;
}
/*****************************************************************************
*****************************************************************************/
static void move_csr(console_t *con)
{
unsigned long temp;
unsigned short off;
unsigned flags;
temp = (con->csr_y * _vc_width + con->csr_x) * 2;
temp = con->fb_adr + temp - _vga_fb_adr;
off = temp;
flags = critb();
/* extra shift because even/odd text mode uses word clocking */
outportb(_crtc_io_adr + 0, 14);
outportb(_crtc_io_adr + 1, off >> 9);
outportb(_crtc_io_adr + 0, 15);
outportb(_crtc_io_adr + 1, off >> 1);
crite(flags);
}
/*****************************************************************************
*****************************************************************************/
void select_vc(unsigned which_con)
{
unsigned long temp;
unsigned short off;
unsigned flags;
if(which_con >= _num_vc)
return;
_curr_vc = _vc + which_con;
temp = (unsigned long)_curr_vc->fb_adr - _vga_fb_adr;
off = temp;
flags = critb();
/* extra shift because even/odd text mode uses word clocking */
outportb(_crtc_io_adr + 0, 12);
outportb(_crtc_io_adr + 1, off >> 9);
outportb(_crtc_io_adr + 0, 13);
outportb(_crtc_io_adr + 1, off >> 1);
move_csr(_curr_vc);
crite(flags);
}
/*****************************************************************************
*****************************************************************************/
/* don't want to use ctype.h */
#define ISDIGIT(X) (((X) >= '0') && ((X) <= '9'))
void putch(console_t *con, unsigned char c)
{
unsigned short att;
att = (unsigned short)con->attrib << 8;
/* state machine to handle the escape sequences
ESC */
if(con->esc == 1)
{
if(c == '[')
{
con->esc++;
con->esc1 = 0;
return;
}
/* else fall-through: zero esc and print c */
}
/* ESC[ */
else if(con->esc == 2)
{
if(ISDIGIT(c))
{
con->esc1 = con->esc1 * 10 + c - '0';
return;
}
else if(c == ';')
{
con->esc++;
con->esc2 = 0;
return;
}
/* ESC[2J -- clear screen */
else if(c == 'J')
{
if(con->esc1 == 2)
{
fmemsetw(LINEAR_DATA_SEL, con->fb_adr,
' ' | att,
_vc_height * _vc_width);
con->csr_x=con->csr_y = 0;
}
}
/* ESC[num1m -- set attribute num1 */
else if(c == 'm')
set_attrib(con->esc1, con);
con->esc = 0; /* anything else with one numeric arg */
return;
}
/* ESC[num1; */
else if(con->esc == 3)
{
if(ISDIGIT(c))
{
con->esc2 = con->esc2 * 10 + c - '0';
return;
}
else if(c == ';')
{
con->esc++; /* ESC[num1;num2; */
con->esc3 = 0;
return;
}
/* ESC[num1;num2H -- move cursor to num1,num2 */
else if(c == 'H')
{
if(con->esc2 < _vc_width)
con->csr_x = con->esc2;
if(con->esc1 < _vc_height)
con->csr_y = con->esc1;
}
/* ESC[num1;num2m -- set attributes num1,num2 */
else if(c == 'm')
{
set_attrib(con->esc1, con);
set_attrib(con->esc2, con);
}
con->esc = 0;
return;
}
/* ESC[num1;num2;num3 */
else if(con->esc == 4)
{
if(ISDIGIT(c))
{
con->esc3 = con->esc3 * 10 + c - '0';
return;
}
/* ESC[num1;num2;num3m -- set attributes num1,num2,num3 */
else if(c == 'm')
{
set_attrib(con->esc1, con);
set_attrib(con->esc2, con);
set_attrib(con->esc3, con);
}
con->esc = 0;
return;
}
con->esc = 0;
/* escape character */
if(c == 0x1B)
{
con->esc = 1;
return;
}
/* backspace */
if(c == 0x08)
{
if(con->csr_x != 0)
con->csr_x--;
}
/* tab */
else if(c == 0x09)
con->csr_x = (con->csr_x + 8) & ~(8 - 1);
/* carriage return */
else if(c == '\r') /* 0x0D */
con->csr_x = 0;
/* line feed */
// else if(c == '\n') /* 0x0A */
// con->csr_y++;
/* CR/LF */
else if(c == '\n') /* ### - 0x0A again */
{
con->csr_x = 0;
con->csr_y++;
}
/* printable ASCII */
else if(c >= ' ')
{
unsigned long where;
where = con->fb_adr + 2 *
(con->csr_y * _vc_width + con->csr_x);
pokew(LINEAR_DATA_SEL, where, c | att);
con->csr_x++;
}
if(con->csr_x >= _vc_width)
{
con->csr_x = 0;
con->csr_y++;
}
scroll(con);
/* move cursor only if the VC we're writing is the current VC */
if(_curr_vc == con)
move_csr(con);
}
/*****************************************************************************
*****************************************************************************/
static void puts(console_t *con, char *str)
{
while(*str != '\0')
{
putch(con, *str);
str++;
}
}
/*****************************************************************************
*****************************************************************************/
DISCARDABLE_CODE(void init_console(void))
{
unsigned temp, v_disp, char_ht;
/* code to detect mono/color emulation
cobbled from info in Finn Thoegersen's VGADOC4
Mono is UNTESTED. */
if((inportb(VGA_MISC_READ) & 0x01) != 0)
{
_crtc_io_adr = 0x3D4; /* color */
_vga_fb_adr = 0xB8000;
}
else
{
_crtc_io_adr = 0x3B4; /* mono */
_vga_fb_adr = 0xB0000;
}
/* figure out width and height of current display:
vertical scan lines displayed */
outportb(_crtc_io_adr, 0x12);
v_disp = inportb(_crtc_io_adr + 1);
/* pull in the 9th and 10th bits from the dread overflow register */
outportb(_crtc_io_adr, 0x07);
temp = inportb(_crtc_io_adr + 1);
if((temp & 0x02) != 0)
v_disp |= 0x100;
if((temp & 0x40) != 0)
v_disp |= 0x200;
/* the value in the register is actually vertical displayed - 1, so fix it */
v_disp++;
/* scan lines/char */
outportb(_crtc_io_adr, 0x09);
char_ht = (inportb(_crtc_io_adr + 1) & 0x1F) + 1;
/* vertical resolution in characters is the quotient.
If the monochrome/color detection is faulty, char_ht may be 0,
and the divide-by-zero will cause a triple fault. */
_vc_height = v_disp / char_ht;
/* horizontal resolution in characters */
outportb(_crtc_io_adr, 0x01);
_vc_width = inportb(_crtc_io_adr + 1) + 1;
#if 1
/* move text framebuffer to A000:0000
This does not work with Bochs */
outportb(VGA_GC_INDEX, 0x06);
outportb(VGA_GC_DATA, 0x06);
_vga_fb_adr = 0xA0000;
/* figure out how many VCs we can have with 64K of display memory
Note: integer divides here */
_num_vc = 65536L / (_vc_width * _vc_height * 2);
#else
/* leave text framebuffer at B800:0000 or B000:0000;
figure out how many VCs we can have with 32K of display memory */
_num_vc = 32768L / (_vc_width * _vc_height * 2);
#endif
if(_num_vc > MAX_VC)
_num_vc = MAX_VC;
/* init VCs (different foreground color for each) */
for(temp = 0; temp < _num_vc; temp++)
{char buf[64];
_curr_vc = _vc + temp;
_curr_vc->attrib = temp + 1;
_curr_vc->fb_adr = _vga_fb_adr +
_vc_width * _vc_height * 2 * temp;
/* ESC[2J is an ANSI-like escape to clear the screen */
sprintf(buf, "\x1B[2J""this is VC#%u (of 0-%u)\n", temp, _num_vc - 1);
puts(_curr_vc, buf); }
// puts("\x1B[2J"); }
select_vc(0);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -