audk/EdkModulePkg/Universal/Console/GraphicsConsole/Dxe/GraphicsConsole.c

1567 lines
42 KiB
C

/*++
Copyright (c) 2006, Intel Corporation
All rights reserved. This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
Module Name:
GraphicsConsole.c
Abstract:
This is the main routine for initializing the Graphics Console support routines.
Revision History
Remaining Tasks
Add all standard Glyphs from EFI 1.02 Specification
Implement optimal automatic Mode creation algorithm
Solve palette issues for mixed graphics and text
When does this protocol reset the palette?
--*/
#include "GraphicsConsole.h"
//
// Function Prototypes
//
EFI_STATUS
EFIAPI
GraphicsConsoleControllerDriverSupported (
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE Controller,
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
);
EFI_STATUS
EFIAPI
GraphicsConsoleControllerDriverStart (
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE Controller,
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
);
EFI_STATUS
EFIAPI
GraphicsConsoleControllerDriverStop (
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE Controller,
IN UINTN NumberOfChildren,
IN EFI_HANDLE *ChildHandleBuffer
);
EFI_STATUS
GetTextColors (
IN EFI_SIMPLE_TEXT_OUT_PROTOCOL *This,
OUT EFI_UGA_PIXEL *Foreground,
OUT EFI_UGA_PIXEL *Background
);
EFI_STATUS
DrawUnicodeWeightAtCursor (
IN EFI_SIMPLE_TEXT_OUT_PROTOCOL *This,
IN CHAR16 UnicodeWeight
);
EFI_STATUS
DrawUnicodeWeightAtCursorN (
IN EFI_SIMPLE_TEXT_OUT_PROTOCOL *This,
IN CHAR16 *UnicodeWeight,
IN UINTN Count
);
EFI_STATUS
EraseCursor (
IN EFI_SIMPLE_TEXT_OUT_PROTOCOL *This
);
//
// Globals
//
GRAPHICS_CONSOLE_DEV mGraphicsConsoleDevTemplate = {
GRAPHICS_CONSOLE_DEV_SIGNATURE,
(EFI_UGA_DRAW_PROTOCOL *) NULL,
{
GraphicsConsoleConOutReset,
GraphicsConsoleConOutOutputString,
GraphicsConsoleConOutTestString,
GraphicsConsoleConOutQueryMode,
GraphicsConsoleConOutSetMode,
GraphicsConsoleConOutSetAttribute,
GraphicsConsoleConOutClearScreen,
GraphicsConsoleConOutSetCursorPosition,
GraphicsConsoleConOutEnableCursor,
(EFI_SIMPLE_TEXT_OUTPUT_MODE *) NULL
},
{
0,
0,
EFI_TEXT_ATTR(EFI_LIGHTGRAY, EFI_BLACK),
0,
0,
TRUE
},
{
{ 80, 25, 0, 0, 0, 0 }, // Mode 0
{ 0, 0, 0, 0, 0, 0 }, // Mode 1
{ 0, 0, 0, 0, 0, 0 } // Mode 2
},
(EFI_UGA_PIXEL *) NULL,
(EFI_HII_HANDLE) 0
};
EFI_HII_PROTOCOL *mHii;
static CHAR16 mCrLfString[3] = { CHAR_CARRIAGE_RETURN, CHAR_LINEFEED, CHAR_NULL };
static EFI_UGA_PIXEL mEfiColors[16] = {
//
// B G R
//
{ 0x00, 0x00, 0x00, 0x00 }, // BLACK
{ 0x98, 0x00, 0x00, 0x00 }, // BLUE
{ 0x00, 0x98, 0x00, 0x00 }, // GREEN
{ 0x98, 0x98, 0x00, 0x00 }, // CYAN
{ 0x00, 0x00, 0x98, 0x00 }, // RED
{ 0x98, 0x00, 0x98, 0x00 }, // MAGENTA
{ 0x00, 0x98, 0x98, 0x00 }, // BROWN
{ 0x98, 0x98, 0x98, 0x00 }, // LIGHTGRAY
{ 0x30, 0x30, 0x30, 0x00 }, // DARKGRAY - BRIGHT BLACK
{ 0xff, 0x00, 0x00, 0x00 }, // LIGHTBLUE - ?
{ 0x00, 0xff, 0x00, 0x00 }, // LIGHTGREEN - ?
{ 0xff, 0xff, 0x00, 0x00 }, // LIGHTCYAN
{ 0x00, 0x00, 0xff, 0x00 }, // LIGHTRED
{ 0xff, 0x00, 0xff, 0x00 }, // LIGHTMAGENTA
{ 0x00, 0xff, 0xff, 0x00 }, // LIGHTBROWN
{ 0xff, 0xff, 0xff, 0x00 } // WHITE
};
static EFI_NARROW_GLYPH mCursorGlyph = {
0x0000,
0x00,
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF }
};
static CHAR16 SpaceStr[] = { (CHAR16)NARROW_CHAR, ' ', 0 };
EFI_DRIVER_BINDING_PROTOCOL gGraphicsConsoleDriverBinding = {
GraphicsConsoleControllerDriverSupported,
GraphicsConsoleControllerDriverStart,
GraphicsConsoleControllerDriverStop,
0x10,
NULL,
NULL
};
EFI_STATUS
EFIAPI
GraphicsConsoleControllerDriverSupported (
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE Controller,
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
)
{
EFI_STATUS Status;
EFI_UGA_DRAW_PROTOCOL *UgaDraw;
EFI_DEVICE_PATH_PROTOCOL *DevicePath;
//
// Open the IO Abstraction(s) needed to perform the supported test
//
Status = gBS->OpenProtocol (
Controller,
&gEfiUgaDrawProtocolGuid,
(VOID **) &UgaDraw,
This->DriverBindingHandle,
Controller,
EFI_OPEN_PROTOCOL_BY_DRIVER
);
if (EFI_ERROR (Status)) {
return Status;
}
//
// We need to ensure that we do not layer on top of a virtual handle.
// We need to ensure that the handles produced by the conspliter do not
// get used.
//
Status = gBS->OpenProtocol (
Controller,
&gEfiDevicePathProtocolGuid,
(VOID **) &DevicePath,
This->DriverBindingHandle,
Controller,
EFI_OPEN_PROTOCOL_BY_DRIVER
);
if (!EFI_ERROR (Status)) {
gBS->CloseProtocol (
Controller,
&gEfiDevicePathProtocolGuid,
This->DriverBindingHandle,
Controller
);
} else {
goto Error;
}
//
// Does Hii Exist? If not, we aren't ready to run
//
Status = EfiLocateHiiProtocol ();
//
// Close the I/O Abstraction(s) used to perform the supported test
//
Error:
gBS->CloseProtocol (
Controller,
&gEfiUgaDrawProtocolGuid,
This->DriverBindingHandle,
Controller
);
return Status;
}
EFI_STATUS
EFIAPI
GraphicsConsoleControllerDriverStart (
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE Controller,
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
)
/*++
Routine Description:
Start the controller.
Arguments:
This - A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
Controller - The handle of the controller to start.
RemainingDevicePath - A pointer to the remaining portion of a devcie path.
Returns:
EFI_SUCCESS - Return successfully.
EFI_OUT_OF_RESOURCES - Out of resources.
--*/
{
EFI_STATUS Status;
GRAPHICS_CONSOLE_DEV *Private;
EFI_HII_PACKAGES *Package;
EFI_HII_FONT_PACK *FontPack;
UINTN NarrowFontSize;
UINT32 HorizontalResolution;
UINT32 VerticalResolution;
UINT32 ColorDepth;
UINT32 RefreshRate;
UINTN MaxMode;
UINTN Columns;
UINTN Rows;
UINT8 *Location;
//
// Initialize the Graphics Console device instance
//
Private = AllocateCopyPool (
sizeof (GRAPHICS_CONSOLE_DEV),
&mGraphicsConsoleDevTemplate
);
if (Private == NULL) {
return EFI_OUT_OF_RESOURCES;
}
Private->SimpleTextOutput.Mode = &(Private->SimpleTextOutputMode);
Status = gBS->OpenProtocol (
Controller,
&gEfiUgaDrawProtocolGuid,
(VOID **) &Private->UgaDraw,
This->DriverBindingHandle,
Controller,
EFI_OPEN_PROTOCOL_BY_DRIVER
);
if (EFI_ERROR (Status)) {
goto Error;
}
//
// Get the HII protocol. If Supported() succeeds, do we really
// need to get HII protocol again?
//
Status = EfiLocateHiiProtocol ();
if (EFI_ERROR (Status)) {
goto Error;
}
NarrowFontSize = ReturnNarrowFontSize ();
FontPack = AllocateZeroPool (sizeof (EFI_HII_FONT_PACK) + NarrowFontSize);
ASSERT (FontPack);
FontPack->Header.Length = (UINT32) (sizeof (EFI_HII_FONT_PACK) + NarrowFontSize);
FontPack->Header.Type = EFI_HII_FONT;
FontPack->NumberOfNarrowGlyphs = (UINT16) (NarrowFontSize / sizeof (EFI_NARROW_GLYPH));
Location = (UINT8 *) (&FontPack->NumberOfWideGlyphs + sizeof (UINT8));
CopyMem (Location, UsStdNarrowGlyphData, NarrowFontSize);
//
// Register our Fonts into the global database
//
Package = PreparePackages (1, NULL, FontPack);
mHii->NewPack (mHii, Package, &(Private->HiiHandle));
gBS->FreePool (Package);
//
// Free the font database
//
gBS->FreePool (FontPack);
//
// If the current mode information can not be retrieved, then attemp to set the default mode
// of 800x600, 32 bit colot, 60 Hz refresh.
//
HorizontalResolution = 800;
VerticalResolution = 600;
ColorDepth = 32;
RefreshRate = 60;
Status = Private->UgaDraw->SetMode (
Private->UgaDraw,
HorizontalResolution,
VerticalResolution,
ColorDepth,
RefreshRate
);
if (EFI_ERROR (Status)) {
//
// Get the current mode information from the UGA Draw Protocol
//
Status = Private->UgaDraw->GetMode (
Private->UgaDraw,
&HorizontalResolution,
&VerticalResolution,
&ColorDepth,
&RefreshRate
);
if (EFI_ERROR (Status)) {
goto Error;
}
}
//
// Compute the maximum number of text Rows and Columns that this current graphics mode can support
//
Columns = HorizontalResolution / GLYPH_WIDTH;
Rows = VerticalResolution / GLYPH_HEIGHT;
//
// See if the mode is too small to support the required 80x25 text mode
//
if (Columns < 80 || Rows < 25) {
goto Error;
}
//
// Add Mode #0 that must be 80x25
//
MaxMode = 0;
Private->ModeData[MaxMode].UgaWidth = HorizontalResolution;
Private->ModeData[MaxMode].UgaHeight = VerticalResolution;
Private->ModeData[MaxMode].DeltaX = (HorizontalResolution - (80 * GLYPH_WIDTH)) >> 1;
Private->ModeData[MaxMode].DeltaY = (VerticalResolution - (25 * GLYPH_HEIGHT)) >> 1;
MaxMode++;
//
// If it is possible to support Mode #1 - 80x50, than add it as an active mode
//
if (Rows >= 50) {
Private->ModeData[MaxMode].UgaWidth = HorizontalResolution;
Private->ModeData[MaxMode].UgaHeight = VerticalResolution;
Private->ModeData[MaxMode].DeltaX = (HorizontalResolution - (80 * GLYPH_WIDTH)) >> 1;
Private->ModeData[MaxMode].DeltaY = (VerticalResolution - (50 * GLYPH_HEIGHT)) >> 1;
MaxMode++;
}
//
// If the graphics mode is 800x600, than add a text mode that uses the entire display
//
if (HorizontalResolution == 800 && VerticalResolution == 600) {
if (MaxMode < 2) {
Private->ModeData[MaxMode].Columns = 0;
Private->ModeData[MaxMode].Rows = 0;
Private->ModeData[MaxMode].UgaWidth = 800;
Private->ModeData[MaxMode].UgaHeight = 600;
Private->ModeData[MaxMode].DeltaX = 0;
Private->ModeData[MaxMode].DeltaY = 0;
MaxMode++;
}
Private->ModeData[MaxMode].Columns = 800 / GLYPH_WIDTH;
Private->ModeData[MaxMode].Rows = 600 / GLYPH_HEIGHT;
Private->ModeData[MaxMode].UgaWidth = 800;
Private->ModeData[MaxMode].UgaHeight = 600;
Private->ModeData[MaxMode].DeltaX = (800 % GLYPH_WIDTH) >> 1;
Private->ModeData[MaxMode].DeltaY = (600 % GLYPH_HEIGHT) >> 1;
MaxMode++;
}
//
// Update the maximum number of modes
//
Private->SimpleTextOutputMode.MaxMode = (INT32) MaxMode;
//
// Determine the number of text modes that this protocol can support
//
Status = GraphicsConsoleConOutSetMode (&Private->SimpleTextOutput, 0);
if (EFI_ERROR (Status)) {
goto Error;
}
DEBUG_CODE (
GraphicsConsoleConOutOutputString (&Private->SimpleTextOutput, (CHAR16 *)L"Graphics Console Started\n\r");
);
//
// Install protocol interfaces for the Graphics Console device.
//
Status = gBS->InstallMultipleProtocolInterfaces (
&Controller,
&gEfiSimpleTextOutProtocolGuid,
&Private->SimpleTextOutput,
NULL
);
Error:
if (EFI_ERROR (Status)) {
//
// Close the UGA IO Protocol
//
gBS->CloseProtocol (
Controller,
&gEfiUgaDrawProtocolGuid,
This->DriverBindingHandle,
Controller
);
//
// Free private data
//
if (Private != NULL) {
gBS->FreePool (Private->LineBuffer);
gBS->FreePool (Private);
}
}
return Status;
}
EFI_STATUS
EFIAPI
GraphicsConsoleControllerDriverStop (
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE Controller,
IN UINTN NumberOfChildren,
IN EFI_HANDLE *ChildHandleBuffer
)
{
EFI_STATUS Status;
EFI_SIMPLE_TEXT_OUT_PROTOCOL *SimpleTextOutput;
GRAPHICS_CONSOLE_DEV *Private;
Status = gBS->OpenProtocol (
Controller,
&gEfiSimpleTextOutProtocolGuid,
(VOID **) &SimpleTextOutput,
This->DriverBindingHandle,
Controller,
EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
if (EFI_ERROR (Status)) {
return EFI_NOT_STARTED;
}
Private = GRAPHICS_CONSOLE_CON_OUT_DEV_FROM_THIS (SimpleTextOutput);
Status = gBS->UninstallProtocolInterface (
Controller,
&gEfiSimpleTextOutProtocolGuid,
&Private->SimpleTextOutput
);
if (!EFI_ERROR (Status)) {
//
// Close the UGA IO Protocol
//
gBS->CloseProtocol (
Controller,
&gEfiUgaDrawProtocolGuid,
This->DriverBindingHandle,
Controller
);
//
// Remove the font pack
//
mHii->RemovePack (mHii, Private->HiiHandle);
//
// Free our instance data
//
if (Private != NULL) {
gBS->FreePool (Private->LineBuffer);
gBS->FreePool (Private);
}
}
return Status;
}
EFI_STATUS
EfiLocateHiiProtocol (
VOID
)
/*++
Routine Description:
Find if the HII protocol is available. If yes, locate the HII protocol
Arguments:
Returns:
--*/
{
EFI_HANDLE Handle;
UINTN Size;
EFI_STATUS Status;
//
// There should only be one - so buffer size is this
//
Size = sizeof (EFI_HANDLE);
Status = gBS->LocateHandle (
ByProtocol,
&gEfiHiiProtocolGuid,
NULL,
&Size,
&Handle
);
if (EFI_ERROR (Status)) {
return Status;
}
Status = gBS->HandleProtocol (
Handle,
&gEfiHiiProtocolGuid,
(VOID **)&mHii
);
return Status;
}
//
// Body of the STO functions
//
EFI_STATUS
EFIAPI
GraphicsConsoleConOutReset (
IN EFI_SIMPLE_TEXT_OUT_PROTOCOL *This,
IN BOOLEAN ExtendedVerification
)
/*++
Routine Description:
Implements SIMPLE_TEXT_OUTPUT.Reset().
If ExtendeVerification is TRUE, then perform dependent Graphics Console
device reset, and set display mode to mode 0.
If ExtendedVerification is FALSE, only set display mode to mode 0.
Arguments:
This - Indicates the calling context.
ExtendedVerification - Indicates that the driver may perform a more exhaustive
verification operation of the device during reset.
Returns:
EFI_SUCCESS
The reset operation succeeds.
EFI_DEVICE_ERROR
The Graphics Console is not functioning correctly
--*/
{
This->SetAttribute (This, EFI_TEXT_ATTR (This->Mode->Attribute & 0x0F, EFI_BACKGROUND_BLACK));
return This->SetMode (This, 0);
}
EFI_STATUS
EFIAPI
GraphicsConsoleConOutOutputString (
IN EFI_SIMPLE_TEXT_OUT_PROTOCOL *This,
IN CHAR16 *WString
)
/*++
Routine Description:
Implements SIMPLE_TEXT_OUTPUT.OutputString().
The Unicode string will be converted to Glyphs and will be
sent to the Graphics Console.
Arguments:
This - Indicates the calling context.
WString - The Null-terminated Unicode string to be displayed on
the Graphics Console.
Returns:
EFI_SUCCESS
The string is output successfully.
EFI_DEVICE_ERROR
The Graphics Console failed to send the string out.
EFI_WARN_UNKNOWN_GLYPH
Indicates that some of the characters in the Unicode string could not
be rendered and are skipped.
--*/
{
GRAPHICS_CONSOLE_DEV *Private;
EFI_UGA_DRAW_PROTOCOL *UgaDraw;
INTN Mode;
UINTN MaxColumn;
UINTN MaxRow;
UINTN Width;
UINTN Height;
UINTN Delta;
EFI_STATUS Status;
BOOLEAN Warning;
EFI_UGA_PIXEL Foreground;
EFI_UGA_PIXEL Background;
UINTN DeltaX;
UINTN DeltaY;
UINTN Count;
UINTN Index;
INT32 OriginAttribute;
//
// Current mode
//
Mode = This->Mode->Mode;
Private = GRAPHICS_CONSOLE_CON_OUT_DEV_FROM_THIS (This);
UgaDraw = Private->UgaDraw;
MaxColumn = Private->ModeData[Mode].Columns;
MaxRow = Private->ModeData[Mode].Rows;
DeltaX = Private->ModeData[Mode].DeltaX;
DeltaY = Private->ModeData[Mode].DeltaY;
Width = MaxColumn * GLYPH_WIDTH;
Height = (MaxRow - 1) * GLYPH_HEIGHT;
Delta = Width * sizeof (EFI_UGA_PIXEL);
//
// The Attributes won't change when during the time OutputString is called
//
GetTextColors (This, &Foreground, &Background);
EraseCursor (This);
Warning = FALSE;
//
// Backup attribute
//
OriginAttribute = This->Mode->Attribute;
while (*WString) {
if (*WString == CHAR_BACKSPACE) {
//
// If the cursor is at the left edge of the display, then move the cursor
// one row up.
//
if (This->Mode->CursorColumn == 0 && This->Mode->CursorRow > 0) {
This->Mode->CursorRow--;
This->Mode->CursorColumn = (INT32) (MaxColumn - 1);
This->OutputString (This, SpaceStr);
EraseCursor (This);
This->Mode->CursorRow--;
This->Mode->CursorColumn = (INT32) (MaxColumn - 1);
} else if (This->Mode->CursorColumn > 0) {
//
// If the cursor is not at the left edge of the display, then move the cursor
// left one column.
//
This->Mode->CursorColumn--;
This->OutputString (This, SpaceStr);
EraseCursor (This);
This->Mode->CursorColumn--;
}
WString++;
} else if (*WString == CHAR_LINEFEED) {
//
// If the cursor is at the bottom of the display, then scroll the display one
// row, and do not update the cursor position. Otherwise, move the cursor
// down one row.
//
if (This->Mode->CursorRow == (INT32) (MaxRow - 1)) {
//
// Scroll Screen Up One Row
//
UgaDraw->Blt (
UgaDraw,
NULL,
EfiUgaVideoToVideo,
DeltaX,
DeltaY + GLYPH_HEIGHT,
DeltaX,
DeltaY,
Width,
Height,
Delta
);
//
// Print Blank Line at last line
//
UgaDraw->Blt (
UgaDraw,
&Background,
EfiUgaVideoFill,
0,
0,
DeltaX,
DeltaY + Height,
Width,
GLYPH_HEIGHT,
Delta
);
} else {
This->Mode->CursorRow++;
}
WString++;
} else if (*WString == CHAR_CARRIAGE_RETURN) {
//
// Move the cursor to the beginning of the current row.
//
This->Mode->CursorColumn = 0;
WString++;
} else if (*WString == WIDE_CHAR) {
This->Mode->Attribute |= EFI_WIDE_ATTRIBUTE;
WString++;
} else if (*WString == NARROW_CHAR) {
This->Mode->Attribute &= (~ (UINT32) EFI_WIDE_ATTRIBUTE);
WString++;
} else {
//
// Print the character at the current cursor position and move the cursor
// right one column. If this moves the cursor past the right edge of the
// display, then the line should wrap to the beginning of the next line. This
// is equivalent to inserting a CR and an LF. Note that if the cursor is at the
// bottom of the display, and the line wraps, then the display will be scrolled
// one line.
// If wide char is going to be displayed, need to display one character at a time
// Or, need to know the display length of a certain string.
//
// Index is used to determine how many character width units (wide = 2, narrow = 1)
// Count is used to determine how many characters are used regardless of their attributes
//
for (Count = 0, Index = 0; (This->Mode->CursorColumn + Index) < MaxColumn; Count++, Index++) {
if (WString[Count] == CHAR_NULL) {
break;
}
if (WString[Count] == CHAR_BACKSPACE) {
break;
}
if (WString[Count] == CHAR_LINEFEED) {
break;
}
if (WString[Count] == CHAR_CARRIAGE_RETURN) {
break;
}
if (WString[Count] == WIDE_CHAR) {
break;
}
if (WString[Count] == NARROW_CHAR) {
break;
}
//
// Is the wide attribute on?
//
if (This->Mode->Attribute & EFI_WIDE_ATTRIBUTE) {
//
// If wide, add one more width unit than normal since we are going to increment at the end of the for loop
//
Index++;
//
// This is the end-case where if we are at column 79 and about to print a wide character
// We should prevent this from happening because we will wrap inappropriately. We should
// not print this character until the next line.
//
if ((This->Mode->CursorColumn + Index + 1) > MaxColumn) {
Index++;
break;
}
}
}
Status = DrawUnicodeWeightAtCursorN (This, WString, Count);
if (EFI_ERROR (Status)) {
Warning = TRUE;
}
//
// At the end of line, output carriage return and line feed
//
WString += Count;
This->Mode->CursorColumn += (INT32) Index;
if (This->Mode->CursorColumn > (INT32) MaxColumn) {
This->Mode->CursorColumn -= 2;
This->OutputString (This, SpaceStr);
}
if (This->Mode->CursorColumn >= (INT32) MaxColumn) {
EraseCursor (This);
This->OutputString (This, mCrLfString);
EraseCursor (This);
}
}
}
This->Mode->Attribute = OriginAttribute;
EraseCursor (This);
if (Warning) {
return EFI_WARN_UNKNOWN_GLYPH;
}
return EFI_SUCCESS;
}
EFI_STATUS
EFIAPI
GraphicsConsoleConOutTestString (
IN EFI_SIMPLE_TEXT_OUT_PROTOCOL *This,
IN CHAR16 *WString
)
/*++
Routine Description:
Implements SIMPLE_TEXT_OUTPUT.TestString().
If one of the characters in the *Wstring is
neither valid valid Unicode drawing characters,
not ASCII code, then this function will return
EFI_UNSUPPORTED.
Arguments:
This - Indicates the calling context.
WString - The Null-terminated Unicode string to be tested.
Returns:
EFI_SUCCESS
The Graphics Console is capable of rendering the output string.
EFI_UNSUPPORTED
Some of the characters in the Unicode string cannot be rendered.
--*/
{
EFI_STATUS Status;
UINT16 GlyphWidth;
UINT32 GlyphStatus;
UINT16 Count;
GRAPHICS_CONSOLE_DEV *Private;
GLYPH_UNION *Glyph;
Private = GRAPHICS_CONSOLE_CON_OUT_DEV_FROM_THIS (This);
GlyphStatus = 0;
Count = 0;
while (WString[Count]) {
Status = mHii->GetGlyph (
mHii,
WString,
&Count,
(UINT8 **) &Glyph,
&GlyphWidth,
&GlyphStatus
);
if (EFI_ERROR (Status)) {
return EFI_UNSUPPORTED;
}
}
return EFI_SUCCESS;
}
EFI_STATUS
EFIAPI
GraphicsConsoleConOutQueryMode (
IN EFI_SIMPLE_TEXT_OUT_PROTOCOL *This,
IN UINTN ModeNumber,
OUT UINTN *Columns,
OUT UINTN *Rows
)
/*++
Routine Description:
Implements SIMPLE_TEXT_OUTPUT.QueryMode().
It returnes information for an available text mode
that the Graphics Console supports.
In this driver,we only support text mode 80x25, which is
defined as mode 0.
Arguments:
This - Indicates the calling context.
ModeNumber - The mode number to return information on.
Columns - The returned columns of the requested mode.
Rows - The returned rows of the requested mode.
Returns:
EFI_SUCCESS
The requested mode information is returned.
EFI_UNSUPPORTED
The mode number is not valid.
--*/
{
GRAPHICS_CONSOLE_DEV *Private;
if (ModeNumber >= (UINTN) This->Mode->MaxMode) {
return EFI_UNSUPPORTED;
}
Private = GRAPHICS_CONSOLE_CON_OUT_DEV_FROM_THIS (This);
*Columns = Private->ModeData[ModeNumber].Columns;
*Rows = Private->ModeData[ModeNumber].Rows;
if (*Columns <= 0 && *Rows <= 0) {
return EFI_UNSUPPORTED;
}
return EFI_SUCCESS;
}
EFI_STATUS
EFIAPI
GraphicsConsoleConOutSetMode (
IN EFI_SIMPLE_TEXT_OUT_PROTOCOL *This,
IN UINTN ModeNumber
)
/*++
Routine Description:
Implements SIMPLE_TEXT_OUTPUT.SetMode().
Set the Graphics Console to a specified mode.
In this driver, we only support mode 0.
Arguments:
This - Indicates the calling context.
ModeNumber - The text mode to set.
Returns:
EFI_SUCCESS
The requested text mode is set.
EFI_DEVICE_ERROR
The requested text mode cannot be set because of Graphics Console device error.
EFI_UNSUPPORTED
The text mode number is not valid.
--*/
{
EFI_STATUS Status;
GRAPHICS_CONSOLE_DEV *Private;
EFI_UGA_DRAW_PROTOCOL *UgaDraw;
GRAPHICS_CONSOLE_MODE_DATA *ModeData;
EFI_UGA_PIXEL *NewLineBuffer;
UINT32 HorizontalResolution;
UINT32 VerticalResolution;
UINT32 ColorDepth;
UINT32 RefreshRate;
Private = GRAPHICS_CONSOLE_CON_OUT_DEV_FROM_THIS (This);
UgaDraw = Private->UgaDraw;
ModeData = &(Private->ModeData[ModeNumber]);
//
// Make sure the requested mode number is supported
//
if (ModeNumber >= (UINTN) This->Mode->MaxMode) {
return EFI_UNSUPPORTED;
}
if (ModeData->Columns <= 0 && ModeData->Rows <= 0) {
return EFI_UNSUPPORTED;
}
//
// Attempt to allocate a line buffer for the requested mode number
//
Status = gBS->AllocatePool (
EfiBootServicesData,
sizeof (EFI_UGA_PIXEL) * ModeData->Columns * GLYPH_WIDTH * GLYPH_HEIGHT,
(VOID **) &NewLineBuffer
);
if (EFI_ERROR (Status)) {
//
// The new line buffer could not be allocated, so return an error.
// No changes to the state of the current console have been made, so the current console is still valid
//
return Status;
}
//
// If the mode has been set at least one other time, then LineBuffer will not be NULL
//
if (Private->LineBuffer != NULL) {
//
// Clear the current text window on the current graphics console
//
This->ClearScreen (This);
//
// If the new mode is the same as the old mode, then just return EFI_SUCCESS
//
if ((INT32) ModeNumber == This->Mode->Mode) {
gBS->FreePool (NewLineBuffer);
return EFI_SUCCESS;
}
//
// Otherwise, the size of the text console and/or the UGA mode will be changed,
// so turn off the cursor, and free the LineBuffer for the current mode
//
This->EnableCursor (This, FALSE);
gBS->FreePool (Private->LineBuffer);
}
//
// Assign the current line buffer to the newly allocated line buffer
//
Private->LineBuffer = NewLineBuffer;
//
// Get the current UGA Draw mode information
//
Status = UgaDraw->GetMode (
UgaDraw,
&HorizontalResolution,
&VerticalResolution,
&ColorDepth,
&RefreshRate
);
if (EFI_ERROR (Status) || HorizontalResolution != ModeData->UgaWidth || VerticalResolution != ModeData->UgaHeight) {
//
// Either no graphics mode is currently set, or it is set to the wrong resolution, so set the new grapghics mode
//
Status = UgaDraw->SetMode (
UgaDraw,
ModeData->UgaWidth,
ModeData->UgaHeight,
32,
60
);
if (EFI_ERROR (Status)) {
//
// The mode set operation failed
//
return Status;
}
} else {
//
// The current graphics mode is correct, so simply clear the entire display
//
Status = UgaDraw->Blt (
UgaDraw,
&mEfiColors[0],
EfiUgaVideoFill,
0,
0,
0,
0,
ModeData->UgaWidth,
ModeData->UgaHeight,
0
);
}
//
// The new mode is valid, so commit the mode change
//
This->Mode->Mode = (INT32) ModeNumber;
//
// Move the text cursor to the upper left hand corner of the displat and enable it
//
This->SetCursorPosition (This, 0, 0);
This->EnableCursor (This, TRUE);
return EFI_SUCCESS;
}
EFI_STATUS
EFIAPI
GraphicsConsoleConOutSetAttribute (
IN EFI_SIMPLE_TEXT_OUT_PROTOCOL *This,
IN UINTN Attribute
)
/*++
Routine Description:
Implements SIMPLE_TEXT_OUTPUT.SetAttribute().
Arguments:
This - Indicates the calling context.
Attrubute - The attribute to set. Only bit0..6 are valid, all other bits
are undefined and must be zero.
Returns:
EFI_SUCCESS
The requested attribute is set.
EFI_DEVICE_ERROR
The requested attribute cannot be set due to Graphics Console port error.
EFI_UNSUPPORTED
The attribute requested is not defined by EFI spec.
--*/
{
if ((Attribute | 0xFF) != 0xFF) {
return EFI_UNSUPPORTED;
}
if ((INT32) Attribute == This->Mode->Attribute) {
return EFI_SUCCESS;
}
EraseCursor (This);
This->Mode->Attribute = (INT32) Attribute;
EraseCursor (This);
return EFI_SUCCESS;
}
EFI_STATUS
EFIAPI
GraphicsConsoleConOutClearScreen (
IN EFI_SIMPLE_TEXT_OUT_PROTOCOL *This
)
/*++
Routine Description:
Implements SIMPLE_TEXT_OUTPUT.ClearScreen().
It clears the Graphics Console's display to the
currently selected background color.
Arguments:
This - Indicates the calling context.
Returns:
EFI_SUCCESS
The operation completed successfully.
EFI_DEVICE_ERROR
The Graphics Console cannot be cleared due to Graphics Console device error.
EFI_UNSUPPORTED
The Graphics Console is not in a valid text mode.
--*/
{
EFI_STATUS Status;
GRAPHICS_CONSOLE_DEV *Private;
GRAPHICS_CONSOLE_MODE_DATA *ModeData;
EFI_UGA_DRAW_PROTOCOL *UgaDraw;
EFI_UGA_PIXEL Foreground;
EFI_UGA_PIXEL Background;
Private = GRAPHICS_CONSOLE_CON_OUT_DEV_FROM_THIS (This);
UgaDraw = Private->UgaDraw;
ModeData = &(Private->ModeData[This->Mode->Mode]);
GetTextColors (This, &Foreground, &Background);
Status = UgaDraw->Blt (
UgaDraw,
&Background,
EfiUgaVideoFill,
0,
0,
0,
0,
ModeData->UgaWidth,
ModeData->UgaHeight,
0
);
This->Mode->CursorColumn = 0;
This->Mode->CursorRow = 0;
EraseCursor (This);
return Status;
}
EFI_STATUS
EFIAPI
GraphicsConsoleConOutSetCursorPosition (
IN EFI_SIMPLE_TEXT_OUT_PROTOCOL *This,
IN UINTN Column,
IN UINTN Row
)
/*++
Routine Description:
Implements SIMPLE_TEXT_OUTPUT.SetCursorPosition().
Arguments:
This - Indicates the calling context.
Column - The row to set cursor to.
Row - The column to set cursor to.
Returns:
EFI_SUCCESS
The operation completed successfully.
EFI_DEVICE_ERROR
The request fails due to Graphics Console device error.
EFI_UNSUPPORTED
The Graphics Console is not in a valid text mode, or the cursor position
is invalid for current mode.
--*/
{
GRAPHICS_CONSOLE_DEV *Private;
GRAPHICS_CONSOLE_MODE_DATA *ModeData;
Private = GRAPHICS_CONSOLE_CON_OUT_DEV_FROM_THIS (This);
ModeData = &(Private->ModeData[This->Mode->Mode]);
if ((Column >= ModeData->Columns) || (Row >= ModeData->Rows)) {
return EFI_UNSUPPORTED;
}
if (((INT32) Column == This->Mode->CursorColumn) && ((INT32) Row == This->Mode->CursorRow)) {
return EFI_SUCCESS;
}
EraseCursor (This);
This->Mode->CursorColumn = (INT32) Column;
This->Mode->CursorRow = (INT32) Row;
EraseCursor (This);
return EFI_SUCCESS;
}
EFI_STATUS
EFIAPI
GraphicsConsoleConOutEnableCursor (
IN EFI_SIMPLE_TEXT_OUT_PROTOCOL *This,
IN BOOLEAN Visible
)
/*++
Routine Description:
Implements SIMPLE_TEXT_OUTPUT.EnableCursor().
In this driver, the cursor cannot be hidden.
Arguments:
This - Indicates the calling context.
Visible - If TRUE, the cursor is set to be visible,
If FALSE, the cursor is set to be invisible.
Returns:
EFI_SUCCESS
The request is valid.
EFI_UNSUPPORTED
The Graphics Console does not support a hidden cursor.
--*/
{
EraseCursor (This);
This->Mode->CursorVisible = Visible;
EraseCursor (This);
return EFI_SUCCESS;
}
EFI_STATUS
GetTextColors (
IN EFI_SIMPLE_TEXT_OUT_PROTOCOL *This,
OUT EFI_UGA_PIXEL *Foreground,
OUT EFI_UGA_PIXEL *Background
)
{
INTN Attribute;
Attribute = This->Mode->Attribute & 0x7F;
*Foreground = mEfiColors[Attribute & 0x0f];
*Background = mEfiColors[Attribute >> 4];
return EFI_SUCCESS;
}
EFI_STATUS
DrawUnicodeWeightAtCursorN (
IN EFI_SIMPLE_TEXT_OUT_PROTOCOL *This,
IN CHAR16 *UnicodeWeight,
IN UINTN Count
)
{
GRAPHICS_CONSOLE_DEV *Private;
EFI_STATUS Status;
EFI_STATUS ReturnStatus;
GLYPH_UNION *Glyph;
GLYPH_UNION GlyphData;
INTN GlyphX;
INTN GlyphY;
EFI_UGA_DRAW_PROTOCOL *UgaDraw;
EFI_UGA_PIXEL Foreground;
EFI_UGA_PIXEL Background;
UINTN Index;
UINTN ArrayIndex;
UINTN Counts;
UINT16 GlyphWidth;
UINT32 GlyphStatus;
Private = GRAPHICS_CONSOLE_CON_OUT_DEV_FROM_THIS (This);
ReturnStatus = EFI_SUCCESS;
GlyphStatus = 0;
GlyphWidth = 0x08;
GetTextColors (This, &Foreground, &Background);
Index = 0;
ArrayIndex = 0;
while (Index < Count) {
if (This->Mode->Attribute & EFI_WIDE_ATTRIBUTE) {
GlyphStatus = WIDE_CHAR;
} else {
GlyphStatus = NARROW_CHAR;
}
Status = mHii->GetGlyph (
mHii,
UnicodeWeight,
(UINT16 *) &Index,
(UINT8 **) &Glyph,
&GlyphWidth,
&GlyphStatus
);
if (EFI_ERROR (Status)) {
ReturnStatus = Status;
}
Counts = 0;
CopyMem (&GlyphData, Glyph, sizeof (GLYPH_UNION));
do {
//
// We are creating the second half of the wide character's BLT buffer
//
if (GlyphWidth == 0x10 && Counts == 1) {
CopyMem (&GlyphData.NarrowGlyph.GlyphCol1, &Glyph->WideGlyph.GlyphCol2, sizeof (Glyph->WideGlyph.GlyphCol2));
}
Counts++;
if (GlyphWidth == 0x10) {
mHii->GlyphToBlt (
mHii,
(UINT8 *) &GlyphData,
Foreground,
Background,
Count * 2,
GLYPH_WIDTH,
GLYPH_HEIGHT,
&Private->LineBuffer[ArrayIndex * GLYPH_WIDTH]
);
} else {
mHii->GlyphToBlt (
mHii,
(UINT8 *) &GlyphData,
Foreground,
Background,
Count,
GLYPH_WIDTH,
GLYPH_HEIGHT,
&Private->LineBuffer[ArrayIndex * GLYPH_WIDTH]
);
}
ArrayIndex++;
} while (Counts < 2 && GlyphWidth == 0x10);
}
//
// If we are printing Wide characters, treat the BLT as if it is twice as many characters
//
if (GlyphWidth == 0x10) {
Count = Count * 2;
}
//
// Blt a character to the screen
//
GlyphX = This->Mode->CursorColumn * GLYPH_WIDTH;
GlyphY = This->Mode->CursorRow * GLYPH_HEIGHT;
UgaDraw = Private->UgaDraw;
UgaDraw->Blt (
UgaDraw,
Private->LineBuffer,
EfiUgaBltBufferToVideo,
0,
0,
GlyphX + Private->ModeData[This->Mode->Mode].DeltaX,
GlyphY + Private->ModeData[This->Mode->Mode].DeltaY,
GLYPH_WIDTH * Count,
GLYPH_HEIGHT,
GLYPH_WIDTH * Count * sizeof (EFI_UGA_PIXEL)
);
return ReturnStatus;
}
EFI_STATUS
EraseCursor (
IN EFI_SIMPLE_TEXT_OUT_PROTOCOL *This
)
{
GRAPHICS_CONSOLE_DEV *Private;
EFI_SIMPLE_TEXT_OUTPUT_MODE *CurrentMode;
INTN GlyphX;
INTN GlyphY;
EFI_UGA_DRAW_PROTOCOL *UgaDraw;
EFI_UGA_PIXEL_UNION Foreground;
EFI_UGA_PIXEL_UNION Background;
EFI_UGA_PIXEL_UNION BltChar[GLYPH_HEIGHT][GLYPH_WIDTH];
UINTN X;
UINTN Y;
CurrentMode = This->Mode;
if (!CurrentMode->CursorVisible) {
return EFI_SUCCESS;
}
Private = GRAPHICS_CONSOLE_CON_OUT_DEV_FROM_THIS (This);
UgaDraw = Private->UgaDraw;
//
// BUGBUG - we need to think about what to do with wide and narrow character deletions.
//
//
// Blt a character to the screen
//
GlyphX = (CurrentMode->CursorColumn * GLYPH_WIDTH) + Private->ModeData[CurrentMode->Mode].DeltaX;
GlyphY = (CurrentMode->CursorRow * GLYPH_HEIGHT) + Private->ModeData[CurrentMode->Mode].DeltaY;
UgaDraw->Blt (
UgaDraw,
(EFI_UGA_PIXEL *) BltChar,
EfiUgaVideoToBltBuffer,
GlyphX,
GlyphY,
0,
0,
GLYPH_WIDTH,
GLYPH_HEIGHT,
GLYPH_WIDTH * sizeof (EFI_UGA_PIXEL)
);
GetTextColors (This, &Foreground.Pixel, &Background.Pixel);
//
// Convert Monochrome bitmap of the Glyph to BltBuffer structure
//
for (Y = 0; Y < GLYPH_HEIGHT; Y++) {
for (X = 0; X < GLYPH_WIDTH; X++) {
if ((mCursorGlyph.GlyphCol1[Y] & (1 << X)) != 0) {
BltChar[Y][GLYPH_WIDTH - X - 1].Raw ^= Foreground.Raw;
}
}
}
UgaDraw->Blt (
UgaDraw,
(EFI_UGA_PIXEL *) BltChar,
EfiUgaBltBufferToVideo,
0,
0,
GlyphX,
GlyphY,
GLYPH_WIDTH,
GLYPH_HEIGHT,
GLYPH_WIDTH * sizeof (EFI_UGA_PIXEL)
);
return EFI_SUCCESS;
}