/*++ Copyright (c) 1993 Microsoft Corporation Module Name: fefb.c (was textmode\kernel\spvidgfb.c) Abstract: Text setup display support for Frame Buffer displays. Author: Hideyuki Nagase (hideyukn) 01-July-1994 Revision History: --*/ #include #pragma hdrstop // // Vector for frame buffer functions. // VIDEO_FUNCTION_VECTOR FrameBufferKanjiVideoVector = { FrameBufferKanjiDisplayString, FrameBufferKanjiClearRegion, FrameBufferKanjiSpecificInit, FrameBufferKanjiSpecificReInit, FrameBufferKanjiSpecificTerminate, FrameBufferKanjiSpecificInitPalette, FrameBufferKanjiSpecificScrollUp }; BOOLEAN FrameBufferKanjiInitialized = FALSE; // // Number of bytes that make up a row of characters. // Equal to the screen stride (number of bytes on a scan line) // multiplies by the height of a char in bytes; double that // if DoubleCharHeight is TRUE. // ULONG KanjiCharRowDelta; ULONG KanjiBytesPerPixel; ULONG KanjiCharWidth; // // Physical font information // extern BOOTFONTBIN_HEADER BootFontHeader; VOID FrameBufferKanjiSpecificInit( IN PVIDEO_MODE_INFORMATION VideoModes, IN ULONG NumberOfModes, IN ULONG ModeSize ) /*++ Routine Description: Perform frame buffer specific initialization. This includes - setting the desired video mode. Arguments: None. Return Value: --*/ { NTSTATUS Status; IO_STATUS_BLOCK IoStatusBlock; VIDEO_MODE VideoMode; PVIDEO_MODE_INFORMATION mode; if(FrameBufferKanjiInitialized) { return; } mode = pFrameBufferDetermineModeToUse(VideoModes,NumberOfModes,ModeSize); if(mode == 0) { SpDisplayRawMessage(SP_SCRN_VIDEO_ERROR_RAW, 2, VIDEOBUG_BADMODE, 0); while(TRUE); // loop forever } // // Save away the mode info in a global. // VideoVariables->VideoModeInfo = *mode; // // Set the desired mode. // VideoMode.RequestedMode = VideoVariables->VideoModeInfo.ModeIndex; Status = ZwDeviceIoControlFile( VideoVariables->hDisplay, NULL, NULL, NULL, &IoStatusBlock, IOCTL_VIDEO_SET_CURRENT_MODE, &VideoMode, sizeof(VideoMode), NULL, 0 ); if(!NT_SUCCESS(Status)) { KdPrint(("SETUP: Unable to set mode %u (status = %lx)\n",VideoMode.RequestedMode,Status)); SpDisplayRawMessage(SP_SCRN_VIDEO_ERROR_RAW, 2, VIDEOBUG_SETMODE, Status); while(TRUE); // loop forever } // // Map the frame buffer. // pSpvidMapVideoMemory(TRUE); FrameBufferKanjiInitialized = TRUE; // // Logical FontGlyph information // FEFontCharacterHeight = BootFontHeader.CharacterImageHeight + BootFontHeader.CharacterTopPad + BootFontHeader.CharacterBottomPad; FEFontCharacterWidth = BootFontHeader.CharacterImageSbcsWidth; // // Determine the width of the screen. If it's double the size // of the minimum number of characters per row (or larger) // then we'll double the width of each character as we draw it. // VideoVariables->ScreenWidth = VideoVariables->VideoModeInfo.VisScreenWidth / FEFontCharacterWidth; // // Determine the height of the screen. If it's double the size // of the minimum number of characters per column (or larger) // then we'll double the height of each character as we draw it. // VideoVariables->ScreenHeight = VideoVariables->VideoModeInfo.VisScreenHeight / FEFontCharacterHeight; KanjiCharRowDelta = VideoVariables->VideoModeInfo.ScreenStride * FEFontCharacterHeight; KanjiBytesPerPixel = VideoVariables->VideoModeInfo.BitsPerPlane / 8; if(KanjiBytesPerPixel == 3) { KanjiBytesPerPixel = 4; } KdPrint(("SETUPDD:KanjiBytesPerPixel = %d\n",KanjiBytesPerPixel)); KanjiCharWidth = FEFontCharacterWidth * KanjiBytesPerPixel; // // Allocate the background buffer, if needed // VideoVariables->ActiveVideoBuffer = VideoVariables->VideoMemoryInfo.FrameBufferBase; if (SP_IS_UPGRADE_GRAPHICS_MODE()) { VideoVariables->VideoBufferSize = VideoVariables->VideoMemoryInfo.FrameBufferLength; VideoVariables->VideoBuffer = SpMemAlloc(VideoVariables->VideoBufferSize); if (VideoVariables->VideoBuffer) { VideoVariables->ActiveVideoBuffer = VideoVariables->VideoBuffer; } else { VideoVariables->VideoBufferSize = 0; SP_SET_UPGRADE_GRAPHICS_MODE(FALSE); } } } VOID FrameBufferKanjiSpecificReInit( VOID ) { NTSTATUS Status; IO_STATUS_BLOCK IoStatusBlock; VIDEO_MODE VideoMode; if(!FrameBufferKanjiInitialized) { return; } // // Set the desired mode. // VideoMode.RequestedMode = VideoVariables->VideoModeInfo.ModeIndex; Status = ZwDeviceIoControlFile( VideoVariables->hDisplay, NULL, NULL, NULL, &IoStatusBlock, IOCTL_VIDEO_SET_CURRENT_MODE, &VideoMode, sizeof(VideoMode), NULL, 0 ); if(!NT_SUCCESS(Status)) { KdPrint(("SETUP: Unable to set mode %u (status = %lx)\n",VideoMode.RequestedMode,Status)); SpDisplayRawMessage(SP_SCRN_VIDEO_ERROR_RAW, 2, VIDEOBUG_SETMODE, Status); while(TRUE); // loop forever } FrameBufferKanjiSpecificInitPalette(); // // Blast the background video information to the // foreground // if (SP_IS_UPGRADE_GRAPHICS_MODE() && VideoVariables->VideoBuffer && VideoVariables->VideoBufferSize) { PUCHAR Source = VideoVariables->VideoBuffer; PUCHAR Destination = VideoVariables->VideoMemoryInfo.FrameBufferBase; ULONG Index; for (Index=0; Index < VideoVariables->VideoBufferSize; Index++) { WRITE_REGISTER_UCHAR(Destination + Index, *(Source + Index)); } SP_SET_UPGRADE_GRAPHICS_MODE(FALSE); } VideoVariables->ActiveVideoBuffer = VideoVariables->VideoMemoryInfo.FrameBufferBase; } BOOLEAN FrameBufferKanjiSpecificInitPalette( VOID ) { BOOLEAN rc; ULONG NumEntries; ULONG BufferSize; PVIDEO_CLUT clut; // NTSTATUS Status; // IO_STATUS_BLOCK IoStatusBlock; UCHAR i; rc = TRUE; // // For non-palette-driven displays, we construct a simple palette // for use w/ gamma correcting adapters. // if(!(VideoVariables->VideoModeInfo.AttributeFlags & VIDEO_MODE_PALETTE_DRIVEN)) { switch(KanjiBytesPerPixel) { case 1: NumEntries = 3; break; case 2: NumEntries = 32; break; default: NumEntries = 255; break; } BufferSize = sizeof(VIDEO_CLUT)+(sizeof(VIDEO_CLUTDATA)*NumEntries); // size is close enough clut = SpMemAlloc(BufferSize); clut->NumEntries = (USHORT)NumEntries; clut->FirstEntry = 0; for(i=0; iLookupTable[i].RgbArray.Red = i; clut->LookupTable[i].RgbArray.Green = i; clut->LookupTable[i].RgbArray.Blue = i; clut->LookupTable[i].RgbArray.Unused = 0; } // Status = ZwDeviceIoControlFile( // hDisplay, // NULL, // NULL, // NULL, // &IoStatusBlock, // IOCTL_VIDEO_SET_COLOR_REGISTERS, // clut, // BufferSize, // NULL, // 0 // ); SpMemFree(clut); // if(!NT_SUCCESS(Status)) { // KdPrint(("SETUP: Unable to set palette (status = %lx)\n",Status)); // rc = FALSE; // } } return(rc); } VOID FrameBufferKanjiSpecificTerminate( VOID ) /*++ Routine Description: Perform frame buffer specific termination. This includes - unmapping the frame buffer from memory Arguments: None. Return Value: --*/ { if(FrameBufferKanjiInitialized) { // // Clear screen for next video mode. // FrameBufferKanjiClearRegion( 0, 0, VideoVariables->ScreenWidth, VideoVariables->ScreenHeight, ATT_FG_BLACK|ATT_BG_BLACK ); // // Unmap video memory // pSpvidMapVideoMemory(FALSE); if (VideoVariables->VideoBuffer && VideoVariables->VideoBufferSize) { SpMemFree(VideoVariables->VideoBuffer); VideoVariables->VideoBuffer = 0; VideoVariables->VideoBufferSize = 0; } FrameBufferKanjiInitialized = FALSE; } } VOID FrameBufferKanjiDisplayString( IN PSTR String, IN UCHAR Attribute, IN ULONG X, // 0-based coordinates (character units) IN ULONG Y ) /*++ Routine Description: Write a string of characters to the display. Arguments: String - supplies a 0-terminated character string in the OEM charset to be displayed at the given position. Attribute - supplies the attributes for characters in the string. X,Y - specify the character-based (0-based) position of the output. Return Value: None. --*/ { ULONG BgColorValue; ULONG FgColorValue; PUCHAR Destination; PUCHAR CharOrigin,LineOrigin,pGlyphRow; ULONG Length; PUCHAR pch; ULONG I,J,K; ULONG CurrentColumn; // // Eliminate invalid coord. // if( X >= VideoVariables->ScreenWidth ) X = 0; if( Y >= VideoVariables->ScreenHeight ) Y = 3; ASSERT(FEFontCharacterWidth == 8); // // Calculate the bit patterns that yield the foreground and background // attributes when poked into the frame buffer. // FgColorValue = VideoVariables->AttributeToColorValue[Attribute & 0x0f]; BgColorValue = VideoVariables->AttributeToColorValue[(Attribute >> 4) & 0x0f]; // // Calculate the address of the upper left pixel of the first character // to be displayed. // CharOrigin = (PUCHAR)VideoVariables->ActiveVideoBuffer + (Y * KanjiCharRowDelta) + (X * KanjiCharWidth); // // Set current column. // CurrentColumn = X; // // Output each character in the string. // for(pch=String; *pch; pch++) { // // Initialize line Origin // LineOrigin = CharOrigin; if(DbcsFontIsDBCSLeadByte(*pch)) { // // This is Full Width Character ( 16 + 1 + 2 * 8 ) // | | | Height // | | Post Leading // | Pre Leading // Real font image body USHORT Word; if((CurrentColumn+1) >= VideoVariables->ScreenWidth) { break; } Word = ((*pch) << 8) | (*(pch+1)); pGlyphRow = DbcsFontGetDbcsFontChar(Word); // // If we can not get image, replace it with full width space. // if(pGlyphRow == NULL) { pGlyphRow = DbcsFontGetDbcsFontChar(FEFontDefaultChar); } // // Draw pre leading lines // for (I = 0; I < BootFontHeader.CharacterTopPad; I += 1 ) { Destination = LineOrigin; for( J = 0; J < BootFontHeader.CharacterImageDbcsWidth; J += 1 ) { switch(KanjiBytesPerPixel) { case 1: *Destination++ = (UCHAR)BgColorValue; break; case 2: *(PUSHORT)Destination = (USHORT)BgColorValue; Destination += 2; break; case 4: *(PULONG)Destination = (ULONG)BgColorValue; Destination += 4; break; } } LineOrigin += VideoVariables->VideoModeInfo.ScreenStride; } // // Draw font glyph body // for (I = 0; I < BootFontHeader.CharacterImageHeight; I += 1 ) { Destination = LineOrigin; for( J = 0; J < 2; J += 1 ) { BYTE ShiftMask = 0x80; for( K = 0; K < 8 ; K += 1 ) { ULONG DrawValue; if (pGlyphRow && (*pGlyphRow & ShiftMask)) DrawValue = FgColorValue; else DrawValue = BgColorValue; switch(KanjiBytesPerPixel) { case 1: *Destination++ = (UCHAR)DrawValue; break; case 2: *(PUSHORT)Destination = (USHORT)DrawValue; Destination += 2; break; case 4: *(PULONG)Destination = (ULONG)DrawValue; Destination += 4; break; } ShiftMask = ShiftMask >> 1; } pGlyphRow ++; } LineOrigin += VideoVariables->VideoModeInfo.ScreenStride; } // // Draw post leading lines // for (I = 0; I < BootFontHeader.CharacterBottomPad; I += 1) { Destination = LineOrigin; for( J = 0; J < BootFontHeader.CharacterImageDbcsWidth; J += 1 ) { switch(KanjiBytesPerPixel) { case 1: *Destination++ = (UCHAR)BgColorValue; break; case 2: *(PUSHORT)Destination = (USHORT)BgColorValue; Destination += 2; break; case 4: *(PULONG)Destination = (ULONG)BgColorValue; Destination += 4; break; } } LineOrigin += VideoVariables->VideoModeInfo.ScreenStride; } CharOrigin += (BootFontHeader.CharacterImageDbcsWidth * KanjiBytesPerPixel); CurrentColumn += 2; // // Move to Next character ( skip Dbcs Trailing byte ) // pch++; } else if(DbcsFontIsGraphicsChar(*pch)) { BYTE ShiftMask = 0x80; ULONG DrawValue; if(CurrentColumn >= VideoVariables->ScreenWidth) { break; } // // Graphics Character special // pGlyphRow = DbcsFontGetGraphicsChar(*pch); if(pGlyphRow == NULL) { pGlyphRow = DbcsFontGetGraphicsChar(0x0); } for (I = 0; I < FEFontCharacterHeight; I += 1 ) { ShiftMask = 0x80; Destination = LineOrigin; for( K = 0; K < 8 ; K += 1 ) { if( *pGlyphRow & ShiftMask ) DrawValue = BgColorValue; else DrawValue = FgColorValue; switch(KanjiBytesPerPixel) { case 1: *Destination++ = (UCHAR)DrawValue; break; case 2: *(PUSHORT)Destination = (USHORT)DrawValue; Destination += 2; break; case 4: *(PULONG)Destination = (ULONG)DrawValue; Destination += 4; break; } ShiftMask = ShiftMask >> 1; } pGlyphRow ++; LineOrigin += VideoVariables->VideoModeInfo.ScreenStride; } CharOrigin += (BootFontHeader.CharacterImageSbcsWidth * KanjiBytesPerPixel); CurrentColumn += 1; } else { if(CurrentColumn >= VideoVariables->ScreenWidth) { break; } pGlyphRow = DbcsFontGetSbcsFontChar(*pch); // // If we can not get image, replace it with half width space. // if(pGlyphRow == NULL) { pGlyphRow = DbcsFontGetSbcsFontChar(0x20); } for (I = 0; I < BootFontHeader.CharacterTopPad; I += 1 ) { Destination = LineOrigin; for( J = 0; J < BootFontHeader.CharacterImageSbcsWidth; J += 1 ) { switch(KanjiBytesPerPixel) { case 1: *Destination++ = (UCHAR)BgColorValue; break; case 2: *(PUSHORT)Destination = (USHORT)BgColorValue; Destination += 2; break; case 4: *(PULONG)Destination = (ULONG)BgColorValue; Destination += 4; break; } } LineOrigin += VideoVariables->VideoModeInfo.ScreenStride; } for (I = 0; I < BootFontHeader.CharacterImageHeight; I += 1 ) { BYTE ShiftMask = 0x80; Destination = LineOrigin; for( K = 0; K < 8 ; K += 1 ) { ULONG DrawValue; if( *pGlyphRow & ShiftMask ) DrawValue = FgColorValue; else DrawValue = BgColorValue; switch(KanjiBytesPerPixel) { case 1: *Destination++ = (UCHAR)DrawValue; break; case 2: *(PUSHORT)Destination = (USHORT)DrawValue; Destination += 2; break; case 4: *(PULONG)Destination = (ULONG)DrawValue; Destination += 4; break; } ShiftMask = ShiftMask >> 1; } pGlyphRow ++; LineOrigin += VideoVariables->VideoModeInfo.ScreenStride; } for (I = 0; I < BootFontHeader.CharacterBottomPad; I += 1) { Destination = LineOrigin; for( J = 0; J < BootFontHeader.CharacterImageSbcsWidth; J += 1 ) { switch(KanjiBytesPerPixel) { case 1: *Destination++ = (UCHAR)BgColorValue; break; case 2: *(PUSHORT)Destination = (USHORT)BgColorValue; Destination += 2; break; case 4: *(PULONG)Destination = (ULONG)BgColorValue; Destination += 4; break; } } LineOrigin += VideoVariables->VideoModeInfo.ScreenStride; } CharOrigin += (BootFontHeader.CharacterImageSbcsWidth * KanjiBytesPerPixel); CurrentColumn += 1; } } } VOID FrameBufferKanjiClearRegion( IN ULONG X, IN ULONG Y, IN ULONG W, IN ULONG H, IN UCHAR Attribute ) /*++ Routine Description: Clear out a screen region to a specific attribute. Arguments: X,Y,W,H - specify rectangle in 0-based character coordinates. Attribute - Low nibble specifies attribute to be filled in the rectangle (ie, the background color to be cleared to). Return Value: None. --*/ { PUCHAR Destination; ULONG Fill; ULONG i; ULONG FillLength; ULONG x; ASSERT(X+W <= VideoVariables->ScreenWidth); ASSERT(Y+H <= VideoVariables->ScreenHeight); if(X+W > VideoVariables->ScreenWidth) { W = VideoVariables->ScreenWidth-X; } if(Y+H > VideoVariables->ScreenHeight) { H = VideoVariables->ScreenHeight-Y; } Fill = VideoVariables->AttributeToColorValue[Attribute & 0x0f]; Destination = (PUCHAR)VideoVariables->ActiveVideoBuffer + (Y * KanjiCharRowDelta) + (X * KanjiCharWidth); FillLength = W * KanjiCharWidth; for(i=0; iVideoModeInfo.ScreenStride; } } BOOLEAN FrameBufferKanjiSpecificScrollUp( IN ULONG TopLine, IN ULONG BottomLine, IN ULONG LineCount, IN UCHAR FillAttribute ) { PUCHAR Source,Target; ULONG Count; Target = (PUCHAR)VideoVariables->ActiveVideoBuffer + (TopLine * KanjiCharRowDelta); Source = Target + (LineCount * KanjiCharRowDelta); Count = (((BottomLine - TopLine) + 1) - LineCount) * KanjiCharRowDelta; RtlMoveMemory(Target,Source,Count); FrameBufferKanjiClearRegion( 0, (BottomLine - LineCount) + 1, VideoVariables->ScreenWidth, LineCount, FillAttribute ); return(TRUE); }