//+---------------------------------------------------------------------------- // // File: video.c // // Module: Video driver // // Synopsis: low-level interface to video memory // // Created: sgasch 5 Jul 2003 // //+---------------------------------------------------------------------------- #include #include "kernel.h" #include "hal.h" #include "rtl.h" #include "video.h" extern BIOS_HARDWARE_BLOCK g_BiosHardwareBlock; // // Local #defines // #define FG_BG_TO_ATTRIB_BYTE(fg,bg) ((fg&0x0F)|((bg&0x0F)<<4)) #define LINES (0) #define COLS (1) #define CRT_ADDR_REG (0x3D4) #define CRT_DATA_REG (0x3D5) #define CRT_CURSOR_LOC_HIGH_REG (0x0E) #define CRT_CURSOR_LOC_LOW_REG (0x0F) #define ZERO_BASED_LINE_COL_TO_BYTE_OFFSET(L,C)\ (((g_bScreenResolution[COLS] << 1) * (L)) + ((C) << 1)) #define ZERO_BASED_LINE_COL_TO_ULONG_OFFSET(L,C)\ (ZERO_BASED_LINE_COL_TO_BYTE_OFFSET((L),(C)) >> 2) // // Global identifiers // BYTE *g_pVideoMemory = NULL; BYTE g_bScreenResolution[2] = { 0, 0 }; BYTE g_bSoftCursor[2] = { 0, 0 }; BYTE g_bColorAttribute = FG_BG_TO_ATTRIB_BYTE(BLACK, WHITE); typedef struct _VIDEO_LOOKUP_ENTRY { CHAR *szBoardName; BYTE *pStartOfVideoMemory; BYTE uScreenLines[3]; } VIDEO_LOOKUP_ENTRY; static VIDEO_LOOKUP_ENTRY g_VideoLookupTable[] = { { "No video adapter", (BYTE *)0x000B0000, { 25, 25, 25 } }, { "Monochrome display adapter", (BYTE *)0x000B0000, { 25, 25, 25 } }, { "CGA", (BYTE *)0x000B8000, { 25, 25, 25 } }, { "Code 3: Undefined", (BYTE *)0x000B0000, { 25, 25, 25 } }, { "EGA with color display", (BYTE *)0x000B8000, { 43, 25, 25 } }, { "EGA with mono display", (BYTE *)0x000B0000, { 43, 25, 25 } }, { "Code 6: Undefined", (BYTE *)0x000B0000, { 25, 25, 25 } }, { "VGA with mono display", (BYTE *)0x000B0000, { 50, 27, 25 } }, { "VGA with color display", (BYTE *)0x000B8000, { 50, 27, 25 } }, { "Code 9: Undefined", (BYTE *)0x000B0000, { 25, 25, 25 } }, { "MCGA with digital color", (BYTE *)0x000B8000, { 25, 25, 25 } }, { "MCGA with monochrome", (BYTE *)0x000B0000, { 25, 25, 25 } }, { "MCGA with analog color", (BYTE *)0x000B8000, { 25, 25, 25 } } }; //+---------------------------------------------------------------------------- // // Function: VideopInitialize // // Synopsis: // // Arguments: void // // Returns: STATUS // //+---------------------------------------------------------------------------- STATUS VideopInitialize(void) { BYTE uType = g_BiosHardwareBlock.bDisplayType; BYTE uIndex = 2; // // Based on the font size (width in pixels), set the index into the // screen lines lookup table // switch(g_BiosHardwareBlock.bFontSize) { case 8: uIndex = 0; break; case 14: uIndex = 1; break; case 16: uIndex = 2; break; } // // If the display type returned by BIOS is known to us, use the // lookup table to populate some globals here. // if (uType <= ARRAY_LENGTH(g_VideoLookupTable)) { g_pVideoMemory = g_VideoLookupTable[uType].pStartOfVideoMemory; g_bScreenResolution[LINES] = g_VideoLookupTable[uType].uScreenLines[uIndex]; } // // Otherwise make some guesses // else { g_pVideoMemory = (BYTE *)0x000B8000; g_bScreenResolution[LINES] = 25; } g_bScreenResolution[COLS] = 80; // // Set color to WHITE on BLACK // VideoSetCurrentColorAttribute(WHITE, BLACK); // // Clear the screen and thus synchronize the hardware and soft cursor // position. // VideoClearScreen(); return(STATUS_SUCCESS); } //+---------------------------------------------------------------------------- // // Function: VideoDriverMain // // Synopsis: // // Arguments: UINT uEvent // // Returns: STATUS // //+---------------------------------------------------------------------------- STATUS VideoDriverMain(UINT uEvent) { switch(uEvent) { case DEVICE_DRIVER_INITIALIZATION: return(VideopInitialize()); case DEVICE_DETATCH: ASSERT(FALSE); return(STATUS_NOT_SUPPORTED); case DEVICE_DRIVER_SHUTDOWN: g_fVideoEnabled = FALSE; return(STATUS_SUCCESS); default: } return(TRUE); } STATUS VideoDriverRead(UINT uAddress, void *pBuffer, UINT uBufferLength); STATUS VideoDriverWrite(UINT uAddress, void *pBuffer, UINT uBufferLength); STATUS VideoDriverIoctl(UINT uIoctlCode, void *pBuffer, UINT uBufferLength); // // Move the hardware cursor on the screen to sync up with the software // cursor position in g_bSoftwareCursor // void VideoSetHardwareCursor(void) { WORD wOffset; // byte offset into video mem BYTE bOrig; // original port contents holder // // Cursor is zero-based (e.g. line 24 is the last one) // ASSERT(g_bSoftCursor[LINES] < g_bScreenResolution[LINES]); ASSERT(g_bSoftCursor[COLS] < g_bScreenResolution[COLS]); wOffset = ZERO_BASED_LINE_COL_TO_BYTE_OFFSET(g_bSoftCursor[LINES], g_bSoftCursor[COLS]); ASSERT(wOffset <= (g_bScreenResolution[LINES] * g_bScreenResolution[COLS]) * 2 - 2); // // Save original contents of CRT address register. // bOrig = in(CRT_ADDR_REG); // // Set the high cursor location byte // out(CRT_ADDR_REG, CRT_CURSOR_LOC_HIGH_REG); out(CRT_DATA_REG, (wOffset >> 8) & 0xFF); IoDelay(); // // Set the low cursor location byte // out(CRT_ADDR_REG, CRT_CURSOR_LOC_LOW_REG); IoDelay(); out(CRT_DATA_REG, (wOffset & 0xFF)); IoDelay(); // // Restore contents of the CRT address register // out(CRT_ADDR_REG, bOrig); IoDelay(); } void VideoSetCurrentColorAttribute(BYTE bFg, BYTE bBg) { bFg &= 0x0F; // restrict these guys to colors bBg &= 0x0F; // and the high intense bit g_bColorAttribute = FG_BG_TO_ATTRIB_BYTE(bFg, bBg); } void VideoClearScreen(void) { ULONG *p = (ULONG *)g_pVideoMemory; ULONG uFill; ULONG uCount; // // Start uCount at the number of ULONGs in visible video memory // uCount = ZERO_BASED_LINE_COL_TO_BYTE_OFFSET(g_bScreenResolution[LINES] - 1, g_bScreenResolution[COLS] - 1); uCount += 2; uCount >>= 2; // // Construct a fill ULONG: blank attrib blank attrib // uFill = 0; uFill |= (ULONG)g_bColorAttribute; uFill |= ((ULONG)g_bColorAttribute) << 16; // // Blast uFills into video memory // while(uCount) { *p++ = uFill; uCount--; } // // Set cursor position to 0,0 // g_bSoftCursor[LINES] = g_bSoftCursor[COLS] = 0; VideoSetHardwareCursor(); } void VideoScroll(void) { ULONG *p = (ULONG *)g_pVideoMemory; ULONG uUlongsPerLine = (g_bScreenResolution[COLS] >> 1); // 2X/4 ULONG i, j; ULONG uFill; ASSERT(sizeof(ULONG) == 4); ASSERT(sizeof(BYTE) == 1); for (i = 0; i < (g_bScreenResolution[LINES] - 2); i++) { // // Start at i, 0. Copy a ULONG up from i+1, 0. Do the whole line i. // for (j = 0; j < uUlongsPerLine; j++) { *p = *(p + uUlongsPerLine); p++; } } // // Construct a fill ULONG: blank attrib blank attrib // uFill = 0; uFill |= (ULONG)g_bColorAttribute; uFill |= ((ULONG)g_bColorAttribute) << 16; // // Blank the last line // p = (ULONG *)(g_pVideoMemory + ZERO_BASED_LINE_COL_TO_BYTE_OFFSET(g_bScreenResolution[LINES] - 1, 0)); for (i = 0; i < uUlongsPerLine; i++) { *p = uFill; p++; } } void VideoPutChar(BYTE c) { BYTE *p = (g_pVideoMemory + ZERO_BASED_LINE_COL_TO_BYTE_OFFSET(g_bSoftCursor[LINES], g_bSoftCursor[COLS])); switch(c) { case '\n': g_bSoftCursor[LINES]++; if (g_bSoftCursor[LINES] >= g_bScreenResolution[LINES]) { VideoScroll(); g_bSoftCursor[LINES] = g_bScreenResolution[LINES] - 1; } g_bSoftCursor[COLS] = 0; return; default: *p = c; p++; *p = g_bColorAttribute; p++; g_bSoftCursor[COLS]++; if (g_bSoftCursor[COLS] >= g_bScreenResolution[COLS]) { g_bSoftCursor[COLS] = 0; g_bSoftCursor[LINES]++; if (g_bSoftCursor[LINES] >= g_bScreenResolution[LINES]) { VideoScroll(); g_bSoftCursor[LINES] = g_bScreenResolution[LINES] - 1; } } } } void VideoPutNullTerminatedString(BYTE *s) { ULONG uSafety = 0; while (*s != 0) { VideoPutChar(*s); s++; uSafety++; if (uSafety > 256) { VideoPutNullTerminatedString("RUNAWAYSTRING!?!\n\0"); break; } } VideoSetHardwareCursor(); } void VideoSetCursorPosition(BYTE bLine, BYTE bCol) { if (bLine >= g_bScreenResolution[LINES]) { bLine = g_bScreenResolution[LINES] - 1; } if (bCol >= g_bScreenResolution[COLS]) { bCol = g_bScreenResolution[COLS] - 1; } g_bSoftCursor[LINES] = bLine; g_bSoftCursor[COLS] = bCol; VideoSetHardwareCursor(); } void VideoGetCursorPosition(BYTE *pbLine, BYTE *pbCol) { *pbLine = g_bSoftCursor[LINES]; *pbCol = g_bSoftCursor[COLS]; } void VideoPrint(CHAR *szFormat, ...) { CHAR *p = szFormat; CHAR *q; CHAR buf[32]; va_list args; INT iVal; UINT uVal; CHAR *szVal; va_start(args, szFormat); while (*p != '\0') { switch (*p) { case '%': p++; switch (*p) { case '\0': goto done; case '%': VideoPutChar('%'); break; case 'd': iVal = va_arg(args, int); q = RtlIntToAscii(iVal, buf, ARRAY_LENGTH(buf), 10); ASSERT(strlen(q) < 20); VideoPutNullTerminatedString(q); break; case 'u': uVal = va_arg(args, unsigned int); q = RtlIntToAscii(uVal, buf, ARRAY_LENGTH(buf), 10); ASSERT(strlen(q) < 20); VideoPutNullTerminatedString(q); break; case 'x': uVal = va_arg(args, unsigned int); q = RtlIntToAscii(uVal, buf, ARRAY_LENGTH(buf), 16); ASSERT(strlen(q) < 20); VideoPutNullTerminatedString(q); break; case 's': szVal = va_arg(args, char *); VideoPutNullTerminatedString(szVal); break; case 'c': iVal = va_arg(args, int); VideoPutChar(iVal & 0xFF); break; default: VideoPutChar(*p); break; } break; default: VideoPutChar(*p); break; } p++; } done: va_end(args); VideoSetHardwareCursor(); }