/* * outch.c - This file contains code for displaying characters * on the console uisng information that should be * maintained by the BIOS in its data Area. * * Copyright (C) 1998 Eric Valette (valette@crf.canon.fr) * Canon Centre Recherche France. * * The license and distribution terms for this file may be * found in found in the file LICENSE in this distribution or at * http://www.rtems.com/license/LICENSE. * * Till Straumann , 2003/9: * - added handling of basic escape sequences (cursor movement * and erasing; just enough for the line editor 'libtecla' to * work...) * $Id$ */ #include #include #include #include extern void wr_cursor(int, unsigned short); #define TAB_SPACE 4 static unsigned short *bitMapBaseAddr; static unsigned short ioCrtBaseAddr; static unsigned short maxCol; static unsigned short maxRow; static unsigned char row; static unsigned char column; static unsigned short attribute; static unsigned int nLines; static void scroll(void) { int i, j; /* Counters */ unsigned short *pt_scroll, *pt_bitmap; /* Pointers on the bit-map */ pt_bitmap = bitMapBaseAddr; j = 0; pt_bitmap = pt_bitmap + j; pt_scroll = pt_bitmap + maxCol; for (i = j; i < (maxRow - 1) * maxCol; i++) { *pt_bitmap++ = *pt_scroll++; } /* * Blank characters are displayed on the last line. */ for (i = 0; i < maxCol; i++) { *pt_bitmap++ = (short) (' ' | attribute); } } static void doCRNL(int cr, int nl) { if (nl) { if (++row == maxRow) { scroll(); /* Scroll the screen now */ row = maxRow - 1; } nLines++; } if (cr) column = 0; /* Move cursor on the next location */ if (cr || nl) wr_cursor(row * maxCol + column, ioCrtBaseAddr); } int (*videoHook)(char, int *)=0; static void advanceCursor() { if (++column == maxCol) doCRNL(1,1); else wr_cursor(row * maxCol + column, ioCrtBaseAddr); } static void gotorc(int r, int c) { column = c; row = r; wr_cursor(row * maxCol + column, ioCrtBaseAddr); } #define ESC ((char)27) /* erase current location without moving the cursor */ #define BLANK ((char)0x7f) static void videoPutChar(char car) { unsigned short *pt_bitmap = bitMapBaseAddr + row * maxCol + column; switch (car) { case '\b': { if (column) column--; /* Move cursor on the previous location */ wr_cursor(row * maxCol + column, ioCrtBaseAddr); return; } case '\t': { int i; i = TAB_SPACE - (column & (TAB_SPACE - 1)); column += i; if (column >= maxCol) { doCRNL(1,1); return; } while (i--) *pt_bitmap++ = ' ' | attribute; wr_cursor(row * maxCol + column, ioCrtBaseAddr); return; } case '\n': { doCRNL(0,1); return; } case 7: { /* Bell code must be inserted here */ return; } case '\r' : { doCRNL(1,0); return; } case BLANK: { *pt_bitmap = ' ' | attribute; /* DONT move the cursor... */ return; } default: { *pt_bitmap = car | attribute; advanceCursor(); return; } } } /* trivial state machine to handle escape sequences: * * --------------------------------- * | | * | | * KEY: esc V [ DCABHKJ esc | * STATE: 0 -----> 27 -----> '[' ----------> -1 ----- * ^\ \ \ \ * KEY: | \other \ other \ other \ other * <------------------------------------- * * in state '-1', the DCABHKJ cases are handled * * (cursor motion and screen clearing) */ #define DONE (-1) static int handleEscape(int oldState, char car) { int rval = 0; int ro,co; switch ( oldState ) { case DONE: /* means the previous char terminated an ESC sequence... */ case 0: if ( 27 == car ) { rval = 27; /* START of an ESC sequence */ } break; case 27: if ( '[' == car ) { rval = car; /* received ESC '[', so far */ } else { /* dump suppressed 'ESC'; outch will append the char */ videoPutChar(ESC); } break; case '[': /* handle 'ESC' '[' sequences here */ ro = row; co = column; rval = DONE; /* done */ switch (car) { case 'D': /* left */ if ( co > 0 ) co--; break; case 'C': /* right */ if ( co < maxCol ) co++; break; case 'A': /* up */ if ( ro > 0 ) ro--; break; case 'B': /* down */ if ( ro < maxRow ) ro++; break; case 'H': /* home */ ro = co = 0; break; case 'K': /* clear to end of line */ while ( column < maxCol - 1 ) videoPutChar(' '); videoPutChar(BLANK); break; case 'J': /* clear to end of screen */ while ( ((row < maxRow-1) || (column < maxCol-1)) ) videoPutChar(' '); videoPutChar(BLANK); break; default: videoPutChar(ESC); videoPutChar('['); /* DONT move the cursor */ ro = -1; rval = 0; break; } /* reset cursor */ if ( ro >= 0) gotorc(ro,co); default: break; } return rval; } void clear_screen(void) { int i,j; for (j = 0; j <= maxRow; j++) { for (i = 0; i <= maxCol; i++) { videoPutChar(' '); } } column = 0; row = 0; } /*-------------------------------------------------------------------------+ | Function: _IBMPC_outch | Description: Higher level (console) interface to consPutc. | Global Variables: None. | Arguments: c - character to write to console. | Returns: Nothing. +--------------------------------------------------------------------------*/ void _IBMPC_outch(char c) { static int escaped = 0; if ( ! (escaped = handleEscape(escaped, c)) ) { if ( '\n' == c ) videoPutChar('\r'); videoPutChar(c); } } /* _IBMPC_outch */ /*-------------------------------------------------------------------------+ | Function: _IBMPC_initVideo | Description: Video system initialization. Hook for any early setup. | Global Variables: bitMapBaseAddr, ioCrtBaseAddr, maxCol, maxRow, row | column, attribute, nLines; | Arguments: None. | Returns: Nothing. +--------------------------------------------------------------------------*/ void _IBMPC_initVideo(void) { unsigned char* pt = (unsigned char*) (VIDEO_MODE_ADDR); if (*pt == VGAMODE7) { bitMapBaseAddr = (unsigned short*) V_MONO; } else { bitMapBaseAddr = (unsigned short*) V_COLOR; } ioCrtBaseAddr = *(unsigned short*) DISPLAY_CRT_BASE_IO_ADDR; maxCol = * (unsigned short*) NB_MAX_COL_ADDR; maxRow = * (unsigned char*) NB_MAX_ROW_ADDR; column = 0; row = 0; attribute = ((BLACK << 4) | WHITE)<<8; nLines = 0; clear_screen(); #ifdef DEBUG_EARLY_STAGE printk("bitMapBaseAddr = %X, display controller base IO = %X\n", (unsigned) bitMapBaseAddr, (unsigned) ioCrtBaseAddr); videoPrintf("maxCol = %d, maxRow = %d\n", (unsigned) maxCol, (unsigned) maxRow); #endif } /* _IBMPC_initVideo */ /* for old DOS compatibility n-curses type of applications */ void gotoxy( int x, int y ) { gotorc(y,x); } int whereX( void ) { return row; } int whereY( void ) { return column; }