/* By Marcus Xing kernel/console.c 与控制台有关的函数 */ #include "type.h" #include "const.h" #include "protect.h" #include "proc.h" #include "console.h" #include "tty.h" #include "global.h" #include "proto.h" /* 内部函数声明 */ static void Set_Cursor(u32 location); static void Set_Video_Start_Addr(u32 start_addr); static void Adjust_Cursor(Console *console); /*------------------------------------------------------------Is_Current_Console 判断是否是参数传来的控制台是否是当前控制台 */ int Is_Current_Console(Console *console) { return &Console_Table[Current_Console] == console; } /*-------------------------------------------------------------------------Flush 刷新当前控制台的显示位置和光标位置,本文件调用 */ void Flush(Console *con) { Set_Video_Start_Addr(con->current_addr / 2); Set_Cursor(con->cursor / 2); } /*------------------------------------------------------------------Init_Console 初始化一个CONSOLE */ void Init_Console(TTY *tty) { int diff = tty - TTY_Table; /* diff保存参数指示的TTY相对TTY_Table的索引 */ tty->console = Console_Table + diff; /* 指向对应的Console */ /* 每个Console的所占的显存大小为8000字节。 每个Console的起始地点为:每份的大小 * diff 当前地址为起始地点,光标也是起始地点 */ int each_console_mem_size = 8000; tty->console->original_addr = each_console_mem_size * diff; tty->console->current_addr = tty->console->original_addr; tty->console->limit = each_console_mem_size; tty->console->cursor = tty->console->original_addr; /* 如果是0号控制台,则光标位置就是d_Disp_Pos值 */ if(diff == 0) { tty->console->cursor = d_Disp_Pos; } /* 否则,写入索引值+'$' */ else { Out_Char(tty->console,'0' + diff); Out_Char(tty->console,'#'); } } /*----------------------------------------------------------------Select_Console 选择控置台 */ void Select_Console(int console_no) { /* 控制台号如果非法直接退出 */ if(console_no < 0 || console_no >= TTY_NUM) { return; } Current_Console = console_no; /* Current_Console改为指定的值 */ Adjust_Cursor(&Console_Table[console_no]); /* 调整光标 */ /* 刷新 */ Flush(&Console_Table[console_no]); } /*-----------------------------------------------------------------Scroll_Screen 滚动当前的控制台 */ void Scroll_Screen(Console *con,int direction) { /* 如果上滚 */ if(direction == 1) { /* 如果显示位置大于原始地址,则显示地址上移1行 */ if(con->current_addr > con->original_addr) { con->current_addr -= ROW_BYTE_NUM; } } /* 如果下滚 */ else if(direction == 0) { /* 如果显示位置 + 160 小于当前控制台的下界,则显示地址下移1行 */ if(con->current_addr + ROW_BYTE_NUM < con->original_addr + con->limit) { con->current_addr += ROW_BYTE_NUM; } } Flush(con); /* 刷新 */ } /*----------------------------------------------------------------------Out_Char 把字符写进参数指定的控制台的显存中 */ void Out_Char(Console *console,char c) { /* 指向显存起始位置0xb8000 + 当前控制台的光标位置 */ u8 *p_video_mem = (u8*)(VIDEO_START_ADDR + console->cursor); u32 row; switch(c) { /* 处理回车 */ case '/n': /* row存放的是当前cursor指向的下一行的值 */ row = console->cursor / ROW_BYTE_NUM; row++; /* 如果row小于当前控制台的最大界限则使cursor指向下一行的开头 */ if(row < ((console->original_addr + console->limit) / ROW_BYTE_NUM)) { console->cursor = row * ROW_BYTE_NUM; } break; /* 处理退格 */ case '/b': /* 如果当前控制台的cursor大于当前控制台的上界,则退格 */ if(console->cursor > console->original_addr) { /* 把字符写入相应的地址 */ *(--p_video_mem) = Make_Color(WHITE,BLACK); *(--p_video_mem) = ' '; /* 光标指向上一个字符 */ console->cursor -= 2; } break; default: /* 如果当前控制台没超当前控制台的下界,则打印字符 */ if(console->cursor < console->original_addr + console->limit) { /* 把字符写入相应的地址 */ *p_video_mem++ = c; *p_video_mem++ = Make_Color(WHITE,BLACK); /* 光标指向下一个字符 */ if(console->cursor + 2 < console->original_addr + console->limit) { console->cursor += 2; } } break; } Adjust_Cursor(console); /* 调整光标 */ } /*--------------------------------------------------------------------Set_Cursor 根据参数设置光标,本文件调用 */ static void Set_Cursor(u32 location) { Disable_Int(); Out_Byte(CRTC_ADDR_REG,CURSOR_H); Out_Byte(CRTC_DATA_REG,(location >> 8) & 0xff); Out_Byte(CRTC_ADDR_REG,CURSOR_L); Out_Byte(CRTC_DATA_REG,location & 0xff); Enable_Int(); } /*-----------------------------------------------------------------Adjust_Cursor 如果当前控制台为参数传来的控制台则调整光标在视野内 */ static void Adjust_Cursor(Console *console) { /* 如果参数等于当前控制台,则调整 */ if(Is_Current_Console(console)) { /* 如果光标超过当前视野的下界,则下滚 */ while(console->cursor > console->current_addr + SCREEN_BYTE_NUM) { Scroll_Screen(console,0); } /* 如果光标超过当前视野的上界,则上滚 */ while(console->cursor < console->current_addr) { Scroll_Screen(console,1); } /* 刷新 */ Flush(console); } } /*----------------------------------------------------------Set_Video_Start_Addr 根据参数设置显示起始位置,本文件调用 */ static void Set_Video_Start_Addr(u32 start_addr) { Disable_Int(); Out_Byte(CRTC_ADDR_REG,START_ADDR_H); Out_Byte(CRTC_DATA_REG,(start_addr >> 8) & 0xff); Out_Byte(CRTC_ADDR_REG,START_ADDR_L); Out_Byte(CRTC_DATA_REG,start_addr & 0xff); Enable_Int(); }