#include "type.h" #include "stdio.h" #include "const.h" #include "protect.h" #include "string.h" #include "fs.h" #include "proc.h" #include "tty.h" #include "console.h" #include "global.h" #include "keyboard.h" #include "proto.h" #include "x86.h" /* local routines */ static void set_cursor(unsigned int position); static void set_video_start_addr(u32 addr); static void flush(CONSOLE* con); static void w_copy(unsigned int dst, const unsigned int src, int size); static void clear_screen(int pos, int len); void scroll_screen(CONSOLE* con, int dir); /***************************************************************************** * init_screen *****************************************************************************/ /** * Initialize the console of a certain tty. * * @param tty Whose console is to be initialized. *****************************************************************************/ void init_screen(TTY* tty) { int nr_tty = tty - tty_table; tty->console = console_table + nr_tty; /* * NOTE: * variables related to `position' and `size' below are * in WORDs, but not in BYTEs. */ int v_mem_size = V_MEM_SIZE >> 1; /* size of Video Memory */ int size_per_con = (v_mem_size / NR_CONSOLES)/80*80; tty->console->orig = nr_tty * size_per_con; tty->console->con_size = size_per_con / SCR_WIDTH * SCR_WIDTH; tty->console->cursor = tty->console->crtc_start = tty->console->orig; tty->console->is_full = 0; tty->console->current_line = 0; if(nr_tty==0){ tty->console->cursor = disp_pos / 2; } const char prompt[] = "[TTY #?]\n"; const char * p = prompt; for (; *p; p++){ out_char(tty->console, *p == '?' ? nr_tty + '0' : *p); } set_cursor(tty->console->cursor); } /***************************************************************************** * out_char *****************************************************************************/ /** * Print a char in a certain console. * * @param con The console to which the char is printed. * @param ch The char to print. *****************************************************************************/ void out_char(CONSOLE* con, char ch) { disable_int(); int cursor_x = (con->cursor - con->orig) % SCR_WIDTH; int cursor_y = (con->cursor - con->orig) / SCR_WIDTH; switch(ch) { case '\n': con->cursor = con->orig + SCR_WIDTH * (cursor_y + 1); break; case '\b': if (con->cursor > con->orig) { con->cursor--; //*(pch - 2) = ' '; //*(pch - 1) = DEFAULT_CHAR_COLOR; disp_pos = con->cursor*2; write_char(' '); } break; default: //*pch++ = ch; //*pch++ = DEFAULT_CHAR_COLOR; disp_pos = con->cursor*2; write_char(ch); con->cursor++; break; } if (con->cursor - con->orig >= con->con_size) { cursor_x = (con->cursor - con->orig) % SCR_WIDTH; cursor_y = (con->cursor - con->orig) / SCR_WIDTH; int cp_orig = con->orig + (cursor_y + 1) * SCR_WIDTH - SCR_SIZE; w_copy(con->orig, cp_orig, SCR_SIZE - SCR_WIDTH); con->crtc_start = con->orig; con->cursor = con->orig + (SCR_SIZE - SCR_WIDTH) + cursor_x; clear_screen(con->cursor, SCR_WIDTH); if (!con->is_full) con->is_full = 1; } //assert(con->cursor - con->orig < con->con_size); while (con->cursor >= con->crtc_start + SCR_SIZE || con->cursor < con->crtc_start) { scroll_screen(con, SCR_UP); clear_screen(con->cursor, SCR_WIDTH); } flush(con); enable_int(); } /***************************************************************************** * clear_screen *****************************************************************************/ /** * Write whitespaces to the screen. * * @param pos Write from here. * @param len How many whitespaces will be written. *****************************************************************************/ static void clear_screen(int pos, int len) { u8 * pch = (u8*)K_PHY2LIN(V_MEM_BASE + pos * 2); while (--len >= 0) { *pch++ = ' '; *pch++ = DEFAULT_CHAR_COLOR; } } /***************************************************************************** * is_current_console *****************************************************************************/ /** * Uses `nr_current_console' to determine if a console is the current one. * * @param con Ptr to console. * * @return TRUE if con is the current console. *****************************************************************************/ int is_current_console(CONSOLE* con) { return (con == &console_table[current_console]); } /***************************************************************************** * set_cursor *****************************************************************************/ /** * 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 void 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(); } /***************************************************************************** * set_video_start_addr *****************************************************************************/ /** * Routine for hardware screen scrolling. * * @param addr Offset in the video memory. *****************************************************************************/ static void 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(); } /***************************************************************************** * select_console *****************************************************************************/ /** * Select a console as the current. * * @param nr_console Console nr, range in [0, NR_CONSOLES-1]. *****************************************************************************/ void select_console(int nr_console) { if ((nr_console < 0) || (nr_console >= NR_CONSOLES)) return; flush(&console_table[current_console = nr_console]); } /***************************************************************************** * scroll_screen *****************************************************************************/ /** * Scroll the screen. * * Note that scrolling UP means the content of the screen will go upwards, so * that the user can see lines below the bottom. Similarly scrolling DOWN means * the content of the screen will go downwards so that the user can see lines * above the top. * * When there is no line below the bottom of the screen, scrolling UP takes no * effects; when there is no line above the top of the screen, scrolling DOWN * takes no effects. * * @param con The console whose screen is to be scrolled. * @param dir SCR_UP : scroll the screen upwards; * SCR_DN : scroll the screen downwards *****************************************************************************/ void scroll_screen(CONSOLE* con, int dir) { /* * variables below are all in-console-offsets (based on con->orig) */ int oldest; /* addr of the oldest available line in the console */ int newest; /* .... .. ... latest ......... .... .. ... ....... */ int scr_top;/* position of the top of current screen */ newest = (con->cursor - con->orig) / SCR_WIDTH * SCR_WIDTH; oldest = con->is_full ? (newest + SCR_WIDTH) % con->con_size : 0; scr_top = con->crtc_start - con->orig; if (dir == SCR_DN) { if (!con->is_full && scr_top > 0) { con->crtc_start -= SCR_WIDTH; } else if (con->is_full && scr_top != oldest) { if (con->cursor - con->orig >= con->con_size - SCR_SIZE) { if (con->crtc_start != con->orig) con->crtc_start -= SCR_WIDTH; } else if (con->crtc_start == con->orig) { scr_top = con->con_size - SCR_SIZE; con->crtc_start = con->orig + scr_top; } else { con->crtc_start -= SCR_WIDTH; } } } else if (dir == SCR_UP) { if (!con->is_full && newest >= scr_top + SCR_SIZE) { con->crtc_start += SCR_WIDTH; } else if (con->is_full && scr_top + SCR_SIZE - SCR_WIDTH != newest) { if (scr_top + SCR_SIZE == con->con_size) con->crtc_start = con->orig; else con->crtc_start += SCR_WIDTH; } } else { //assert(dir == SCR_DN || dir == SCR_UP); } flush(con); } /***************************************************************************** * flush *****************************************************************************/ /** * Set the cursor and starting address of a console by writing the * CRT Controller Registers. * * @param con The console to be set. *****************************************************************************/ static void flush(CONSOLE* con) { if (is_current_console(con)) { set_cursor(con->cursor); set_video_start_addr(con->crtc_start); } } /***************************************************************************** * w_copy *****************************************************************************/ /** * Copy data in WORDS. * * Note that the addresses of dst and src are not pointers, but integers, 'coz * in most cases we pass integers into it as parameters. * * @param dst Addr of destination. * @param src Addr of source. * @param size How many words will be copied. *****************************************************************************/ static void w_copy(unsigned int dst, const unsigned int src, int size) { memcpy((void*)(V_MEM_BASE + (dst << 1)), (void*)(V_MEM_BASE + (src << 1)), size << 1); }