/** @file Implementation for synchronous EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL protocol. ;****************************************************************************** ;* Copyright (c) 2013, 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" // // Body of the ConOut functions // /** Scroll down screen one line. @param TerminalDevice Terminal Device. @param MaxColumn The maximum column of terminal screen @param MaxRow The maximum row of terminal screen **/ VOID SyncTerminalScrollScreen ( IN TERMINAL_DEV *TerminalDevice, IN UINTN MaxColumn, IN UINTN MaxRow ) { EFI_STATUS Status; UINTN StrLength; UINTN Value; UINTN Index; if (TerminalDevice->TerminalType == LOGTERMTYPE) { return; } // // Move cursor to last row // Index = 0; while (gSetCursorToLastRowStr[Index] != CHAR_NULL) { StrLength = 1; Status = TerminalDevice->SerialIo->Write ( TerminalDevice->SerialIo, &StrLength, &gSetCursorToLastRowStr[Index] ); Index++; } // // Scroll screen // Index = 0; while (gScrollDownStr[Index] != CHAR_NULL) { StrLength = 1; Status = TerminalDevice->SerialIo->Write ( TerminalDevice->SerialIo, &StrLength, &gScrollDownStr[Index] ); Index++; } // // control sequence to move the cursor // Value = MaxRow; 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 = 0; 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); // // Restore cursor // Index = 0; while (gSetCursorPositionString[Index] != CHAR_NULL) { StrLength = 1; Status = TerminalDevice->SerialIo->Write ( TerminalDevice->SerialIo, &StrLength, &gSetCursorPositionString[Index] ); Index++; } } /** 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 SyncTerminalConOutReset ( IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, IN BOOLEAN ExtendedVerification ) { EFI_STATUS Status; TERMINAL_DEV *TerminalDevice; UINTN StringLen; TerminalDevice = TERMINAL_CON_OUT_DEV_FROM_THIS (This); // // Reset Terminal, Send out "c" // if (TerminalDevice->TerminalType != LOGTERMTYPE) { StringLen = 2; Status = TerminalDevice->SerialIo->Write (TerminalDevice->SerialIo, &StringLen, gResetDeviceString); } // // 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); ASSERT_EFI_ERROR(Status); 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 SyncTerminalConOutOutputString ( 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; INT32 AtributeSetting; // // flag used to indicate whether condition happens which will cause // return EFI_WARN_UNKNOWN_GLYPH // BOOLEAN Warning; ValidBytes = 0; Warning = FALSE; // // get Terminal device data structure pointer. // TerminalDevice = TERMINAL_CON_OUT_DEV_FROM_THIS (This); // // Get current display mode // Mode = This->Mode; if (Mode->Mode >= TerminalDevice->SimpleTextOutputMode.MaxMode) { return EFI_UNSUPPORTED; } This->QueryMode ( This, Mode->Mode, &MaxColumn, &MaxRow ); for (; *WString != CHAR_NULL; WString++) { AtributeSetting = Mode->Attribute; switch (TerminalDevice->TerminalType) { case PCANSITYPE: case VT100TYPE: case LOGTERMTYPE: Vt100PlusSwitchCharSet (&TerminalDevice->SimpleTextOutput, VT100_ASCII_CHAR_SET); OutputChar = &AsciiChar; if ((*WString == WIDE_CHAR || *WString == NARROW_CHAR)) { // // Here didn't support Wide Character. // break; } else 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; } // // Output character // Length = 1; Status = TerminalDevice->SerialIo->Write ( TerminalDevice->SerialIo, &Length, OutputChar ); if (EFI_ERROR (Status)) { goto OutputError; } break; case VT100PLUSTYPE: OutputChar = &AsciiChar; Status = EFI_SUCCESS; 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; } // // Output character // Length = 1; Status = TerminalDevice->SerialIo->Write ( TerminalDevice->SerialIo, &Length, OutputChar ); if (EFI_ERROR (Status)) { goto OutputError; } break; case VTUTF8TYPE: switch (*WString) { case WIDE_CHAR: AtributeSetting |= EFI_WIDE_ATTRIBUTE; break; case NARROW_CHAR: AtributeSetting &= (~ (UINT32) EFI_WIDE_ATTRIBUTE); break; default: // // Only UTF8 support Wide Character, // Translate Wide Character Unicode // if (AtributeSetting & EFI_WIDE_ATTRIBUTE) { WideUnicode (*WString, WString); } 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--; } 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++; } 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++; } } 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 SyncTerminalConOutTestString ( 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 SyncTerminalConOutQueryMode ( 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 SyncTerminalConOutSetMode ( 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); TerminalDevice->OutputEscChar = TRUE; Status = AdjustTerminalResolution (This, ModeNumber); 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 SyncTerminalConOutSetAttribute ( 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: // // 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: // // EFI_LIGHTGRAY // BackgroundControl = 47; break; } if ((TerminalDevice->TerminalFeatureFlag & CR_TERMINAL_VIDEO_FLAG) == CR_TERMINAL_VIDEO_MONO) { 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)); // // save current column and row // for future scrolling back use. // SavedColumn = This->Mode->CursorColumn; SavedRow = This->Mode->CursorRow; TerminalDevice->OutputEscChar = TRUE; Status = OutputEscSquenceString (This, gSetAttributeString); 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 SyncTerminalConOutClearScreen ( 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 = OutputEscSquenceString (This, gClearScreenString); 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 SyncTerminalConOutSetCursorPosition ( 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; } // // 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); TerminalDevice->OutputEscChar = TRUE; Status = OutputEscSquenceString (This, gSetCursorPositionString); 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 SyncTerminalConOutEnableCursor ( IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, IN BOOLEAN Visible ) { if (!Visible) { return EFI_UNSUPPORTED; } return EFI_SUCCESS; }