📄 vgadrv.c
字号:
/*
* ExpOS
* Origin Author: Larry Li
* Modify: Hyl.linuxfourm.net 2003.4.6
* Creation Date: 2003.2.12
*/
/*
* TODO:
* 修改为 VGA12h 640x480x16 色模拟 VGA03 模式以显示汉字 GB2312 字符
* 注意:在 VGA12h 将光标失去光标支持.
*/
#include <arch.h>
#include <string.h>
#include <drv/vga.h>
extern int char_color, back_color,pos, cursor_x, cursor_y;
unsigned char *pvram;
extern char _graph ;
static unsigned char vga12h[VGA_NUM_REGS] = {
/* MISC */
0xE3,
/* SEQ */
0x03, 0x01, 0x08, 0x00, 0x06,
/* CRTC */
0x5F, 0x4F, 0x50, 0x82, 0x54, 0x80, 0x0B, 0x3E,
0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xEA, 0x0C, 0xDF, 0x28, 0x00, 0xE7, 0x04, 0xE3, 0xFF,
/* GC */
0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x05, 0x0F, 0xFF,
/* AC */
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07,
0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
0x01, 0x00, 0x0F, 0x00, 0x00
};
static void switch_vga_mode(unsigned char *regs)
{
unsigned i;
/* write MISCELLANEOUS reg */
outb(VGA_MISC_WRITE,*regs );
regs++;
/* write SEQUENCER regs */
for (i = 0; i < VGA_NUM_SEQ_REGS; i++) {
outb(VGA_SEQ_INDEX,i );
outb(VGA_SEQ_DATA,*regs );
regs++;
}
/* unlock CRTC registers */
outb(VGA_CRTC_INDEX,0x03 );
outb(VGA_CRTC_DATA,inb(VGA_CRTC_DATA) | 0x80 );
outb(VGA_CRTC_INDEX,0x11 );
outb(VGA_CRTC_DATA,inb(VGA_CRTC_DATA) & ~0x80 );
/* make sure they remain unlocked */
regs[0x03] |= 0x80;
regs[0x11] &= ~0x80;
/* write CRTC regs */
for (i = 0; i < VGA_NUM_CRTC_REGS; i++) {
outb(VGA_CRTC_INDEX,i );
outb(VGA_CRTC_DATA,*regs );
regs++;
}
/* write GRAPHICS CONTROLLER regs */
for (i = 0; i < VGA_NUM_GC_REGS; i++) {
outb(VGA_GC_INDEX,i );
outb(VGA_GC_DATA,*regs );
regs++;
}
/* write ATTRIBUTE CONTROLLER regs */
for (i = 0; i < VGA_NUM_AC_REGS; i++) {
(void) inb(VGA_INSTAT_READ);
outb(VGA_AC_INDEX,i );
outb(VGA_AC_WRITE,*regs );
regs++;
}
/* lock 16-color palette and unblank display */
(void) inb(VGA_INSTAT_READ);
outb(VGA_AC_INDEX,0x20 );
}
/*------------------------------------------------------------------------
Procedure: vga_init ID:1
Purpose: 显示初始化
Input: 从启动 7C00h 偏移 510, 511 处读取寄存的 x, y 坐标值
Output:
Errors:
------------------------------------------------------------------------*/
void vga_init(void)
{
{
switch_vga_mode(vga12h);
_graph = 1;
clear_vram();
extern char log_buf[];
//puts(log_buf);
kprintf(log_buf);
/* `~ 逃逸序列,后跟一个十六进制数 0-A 表示颜色。`~ 两个字符共用一个键通常在 Esc 键下面 */
//puts("`~AOK`~F! `~C中文`~E GB2312 `~7显示已启动,");
}
#if 0
{
int x, y;
/* unsigned char val; */
x = *(unsigned char *)(0x7C00 + 510);
y = *(unsigned char *)(0x7C00 + 511);
x = 0;
y++;
gotoxy(x, y);
clear_vram();
}
#endif
}
void vga_pixel(unsigned int x, unsigned int y, unsigned int c)
{
unsigned char *off;
unsigned int mask, i, pmask;
x %= WIDTH;
y %= HEIGHT;
c %= COLORS;
off = VRAM + COLS * y + (x >> 3);
x &= 7;
mask = 0x80 >> x;
pmask = 1;
for (i = 0; i < 4; i++) {
outb(VGA_GC_INDEX,4 );
outb(VGA_GC_DATA,i );
outb(VGA_SEQ_INDEX,2 );
outb(VGA_SEQ_DATA,(1 << i) );
if (pmask & c)
*off |= mask;
else
*off &= ~mask;
pmask <<= 1;
}
}
void vga_outbyte(unsigned int col, unsigned int y, unsigned char mask, unsigned int c)
{
unsigned char *off;
unsigned int i, pmask;
col %= COLS;
y %= HEIGHT;
c %= COLORS;
off = VRAM + COLS * y + col;
pmask = 1;
for (i = 0; i < 4; i++) {
outb(VGA_GC_INDEX,4 );
outb(VGA_GC_DATA,i );
outb(VGA_SEQ_INDEX,2 );
outb(VGA_SEQ_DATA,(1 << i) );
if (pmask & c)
*off |= mask;
else
*off &= ~mask;
pmask <<= 1;
}
}
/*
* Procedure: clear_vram ID:1
* Purpose: 清屏
* 循环赋值
* Input:
* Output:
* Errors:
*/
void clear_vram(void)
{
if(_graph){
#ifdef USE_PUTPIXEL
int x, y;
for (y = 0; y < HEIGHT; y++)
for (x = 0; x < WIDTH; x++)
vga_pixel(x, y, back_color);
#endif
#ifdef OUTBYTE
int col, y;
for (y = 0; y < TIPS_POS; y++)
for (col = 0; col < COLS; col++)
vga_outbyte(col, y, 0xFF, back_color);
for (col = 0; col < COLS; col++)
vga_outbyte(col, y, 0xFF, WHITE);
for (y++; y < HEIGHT; y++)
for (col = 0; col < COLS; col++)
vga_outbyte(col, y, 0xFF, WHITE);
#else
/* 使用四个页面分别刷新,减少寄存器操作,加快速度 */
/*??? 关闭显示后进行操作,避免花屏现象? */
unsigned int i, j;
unsigned char *off;
for (i = 0; i < 4; i++) {
outb(VGA_SEQ_INDEX,2 );
outb(VGA_SEQ_DATA,(1 << i) );
off = VRAM;
if ((1 << i) & back_color)
for (j = 0; j <= COLS * TIPS_POS; j++)
*off++ = 0x0;
else
for (j = 0; j <= COLS * TIPS_POS; j++)
*off++ = 0;
if ((1 << i) & BLACK)
for (; j < COLS * (TIPS_POS + 1); j++)
*off++ = 0x0;
else
for (; j < COLS * (TIPS_POS + 1); j++)
*off++ = 0;
if ((1 << i) & BLACK)
for (; j < COLS * HEIGHT; j++)
*off++ = 0x0;
else
for (; j < COLS * HEIGHT; j++)
*off++ = 0;
}
#endif
}else{
/* it is used to clear the video ram */
int i;
unsigned char *p = (unsigned char *) 0xc00B8000;
/* set blank */
for (i = 0; i < 80 * 25; i++) {
*p = ' ';
p = p + 2;
}
p = (unsigned char *) 0xc00B8001;
/* background black */
for (i = 0; i < 80 * 25; i++) {
*p = 7;
p = p + 2;
}
}
return;
}
/*
Procedure: gotoxy ID:1
Purpose: 设置当前光标及显示字符位置
Input: x, y 坐标
Output:
Errors: ?光标显示问题
*/
inline void gotoxy(unsigned int x, unsigned int y)
{
pos = (COLS * y + x) * 2;
cli();
outb(VGA_IN,14 );
outb(VGA_DATA,0xFF & (pos >> 9) );
outb(15, VGA_IN);
outb(VGA_DATA, 0xFF & (pos >> 1));
sti();
cursor_x = x;
cursor_y = y;
}
static inline phys_copy(unsigned char *src,unsigned char *dst,
unsigned int n)
{
int d0, d1, d2;
#if 0
__asm__ __volatile__(
"rep\n\t"
"movsb"
: "=&c" (d0), "=&S" (d1), "=&D" (d2)
:"0" (n),"1" (src),"2" (dst)
: "memory");
//#else
__asm__ __volatile__(
"std\n\t"
"rep\n\t"
"movsb\n\t"
"cld"
: "=&c" (d0), "=&S" (d1), "=&D" (d2)
:"0" (n),
"1" (n-1+(const char *)src),
"2" (n-1+(char *)dst)
:"memory");
#endif
#if 1
int i;
for(i = 0;i < n;i++)
{
*src = *dst;
src++;
dst++;
}
return;
#endif
}
/*
* Procedure: scroll_up ID:1
* Purpose: 向上滚动一行屏幕
* Input:
* Output:
* Errors: ?直接显存拷贝。
*/
void scroll_up(void)
{
if(_graph)
{
int i, j;
unsigned char *off;
for (i = 0; i < 4; i++) {
outb(VGA_GC_INDEX,4 );
outb(VGA_GC_DATA,i );
outb(VGA_SEQ_INDEX,2 );
outb(VGA_SEQ_DATA,(1 << i) );
phys_copy(VRAM, VRAM + COLS * LINE_HEIGHT, COLS * (ROWS - 1) * LINE_HEIGHT);
off = VRAM + COLS * LINE_HEIGHT * (ROWS - 1);
if ((1 << i) & back_color)
for (j = 0; j < COLS * LINE_HEIGHT; j++)
*off++ = 0xFF;
else
for (j = 0; j < COLS * LINE_HEIGHT; j++)
*off++ = 0;
}/*end for*/
}else{
unsigned char *p = (unsigned char *)0xB8000;
unsigned char *p2 = (unsigned char *)(0xB8000 + COLS * 2);
unsigned int count = (ROWS -1) * COLS * 2;
int i;
phys_copy(p, p2,count); /* src ,dst ,count */
/* then clear the bottom line */
p = (unsigned char *)(0xB8000 + (ROWS - 1) * 2 * COLS);
for (i = 0; i < COLS * 2; i += 2)
p[i] = ' ';
}
return;
}
#if 0
#ifdef HAS_PCXBACK
typedef struct {
char manufacturer;
char version;
char encoding;
char bitsperpixel;
short xmin, ymin;
short xmax, ymax;
short hres, vres;
char palette[48];
char reserved;
char colorplanes;
short width;
short palettetype;
char filler[58];
} PCXHEAD;
extern unsigned char *BACK;
void show_pcxback()
{
int i, j, k;
int n, c;
int w, h, bytes;
PCXHEAD *ph;
unsigned char *data, *vga;
unsigned char buf[COLS];
ph = (PCXHEAD *)BACK;
if (ph->manufacturer != 0x0A)
return;
w = (ph->xmax - ph->xmin) + 1;
h = (ph->ymax - ph->ymin) + 1;
bytes = ph->width;
data = (unsigned char *)(BACK + sizeof(PCXHEAD));
for (i = 0; i < h; i++) {
for (j = 0; j < 4; j++) {
n = 0;
do {
c = *data++;
if ((c & 0xC0) == 0xC0) {
k = c & 0x3F;
c = *data++;
while (k--)
buf[n++] = c;
} else
buf[n++] = c;
} while (n < bytes && n < COLS);
vga = VRAM + i * COLS;
for (k = 0; k < bytes; k++)
vga[k] = buf[k];
}
}
}
#endif /* HAS_PCXBACK */
#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -