/** @file | |
Implementation for EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL protocol. | |
Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR> | |
Copyright (C) 2016 Silicon Graphics, Inc. All rights reserved.<BR> | |
SPDX-License-Identifier: BSD-2-Clause-Patent | |
**/ | |
#include "Terminal.h" | |
// | |
// This list is used to define the valid extend chars. | |
// It also provides a mapping from Unicode to PCANSI or | |
// ASCII. The ASCII mapping we just made up. | |
// | |
// | |
UNICODE_TO_CHAR UnicodeToPcAnsiOrAscii[] = { | |
{ BOXDRAW_HORIZONTAL, 0xc4, L'-' }, | |
{ BOXDRAW_VERTICAL, 0xb3, L'|' }, | |
{ BOXDRAW_DOWN_RIGHT, 0xda, L'/' }, | |
{ BOXDRAW_DOWN_LEFT, 0xbf, L'\\' }, | |
{ BOXDRAW_UP_RIGHT, 0xc0, L'\\' }, | |
{ BOXDRAW_UP_LEFT, 0xd9, L'/' }, | |
{ BOXDRAW_VERTICAL_RIGHT, 0xc3, L'|' }, | |
{ BOXDRAW_VERTICAL_LEFT, 0xb4, L'|' }, | |
{ BOXDRAW_DOWN_HORIZONTAL, 0xc2, L'+' }, | |
{ BOXDRAW_UP_HORIZONTAL, 0xc1, L'+' }, | |
{ BOXDRAW_VERTICAL_HORIZONTAL, 0xc5, L'+' }, | |
{ BOXDRAW_DOUBLE_HORIZONTAL, 0xcd, L'-' }, | |
{ BOXDRAW_DOUBLE_VERTICAL, 0xba, L'|' }, | |
{ BOXDRAW_DOWN_RIGHT_DOUBLE, 0xd5, L'/' }, | |
{ BOXDRAW_DOWN_DOUBLE_RIGHT, 0xd6, L'/' }, | |
{ BOXDRAW_DOUBLE_DOWN_RIGHT, 0xc9, L'/' }, | |
{ BOXDRAW_DOWN_LEFT_DOUBLE, 0xb8, L'\\' }, | |
{ BOXDRAW_DOWN_DOUBLE_LEFT, 0xb7, L'\\' }, | |
{ BOXDRAW_DOUBLE_DOWN_LEFT, 0xbb, L'\\' }, | |
{ BOXDRAW_UP_RIGHT_DOUBLE, 0xd4, L'\\' }, | |
{ BOXDRAW_UP_DOUBLE_RIGHT, 0xd3, L'\\' }, | |
{ BOXDRAW_DOUBLE_UP_RIGHT, 0xc8, L'\\' }, | |
{ BOXDRAW_UP_LEFT_DOUBLE, 0xbe, L'/' }, | |
{ BOXDRAW_UP_DOUBLE_LEFT, 0xbd, L'/' }, | |
{ BOXDRAW_DOUBLE_UP_LEFT, 0xbc, L'/' }, | |
{ BOXDRAW_VERTICAL_RIGHT_DOUBLE, 0xc6, L'|' }, | |
{ BOXDRAW_VERTICAL_DOUBLE_RIGHT, 0xc7, L'|' }, | |
{ BOXDRAW_DOUBLE_VERTICAL_RIGHT, 0xcc, L'|' }, | |
{ BOXDRAW_VERTICAL_LEFT_DOUBLE, 0xb5, L'|' }, | |
{ BOXDRAW_VERTICAL_DOUBLE_LEFT, 0xb6, L'|' }, | |
{ BOXDRAW_DOUBLE_VERTICAL_LEFT, 0xb9, L'|' }, | |
{ BOXDRAW_DOWN_HORIZONTAL_DOUBLE, 0xd1, L'+' }, | |
{ BOXDRAW_DOWN_DOUBLE_HORIZONTAL, 0xd2, L'+' }, | |
{ BOXDRAW_DOUBLE_DOWN_HORIZONTAL, 0xcb, L'+' }, | |
{ BOXDRAW_UP_HORIZONTAL_DOUBLE, 0xcf, L'+' }, | |
{ BOXDRAW_UP_DOUBLE_HORIZONTAL, 0xd0, L'+' }, | |
{ BOXDRAW_DOUBLE_UP_HORIZONTAL, 0xca, L'+' }, | |
{ BOXDRAW_VERTICAL_HORIZONTAL_DOUBLE, 0xd8, L'+' }, | |
{ BOXDRAW_VERTICAL_DOUBLE_HORIZONTAL, 0xd7, L'+' }, | |
{ BOXDRAW_DOUBLE_VERTICAL_HORIZONTAL, 0xce, L'+' }, | |
{ BLOCKELEMENT_FULL_BLOCK, 0xdb, L'*' }, | |
{ BLOCKELEMENT_LIGHT_SHADE, 0xb0, L'+' }, | |
{ GEOMETRICSHAPE_UP_TRIANGLE, '^', L'^' }, | |
{ GEOMETRICSHAPE_RIGHT_TRIANGLE, '>', L'>' }, | |
{ GEOMETRICSHAPE_DOWN_TRIANGLE, 'v', L'v' }, | |
{ GEOMETRICSHAPE_LEFT_TRIANGLE, '<', L'<' }, | |
{ ARROW_LEFT, '<', L'<' }, | |
{ ARROW_UP, '^', L'^' }, | |
{ ARROW_RIGHT, '>', L'>' }, | |
{ ARROW_DOWN, 'v', L'v' }, | |
{ 0x0000, 0x00, L'\0' } | |
}; | |
CHAR16 mSetModeString[] = { ESC, '[', '=', '3', 'h', 0 }; | |
CHAR16 mSetAttributeString[] = { ESC, '[', '0', 'm', ESC, '[', '4', '0', 'm', ESC, '[', '4', '0', 'm', 0 }; | |
CHAR16 mClearScreenString[] = { ESC, '[', '2', 'J', 0 }; | |
CHAR16 mSetCursorPositionString[] = { ESC, '[', '0', '0', ';', '0', '0', 'H', 0 }; | |
CHAR16 mCursorForwardString[] = { ESC, '[', '0', '0', 'C', 0 }; | |
CHAR16 mCursorBackwardString[] = { ESC, '[', '0', '0', 'D', 0 }; | |
// | |
// Body of the ConOut functions | |
// | |
/** | |
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 | |
TerminalConOutReset ( | |
IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, | |
IN BOOLEAN ExtendedVerification | |
) | |
{ | |
EFI_STATUS Status; | |
TERMINAL_DEV *TerminalDevice; | |
TerminalDevice = TERMINAL_CON_OUT_DEV_FROM_THIS (This); | |
// | |
// 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)); | |
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 | |
TerminalConOutOutputString ( | |
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 GraphicChar; | |
CHAR8 AsciiChar; | |
EFI_STATUS Status; | |
UINT8 ValidBytes; | |
CHAR8 CrLfStr[2]; | |
// | |
// flag used to indicate whether condition happens which will cause | |
// return EFI_WARN_UNKNOWN_GLYPH | |
// | |
BOOLEAN Warning; | |
ValidBytes = 0; | |
Warning = FALSE; | |
AsciiChar = 0; | |
// | |
// get Terminal device data structure pointer. | |
// | |
TerminalDevice = TERMINAL_CON_OUT_DEV_FROM_THIS (This); | |
// | |
// Get current display mode | |
// | |
Mode = This->Mode; | |
if (Mode->Mode >= Mode->MaxMode) { | |
return EFI_UNSUPPORTED; | |
} | |
This->QueryMode ( | |
This, | |
Mode->Mode, | |
&MaxColumn, | |
&MaxRow | |
); | |
for ( ; *WString != CHAR_NULL; WString++) { | |
switch (TerminalDevice->TerminalType) { | |
case TerminalTypePcAnsi: | |
case TerminalTypeVt100: | |
case TerminalTypeVt100Plus: | |
case TerminalTypeTtyTerm: | |
case TerminalTypeLinux: | |
case TerminalTypeXtermR6: | |
case TerminalTypeVt400: | |
case TerminalTypeSCO: | |
if (!TerminalIsValidTextGraphics (*WString, &GraphicChar, &AsciiChar)) { | |
// | |
// If it's not a graphic character convert Unicode to ASCII. | |
// | |
GraphicChar = (CHAR8)*WString; | |
if (!(TerminalIsValidAscii (GraphicChar) || TerminalIsValidEfiCntlChar (GraphicChar))) { | |
// | |
// 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 ((GraphicChar == 27) && TerminalDevice->OutputEscChar) { | |
GraphicChar = 27; | |
} else { | |
GraphicChar = '?'; | |
Warning = TRUE; | |
} | |
} | |
AsciiChar = GraphicChar; | |
} | |
if (TerminalDevice->TerminalType != TerminalTypePcAnsi) { | |
GraphicChar = AsciiChar; | |
} | |
Length = 1; | |
Status = TerminalDevice->SerialIo->Write ( | |
TerminalDevice->SerialIo, | |
&Length, | |
&GraphicChar | |
); | |
if (EFI_ERROR (Status)) { | |
goto OutputError; | |
} | |
break; | |
case TerminalTypeVtUtf8: | |
UnicodeToUtf8 (*WString, &Utf8Char, &ValidBytes); | |
Length = ValidBytes; | |
Status = TerminalDevice->SerialIo->Write ( | |
TerminalDevice->SerialIo, | |
&Length, | |
(UINT8 *)&Utf8Char | |
); | |
if (EFI_ERROR (Status)) { | |
goto OutputError; | |
} | |
break; | |
} | |
// | |
// Update cursor position. | |
// | |
switch (*WString) { | |
case CHAR_BACKSPACE: | |
if (Mode->CursorColumn > 0) { | |
Mode->CursorColumn--; | |
} | |
break; | |
case CHAR_LINEFEED: | |
if (Mode->CursorRow < (INT32)(MaxRow - 1)) { | |
Mode->CursorRow++; | |
} | |
break; | |
case CHAR_CARRIAGE_RETURN: | |
Mode->CursorColumn = 0; | |
break; | |
default: | |
if (Mode->CursorColumn < (INT32)(MaxColumn - 1)) { | |
Mode->CursorColumn++; | |
} else { | |
Mode->CursorColumn = 0; | |
if (Mode->CursorRow < (INT32)(MaxRow - 1)) { | |
Mode->CursorRow++; | |
} | |
if ((TerminalDevice->TerminalType == TerminalTypeTtyTerm) && | |
!TerminalDevice->OutputEscChar) | |
{ | |
// | |
// We've written the last character on the line. The | |
// terminal doesn't actually wrap its cursor until we print | |
// the next character, but the driver thinks it has wrapped | |
// already. Print CR LF to synchronize the terminal with | |
// the driver, but only if we're not in the middle of | |
// printing an escape sequence. | |
// | |
CrLfStr[0] = '\r'; | |
CrLfStr[1] = '\n'; | |
Length = sizeof (CrLfStr); | |
Status = TerminalDevice->SerialIo->Write ( | |
TerminalDevice->SerialIo, | |
&Length, | |
CrLfStr | |
); | |
if (EFI_ERROR (Status)) { | |
goto OutputError; | |
} | |
} | |
} | |
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_OUTPUT_ERROR), | |
TerminalDevice->DevicePath | |
); | |
return EFI_DEVICE_ERROR; | |
} | |
/** | |
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 | |
TerminalConOutTestString ( | |
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 TerminalTypePcAnsi: | |
case TerminalTypeVt100: | |
case TerminalTypeVt100Plus: | |
case TerminalTypeTtyTerm: | |
Status = AnsiTestString (TerminalDevice, WString); | |
break; | |
case TerminalTypeVtUtf8: | |
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 | |
TerminalConOutQueryMode ( | |
IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, | |
IN UINTN ModeNumber, | |
OUT UINTN *Columns, | |
OUT UINTN *Rows | |
) | |
{ | |
TERMINAL_DEV *TerminalDevice; | |
if (ModeNumber >= (UINTN)This->Mode->MaxMode) { | |
return EFI_UNSUPPORTED; | |
} | |
// | |
// Get Terminal device data structure pointer. | |
// | |
TerminalDevice = TERMINAL_CON_OUT_DEV_FROM_THIS (This); | |
*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 | |
TerminalConOutSetMode ( | |
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)This->Mode->MaxMode) { | |
return EFI_UNSUPPORTED; | |
} | |
// | |
// Set the current mode | |
// | |
This->Mode->Mode = (INT32)ModeNumber; | |
This->ClearScreen (This); | |
TerminalDevice->OutputEscChar = TRUE; | |
Status = This->OutputString (This, mSetModeString); | |
TerminalDevice->OutputEscChar = FALSE; | |
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 | |
TerminalConOutSetAttribute ( | |
IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, | |
IN UINTN Attribute | |
) | |
{ | |
UINT8 ForegroundControl; | |
UINT8 BackgroundControl; | |
UINT8 BrightControl; | |
INT32 SavedColumn; | |
INT32 SavedRow; | |
EFI_STATUS Status; | |
TERMINAL_DEV *TerminalDevice; | |
SavedColumn = 0; | |
SavedRow = 0; | |
// | |
// get Terminal device data structure pointer. | |
// | |
TerminalDevice = TERMINAL_CON_OUT_DEV_FROM_THIS (This); | |
// | |
// only the bit0..6 of the Attribute is valid | |
// | |
if ((Attribute | 0x7f) != 0x7f) { | |
return EFI_UNSUPPORTED; | |
} | |
// | |
// Skip outputting the command string for the same attribute | |
// It improves the terminal performance significantly | |
// | |
if (This->Mode->Attribute == (INT32)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; | |
default: | |
case EFI_LIGHTGRAY: | |
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; | |
default: | |
case EFI_LIGHTGRAY: | |
BackgroundControl = 47; | |
break; | |
} | |
// | |
// terminal emulator's control sequence to set attributes | |
// | |
mSetAttributeString[BRIGHT_CONTROL_OFFSET] = (CHAR16)('0' + BrightControl); | |
mSetAttributeString[FOREGROUND_CONTROL_OFFSET + 0] = (CHAR16)('0' + (ForegroundControl / 10)); | |
mSetAttributeString[FOREGROUND_CONTROL_OFFSET + 1] = (CHAR16)('0' + (ForegroundControl % 10)); | |
mSetAttributeString[BACKGROUND_CONTROL_OFFSET + 0] = (CHAR16)('0' + (BackgroundControl / 10)); | |
mSetAttributeString[BACKGROUND_CONTROL_OFFSET + 1] = (CHAR16)('0' + (BackgroundControl % 10)); | |
// | |
// save current column and row | |
// for future scrolling back use. | |
// | |
SavedColumn = This->Mode->CursorColumn; | |
SavedRow = This->Mode->CursorRow; | |
TerminalDevice->OutputEscChar = TRUE; | |
Status = This->OutputString (This, mSetAttributeString); | |
TerminalDevice->OutputEscChar = FALSE; | |
if (EFI_ERROR (Status)) { | |
return EFI_DEVICE_ERROR; | |
} | |
// | |
// scroll back to saved cursor position. | |
// | |
This->Mode->CursorColumn = SavedColumn; | |
This->Mode->CursorRow = SavedRow; | |
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 | |
TerminalConOutClearScreen ( | |
IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This | |
) | |
{ | |
EFI_STATUS Status; | |
TERMINAL_DEV *TerminalDevice; | |
TerminalDevice = TERMINAL_CON_OUT_DEV_FROM_THIS (This); | |
// | |
// control sequence for clear screen request | |
// | |
TerminalDevice->OutputEscChar = TRUE; | |
Status = This->OutputString (This, mClearScreenString); | |
TerminalDevice->OutputEscChar = FALSE; | |
if (EFI_ERROR (Status)) { | |
return EFI_DEVICE_ERROR; | |
} | |
Status = This->SetCursorPosition (This, 0, 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 | |
TerminalConOutSetCursorPosition ( | |
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; | |
CHAR16 *String; | |
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; | |
} | |
// | |
// control sequence to move the cursor | |
// | |
// Optimize cursor motion control sequences for TtyTerm. Move | |
// within the current line if possible, and don't output anyting if | |
// it isn't necessary. | |
// | |
if ((TerminalDevice->TerminalType == TerminalTypeTtyTerm) && | |
((UINTN)Mode->CursorRow == Row)) | |
{ | |
if ((UINTN)Mode->CursorColumn > Column) { | |
mCursorBackwardString[FW_BACK_OFFSET + 0] = (CHAR16)('0' + ((Mode->CursorColumn - Column) / 10)); | |
mCursorBackwardString[FW_BACK_OFFSET + 1] = (CHAR16)('0' + ((Mode->CursorColumn - Column) % 10)); | |
String = mCursorBackwardString; | |
} else if (Column > (UINTN)Mode->CursorColumn) { | |
mCursorForwardString[FW_BACK_OFFSET + 0] = (CHAR16)('0' + ((Column - Mode->CursorColumn) / 10)); | |
mCursorForwardString[FW_BACK_OFFSET + 1] = (CHAR16)('0' + ((Column - Mode->CursorColumn) % 10)); | |
String = mCursorForwardString; | |
} else { | |
String = L""; // No cursor motion necessary | |
} | |
} else { | |
mSetCursorPositionString[ROW_OFFSET + 0] = (CHAR16)('0' + ((Row + 1) / 10)); | |
mSetCursorPositionString[ROW_OFFSET + 1] = (CHAR16)('0' + ((Row + 1) % 10)); | |
mSetCursorPositionString[COLUMN_OFFSET + 0] = (CHAR16)('0' + ((Column + 1) / 10)); | |
mSetCursorPositionString[COLUMN_OFFSET + 1] = (CHAR16)('0' + ((Column + 1) % 10)); | |
String = mSetCursorPositionString; | |
} | |
TerminalDevice->OutputEscChar = TRUE; | |
Status = This->OutputString (This, String); | |
TerminalDevice->OutputEscChar = FALSE; | |
if (EFI_ERROR (Status)) { | |
return EFI_DEVICE_ERROR; | |
} | |
// | |
// 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 | |
TerminalConOutEnableCursor ( | |
IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, | |
IN BOOLEAN Visible | |
) | |
{ | |
if (!Visible) { | |
return EFI_UNSUPPORTED; | |
} | |
return EFI_SUCCESS; | |
} | |
/** | |
Detects if a Unicode char is for Box Drawing text graphics. | |
@param Graphic Unicode char to test. | |
@param PcAnsi Optional pointer to return PCANSI equivalent of | |
Graphic. | |
@param Ascii Optional pointer to return ASCII equivalent of | |
Graphic. | |
@retval TRUE If Graphic is a supported Unicode Box Drawing character. | |
**/ | |
BOOLEAN | |
TerminalIsValidTextGraphics ( | |
IN CHAR16 Graphic, | |
OUT CHAR8 *PcAnsi OPTIONAL, | |
OUT CHAR8 *Ascii OPTIONAL | |
) | |
{ | |
UNICODE_TO_CHAR *Table; | |
if ((((Graphic & 0xff00) != 0x2500) && ((Graphic & 0xff00) != 0x2100))) { | |
// | |
// Unicode drawing code charts are all in the 0x25xx range, | |
// arrows are 0x21xx | |
// | |
return FALSE; | |
} | |
for (Table = UnicodeToPcAnsiOrAscii; Table->Unicode != 0x0000; Table++) { | |
if (Graphic == Table->Unicode) { | |
if (PcAnsi != NULL) { | |
*PcAnsi = Table->PcAnsi; | |
} | |
if (Ascii != NULL) { | |
*Ascii = Table->Ascii; | |
} | |
return TRUE; | |
} | |
} | |
return FALSE; | |
} | |
/** | |
Detects if a valid ASCII char. | |
@param Ascii An ASCII character. | |
@retval TRUE If it is a valid ASCII character. | |
@retval FALSE If it is not a valid ASCII character. | |
**/ | |
BOOLEAN | |
TerminalIsValidAscii ( | |
IN CHAR16 Ascii | |
) | |
{ | |
// | |
// valid ascii code lies in the extent of 0x20 ~ 0x7f | |
// | |
if ((Ascii >= 0x20) && (Ascii <= 0x7f)) { | |
return TRUE; | |
} | |
return FALSE; | |
} | |
/** | |
Detects if a valid EFI control character. | |
@param CharC An input EFI Control character. | |
@retval TRUE If it is a valid EFI control character. | |
@retval FALSE If it is not a valid EFI control character. | |
**/ | |
BOOLEAN | |
TerminalIsValidEfiCntlChar ( | |
IN CHAR16 CharC | |
) | |
{ | |
// | |
// only support four control characters. | |
// | |
if ((CharC == CHAR_NULL) || | |
(CharC == CHAR_BACKSPACE) || | |
(CharC == CHAR_LINEFEED) || | |
(CharC == CHAR_CARRIAGE_RETURN) || | |
(CharC == CHAR_TAB) | |
) | |
{ | |
return TRUE; | |
} | |
return FALSE; | |
} |