+++ /dev/null
-/*
- * GeekOS text screen output
- * Copyright (c) 2001,2003,2004 David H. Hovemeyer <daveho@cs.umd.edu>
- * $Revision: 1.1 $
- *
- * This is free software. You are permitted to use,
- * redistribute, and modify it as specified in the file "COPYING".
- */
-
-#include <stdarg.h>
-#include <geekos/kassert.h>
-#include <geekos/ktypes.h>
-#include <geekos/io.h>
-#include <geekos/int.h>
-#include <geekos/fmtout.h>
-#include <geekos/screen.h>
-
-/*
- * Information sources for VT100 and ANSI escape sequences:
- * - http://www.lns.cornell.edu/~pvhp/dcl/vt100.html
- * - http://en.wikipedia.org/wiki/ANSI_escape_code
- */
-
-/* ----------------------------------------------------------------------
- * Private functions and data
- * ---------------------------------------------------------------------- */
-
-#define ESC ((char) 0x1B)
-#define DEFAULT_ATTRIBUTE ATTRIB(BLACK, GRAY)
-
-enum State {
- S_NORMAL, /* Normal state - output is echoed verbatim */
- S_ESC, /* Saw ESC character - begin output escape sequence */
- S_ESC2, /* Saw '[' character - continue output escape sequence */
- S_ARG, /* Scanning a numeric argument */
- S_CMD, /* Command */
-};
-
-#define MAXARGS 8 /* Max args that can be passed to esc sequence */
-
-struct Console_State {
- /* Current state information */
- int row, col;
- int saveRow, saveCol;
- uchar_t currentAttr;
-
- /* Working variables for processing escape sequences. */
- enum State state;
- int argList[MAXARGS];
- int numArgs;
-};
-
-static struct Console_State s_cons;
-
-#define NUM_SCREEN_DWORDS ((NUMROWS * NUMCOLS * 2) / 4)
-#define NUM_SCROLL_DWORDS (((NUMROWS-1) * NUMCOLS * 2) / 4)
-#define NUM_DWORDS_PER_LINE ((NUMCOLS*2)/4)
-#define FILL_DWORD (0x00200020 | (s_cons.currentAttr<<24) | (s_cons.currentAttr<<8))
-
-/*
- * Scroll the display one line.
- * We speed things up by copying 4 bytes at a time.
- */
-static void Scroll(void)
-{
- uint_t* v;
- int i, n = NUM_SCROLL_DWORDS;
- uint_t fill = FILL_DWORD;
-
- /* Move lines 1..NUMROWS-1 up one position. */
- for (v = (uint_t*)VIDMEM, i = 0; i < n; ++i) {
- *v = *(v + NUM_DWORDS_PER_LINE);
- ++v;
- }
-
- /* Clear out last line. */
- for (v = (uint_t*)VIDMEM + n, i = 0; i < NUM_DWORDS_PER_LINE; ++i)
- *v++ = fill;
-}
-
-/*
- * Clear current cursor position to end of line using
- * current attribute.
- */
-static void Clear_To_EOL(void)
-{
- int n = (NUMCOLS - s_cons.col);
- uchar_t* v = VIDMEM + s_cons.row*(NUMCOLS*2) + s_cons.col*2;
- while (n-- > 0) {
- *v++ = ' ';
- *v++ = s_cons.currentAttr;
- }
-}
-
-/*
- * Move to the beginning of the next line, scrolling
- * if necessary.
- */
-static void Newline(void)
-{
- ++s_cons.row;
- s_cons.col = 0;
- if (s_cons.row == NUMROWS) {
- Scroll();
- s_cons.row = NUMROWS - 1;
- }
-}
-
-/*
- * Write the graphic representation of given character to the screen
- * at current position, with current attribute, scrolling if
- * necessary.
- */
-static void Put_Graphic_Char(int c)
-{
- uchar_t* v = VIDMEM + s_cons.row*(NUMCOLS*2) + s_cons.col*2;
-
- /* Put character at current position */
- *v++ = (uchar_t) c;
- *v = s_cons.currentAttr;
-
- if (s_cons.col < NUMCOLS - 1)
- ++s_cons.col;
- else
- Newline();
-}
-
-/*
- * Put one character to the screen using the current cursor position
- * and attribute, scrolling if needed. The caller should update
- * the cursor position once all characters have been written.
- */
-static void Output_Literal_Character(int c)
-{
- int numSpaces;
-
- switch (c) {
- case '\n':
- Clear_To_EOL();
- Newline();
- break;
-
- case '\t':
- numSpaces = TABWIDTH - (s_cons.col % TABWIDTH);
- while (numSpaces-- > 0)
- Put_Graphic_Char(' ');
- break;
-
- default:
- Put_Graphic_Char(c);
- break;
- }
-
-#ifndef NDEBUG
- /*
- * When compiled with --enable-port-e9-hack, Bochs will send writes
- * to port E9 to the console. This helps tremendously with debugging,
- * because it allows debug Print() statements to be visible after
- * Bochs has exited.
- */
- Out_Byte(0xE9, c);
-#endif
-}
-
-/*
- * Move the cursor to a new position, stopping at the screen borders.
- */
-static void Move_Cursor(int row, int col)
-{
- if (row < 0)
- row = 0;
- else if (row >= NUMROWS)
- row = NUMROWS - 1;
-
- if (col < 0)
- col = 0;
- else if (col >= NUMCOLS)
- col = NUMCOLS - 1;
-
- s_cons.row = row;
- s_cons.col = col;
-}
-
-/*
- * Table mapping ANSI colors to VGA text mode colors.
- */
-static const uchar_t s_ansiToVgaColor[] = {
- BLACK,RED,GREEN,AMBER,BLUE,MAGENTA,CYAN,GRAY
-};
-
-/*
- * Update the attributes specified by the arguments
- * of the escape sequence.
- */
-static void Update_Attributes(void)
-{
- int i;
- int attr = s_cons.currentAttr & ~(BRIGHT);
-
- for (i = 0; i < s_cons.numArgs; ++i) {
- int value = s_cons.argList[i];
- if (value == 0)
- attr = DEFAULT_ATTRIBUTE;
- else if (value == 1)
- attr |= BRIGHT;
- else if (value >= 30 && value <= 37)
- attr = (attr & ~0x7) | s_ansiToVgaColor[value - 30];
- else if (value >= 40 && value <= 47)
- attr = (attr & ~(0x7 << 4)) | (s_ansiToVgaColor[value - 40] << 4);
- }
- s_cons.currentAttr = attr;
-}
-
-/* Reset to cancel or finish processing an escape sequence. */
-static void Reset(void)
-{
- s_cons.state = S_NORMAL;
- s_cons.numArgs = 0;
-}
-
-/* Start an escape sequence. */
-static void Start_Escape(void)
-{
- s_cons.state = S_ESC;
- s_cons.numArgs = 0;
-}
-
-/* Start a numeric argument to an escape sequence. */
-static void Start_Arg(int argNum)
-{
- KASSERT(s_cons.numArgs == argNum);
- s_cons.numArgs++;
- s_cons.state = S_ARG;
- if (argNum < MAXARGS)
- s_cons.argList[argNum] = 0;
-}
-
-/* Save current cursor position. */
-static void Save_Cursor(void)
-{
- s_cons.saveRow = s_cons.row;
- s_cons.saveCol = s_cons.col;
-}
-
-/* Restore saved cursor position. */
-static void Restore_Cursor(void)
-{
- s_cons.row = s_cons.saveRow;
- s_cons.col = s_cons.saveCol;
-}
-
-/* Add a digit to current numeric argument. */
-static void Add_Digit(int c)
-{
- KASSERT(ISDIGIT(c));
- if (s_cons.numArgs < MAXARGS) {
- int argNum = s_cons.numArgs - 1;
- s_cons.argList[argNum] *= 10;
- s_cons.argList[argNum] += (c - '0');
- }
-}
-
-/*
- * Get a numeric argument.
- * Returns zero if that argument was not actually specified.
- */
-static int Get_Arg(int argNum)
-{
- return argNum < s_cons.numArgs ? s_cons.argList[argNum] : 0;
-}
-
-/*
- * The workhorse output function.
- * Depending on the current console output state,
- * does literal character output or processes part of
- * an escape sequence.
- */
-static void Put_Char_Imp(int c)
-{
-again:
- switch (s_cons.state) {
- case S_NORMAL:
- if (c == ESC)
- Start_Escape();
- else
- Output_Literal_Character(c);
- break;
-
- case S_ESC:
- if (c == '[')
- s_cons.state = S_ESC2;
- else
- Reset();
- break;
-
- case S_ESC2:
- if (ISDIGIT(c)) {
- Start_Arg(0);
- goto again;
- } else if (c == ';') {
- /* Special case: for "n;m" commands, "n" is implicitly 1 if omitted */
- Start_Arg(0);
- Add_Digit('1');
- Start_Arg(1);
- } else {
- s_cons.state = S_CMD;
- goto again;
- }
- break;
-
- case S_ARG:
- if (ISDIGIT(c))
- Add_Digit(c);
- else if (c == ';')
- Start_Arg(s_cons.numArgs);
- else {
- s_cons.state = S_CMD;
- goto again;
- }
- break;
-
- case S_CMD:
- switch (c) {
- case 'K': Clear_To_EOL(); break;
- case 's': Save_Cursor(); break;
- case 'u': Restore_Cursor(); break;
- case 'A': Move_Cursor(s_cons.row - Get_Arg(0), s_cons.col); break;
- case 'B': Move_Cursor(s_cons.row + Get_Arg(0), s_cons.col); break;
- case 'C': Move_Cursor(s_cons.row, s_cons.col + Get_Arg(0)); break;
- case 'D': Move_Cursor(s_cons.row, s_cons.col - Get_Arg(0)); break;
- case 'm': Update_Attributes(); break;
- case 'f': case 'H':
- if (s_cons.numArgs == 2) Move_Cursor(Get_Arg(0)-1, Get_Arg(1)-1); break;
- case 'J':
- if (s_cons.numArgs == 1 && Get_Arg(0) == 2) {
- Clear_Screen();
- Put_Cursor(0, 0);
- }
- break;
- default: break;
- }
- Reset();
- break;
-
- default:
- KASSERT(false);
- }
-}
-
-/*
- * Update the location of the hardware cursor.
- */
-static void Update_Cursor(void)
-{
- /*
- * The cursor location is a character offset from the beginning
- * of page memory (I think).
- */
- uint_t characterPos = (s_cons.row * NUMCOLS) + s_cons.col;
- uchar_t origAddr;
-
- /*
- * Save original contents of CRT address register.
- * It is considered good programming practice to restore
- * it to its original value after modifying it.
- */
- origAddr = In_Byte(CRT_ADDR_REG);
- IO_Delay();
-
- /* Set the high cursor location byte */
- Out_Byte(CRT_ADDR_REG, CRT_CURSOR_LOC_HIGH_REG);
- IO_Delay();
- Out_Byte(CRT_DATA_REG, (characterPos>>8) & 0xff);
- IO_Delay();
-
- /* Set the low cursor location byte */
- Out_Byte(CRT_ADDR_REG, CRT_CURSOR_LOC_LOW_REG);
- IO_Delay();
- Out_Byte(CRT_DATA_REG, characterPos & 0xff);
- IO_Delay();
-
- /* Restore contents of the CRT address register */
- Out_Byte(CRT_ADDR_REG, origAddr);
-}
-
-/* ----------------------------------------------------------------------
- * Public functions
- * ---------------------------------------------------------------------- */
-
-/*
- * Initialize the screen module.
- */
-void Init_Screen(void)
-{
- bool iflag = Begin_Int_Atomic();
-
- s_cons.row = s_cons.col = 0;
- s_cons.currentAttr = DEFAULT_ATTRIBUTE;
- Clear_Screen();
-
- End_Int_Atomic(iflag);
- Print("Screen Inited\n");
-}
-
-/*
- * Clear the screen using the current attribute.
- */
-void Clear_Screen(void)
-{
- uint_t* v = (uint_t*)VIDMEM;
- int i;
- uint_t fill = FILL_DWORD;
-
- bool iflag = Begin_Int_Atomic();
-
- for (i = 0; i < NUM_SCREEN_DWORDS; ++i)
- *v++ = fill;
-
- End_Int_Atomic(iflag);
-}
-
-/*
- * Get current cursor position.
- */
-void Get_Cursor(int* row, int* col)
-{
- bool iflag = Begin_Int_Atomic();
- *row = s_cons.row;
- *col = s_cons.col;
- End_Int_Atomic(iflag);
-}
-
-/*
- * Set the current cursor position.
- * Return true if successful, or false if the specified
- * cursor position is invalid.
- */
-bool Put_Cursor(int row, int col)
-{
- bool iflag;
-
- if (row < 0 || row >= NUMROWS || col < 0 || col >= NUMCOLS)
- return false;
-
- iflag = Begin_Int_Atomic();
- s_cons.row = row;
- s_cons.col = col;
- Update_Cursor();
- End_Int_Atomic(iflag);
-
- return true;
-}
-
-/*
- * Get the current character attribute.
- */
-uchar_t Get_Current_Attr(void)
-{
- return s_cons.currentAttr;
-}
-
-/*
- * Set the current character attribute.
- */
-void Set_Current_Attr(uchar_t attrib)
-{
- bool iflag = Begin_Int_Atomic();
- s_cons.currentAttr = attrib;
- End_Int_Atomic(iflag);
-}
-
-/*
- * Write a single character to the screen at current position
- * using current attribute, handling scrolling, special characters, etc.
- */
-void Put_Char(int c)
-{
- bool iflag = Begin_Int_Atomic();
- Put_Char_Imp(c);
- Update_Cursor();
- End_Int_Atomic(iflag);
-}
-
-/*
- * Write a string of characters to the screen at current cursor
- * position using current attribute.
- */
-void Put_String(const char* s)
-{
- bool iflag = Begin_Int_Atomic();
- while (*s != '\0')
- Put_Char_Imp(*s++);
- Update_Cursor();
- End_Int_Atomic(iflag);
-}
-
-/*
- * Write a buffer of characters at current cursor position
- * using current attribute.
- */
-void Put_Buf(const char* buf, ulong_t length)
-{
- bool iflag = Begin_Int_Atomic();
- while (length > 0) {
- Put_Char_Imp(*buf++);
- --length;
- }
- Update_Cursor();
- End_Int_Atomic(iflag);
-}
-
-/* Support for Print(). */
-static void Print_Emit(struct Output_Sink *o, int ch) { Put_Char_Imp(ch); }
-static void Print_Finish(struct Output_Sink *o) { Update_Cursor(); }
-static struct Output_Sink s_outputSink = { &Print_Emit, &Print_Finish };
-
-/*
- * Print to console using printf()-style formatting.
- * Calls into Format_Output in common library.
- */
-
-static __inline__ void PrintInternal(const char * format, va_list ap) {
- Format_Output(&s_outputSink, format, ap);
-}
-
-
-void Print(const char *fmt, ...)
-{
- va_list args;
-
- bool iflag = Begin_Int_Atomic();
-
- va_start(args, fmt);
- PrintInternal(fmt, args);
- va_end(args);
-
- End_Int_Atomic(iflag);
-}
-
-void PrintList(const char * fmt, va_list ap) {
- bool iflag = Begin_Int_Atomic();
- PrintInternal(fmt, ap);
- End_Int_Atomic(iflag);
-}