alder_lake_bios/Insyde/InsydeCrPkg/TerminalDxe/TerminalConOutAsync.c

2080 lines
54 KiB
C

/** @file
Implementation for asynchronous EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL protocol.
;******************************************************************************
;* Copyright (c) 2012, Insyde Software Corp. All Rights Reserved.
;*
;* You may not reproduce, distribute, publish, display, perform, modify, adapt,
;* transmit, broadcast, present, recite, release, license or otherwise exploit
;* any part of this publication in any form, by any means, without the prior
;* written permission of Insyde Software Corporation.
;*
;******************************************************************************
*/
#include "Terminal.h"
UINTN mTerminalAmount = 0;
LIST_ENTRY mTermEventLists;
LIST_ENTRY *mCurrentTermEvent = NULL;
extern BOOLEAN gEscProcess;
/**
Implements EFI_SIMPLE_TEXT_OUT_PROTOCOL.OutputString().
The Unicode string will be converted to terminal expressible data stream
and save into screen buffer.
@param This Indicates the calling context.
@param WString The Null-terminated Unicode string to be displayed on
the terminal screen.
@retval EFI_SUCCESS The string is output successfully.
@retval EFI_DEVICE_ERROR The serial port fails to send the string out.
@retval EFI_WARN_UNKNOWN_GLYPH Indicates that some of the characters in the Unicode string could not
be rendered and are skipped.
**/
EFI_STATUS
EFIAPI
PrivateOutputString (
IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
IN CHAR16 *WString
)
{
TERMINAL_DEV *TerminalDevice;
EFI_SIMPLE_TEXT_OUTPUT_MODE *Mode;
UINTN MaxColumn;
UINTN MaxRow;
UINTN Length;
UTF8_CHAR Utf8Char;
CHAR8 AnsiDrawChar;
CHAR8 AsciiChar;
CHAR8 AsciiDrawChar;
CHAR8 LineDrawChar;
CHAR8 *OutputChar;
EFI_STATUS Status;
UINT8 ValidBytes;
//
// flag used to indicate whether condition happens which will cause
// return EFI_WARN_UNKNOWN_GLYPH
//
BOOLEAN Warning;
ValidBytes = 0;
Warning = FALSE;
OutputChar = NULL;
//
// get Terminal device data structure pointer.
//
TerminalDevice = TERMINAL_CON_OUT_DEV_FROM_THIS (This);
//
// Get current display mode
//
Mode = This->Mode;
This->QueryMode (
This,
Mode->Mode,
&MaxColumn,
&MaxRow
);
for (; *WString != CHAR_NULL; WString++) {
switch (TerminalDevice->TerminalType) {
case PCANSITYPE:
case VT100TYPE:
case LOGTERMTYPE:
OutputChar = &AsciiChar;
if (!TerminalIsValidTextGraphics (*WString, &AnsiDrawChar, &AsciiDrawChar, NULL)) {
//
// Text character: Convert Text character form Unicode to ASCII.
//
AsciiChar = (CHAR8) *WString;
if (!(TerminalIsValidAscii (AsciiChar) || TerminalIsValidEfiCntlChar (AsciiChar))) {
//
// when this driver use the OutputString to output control string,
// TerminalDevice->OutputEscChar is set to let the Esc char
// to be output to the terminal emulation software.
//
if (!(AsciiChar == ESC) || !TerminalDevice->OutputEscChar) {
AsciiChar = '?';
Warning = TRUE;
}
}
} else if (TerminalDevice->TerminalType == PCANSITYPE ) {
//
// ANSI Graphic character
//
OutputChar = &AnsiDrawChar;
} else if (TerminalDevice->TerminalType == VT100TYPE) {
//
// ASCII Graphic character
//
OutputChar = &AsciiDrawChar;
} else if (TerminalDevice->TerminalType == LOGTERMTYPE) {
//
// ASCII Graphic character
//
OutputChar = &AsciiDrawChar;
}
Length = 1;
Status = TerminalDevice->SerialIo->Write (
TerminalDevice->SerialIo,
&Length,
OutputChar
);
if (EFI_ERROR (Status)) {
goto OutputError;
}
//
// Update Terminal Current Cursor Position
//
TerminalDevice->TerCol = (TerminalDevice->TerCol == MaxColumn - 1)? 0 : (TerminalDevice->TerCol + 1);
break;
case VT100PLUSTYPE:
Status = EFI_SUCCESS;
OutputChar = &AsciiChar;
if ((*WString == WIDE_CHAR || *WString == NARROW_CHAR)) {
//
// Here didn't support Wide Character.
//
break;
} else if (!TerminalIsValidTextGraphics (*WString, &AnsiDrawChar, &AsciiDrawChar, &LineDrawChar)) {
//
// Text character: Convert Text character form Unicode to ASCII.
//
AsciiChar = (CHAR8)*WString;
if (!(TerminalIsValidAscii (AsciiChar) || TerminalIsValidEfiCntlChar (AsciiChar))) {
//
// when this driver use the OutputString to output control string,
// TerminalDevice->OutputEscChar is set to let the Esc char
// to be output to the terminal emulation software.
//
if (!(AsciiChar == ESC) || !TerminalDevice->OutputEscChar) {
AsciiChar = '?';
Warning = TRUE;
}
}
//
// Output text characters
//
if (TerminalDevice->OutputEscChar == FALSE) {
Status = Vt100PlusSwitchCharSet (&TerminalDevice->SimpleTextOutput, VT100_ASCII_CHAR_SET);
}
OutputChar = &AsciiChar;
} else if (TerminalDevice->OutputEscChar == FALSE) {
//
// Graphics character: Select Graphics CharSet
//
if ( InLineDrawTable(LineDrawChar) &&
((TerminalDevice->TerminalFeatureFlag & CR_TERMINAL_CHARSET_FLAG) == CR_TERMINAL_CHARSET_GRAPHIC)) {
//
// Use Line Draw Character Set
//
Status = Vt100PlusSwitchCharSet (&TerminalDevice->SimpleTextOutput, VT100_GRAPH_CHAR_SET);
OutputChar = &LineDrawChar;
} else {
//
// Use ASCII Character Set
//
Status = Vt100PlusSwitchCharSet (&TerminalDevice->SimpleTextOutput, VT100_ASCII_CHAR_SET);
OutputChar = &AsciiDrawChar;
}
}
if (EFI_ERROR (Status)) {
goto OutputError;
}
Length = 1;
Status = TerminalDevice->SerialIo->Write (
TerminalDevice->SerialIo,
&Length,
OutputChar
);
if (EFI_ERROR (Status)) {
goto OutputError;
}
//
// Update Terminal Current Cursor Position
//
TerminalDevice->TerCol = (TerminalDevice->TerCol == MaxColumn - 1)? 0 : (TerminalDevice->TerCol + 1);
break;
case VTUTF8TYPE:
UnicodeToUtf8 (*WString, &Utf8Char, &ValidBytes);
Length = ValidBytes;
Status = TerminalDevice->SerialIo->Write (
TerminalDevice->SerialIo,
&Length,
(UINT8 *) &Utf8Char
);
if (EFI_ERROR (Status)) {
goto OutputError;
}
//
// Update Terminal Current Cursor Position
//
TerminalDevice->TerCol = (TerminalDevice->TerCol == MaxColumn - 1)? 0 : (TerminalDevice->TerCol + 1);
break;
}
}
if (Warning) {
return EFI_WARN_UNKNOWN_GLYPH;
}
return EFI_SUCCESS;
OutputError:
REPORT_STATUS_CODE_WITH_DEVICE_PATH (
EFI_ERROR_CODE | EFI_ERROR_MINOR,
(EFI_PERIPHERAL_REMOTE_CONSOLE | EFI_P_EC_CONTROLLER_ERROR),
TerminalDevice->DevicePath
);
return EFI_DEVICE_ERROR;
}
/**
Implements EFI_SIMPLE_TEXT_OUT_PROTOCOL.SetAttribute().
@param This Pointer to EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL
@param Attribute The attribute to set. Only bit0..6 are valid, all other bits
are undefined and must be zero
@retval EFI_SUCCESS The requested attribute is set.
@retval EFI_DEVICE_ERROR The requested attribute cannot be set due to serial port error.
@retval EFI_UNSUPPORTED The attribute requested is not defined by EFI spec.
**/
EFI_STATUS
EFIAPI
PrivateSetAttribute (
IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
IN UINTN Attribute
)
{
UINT8 ForegroundControl;
UINT8 BackgroundControl;
UINT8 BrightControl;
EFI_STATUS Status;
TERMINAL_DEV *TerminalDevice;
//
// get Terminal device data structure pointer.
//
TerminalDevice = TERMINAL_CON_OUT_DEV_FROM_THIS (This);
//
// Speed up:
// If current attribute is the same, dont't need to send command
//
if (TerminalDevice->TermCurAttr == Attribute) {
return EFI_SUCCESS;
}
//
// convert Attribute value to terminal emulator
// understandable foreground color
//
switch (Attribute & 0x07) {
case EFI_BLACK:
ForegroundControl = 30;
break;
case EFI_BLUE:
ForegroundControl = 34;
break;
case EFI_GREEN:
ForegroundControl = 32;
break;
case EFI_CYAN:
ForegroundControl = 36;
break;
case EFI_RED:
ForegroundControl = 31;
break;
case EFI_MAGENTA:
ForegroundControl = 35;
break;
case EFI_BROWN:
ForegroundControl = 33;
break;
//
// EFI_LIGHTGRAY
//
default:
ForegroundControl = 37;
break;
}
//
// bit4 of the Attribute indicates bright control
// of terminal emulator.
//
BrightControl = (UINT8) ((Attribute >> 3) & 1);
//
// convert Attribute value to terminal emulator
// understandable background color.
//
switch ((Attribute >> 4) & 0x07) {
case EFI_BLACK:
BackgroundControl = 40;
break;
case EFI_BLUE:
BackgroundControl = 44;
break;
case EFI_GREEN:
BackgroundControl = 42;
break;
case EFI_CYAN:
BackgroundControl = 46;
break;
case EFI_RED:
BackgroundControl = 41;
break;
case EFI_MAGENTA:
BackgroundControl = 45;
break;
case EFI_BROWN:
BackgroundControl = 43;
break;
//
// EFI_LIGHTGRAY:
//
default:
BackgroundControl = 47;
break;
}
if ((TerminalDevice->TerminalFeatureFlag & CR_TERMINAL_VIDEO_FLAG) == CR_TERMINAL_VIDEO_MONO) {
if (BackgroundControl == 40) {
//Background = BLACK -> Background = WHITE Foreground = BLACK
BackgroundControl = 47;
ForegroundControl = 30;
}
else {
BackgroundControl = 40;
ForegroundControl = 37;
}
}
//
// terminal emulator's control sequence to set attributes
//
gSetAttributeString[BRIGHT_CONTROL_OFFSET] = (CHAR16) ('0' + BrightControl);
gSetAttributeString[FOREGROUND_CONTROL_OFFSET + 0] = (CHAR16) ('0' + (ForegroundControl / 10));
gSetAttributeString[FOREGROUND_CONTROL_OFFSET + 1] = (CHAR16) ('0' + (ForegroundControl % 10));
gSetAttributeString[BACKGROUND_CONTROL_OFFSET + 0] = (CHAR16) ('0' + (BackgroundControl / 10));
gSetAttributeString[BACKGROUND_CONTROL_OFFSET + 1] = (CHAR16) ('0' + (BackgroundControl % 10));
Status = OutputEscSquenceString (This, gSetAttributeString);
if (EFI_ERROR (Status)) {
return EFI_DEVICE_ERROR;
}
TerminalDevice->TermCurAttr = Attribute;
return EFI_SUCCESS;
}
/**
Send changing cursor ESC squence code to terminal.
@param This Pointer to EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL
@param Column The column to set cursor
@param Row The row to set cursor.
@retval EFI_SUCCESS The requested cursor position is set.
@retval EFI_DEVICE_ERROR The requested cursor position cannot be set due to serial port error.
@retval EFI_UNSUPPORTED The cursor position requested is not defined by EFI spec.
**/
EFI_STATUS
EFIAPI
PrivateSetCursorPosition (
IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
IN UINTN Column,
IN UINTN Row
)
{
EFI_SIMPLE_TEXT_OUTPUT_MODE *Mode;
UINTN MaxColumn;
UINTN MaxRow;
EFI_STATUS Status;
TERMINAL_DEV *TerminalDevice;
UINTN Value;
TerminalDevice = TERMINAL_CON_OUT_DEV_FROM_THIS (This);
//
// get current mode
//
Mode = This->Mode;
//
// get geometry of current mode
//
Status = This->QueryMode (
This,
Mode->Mode,
&MaxColumn,
&MaxRow
);
if (EFI_ERROR (Status)) {
return EFI_UNSUPPORTED;
}
if (Column >= MaxColumn || Row >= MaxRow) {
return EFI_UNSUPPORTED;
}
//
// Speed up:
// If current cursor is the same, dont't need to send command
//
if (TerminalDevice->TerRow == Row && \
TerminalDevice->TerCol == Column) {
return EFI_SUCCESS;
}
//
// control sequence to move the cursor
//
Value = Row + 1;
gSetCursorPositionString[ROW_OFFSET + 0] = (CHAR16) ('0' + (Value / 100));
Value = (Value % 100);
gSetCursorPositionString[ROW_OFFSET + 1] = (CHAR16) ('0' + (Value / 10));
Value = (Value % 10);
gSetCursorPositionString[ROW_OFFSET + 2] = (CHAR16) ('0' + Value);
Value = Column + 1;
gSetCursorPositionString[COLUMN_OFFSET + 0] = (CHAR16) ('0' + (Value / 100));
Value = (Value % 100);
gSetCursorPositionString[COLUMN_OFFSET + 1] = (CHAR16) ('0' + (Value / 10));
Value = (Value % 10);
gSetCursorPositionString[COLUMN_OFFSET + 2] = (CHAR16) ('0' + Value);
Status = OutputEscSquenceString (This, gSetCursorPositionString);
if (EFI_ERROR (Status)) {
return EFI_DEVICE_ERROR;
}
TerminalDevice->TerRow = Row;
TerminalDevice->TerCol = Column;
return EFI_SUCCESS;
}
/**
Scroll down screen buffer one line.
@param TerminalDevice Terminal device
**/
VOID
ScrollScreenBuffer (
IN TERMINAL_DEV *TerminalDevice
)
{
EFI_SIMPLE_TEXT_OUTPUT_MODE *Mode;
CHAR16 *ScrChar;
CHAR16 *TerChar;
UINT8 *ScrAttribute;
UINT8 *TerAttribute;
UINTN Column;
UINTN MaxColumn, MaxRow;
//
// Get current display mode and variable in private data
//
Mode = TerminalDevice->SimpleTextOutput.Mode;
TerminalDevice->SimpleTextOutput.QueryMode (
&(TerminalDevice->SimpleTextOutput),
Mode->Mode,
&MaxColumn,
&MaxRow
);
ScrChar = TerminalDevice->PtrScrChar;
ScrAttribute = TerminalDevice->PtrScrAttr;
TerChar = TerminalDevice->PtrTerChar;
TerAttribute = TerminalDevice->PtrTerAttr;
//
// Scroll Character and Character Buffer together
//
CopyMem (
ScrChar,
&(ScrChar[1 * MaxColumn]),
(MaxRow - 1) * MaxColumn * sizeof (CHAR16)
);
CopyMem (
TerChar,
&(TerChar[1 * MaxColumn]),
(MaxRow - 1) * MaxColumn * sizeof (CHAR16)
);
//
// Scroll Attribute and Attribute Buffer togeter
//
CopyMem (
ScrAttribute,
&(ScrAttribute[1 * MaxColumn]),
(MaxRow - 1) * MaxColumn * sizeof (UINT8)
);
CopyMem (
TerAttribute,
&(TerAttribute[1 * MaxColumn]),
(MaxRow - 1) * MaxColumn * sizeof (UINT8)
);
//
// Clear last new line
//
for (Column =0; Column < MaxColumn; Column ++) {
CopyMem (&ScrChar[(MaxRow - 1) * MaxColumn + Column], L" ", 2);
CopyMem (&TerChar[(MaxRow - 1) * MaxColumn + Column], L" ", 2);
}
CopyMem (
&ScrAttribute[(MaxRow - 1) * MaxColumn],
&ScrAttribute[(MaxRow - 2) * MaxColumn],
(MaxColumn * sizeof (UINT8))
);
CopyMem (
&TerAttribute[(MaxRow - 1) * MaxColumn],
&ScrAttribute[(MaxRow - 2) * MaxColumn],
(MaxColumn * sizeof (UINT8))
);
}
/**
Scroll down screen buffer one line.
@param This Indicates the calling context
**/
VOID
ScrollScreen (
IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This
)
{
EFI_SIMPLE_TEXT_OUTPUT_MODE *Mode;
UINTN MaxRow;
UINTN MaxColumn;
UINT8 *ScrAttribute;
UINT8 NewLinAttribute;
TERMINAL_DEV *TerminalDevice;
TerminalDevice = TERMINAL_CON_OUT_DEV_FROM_THIS (This);
//
// Get current display mode and variable in private data
//
Mode = TerminalDevice->SimpleTextOutput.Mode;
TerminalDevice->SimpleTextOutput.QueryMode (
&(TerminalDevice->SimpleTextOutput),
Mode->Mode,
&MaxColumn,
&MaxRow
);
//
// Make new line attribute
//
ScrAttribute = TerminalDevice->PtrScrAttr;
NewLinAttribute = (UINT8)This->Mode->Attribute;
//
// Send change line command to terminal and scroll buffer
//
PrivateSetAttribute (&(TerminalDevice->SimpleTextOutput), NewLinAttribute);
OutputEscSquenceString (&(TerminalDevice->SimpleTextOutput), gSetCursorToLastRowStr);
OutputEscSquenceString (&(TerminalDevice->SimpleTextOutput), gScrollDownStr);
PrivateSetCursorPosition (&(TerminalDevice->SimpleTextOutput), 0, (MaxRow - 1));
ScrollScreenBuffer (TerminalDevice);
return;
}
/**
Update screen character and attribute buffer.
@param TerminalDevice Terminal device
@param Column Coulumn to updated
@param Row Row to updated
**/
VOID
UpdateScreenDataAttriBuffer (
IN TERMINAL_DEV *TerminalDevice,
IN UINTN Column,
IN UINTN Row
)
{
EFI_SIMPLE_TEXT_OUTPUT_MODE *Mode;
CHAR16 *ScrChar;
CHAR16 *TerChar;
UINT8 *ScrAttribute;
UINT8 *TerAttribute;
UINTN MaxColumn;
UINTN MaxRow;
//
// Get current display mode
//
Mode = TerminalDevice->SimpleTextOutput.Mode;
TerminalDevice->SimpleTextOutput.QueryMode (
&(TerminalDevice->SimpleTextOutput),
Mode->Mode,
&MaxColumn,
&MaxRow
);
TerChar = TerminalDevice->PtrTerChar;
ScrChar = TerminalDevice->PtrScrChar;
ScrAttribute = TerminalDevice->PtrScrAttr;
TerAttribute = TerminalDevice->PtrTerAttr;
//
// Update screen character and attribute buffer
//
TerChar[Row * MaxColumn + Column] = ScrChar[Row * MaxColumn + Column];
TerAttribute[Row * MaxColumn + Column] = ScrAttribute[Row * MaxColumn + Column];
}
/**
Refreash choosed row to update terminal.
This function will calculate witch position need to update on terminal.
@param TerminalDevice Terminal device
@param Row Row to updated
@retval EFI_SUCCESS Success for update this ro.
@retval EFI_DEVICE_ERROR No anything need updated.
@retval EFI_UNSUPPORTED Skip first/last row.
**/
EFI_STATUS
RefreshScreenRow (
IN TERMINAL_DEV *TerminalDevice,
IN UINTN Row,
IN EFI_EVENT ConOutTimeOutEvent
)
{
EFI_SIMPLE_TEXT_OUTPUT_MODE *Mode;
CHAR16 *ScrChar;
CHAR16 *TerChar;
UINT8 *ScrAttribute;
UINT8 *TerAttribute;
UINT8 TempScrAttribute;
UINTN ColumnIndex;
UINTN MaxColumn, MaxRow;
CHAR16 Outchar[2];
UINTN ColUpdateTail;
UINTN ColUpdateHead;
BOOLEAN SkipFirstRow;
UINTN TerminalRow;
BOOLEAN UpdateIsSpace;
//
// Get current display mode and variable in private data
//
Mode = TerminalDevice->SimpleTextOutput.Mode;
TerminalDevice->SimpleTextOutput.QueryMode (
&(TerminalDevice->SimpleTextOutput),
Mode->Mode,
&MaxColumn,
&MaxRow
);
if (Row >= MaxRow) {
return EFI_INVALID_PARAMETER;
}
//
// Check 24 Row Policy
//
SkipFirstRow = FALSE;
if ((TerminalDevice->TerminalFeatureFlag & CR_TERMINAL_ROW_FLAG) == CR_TERMINAL_ROW_24 && \
(MaxColumn == 80) && (MaxRow == 25)) {
if ((TerminalDevice->TerminalFeatureFlag & CR_24ROWS_POLICY_FLAG) == CR_24ROWS_POLICY_DEL_FIRST) {
SkipFirstRow = TRUE;
if (Row == 0) {
//
// Skip First Row
//
return EFI_ABORTED;
}
} else {
if (Row == 24) {
//
// Skip Last Row
//
return EFI_ABORTED;
}
}
}
//
// Calculate needed changed character from head
//
ScrAttribute = TerminalDevice->PtrScrAttr + Row * MaxColumn;
TerAttribute = TerminalDevice->PtrTerAttr + Row * MaxColumn;
ScrChar = TerminalDevice->PtrScrChar + Row * MaxColumn;
TerChar = TerminalDevice->PtrTerChar + Row * MaxColumn;
ColUpdateHead = 0;
for (ColumnIndex = 0; ColumnIndex < MaxColumn; ColumnIndex ++) {
if (*TerAttribute != *ScrAttribute || \
*TerChar != *ScrChar) {
ColUpdateHead = ColumnIndex;
break;
}
ScrAttribute ++;
TerAttribute ++;
ScrChar ++;
TerChar ++;
}
//
// Check all the same?
//
if (ColumnIndex >= MaxColumn) {
return EFI_ALREADY_STARTED;
}
//
// Calculate needed changed character from tail
//
ScrAttribute = TerminalDevice->PtrScrAttr + Row * MaxColumn + (MaxColumn - 1);
TerAttribute = TerminalDevice->PtrTerAttr + Row * MaxColumn + (MaxColumn - 1);
ScrChar = TerminalDevice->PtrScrChar + Row * MaxColumn + (MaxColumn - 1);
TerChar = TerminalDevice->PtrTerChar + Row * MaxColumn + (MaxColumn - 1);
ColUpdateTail = MaxColumn;
for (ColumnIndex = MaxColumn; ColumnIndex != 0; ColumnIndex --) {
if (*TerAttribute != *ScrAttribute || \
*TerChar != *ScrChar) {
ColUpdateTail = ColumnIndex;
break;
}
ScrAttribute --;
TerAttribute --;
ScrChar --;
TerChar --;
}
//
// If need skip first row, offset row 2-24 up
//
if (SkipFirstRow) {
TerminalRow = Row - 1;
} else {
TerminalRow = Row;
}
//
// Check if all space word in updated region
//
ScrChar = TerminalDevice->PtrScrChar + Row * MaxColumn;
ScrAttribute = TerminalDevice->PtrScrAttr + Row * MaxColumn;
TempScrAttribute = *ScrAttribute;
UpdateIsSpace = TRUE;
for (ColumnIndex = 0; ColumnIndex < MaxColumn; ColumnIndex ++) {
if ((*ScrChar != 0x20) || (*ScrAttribute != TempScrAttribute)) {
UpdateIsSpace = FALSE;
break;
}
ScrChar ++;
ScrAttribute ++;
}
//
// Move cursor to current row
//
PrivateSetCursorPosition (&(TerminalDevice->SimpleTextOutput), ColUpdateHead, TerminalRow);
ScrAttribute = TerminalDevice->PtrScrAttr + Row * MaxColumn;
TerAttribute = TerminalDevice->PtrTerAttr + Row * MaxColumn;
ScrChar = TerminalDevice->PtrScrChar + Row * MaxColumn;
TerChar = TerminalDevice->PtrTerChar + Row * MaxColumn;
ScrAttribute += ColUpdateHead;
TerAttribute += ColUpdateHead;
ScrChar += ColUpdateHead;
TerChar += ColUpdateHead;
if (UpdateIsSpace) {
//
// Speed up if only need update space line, use ESC command
//
PrivateSetAttribute (&(TerminalDevice->SimpleTextOutput), (UINTN)*ScrAttribute);
OutputEscSquenceString (&(TerminalDevice->SimpleTextOutput), gEraseLine);
}
ZeroMem (Outchar, 2 * sizeof(CHAR16));
for (ColumnIndex = ColUpdateHead; ColumnIndex < ColUpdateTail; ColumnIndex ++) {
if (!UpdateIsSpace) {
PrivateSetAttribute (&(TerminalDevice->SimpleTextOutput), (UINTN)*ScrAttribute);
//
// Send character
//
Outchar[0] = *ScrChar;
PrivateOutputString (&(TerminalDevice->SimpleTextOutput), Outchar);
}
UpdateScreenDataAttriBuffer (TerminalDevice, ColumnIndex, Row);
if (*ScrAttribute & EFI_WIDE_ATTRIBUTE) {
ScrAttribute += 2;
TerAttribute += 2;
ScrChar += 2;
TerChar += 2;
} else {
ScrAttribute += 1;
TerAttribute += 1;
ScrChar += 1;
TerChar += 1;
}
}
return EFI_SUCCESS;
}
/**
Refreash Screen on Terminal Event Handler.
This routine will check terminal screen buffer to determine witch posiction
need to update character to terminal.
@param Event Event
@param Context Event Context Pointer
**/
VOID
RefreshScreenRoutine (
IN EFI_EVENT Event,
IN VOID *Context
)
{
TERMINAL_DEV *TerminalDevice;
EFI_SIMPLE_TEXT_OUTPUT_MODE *Mode;
UINTN Row;
UINTN MaxColumn, MaxRow;
UINT32 SerialControl;
CHAR16 *ScrChar;
CHAR16 *TerChar;
UINT8 *ScrAttribute;
UINT8 *TerAttribute;
UINTN LastRow;
#ifdef EFI_DEBUG
UINT32 OutputAttribute;
#endif
UINTN FirstRow;
EFI_STATUS RefreshStatus;
EFI_STATUS Status;
EFI_EVENT ConOutTimeOutEvent;
EFI_STATUS TimerStatus;
BOOLEAN NoAnyUpdate;
#ifndef EFI_DEBUG
UINTN TermCursorRow;
#endif
TerminalDevice = (TERMINAL_DEV *)Context;
ConOutTimeOutEvent = NULL;
//
// Avoid send ESC command be interrupt
//
if (gEscProcess) {
goto FinishRoutine;
}
//
// Check serial mode is not in loop back mode
//
TerminalDevice->SerialIo->GetControl (TerminalDevice->SerialIo, &SerialControl);
if (SerialControl & (EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE | EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE)) {
return;
}
//
// Start Timeout Timer
//
Status = gBS->CreateEvent (EVT_TIMER, TPL_CALLBACK, NULL, NULL, &ConOutTimeOutEvent);
if (EFI_ERROR (Status)) {
return;
}
gBS->SetTimer(ConOutTimeOutEvent, TimerRelative, REFRESH_ROUTING_TIMEOUT);
TerChar = TerminalDevice->PtrTerChar;
ScrChar = TerminalDevice->PtrScrChar;
ScrAttribute = TerminalDevice->PtrScrAttr;
TerAttribute = TerminalDevice->PtrTerAttr;
LastRow = TerminalDevice->LastRow;
//
// Get current display mode and buffer point
//
Mode = TerminalDevice->SimpleTextOutput.Mode;
TerminalDevice->SimpleTextOutput.QueryMode (
&(TerminalDevice->SimpleTextOutput),
Mode->Mode,
&MaxColumn,
&MaxRow
);
//
// Check 24 Row Policy
//
FirstRow = 0;
if ((TerminalDevice->TerminalFeatureFlag & CR_TERMINAL_ROW_FLAG) == CR_TERMINAL_ROW_24) {
if ((TerminalDevice->TerminalFeatureFlag & CR_24ROWS_POLICY_FLAG) == CR_24ROWS_POLICY_DEL_FIRST) {
FirstRow = 1;
} else {
FirstRow = 0;
MaxRow = MaxRow - 1;
}
}
NoAnyUpdate = TRUE;
RefreshStatus = EFI_SUCCESS;
for (Row =FirstRow; Row < MaxRow; Row ++) {
RefreshStatus = RefreshScreenRow (TerminalDevice, LastRow, ConOutTimeOutEvent);
//
// Check if anything need update?
//
if (RefreshStatus == EFI_SUCCESS) {
NoAnyUpdate = FALSE;
}
//
// Check is it Timeout?
//
TimerStatus = gBS->CheckEvent (ConOutTimeOutEvent);
if (!EFI_ERROR (TimerStatus)) {
break;
}
LastRow ++;
if (LastRow >= MaxRow) {
LastRow = 0;
}
}
TerminalDevice->LastRow = LastRow;
//
// If there is debug message, always move cursor to left-top to avoid screen disturbance
//
#ifdef EFI_DEBUG
//
// Restore default attribute (Foreground: White Background: Black)
//
OutputAttribute = 0;
OutputAttribute = (EFI_BLACK << 4) | EFI_LIGHTGRAY;
PrivateSetAttribute (&(TerminalDevice->SimpleTextOutput), OutputAttribute);
//
// Restore cursor to left top
//
PrivateSetCursorPosition (&(TerminalDevice->SimpleTextOutput), 0, 0);
#else
//
// If in 24 row without first line, adjust row number of cursor
//
TermCursorRow = Mode->CursorRow;
if ((TerminalDevice->TerminalFeatureFlag & CR_TERMINAL_ROW_FLAG) == CR_TERMINAL_ROW_24 && \
(MaxColumn == 80) && (MaxRow == 25)) {
if ((TerminalDevice->TerminalFeatureFlag & CR_24ROWS_POLICY_FLAG) == CR_24ROWS_POLICY_DEL_FIRST) {
TermCursorRow = Mode->CursorRow - 1;
}
}
//
// Move cursor to current position if nothong need update
//
if (NoAnyUpdate) {
PrivateSetCursorPosition (
&(TerminalDevice->SimpleTextOutput),
Mode->CursorColumn, // Column,
TermCursorRow // Row
);
}
#endif
FinishRoutine:
TriggerNextTermEvent (Context);
if (ConOutTimeOutEvent != NULL) {
gBS->CloseEvent (ConOutTimeOutEvent);
}
return;
}
/**
Free pool buffer safely.
@param Buffer Point to the specific buffer that want to free.
**/
VOID
SafeFreePool (
IN VOID *Buffer
)
{
if (Buffer != NULL) {
gBS->FreePool (Buffer);
}
}
/**
Initialize used screen buffer.
@param TerminalDevice Terminal device
**/
VOID
InitializeScreenBuffer (
IN TERMINAL_DEV *TerminalDevice
)
{
UINTN MaxResolution, Resolution;
UINTN Index;
UINTN MaxMode;
//
// Find the maximum supported screen resolution
//
MaxResolution = TerminalDevice->TerminalConsoleModeData[0].Columns * TerminalDevice->TerminalConsoleModeData[0].Rows;
MaxMode = TerminalDevice->SimpleTextOutputMode.MaxMode;
for (Index = 1; Index < MaxMode; Index ++) {
Resolution = TerminalDevice->TerminalConsoleModeData[Index].Columns * TerminalDevice->TerminalConsoleModeData[Index].Rows;
if (MaxResolution < Resolution) {
MaxResolution = Resolution;
}
}
//
// Allocate Buffers
//
TerminalDevice->PtrScrChar = AllocateZeroPool (MaxResolution * sizeof (CHAR16));
TerminalDevice->PtrTerChar = AllocateZeroPool (MaxResolution * sizeof (CHAR16));
TerminalDevice->PtrScrAttr = AllocateZeroPool (MaxResolution * sizeof (UINT8));
TerminalDevice->PtrTerAttr = AllocateZeroPool (MaxResolution * sizeof (UINT8));
}
/**
Remove Menu option list.
@param RefreshEvent The specific event to removed from refresh even lsit.
**/
VOID
RemoveRefreshEventList (
IN EFI_EVENT RefreshEvent
)
{
TERMINAL_REFRESH_EVENT_LIST *TermEventList;
LIST_ENTRY *Link;
for (Link = mTermEventLists.ForwardLink; Link != &mTermEventLists; Link = Link->ForwardLink) {
TermEventList = CR (Link, TERMINAL_REFRESH_EVENT_LIST, Link, TERM_REFRESH_EVENT_LIST_SIGNATURE);
if (TermEventList->RefreshEvent == RefreshEvent) {
RemoveEntryList (&TermEventList->Link);
gBS->FreePool (TermEventList);
break;
}
}
}
/**
The function to close refresh screen event.
@param TerminalDevice Terminal device
**/
VOID
CloseRefreshScreenRoutine (
IN TERMINAL_DEV *TerminalDevice
)
{
TERMINAL_REFRESH_EVENT_LIST *TermEventList;
VOID *Context = NULL;
TermEventList = CR (mCurrentTermEvent, TERMINAL_REFRESH_EVENT_LIST, Link, TERM_REFRESH_EVENT_LIST_SIGNATURE);
if (TermEventList->RefreshEvent == TerminalDevice->EventRefreshScreen) {
TriggerNextTermEvent (Context);
}
//
// Close Event then remove from Link List
//
RemoveRefreshEventList (TerminalDevice->EventRefreshScreen);
if (TerminalDevice->EventRefreshScreen != NULL) {
DEBUG ((EFI_D_INFO | EFI_D_LOAD, "\nClose RefreshScreenRoutine !!!\n"));
gBS->CloseEvent (TerminalDevice->EventRefreshScreen);
TerminalDevice->EventRefreshScreen = NULL;
}
//
// Free Allocated Buffers
//
SafeFreePool(TerminalDevice->PtrScrChar);
SafeFreePool(TerminalDevice->PtrTerChar);
SafeFreePool(TerminalDevice->PtrScrAttr);
SafeFreePool(TerminalDevice->PtrTerAttr);
return;
}
/**
The function to close refresh screen event.
@param TerminalDevice Terminal device
**/
VOID
AddRefreshEventList (
IN EFI_EVENT RefreshEvent,
IN UINTN TerminalCount
)
{
TERMINAL_REFRESH_EVENT_LIST *TermEventListEntry;
TermEventListEntry = AllocateZeroPool (sizeof (TERMINAL_REFRESH_EVENT_LIST));
if (TermEventListEntry != NULL) {
TermEventListEntry->Signature = TERM_REFRESH_EVENT_LIST_SIGNATURE;
TermEventListEntry->RefreshEvent = RefreshEvent;
InsertTailList (&mTermEventLists, &TermEventListEntry->Link);
if (TerminalCount == 1) {
mCurrentTermEvent = &TermEventListEntry->Link;
}
}
}
/**
Initialize terminal refresh screen event list.
**/
VOID
InitRefreshEventList (
VOID
)
{
InitializeListHead (&mTermEventLists);
}
/**
The function to trigger next terminal refresh screen event.
@param Context the context of event
**/
VOID
TriggerNextTermEvent (
IN VOID *Context
)
{
TERMINAL_REFRESH_EVENT_LIST *TermEventList;
if (!IsListEmpty (&mTermEventLists)) {
mCurrentTermEvent = mCurrentTermEvent->ForwardLink;
if (mCurrentTermEvent == &mTermEventLists) {
mCurrentTermEvent = mTermEventLists.ForwardLink;
}
if (mCurrentTermEvent != NULL) {
TermEventList = CR (mCurrentTermEvent, TERMINAL_REFRESH_EVENT_LIST, Link, TERM_REFRESH_EVENT_LIST_SIGNATURE);
if (TermEventList->RefreshEvent != NULL) {
gBS->SetTimer (TermEventList->RefreshEvent, TimerRelative, REFRESH_ROUTING_INTERVAL);
}
}
}
}
/**
Create Timer event to refresh terminal screen.
@param TerminalDevice Terminal device
@param TerminalCount The number of terminal device in refresh screen list
@retval EFI_SUCCESS Refresh screen event initial success.
@retval Others event intial fail.
**/
EFI_STATUS
InitialRefreshScreenRoutine (
IN TERMINAL_DEV *TerminalDevice,
IN UINTN TerminalCount
)
{
EFI_STATUS Status;
TerminalDevice->LastRow = 0;
InitializeScreenBuffer (TerminalDevice);
Status = gBS->CreateEvent (
EVT_TIMER | EVT_NOTIFY_SIGNAL,
TPL_CALLBACK,
RefreshScreenRoutine,
TerminalDevice,
&(TerminalDevice->EventRefreshScreen)
);
if (!EFI_ERROR(Status)) {
AddRefreshEventList (TerminalDevice->EventRefreshScreen, TerminalCount);
}
return Status;
}
/**
Monitor remote terminal was exist or not event handler.
@param Event The event callback of monitor remote terminal routine
@param Context The event context
**/
VOID
MonitorRemoteTermRoutine (
IN EFI_EVENT Event,
IN VOID *Context
)
{
EFI_SERIAL_IO_PROTOCOL *SerialIo;
TERMINAL_DEV *TerminalDevice;
EFI_STATUS Status;
TerminalDevice = (TERMINAL_DEV *)Context;
SerialIo = TerminalDevice->SerialIo;
//
// Depend on remote terminal status to set next time monitor event.
//
if (TerminalDevice->RemoteTermExist) {
//
//If romote terminal exist, set next event occur in next 30 secs.
//
Status = gBS->SetTimer (TerminalDevice->EventAutoRefresh, TimerRelative, (30000 * TICKS_PER_MS));
TerminalDevice->LastRemoteTermStatus = TRUE;
} else {
//
//If romote terminal exist, set next event occur in next 5 secs.
//
Status = gBS->SetTimer (TerminalDevice->EventAutoRefresh, TimerRelative, (5000 * TICKS_PER_MS));
TerminalDevice->LastRemoteTermStatus = FALSE;
}
//
// Write get device status esc sequence code
//
OutputEscSquenceString (&TerminalDevice->SimpleTextOutput, gGetTermStatusString);
//
// Set remote Terminal status as not exist as default.
//
TerminalDevice->RemoteTermExist = FALSE;
}
/**
Create Timer event to monitor remote termial.
@param TerminalDevice Terminal Device
@retval EFI_SUCCESS monitor remote terminal event initial success.
@retval Others event intial fail.
**/
EFI_STATUS
InitialAutoRefreshRoutine (
IN TERMINAL_DEV *TerminalDevice
)
{
EFI_STATUS Status;
//
// Create Timer event to monitor remote termial
//
Status = gBS->CreateEvent (
EVT_TIMER | EVT_NOTIFY_SIGNAL,
TPL_CALLBACK,
MonitorRemoteTermRoutine,
TerminalDevice,
&(TerminalDevice->EventAutoRefresh)
);
if (!EFI_ERROR(Status)) {
//
// Set next event occur in next 5 secs.
//
Status = gBS->SetTimer (TerminalDevice->EventAutoRefresh, TimerRelative, (5000 * TICKS_PER_MS));
}
TerminalDevice->RemoteTermExist = FALSE;
TerminalDevice->LastRemoteTermStatus = FALSE;
return Status;
}
/**
Close monitor remote termial timer event.
@param TerminalDevice Terminal Device
**/
VOID
CloseAutoRefreshRoutine (
IN TERMINAL_DEV *TerminalDevice
)
{
if (TerminalDevice->EventAutoRefresh != NULL) {
gBS->CloseEvent (TerminalDevice->EventAutoRefresh);
}
return;
}
/**
This function will clean up terminal's Char and Attribute buffer.
@param TerminalDevice Terminal Device
**/
VOID
ClearTermCharAndAttriBuffer (
IN TERMINAL_DEV *TerminalDevice
)
{
CHAR16 *TerChar;
UINT8 *TerAttr;
UINTN MaxResolution;
UINTN Resolution;
UINTN Index;
UINTN MaxMode;
TerChar = TerminalDevice->PtrTerChar;
TerAttr = TerminalDevice->PtrTerAttr;
//
// Find the maximum supported screen resolution
//
MaxResolution = TerminalDevice->TerminalConsoleModeData[0].Columns * TerminalDevice->TerminalConsoleModeData[0].Rows;
MaxMode = TerminalDevice->SimpleTextOutputMode.MaxMode;
for (Index = 1; Index < MaxMode; Index ++) {
Resolution = TerminalDevice->TerminalConsoleModeData[Index].Columns * TerminalDevice->TerminalConsoleModeData[Index].Rows;
if (MaxResolution < Resolution) {
MaxResolution = Resolution;
}
}
//
// Clear terminal screen and attribute buffer
//
SetMem (TerChar, (MaxResolution * sizeof (CHAR16)), 0);
SetMem (TerAttr, (MaxResolution * sizeof (UINT8)), 0);
}
/**
Implements EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.Reset().
If ExtendeVerification is TRUE, then perform dependent serial device reset,
and set display mode to mode 0.
If ExtendedVerification is FALSE, only set display mode to mode 0.
@param This Indicates the calling context.
@param ExtendedVerification Indicates that the driver may perform a more
exhaustive verification operation of the device
during reset.
@retval EFI_SUCCESS The reset operation succeeds.
@retval EFI_DEVICE_ERROR The terminal is not functioning correctly or the serial port reset fails.
**/
EFI_STATUS
EFIAPI
AsyncTerminalConOutReset (
IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
IN BOOLEAN ExtendedVerification
)
{
EFI_STATUS Status;
TERMINAL_DEV *TerminalDevice;
TerminalDevice = TERMINAL_CON_OUT_DEV_FROM_THIS (This);
//
// Reset Terminal, Send out "<ESC>c"
//
OutputEscSquenceString (This, gResetDeviceString);
//
// Disable Auto Wrap mode, Send out "ESC [ ? 7 l"
//
OutputEscSquenceString (This, gDiableAutoWrapString);
//
// Perform a more exhaustive reset by resetting the serial port.
//
if (ExtendedVerification) {
//
// Report progress code here
//
REPORT_STATUS_CODE_WITH_DEVICE_PATH (
EFI_PROGRESS_CODE,
(EFI_PERIPHERAL_REMOTE_CONSOLE | EFI_P_PC_RESET),
TerminalDevice->DevicePath
);
Status = TerminalDevice->SerialIo->Reset (TerminalDevice->SerialIo);
if (EFI_ERROR (Status)) {
//
// Report error code here
//
REPORT_STATUS_CODE_WITH_DEVICE_PATH (
EFI_ERROR_CODE | EFI_ERROR_MINOR,
(EFI_PERIPHERAL_REMOTE_CONSOLE | EFI_P_EC_CONTROLLER_ERROR),
TerminalDevice->DevicePath
);
return Status;
}
}
This->SetAttribute (This, EFI_TEXT_ATTR (This->Mode->Attribute & 0x0F, EFI_BLACK));
Vt100PlusSwitchCharSet (This, VT100_ASCII_CHAR_SET);
Status = This->SetMode (This, 0);
return Status;
}
/**
Implements EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.OutputString().
The Unicode string will be converted to terminal expressible data stream
and send to terminal via serial port.
@param This Indicates the calling context.
@param WString The Null-terminated Unicode string to be displayed
on the terminal screen.
@retval EFI_SUCCESS The string is output successfully.
@retval EFI_DEVICE_ERROR The serial port fails to send the string out.
@retval EFI_WARN_UNKNOWN_GLYPH Indicates that some of the characters in the Unicode string could not
be rendered and are skipped.
@retval EFI_UNSUPPORTED If current display mode is out of range.
**/
EFI_STATUS
EFIAPI
AsyncTerminalConOutOutputString (
IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
IN CHAR16 *WString
)
{
TERMINAL_DEV *TerminalDevice;
EFI_SIMPLE_TEXT_OUTPUT_MODE *Mode;
UINTN MaxColumn;
UINTN MaxRow;
CHAR16 *ScrChar;
UINT8 *AttrBuffer;
CHAR16 Unicode;
UINT32 GlyphWidth;
INT32 AtributeSetting;
//
// get Terminal device data structure pointer.
//
TerminalDevice = TERMINAL_CON_OUT_DEV_FROM_THIS (This);
//
// Get current display mode
//
Mode = This->Mode;
This->QueryMode (
This,
Mode->Mode,
&MaxColumn,
&MaxRow
);
ScrChar = TerminalDevice->PtrScrChar;
AttrBuffer = TerminalDevice->PtrScrAttr;
GlyphWidth = 0;
for (; *WString != CHAR_NULL; WString++) {
AtributeSetting = Mode->Attribute;
//
// Update screen RAW data buffer
//
switch (*WString) {
case CHAR_BACKSPACE:
if (Mode->CursorColumn > 0) {
Mode->CursorColumn--;
}
else if ( Mode->CursorColumn == 0 && Mode->CursorRow > 0) {
Mode->CursorRow--;
Mode->CursorColumn = (INT32) MaxColumn - 1;
}
break;
case CHAR_LINEFEED:
if (Mode->CursorRow < (INT32) (MaxRow - 1)) {
Mode->CursorRow++;
}
else {
ScrollScreen (This);
}
break;
case CHAR_CARRIAGE_RETURN:
Mode->CursorColumn = 0;
break;
case WIDE_CHAR:
AtributeSetting |= EFI_WIDE_ATTRIBUTE;
break;
case NARROW_CHAR:
AtributeSetting &= (~ (UINT32) EFI_WIDE_ATTRIBUTE);
break;
default:
Unicode = *WString;
GlyphWidth = 1;
//
// Only UTF8 support Wide Character,
// Translate Wide Character Unicode and calculate glyph width
//
if (TerminalDevice->TerminalType == VTUTF8TYPE) {
if (AtributeSetting & EFI_WIDE_ATTRIBUTE) {
WideUnicode (Unicode, &Unicode);
GlyphWidth = 2;
} else {
//
// If current attribute is narrow, still check if this chatacter belongs to wide glyph or not.
//
GlyphWidth = ConsoleLibGetGlyphWidth (*WString);
if (GlyphWidth >= 2) {
AtributeSetting |= EFI_WIDE_ATTRIBUTE;
}
}
}
ScrChar[(Mode->CursorRow * MaxColumn) + Mode->CursorColumn] = Unicode;
//
// Update screen attribute buffer
//
AttrBuffer[(Mode->CursorRow * MaxColumn) + Mode->CursorColumn] = (UINT8) AtributeSetting;
if (Mode->CursorColumn < (INT32) (MaxColumn - 1)) {
//
// move to next column
//
Mode->CursorColumn += GlyphWidth;
if (Mode->CursorColumn > (INT32)(MaxColumn - 1)) {
//
// For avoid over column
//
Mode->CursorColumn = (INT32) MaxColumn - 1;
}
} else {
//
// move to next row
//
Mode->CursorColumn = 0;
if (Mode->CursorRow < (INT32) (MaxRow - 1)) {
Mode->CursorRow++;
}
else {
ScrollScreen (This);
}
}
break;
};
}
return EFI_SUCCESS;
}
/**
Implements EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.TestString().
If one of the characters in the *Wstring is neither valid Unicode drawing characters,
not ASCII code, then this function will return EFI_UNSUPPORTED.
@param This Indicates the calling context.
@param WString The Null-terminated Unicode string to be tested.
@retval EFI_SUCCESS The terminal is capable of rendering the output string.
@retval EFI_UNSUPPORTED Some of the characters in the Unicode string cannot be rendered.
**/
EFI_STATUS
EFIAPI
AsyncTerminalConOutTestString (
IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
IN CHAR16 *WString
)
{
TERMINAL_DEV *TerminalDevice;
EFI_STATUS Status;
//
// get Terminal device data structure pointer.
//
TerminalDevice = TERMINAL_CON_OUT_DEV_FROM_THIS (This);
switch (TerminalDevice->TerminalType) {
case PCANSITYPE:
case VT100TYPE:
case VT100PLUSTYPE:
case LOGTERMTYPE:
Status = AnsiTestString (TerminalDevice, WString);
break;
case VTUTF8TYPE:
Status = VTUTF8TestString (TerminalDevice, WString);
break;
default:
Status = EFI_UNSUPPORTED;
break;
}
return Status;
}
/**
Implements EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.QueryMode().
It returns information for an available text mode
that the terminal supports.
@param This Indicates the calling context.
@param ModeNumber The mode number to return information on.
@param Columns The returned columns of the requested mode.
@param Rows The returned rows of the requested mode.
@retval EFI_SUCCESS The requested mode information is returned.
@retval EFI_UNSUPPORTED The mode number is not valid.
**/
EFI_STATUS
EFIAPI
AsyncTerminalConOutQueryMode (
IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
IN UINTN ModeNumber,
OUT UINTN *Columns,
OUT UINTN *Rows
)
{
TERMINAL_DEV *TerminalDevice;
//
// Get Terminal device data structure pointer.
//
TerminalDevice = TERMINAL_CON_OUT_DEV_FROM_THIS (This);
if (ModeNumber >= (UINTN) TerminalDevice->SimpleTextOutputMode.MaxMode) {
return EFI_UNSUPPORTED;
}
//
// Get Terminal device data structure pointer.
//
*Columns = TerminalDevice->TerminalConsoleModeData[ModeNumber].Columns;
*Rows = TerminalDevice->TerminalConsoleModeData[ModeNumber].Rows;
return EFI_SUCCESS;
}
/**
Implements EFI_SIMPLE_TEXT_OUT.SetMode().
Set the terminal to a specified display mode. In this driver, we only support mode 0.
@param This Indicates the calling context.
@param ModeNumber The text mode to set.
@retval EFI_SUCCESS The requested text mode is set.
@retval EFI_DEVICE_ERROR The requested text mode cannot be set
because of serial device error.
@retval EFI_UNSUPPORTED The text mode number is not valid.
**/
EFI_STATUS
EFIAPI
AsyncTerminalConOutSetMode (
IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
IN UINTN ModeNumber
)
{
EFI_STATUS Status;
TERMINAL_DEV *TerminalDevice;
//
// get Terminal device data structure pointer.
//
TerminalDevice = TERMINAL_CON_OUT_DEV_FROM_THIS (This);
if (ModeNumber >= (UINTN) (TerminalDevice->SimpleTextOutputMode.MaxMode)) {
return EFI_UNSUPPORTED;
}
//
// Set the current mode
//
This->Mode->Mode = (INT32) ModeNumber;
This->ClearScreen (This);
Status = AdjustTerminalResolution (This, ModeNumber);
if (EFI_ERROR (Status)) {
return EFI_DEVICE_ERROR;
}
This->Mode->Mode = (INT32) ModeNumber;
Status = This->ClearScreen (This);
if (EFI_ERROR (Status)) {
return EFI_DEVICE_ERROR;
}
return EFI_SUCCESS;
}
/**
Implements EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.SetAttribute().
@param This Indicates the calling context.
@param Attribute The attribute to set. Only bit0..6 are valid, all other bits
are undefined and must be zero.
@retval EFI_SUCCESS The requested attribute is set.
@retval EFI_DEVICE_ERROR The requested attribute cannot be set due to serial port error.
@retval EFI_UNSUPPORTED The attribute requested is not defined by EFI spec.
**/
EFI_STATUS
EFIAPI
AsyncTerminalConOutSetAttribute (
IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
IN UINTN Attribute
)
{
TERMINAL_DEV *TerminalDevice;
//
// get Terminal device data structure pointer.
//
TerminalDevice = TERMINAL_CON_OUT_DEV_FROM_THIS (This);
if ((Attribute | 0xFF) != 0xFF) {
return EFI_UNSUPPORTED;
}
This->Mode->Attribute = (INT32) Attribute;
return EFI_SUCCESS;
}
/**
Implements EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.ClearScreen().
It clears the ANSI terminal's display to the currently selected background color.
@param This Indicates the calling context.
@retval EFI_SUCCESS The operation completed successfully.
@retval EFI_DEVICE_ERROR The terminal screen cannot be cleared due to serial port error.
@retval EFI_UNSUPPORTED The terminal is not in a valid display mode.
**/
EFI_STATUS
EFIAPI
AsyncTerminalConOutClearScreen (
IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This
)
{
EFI_STATUS Status;
TERMINAL_DEV *TerminalDevice;
EFI_SIMPLE_TEXT_OUTPUT_MODE *Mode;
UINTN MaxColumn;
UINTN MaxRow;
UINTN BufferSize;
CHAR16 *ScrChar;
CHAR16 *TerChar;
UINTN Row, Column;
UINTN MaxResolution;
UINTN Resolution;
UINTN Index;
UINTN MaxMode;
UINT32 OutputAttribute;
TerminalDevice = TERMINAL_CON_OUT_DEV_FROM_THIS (This);
Mode = This->Mode;
This->QueryMode (
This,
Mode->Mode,
&MaxColumn,
&MaxRow
);
ScrChar = TerminalDevice->PtrScrChar;
TerChar = TerminalDevice->PtrTerChar;
OutputAttribute = 0;
//
// Restore default attribute (Foreground: White Background: Black)
//
OutputAttribute = Mode->Attribute;
PrivateSetAttribute (&(TerminalDevice->SimpleTextOutput), OutputAttribute);
//
// Erases the screen with the background colour and moves the cursor to home.
//
Status = OutputEscSquenceString (This, gClearScreenString);
//
// Find the maximum supported screen resolution
//
MaxResolution = TerminalDevice->TerminalConsoleModeData[0].Columns * TerminalDevice->TerminalConsoleModeData[0].Rows;
MaxMode = TerminalDevice->SimpleTextOutputMode.MaxMode;
for (Index = 1; Index < MaxMode; Index ++) {
Resolution = TerminalDevice->TerminalConsoleModeData[Index].Columns * TerminalDevice->TerminalConsoleModeData[Index].Rows;
if (MaxResolution < Resolution) {
MaxResolution = Resolution;
}
}
//
// Clear screen buffer and terminal buffer
//
for (Row = 0; Row < MaxRow; Row ++) {
for (Column = 0; Column < MaxColumn; Column ++) {
CopyMem (&(ScrChar[Row * MaxColumn + Column]), L" ", 2);
CopyMem (&(TerChar[Row * MaxColumn + Column]), L" ", 2);
}
}
BufferSize = MaxResolution * sizeof (UINT8);
SetMem (TerminalDevice->PtrScrAttr, BufferSize, EFI_LIGHTGRAY | EFI_BACKGROUND_BLACK);
SetMem (TerminalDevice->PtrTerAttr, BufferSize, EFI_LIGHTGRAY | EFI_BACKGROUND_BLACK);
//
// Status = This->SetCursorPosition (This, 0, 0);
//
Mode->CursorRow = 0;
Mode->CursorColumn = 0;
return Status;
}
/**
Implements EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.SetCursorPosition().
@param This Indicates the calling context.
@param Column The row to set cursor to.
@param Row The column to set cursor to.
@retval EFI_SUCCESS The operation completed successfully.
@retval EFI_DEVICE_ERROR The request fails due to serial port error.
@retval EFI_UNSUPPORTED The terminal is not in a valid text mode, or the cursor position
is invalid for current mode.
**/
EFI_STATUS
EFIAPI
AsyncTerminalConOutSetCursorPosition (
IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
IN UINTN Column,
IN UINTN Row
)
{
EFI_SIMPLE_TEXT_OUTPUT_MODE *Mode;
UINTN MaxColumn;
UINTN MaxRow;
EFI_STATUS Status;
TERMINAL_DEV *TerminalDevice;
TerminalDevice = TERMINAL_CON_OUT_DEV_FROM_THIS (This);
//
// get current mode
//
Mode = This->Mode;
//
// get geometry of current mode
//
Status = This->QueryMode (
This,
Mode->Mode,
&MaxColumn,
&MaxRow
);
if (EFI_ERROR (Status)) {
return EFI_UNSUPPORTED;
}
if (Column >= MaxColumn || Row >= MaxRow) {
return EFI_UNSUPPORTED;
}
//
// update current cursor position
// in the Mode data structure.
//
Mode->CursorColumn = (INT32) Column;
Mode->CursorRow = (INT32) Row;
return EFI_SUCCESS;
}
/**
Implements SIMPLE_TEXT_OUTPUT.EnableCursor().
In this driver, the cursor cannot be hidden.
@param This Indicates the calling context.
@param Visible If TRUE, the cursor is set to be visible,
If FALSE, the cursor is set to be invisible.
@retval EFI_SUCCESS The request is valid.
@retval EFI_UNSUPPORTED The terminal does not support cursor hidden.
**/
EFI_STATUS
EFIAPI
AsyncTerminalConOutEnableCursor (
IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
IN BOOLEAN Visible
)
{
if (!Visible) {
return EFI_UNSUPPORTED;
}
return EFI_SUCCESS;
}