Generate the options for the drop-down list from the GOP resolutions. Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Laszlo Ersek <ler...@redhat.com> ---
Notes: - replace GOP Depex with GOP installation callback OvmfPkg/PlatformDxe/Platform.inf | 2 + OvmfPkg/PlatformDxe/Platform.c | 240 +++++++++++++++++++++++++++++++++++---- 2 files changed, 222 insertions(+), 20 deletions(-) diff --git a/OvmfPkg/PlatformDxe/Platform.inf b/OvmfPkg/PlatformDxe/Platform.inf index 5997e34..16cd9ab 100644 --- a/OvmfPkg/PlatformDxe/Platform.inf +++ b/OvmfPkg/PlatformDxe/Platform.inf @@ -42,6 +42,7 @@ DevicePathLib HiiLib MemoryAllocationLib + PrintLib UefiBootServicesTableLib UefiHiiServicesLib UefiLib @@ -54,6 +55,7 @@ [Protocols] gEfiDevicePathProtocolGuid ## PRODUCES + gEfiGraphicsOutputProtocolGuid ## CONSUMES gEfiHiiConfigAccessProtocolGuid ## PRODUCES [Guids] diff --git a/OvmfPkg/PlatformDxe/Platform.c b/OvmfPkg/PlatformDxe/Platform.c index 4b14162..c3021e8 100644 --- a/OvmfPkg/PlatformDxe/Platform.c +++ b/OvmfPkg/PlatformDxe/Platform.c @@ -18,9 +18,12 @@ #include <Library/DebugLib.h> #include <Library/DevicePathLib.h> #include <Library/HiiLib.h> +#include <Library/MemoryAllocationLib.h> +#include <Library/PrintLib.h> #include <Library/UefiBootServicesTableLib.h> #include <Library/UefiHiiServicesLib.h> #include <Protocol/DevicePath.h> +#include <Protocol/GraphicsOutput.h> #include <Protocol/HiiConfigAccess.h> #include <Guid/MdeModuleHii.h> #include <Guid/OvmfPlatformConfig.h> @@ -98,6 +101,29 @@ STATIC EFI_HII_HANDLE mInstalledPackages; extern UINT8 PlatformDxeStrings[]; extern UINT8 PlatformFormsBin[]; +// +// We want to be notified about GOP installations until we find one GOP +// interface that lets us populate the form. +// +STATIC EFI_EVENT mGopEvent; + +// +// The registration record underneath this pointer allows us to iterate through +// the GOP instances one by one. +// +STATIC VOID *mGopTracker; + +// +// Cache the resolutions we get from the GOP. +// +typedef struct { + UINT32 X; + UINT32 Y; +} GOP_MODE; + +STATIC UINTN mNumGopModes; +STATIC GOP_MODE *mGopModes; + /** This function is called by the HII machinery when it fetches the form state. @@ -180,6 +206,68 @@ Callback ( /** + Query and save all resolutions supported by the GOP. + + @param[in] Gop The Graphics Output Protocol instance to query. + + @param[out] NumGopModes The number of modes supported by the GOP. On output, + this parameter will be positive. + + @param[out] GopModes On output, a dynamically allocated array containing + the resolutions returned by the GOP. The caller is + responsible for freeing the array after use. + + @retval EFI_UNSUPPORTED No modes found. + @retval EFI_OUT_OF_RESOURCES Failed to allocate GopModes. + @return Error codes from Gop->QueryMode(). + +**/ +STATIC +EFI_STATUS +EFIAPI +QueryGopModes ( + IN EFI_GRAPHICS_OUTPUT_PROTOCOL *Gop, + OUT UINTN *NumGopModes, + OUT GOP_MODE **GopModes + ) +{ + EFI_STATUS Status; + UINT32 ModeNumber; + + if (Gop->Mode->MaxMode == 0) { + return EFI_UNSUPPORTED; + } + *NumGopModes = Gop->Mode->MaxMode; + + *GopModes = AllocatePool (Gop->Mode->MaxMode * sizeof **GopModes); + if (*GopModes == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + for (ModeNumber = 0; ModeNumber < Gop->Mode->MaxMode; ++ModeNumber) { + EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Info; + UINTN SizeOfInfo; + + Status = Gop->QueryMode (Gop, ModeNumber, &SizeOfInfo, &Info); + if (EFI_ERROR (Status)) { + goto FreeGopModes; + } + + (*GopModes)[ModeNumber].X = Info->HorizontalResolution; + (*GopModes)[ModeNumber].Y = Info->VerticalResolution; + FreePool (Info); + } + + return EFI_SUCCESS; + +FreeGopModes: + FreePool (*GopModes); + + return Status; +} + + +/** Create a set of "one-of-many" (ie. "drop down list") option IFR opcodes, based on available GOP resolutions, to be placed under a "one-of-many" (ie. "drop down list") opcode. @@ -193,6 +281,10 @@ Callback ( resolutions. The caller is responsible for freeing OpCodeBuffer with HiiFreeOpCodeHandle() after use. + @param[in] NumGopModes Number of entries in GopModes. + + @param[in] GopModes Array of resolutions retrieved from the GOP. + @retval EFI_SUCESS Opcodes have been successfully produced. @return Status codes from underlying functions. PackageList may @@ -204,30 +296,39 @@ EFI_STATUS EFIAPI CreateResolutionOptions ( IN EFI_HII_HANDLE *PackageList, - OUT VOID **OpCodeBuffer + OUT VOID **OpCodeBuffer, + IN UINTN NumGopModes, + IN GOP_MODE *GopModes ) { - EFI_STATUS Status; - VOID *OutputBuffer; - EFI_STRING_ID NewString; - VOID *OpCode; + EFI_STATUS Status; + VOID *OutputBuffer; + UINTN ModeNumber; OutputBuffer = HiiAllocateOpCodeHandle (); if (OutputBuffer == NULL) { return EFI_OUT_OF_RESOURCES; } - NewString = HiiSetString (PackageList, 0 /* new string */, L"800x600", - NULL /* for all languages */); - if (NewString == 0) { - Status = EFI_OUT_OF_RESOURCES; - goto FreeOutputBuffer; - } - OpCode = HiiCreateOneOfOptionOpCode (OutputBuffer, NewString, - 0 /* Flags */, EFI_IFR_NUMERIC_SIZE_4, 0 /* Value */); - if (OpCode == NULL) { - Status = EFI_OUT_OF_RESOURCES; - goto FreeOutputBuffer; + for (ModeNumber = 0; ModeNumber < NumGopModes; ++ModeNumber) { + CHAR16 Desc[MAXSIZE_RES_CUR]; + EFI_STRING_ID NewString; + VOID *OpCode; + + UnicodeSPrintAsciiFormat (Desc, sizeof Desc, "%Ldx%Ld", + (INT64) GopModes[ModeNumber].X, (INT64) GopModes[ModeNumber].Y); + NewString = HiiSetString (PackageList, 0 /* new string */, Desc, + NULL /* for all languages */); + if (NewString == 0) { + Status = EFI_OUT_OF_RESOURCES; + goto FreeOutputBuffer; + } + OpCode = HiiCreateOneOfOptionOpCode (OutputBuffer, NewString, + 0 /* Flags */, EFI_IFR_NUMERIC_SIZE_4, ModeNumber); + if (OpCode == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto FreeOutputBuffer; + } } *OpCodeBuffer = OutputBuffer; @@ -244,6 +345,9 @@ FreeOutputBuffer: Populate the form identified by the (PackageList, FormSetGuid, FormId) triplet. + The drop down list of video resolutions is generated from (NumGopModes, + GopModes). + @retval EFI_SUCESS Form successfully updated. @return Status codes from underlying functions. @@ -254,7 +358,9 @@ EFIAPI PopulateForm ( IN EFI_HII_HANDLE *PackageList, IN EFI_GUID *FormSetGuid, - IN EFI_FORM_ID FormId + IN EFI_FORM_ID FormId, + IN UINTN NumGopModes, + IN GOP_MODE *GopModes ) { EFI_STATUS Status; @@ -291,7 +397,8 @@ PopulateForm ( // // 3.1. Get a list of resolutions. // - Status = CreateResolutionOptions (PackageList, &OpCodeBuffer2); + Status = CreateResolutionOptions (PackageList, &OpCodeBuffer2, + NumGopModes, GopModes); if (EFI_ERROR (Status)) { goto FreeOpCodeBuffer; } @@ -380,6 +487,66 @@ ExecutePlatformConfig ( /** + Notification callback for GOP interface installation. + + @param[in] Event Event whose notification function is being invoked. + + @param[in] Context The pointer to the notification function's context, which + is implementation-dependent. +**/ +STATIC +VOID +EFIAPI +GopInstalled ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + EFI_STATUS Status; + EFI_GRAPHICS_OUTPUT_PROTOCOL *Gop; + + ASSERT (Event == mGopEvent); + + // + // Check further GOPs. + // + for (;;) { + mNumGopModes = 0; + mGopModes = NULL; + + Status = gBS->LocateProtocol (&gEfiGraphicsOutputProtocolGuid, mGopTracker, + (VOID **) &Gop); + if (EFI_ERROR (Status)) { + return; + } + + Status = QueryGopModes (Gop, &mNumGopModes, &mGopModes); + if (EFI_ERROR (Status)) { + continue; + } + + Status = PopulateForm (mInstalledPackages, &gOvmfPlatformConfigGuid, + FORMID_MAIN_FORM, mNumGopModes, mGopModes); + if (EFI_ERROR (Status)) { + FreePool (mGopModes); + continue; + } + + break; + } + + // + // Success -- so uninstall this callback. Closing the event removes all + // pending notifications and all protocol registrations. + // + Status = gBS->CloseEvent (mGopEvent); + ASSERT_EFI_ERROR (Status); + mGopEvent = NULL; + mGopTracker = NULL; +} + + +/** Entry point for this driver. @param[in] ImageHandle Image handle of this driver. @@ -431,14 +598,29 @@ PlatformInit ( goto UninstallProtocols; } - Status = PopulateForm (mInstalledPackages, &gOvmfPlatformConfigGuid, - FORMID_MAIN_FORM); + Status = gBS->CreateEvent (EVT_NOTIFY_SIGNAL, TPL_CALLBACK, &GopInstalled, + NULL /* Context */, &mGopEvent); if (EFI_ERROR (Status)) { goto RemovePackages; } + Status = gBS->RegisterProtocolNotify (&gEfiGraphicsOutputProtocolGuid, + mGopEvent, &mGopTracker); + if (EFI_ERROR (Status)) { + goto CloseGopEvent; + } + + // + // Check already installed GOPs. + // + Status = gBS->SignalEvent (mGopEvent); + ASSERT_EFI_ERROR (Status); + return EFI_SUCCESS; +CloseGopEvent: + gBS->CloseEvent (mGopEvent); + RemovePackages: HiiRemovePackages (mInstalledPackages); @@ -463,6 +645,24 @@ PlatformUnload ( IN EFI_HANDLE ImageHandle ) { + if (mGopEvent == NULL) { + // + // The GOP callback ran successfully and unregistered itself. Release the + // resources allocated there. + // + ASSERT (mGopModes != NULL); + FreePool (mGopModes); + } else { + // + // Otherwise we need to unregister the callback. + // + ASSERT (mGopModes == NULL); + gBS->CloseEvent (mGopEvent); + } + + // + // Release resources allocated by the entry point. + // HiiRemovePackages (mInstalledPackages); gBS->UninstallMultipleProtocolInterfaces (ImageHandle, &gEfiDevicePathProtocolGuid, &mPkgDevicePath, -- 1.8.3.1 ------------------------------------------------------------------------------ Subversion Kills Productivity. Get off Subversion & Make the Move to Perforce. With Perforce, you get hassle-free workflows. Merge that actually works. Faster operations. Version large binaries. Built-in WAN optimization and the freedom to use Git, Perforce or both. Make the move to Perforce. http://pubads.g.doubleclick.net/gampad/clk?id=122218951&iu=/4140/ostg.clktrk _______________________________________________ edk2-devel mailing list edk2-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/edk2-devel