/** This function will change video resolution and text mode according to defined setup mode or defined boot mode @param IsSetupMode Indicate mode is changed to setup mode or boot mode. @retval EFI_SUCCESS Mode is changed successfully. @retval Others Mode failed to be changed. **/ EFI_STATUS EFIAPI BmBdsSetConsoleMode ( BOOLEAN IsSetupMode ) { EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput; EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *SimpleTextOut; UINTN SizeOfInfo; EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Info; UINT32 MaxGopMode; UINT32 MaxTextMode; UINT32 ModeNumber; UINT32 NewHorizontalResolution; UINT32 NewVerticalResolution; UINT32 NewColumns; UINT32 NewRows; UINTN HandleCount; EFI_HANDLE *HandleBuffer; EFI_STATUS Status; UINTN Index; UINTN CurrentColumn; UINTN CurrentRow; MaxGopMode = 0; MaxTextMode = 0; // // Get current video resolution and text mode // Status = gBS->HandleProtocol ( gST->ConsoleOutHandle, &gEfiGraphicsOutputProtocolGuid, (VOID**)&GraphicsOutput ); if (EFI_ERROR (Status)) { GraphicsOutput = NULL; } Status = gBS->HandleProtocol ( gST->ConsoleOutHandle, &gEfiSimpleTextOutProtocolGuid, (VOID**)&SimpleTextOut ); if (EFI_ERROR (Status)) { SimpleTextOut = NULL; } if ((GraphicsOutput == NULL) || (SimpleTextOut == NULL)) { return EFI_UNSUPPORTED; } if (IsSetupMode) { // // The requried resolution and text mode is setup mode. // NewHorizontalResolution = mBmSetupHorizontalResolution; NewVerticalResolution = mBmSetupVerticalResolution; NewColumns = mBmSetupTextModeColumn; NewRows = mBmSetupTextModeRow; } else { // // The required resolution and text mode is boot mode. // NewHorizontalResolution = mBmBootHorizontalResolution; NewVerticalResolution = mBmBootVerticalResolution; NewColumns = mBmBootTextModeColumn; NewRows = mBmBootTextModeRow; } if (GraphicsOutput != NULL) { MaxGopMode = GraphicsOutput->Mode->MaxMode; } if (SimpleTextOut != NULL) { MaxTextMode = SimpleTextOut->Mode->MaxMode; } // // 1. If current video resolution is same with required video resolution, // video resolution need not be changed. // 1.1. If current text mode is same with required text mode, text mode need not be changed. // 1.2. If current text mode is different from required text mode, text mode need be changed. // 2. If current video resolution is different from required video resolution, we need restart whole console drivers. // for (ModeNumber = 0; ModeNumber < MaxGopMode; ModeNumber++) { Status = GraphicsOutput->QueryMode ( GraphicsOutput, ModeNumber, &SizeOfInfo, &Info ); if (!EFI_ERROR (Status)) { if ((Info->HorizontalResolution == NewHorizontalResolution) && (Info->VerticalResolution == NewVerticalResolution)) { if ((GraphicsOutput->Mode->Info->HorizontalResolution == NewHorizontalResolution) && (GraphicsOutput->Mode->Info->VerticalResolution == NewVerticalResolution)) { // // Current resolution is same with required resolution, check if text mode need be set // Status = SimpleTextOut->QueryMode (SimpleTextOut, SimpleTextOut->Mode->Mode, &CurrentColumn, &CurrentRow); ASSERT_EFI_ERROR (Status); if (CurrentColumn == NewColumns && CurrentRow == NewRows) { // // If current text mode is same with required text mode. Do nothing // FreePool (Info); return EFI_SUCCESS; } else { // // If current text mode is different from requried text mode. Set new video mode // for (Index = 0; Index < MaxTextMode; Index++) { Status = SimpleTextOut->QueryMode (SimpleTextOut, Index, &CurrentColumn, &CurrentRow); if (!EFI_ERROR(Status)) { if ((CurrentColumn == NewColumns) && (CurrentRow == NewRows)) { // // Required text mode is supported, set it. // Status = SimpleTextOut->SetMode (SimpleTextOut, Index); ASSERT_EFI_ERROR (Status); // // Update text mode PCD. // Status = PcdSet32S (PcdConOutColumn, mBmSetupTextModeColumn); ASSERT_EFI_ERROR (Status); Status = PcdSet32S (PcdConOutRow, mBmSetupTextModeRow); ASSERT_EFI_ERROR (Status); FreePool (Info); return EFI_SUCCESS; } } } if (Index == MaxTextMode) { // // If requried text mode is not supported, return error. // FreePool (Info); return EFI_UNSUPPORTED; } } } else { // // If current video resolution is not same with the new one, set new video resolution. // In this case, the driver which produces simple text out need be restarted. // Status = GraphicsOutput->SetMode (GraphicsOutput, ModeNumber); if (!EFI_ERROR (Status)) { FreePool (Info); break; } } } FreePool (Info); } } if (ModeNumber == MaxGopMode) { // // If the resolution is not supported, return error. // return EFI_UNSUPPORTED; } // // Set PCD to Inform GraphicsConsole to change video resolution. // Set PCD to Inform Consplitter to change text mode. // Status = PcdSet32S (PcdVideoHorizontalResolution, NewHorizontalResolution); ASSERT_EFI_ERROR (Status); Status = PcdSet32S (PcdVideoVerticalResolution, NewVerticalResolution); ASSERT_EFI_ERROR (Status); Status = PcdSet32S (PcdConOutColumn, NewColumns); ASSERT_EFI_ERROR (Status); Status = PcdSet32S (PcdConOutRow, NewRows); ASSERT_EFI_ERROR (Status); // // Video mode is changed, so restart graphics console driver and higher level driver. // Reconnect graphics console driver and higher level driver. // Locate all the handles with GOP protocol and reconnect it. // Status = gBS->LocateHandleBuffer ( ByProtocol, &gEfiSimpleTextOutProtocolGuid, NULL, &HandleCount, &HandleBuffer ); if (!EFI_ERROR (Status)) { for (Index = 0; Index < HandleCount; Index++) { gBS->DisconnectController (HandleBuffer[Index], NULL, NULL); } for (Index = 0; Index < HandleCount; Index++) { gBS->ConnectController (HandleBuffer[Index], NULL, NULL, TRUE); } if (HandleBuffer != NULL) { FreePool (HandleBuffer); } } return EFI_SUCCESS; }
/** Fill console handle in System Table if there are no valid console handle in. Firstly, check the validation of console handle in System Table. If it is invalid, update it by the first console device handle from EFI console variable. @param VarName The name of the EFI console variable. @param ConsoleGuid Specified Console protocol GUID. @param ConsoleHandle On IN, console handle in System Table to be checked. On OUT, new console handle in system table. @param ProtocolInterface On IN, console protocol on console handle in System Table to be checked. On OUT, new console protocol on new console handle in system table. @retval TRUE System Table has been updated. @retval FALSE System Table hasn't been updated. **/ BOOLEAN UpdateSystemTableConsole ( IN CHAR16 *VarName, IN EFI_GUID *ConsoleGuid, IN OUT EFI_HANDLE *ConsoleHandle, IN OUT VOID **ProtocolInterface ) { EFI_STATUS Status; UINTN DevicePathSize; EFI_DEVICE_PATH_PROTOCOL *FullDevicePath; EFI_DEVICE_PATH_PROTOCOL *VarConsole; EFI_DEVICE_PATH_PROTOCOL *Instance; VOID *Interface; EFI_HANDLE NewHandle; EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *TextOut; ASSERT (VarName != NULL); ASSERT (ConsoleHandle != NULL); ASSERT (ConsoleGuid != NULL); ASSERT (ProtocolInterface != NULL); if (*ConsoleHandle != NULL) { Status = gBS->HandleProtocol ( *ConsoleHandle, ConsoleGuid, &Interface ); if (Status == EFI_SUCCESS && Interface == *ProtocolInterface) { // // If ConsoleHandle is valid and console protocol on this handle also // also matched, just return. // return FALSE; } } // // Get all possible consoles device path from EFI variable // VarConsole = BdsLibGetVariableAndSize ( VarName, &gEfiGlobalVariableGuid, &DevicePathSize ); if (VarConsole == NULL) { // // If there is no any console device, just return. // return FALSE; } FullDevicePath = VarConsole; do { // // Check every instance of the console variable // Instance = GetNextDevicePathInstance (&VarConsole, &DevicePathSize); if (Instance == NULL) { FreePool (FullDevicePath); ASSERT (FALSE); } // // Find console device handle by device path instance // Status = gBS->LocateDevicePath ( ConsoleGuid, &Instance, &NewHandle ); if (!EFI_ERROR (Status)) { // // Get the console protocol on this console device handle // Status = gBS->HandleProtocol ( NewHandle, ConsoleGuid, &Interface ); if (!EFI_ERROR (Status)) { // // Update new console handle in System Table. // *ConsoleHandle = NewHandle; *ProtocolInterface = Interface; if (CompareGuid (ConsoleGuid, &gEfiSimpleTextOutProtocolGuid)) { // // If it is console out device, set console mode 80x25 if current mode is invalid. // TextOut = (EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *) Interface; if (TextOut->Mode->Mode == -1) { TextOut->SetMode (TextOut, 0); } } return TRUE; } } } while (Instance != NULL); // // No any available console devcie found. // return FALSE; }