diff options
Diffstat (limited to 'MdeModulePkg/Universal/SetupBrowserDxe/Setup.c')
-rw-r--r-- | MdeModulePkg/Universal/SetupBrowserDxe/Setup.c | 2286 |
1 files changed, 2286 insertions, 0 deletions
diff --git a/MdeModulePkg/Universal/SetupBrowserDxe/Setup.c b/MdeModulePkg/Universal/SetupBrowserDxe/Setup.c new file mode 100644 index 0000000000..d14dac0373 --- /dev/null +++ b/MdeModulePkg/Universal/SetupBrowserDxe/Setup.c @@ -0,0 +1,2286 @@ +/** @file +Copyright (c) 2007, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + Setup.c + +Abstract: + + Entry and initialization module for the browser. + + +**/ + +#include "Setup.h" +#include "Ui.h" + + +SETUP_DRIVER_PRIVATE_DATA mPrivateData = { + SETUP_DRIVER_SIGNATURE, + NULL, + { + SendForm, + BrowserCallback + }, + { + UnicodeVSPrint + } +}; + +EFI_HII_DATABASE_PROTOCOL *mHiiDatabase; +EFI_HII_STRING_PROTOCOL *mHiiString; +EFI_HII_CONFIG_ROUTING_PROTOCOL *mHiiConfigRouting; + +BANNER_DATA *BannerData; +EFI_HII_HANDLE FrontPageHandle; +UINTN gClassOfVfr; +UINTN gFunctionKeySetting; +BOOLEAN gResetRequired; +BOOLEAN gNvUpdateRequired; +EFI_HII_HANDLE gHiiHandle; +BOOLEAN gFirstIn; +UINT16 gDirection; +EFI_SCREEN_DESCRIPTOR gScreenDimensions; +BOOLEAN gUpArrow; +BOOLEAN gDownArrow; + +// +// Browser Global Strings +// +CHAR16 *gFunctionOneString; +CHAR16 *gFunctionTwoString; +CHAR16 *gFunctionNineString; +CHAR16 *gFunctionTenString; +CHAR16 *gEnterString; +CHAR16 *gEnterCommitString; +CHAR16 *gEscapeString; +CHAR16 *gSaveFailed; +CHAR16 *gMoveHighlight; +CHAR16 *gMakeSelection; +CHAR16 *gDecNumericInput; +CHAR16 *gHexNumericInput; +CHAR16 *gToggleCheckBox; +CHAR16 *gPromptForData; +CHAR16 *gPromptForPassword; +CHAR16 *gPromptForNewPassword; +CHAR16 *gConfirmPassword; +CHAR16 *gConfirmError; +CHAR16 *gPassowordInvalid; +CHAR16 *gPressEnter; +CHAR16 *gEmptyString; +CHAR16 *gAreYouSure; +CHAR16 *gYesResponse; +CHAR16 *gNoResponse; +CHAR16 *gMiniString; +CHAR16 *gPlusString; +CHAR16 *gMinusString; +CHAR16 *gAdjustNumber; + +CHAR16 gPromptBlockWidth; +CHAR16 gOptionBlockWidth; +CHAR16 gHelpBlockWidth; + +EFI_GUID gZeroGuid = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +EFI_GUID gSetupBrowserGuid = { + 0xab368524, 0xb60c, 0x495b, 0xa0, 0x9, 0x12, 0xe8, 0x5b, 0x1a, 0xea, 0x32 +}; + +FUNCTIION_KEY_SETTING gFunctionKeySettingTable[] = { + // + // Boot Manager + // + { + { + 0x847bc3fe, + 0xb974, + 0x446d, + 0x94, + 0x49, + 0x5a, + 0xd5, + 0x41, + 0x2e, + 0x99, + 0x3b + }, + NONE_FUNCTION_KEY_SETTING + }, + // + // Device Manager + // + { + { + 0x3ebfa8e6, + 0x511d, + 0x4b5b, + 0xa9, + 0x5f, + 0xfb, + 0x38, + 0x26, + 0xf, + 0x1c, + 0x27 + }, + NONE_FUNCTION_KEY_SETTING + }, + // + // BMM FormSet. + // + { + { + 0x642237c7, + 0x35d4, + 0x472d, + 0x83, + 0x65, + 0x12, + 0xe0, + 0xcc, + 0xf2, + 0x7a, + 0x22 + }, + NONE_FUNCTION_KEY_SETTING + }, + // + // BMM File Explorer FormSet. + // + { + { + 0x1f2d63e1, + 0xfebd, + 0x4dc7, + 0x9c, + 0xc5, + 0xba, + 0x2b, + 0x1c, + 0xef, + 0x9c, + 0x5b + }, + NONE_FUNCTION_KEY_SETTING + }, +}; + +//@MT: EFI_DRIVER_ENTRY_POINT (InitializeSetup) + +EFI_STATUS +EFIAPI +SendForm ( + IN CONST EFI_FORM_BROWSER2_PROTOCOL *This, + IN EFI_HII_HANDLE *Handles, + IN UINTN HandleCount, + IN EFI_GUID *FormSetGuid, OPTIONAL + IN UINT16 FormId, OPTIONAL + IN CONST EFI_SCREEN_DESCRIPTOR *ScreenDimensions, OPTIONAL + OUT EFI_BROWSER_ACTION_REQUEST *ActionRequest OPTIONAL + ) +/*++ + +Routine Description: + This is the routine which an external caller uses to direct the browser + where to obtain it's information. + +Arguments: + This - The Form Browser protocol instanse. + Handles - A pointer to an array of Handles. If HandleCount > 1 we + display a list of the formsets for the handles specified. + HandleCount - The number of Handles specified in Handle. + FormSetGuid - This field points to the EFI_GUID which must match the Guid + field in the EFI_IFR_FORM_SET op-code for the specified + forms-based package. If FormSetGuid is NULL, then this + function will display the first found forms package. + FormId - This field specifies which EFI_IFR_FORM to render as the first + displayable page. If this field has a value of 0x0000, then + the forms browser will render the specified forms in their encoded order. + ScreenDimenions - This allows the browser to be called so that it occupies a + portion of the physical screen instead of dynamically determining the screen dimensions. + ActionRequest - Points to the action recommended by the form. + +Returns: + EFI_SUCCESS - The function completed successfully. + EFI_INVALID_PARAMETER - One of the parameters has an invalid value. + EFI_NOT_FOUND - No valid forms could be found to display. + +--*/ +{ + EFI_STATUS Status; + UI_MENU_SELECTION *Selection; + UINTN Index; + FORM_BROWSER_FORMSET *FormSet; + + Status = EFI_SUCCESS; + ZeroMem (&gScreenDimensions, sizeof (EFI_SCREEN_DESCRIPTOR)); + + // + // Seed the dimensions in the global + // + gST->ConOut->QueryMode ( + gST->ConOut, + gST->ConOut->Mode->Mode, + &gScreenDimensions.RightColumn, + &gScreenDimensions.BottomRow + ); + + if (ScreenDimensions != NULL) { + // + // Check local dimension vs. global dimension. + // + if ((gScreenDimensions.RightColumn < ScreenDimensions->RightColumn) || + (gScreenDimensions.BottomRow < ScreenDimensions->BottomRow) + ) { + return EFI_INVALID_PARAMETER; + } else { + // + // Local dimension validation. + // + if ((ScreenDimensions->RightColumn > ScreenDimensions->LeftColumn) && + (ScreenDimensions->BottomRow > ScreenDimensions->TopRow) && + ((ScreenDimensions->RightColumn - ScreenDimensions->LeftColumn) > 2) && + ( + (ScreenDimensions->BottomRow - ScreenDimensions->TopRow) > STATUS_BAR_HEIGHT + + SCROLL_ARROW_HEIGHT * + 2 + + FRONT_PAGE_HEADER_HEIGHT + + FOOTER_HEIGHT + + 1 + ) + ) { + CopyMem (&gScreenDimensions, (VOID *) ScreenDimensions, sizeof (EFI_SCREEN_DESCRIPTOR)); + } else { + return EFI_INVALID_PARAMETER; + } + } + } + + gOptionBlockWidth = (CHAR16) ((gScreenDimensions.RightColumn - gScreenDimensions.LeftColumn) / 3); + gHelpBlockWidth = gOptionBlockWidth; + gPromptBlockWidth = gOptionBlockWidth; + + // + // Initialize the strings for the browser, upon exit of the browser, the strings will be freed + // + InitializeBrowserStrings (); + + gFunctionKeySetting = DEFAULT_FUNCTION_KEY_SETTING; + gClassOfVfr = EFI_SETUP_APPLICATION_SUBCLASS; + + // + // Ensure we are in Text mode + // + if (gFirstIn) { + gFirstIn = FALSE; + gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK)); + DisableQuietBoot (); + } + + for (Index = 0; Index < HandleCount; Index++) { + Selection = AllocateZeroPool (sizeof (UI_MENU_SELECTION)); + ASSERT (Selection != NULL); + + Selection->Handle = Handles[Index]; + if (FormSetGuid != NULL) { + CopyMem (&Selection->FormSetGuid, FormSetGuid, sizeof (EFI_GUID)); + Selection->FormId = FormId; + } + + do { + FormSet = AllocateZeroPool (sizeof (FORM_BROWSER_FORMSET)); + ASSERT (FormSet != NULL); + + // + // Initialize internal data structures of FormSet + // + Status = InitializeFormSet (Selection->Handle, &Selection->FormSetGuid, FormSet); + if (EFI_ERROR (Status)) { + DestroyFormSet (FormSet); + break; + } + Selection->FormSet = FormSet; + + // + // Initialize current settings of Questions in this FormSet + // + Status = InitializeCurrentSetting (FormSet); + if (EFI_ERROR (Status)) { + DestroyFormSet (FormSet); + break; + } + + // + // Display this formset + // + gCurrentSelection = Selection; + + Status = SetupBrowser (Selection); + + gCurrentSelection = NULL; + DestroyFormSet (FormSet); + + if (EFI_ERROR (Status)) { + break; + } + + } while (Selection->Action == UI_ACTION_REFRESH_FORMSET); + + gBS->FreePool (Selection); + } + + if (ActionRequest != NULL) { + *ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE; + if (gResetRequired) { + *ActionRequest = EFI_BROWSER_ACTION_REQUEST_RESET; + } + } + + FreeBrowserStrings (); + + gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK)); + gST->ConOut->ClearScreen (gST->ConOut); + + return Status; +} + + +/** + This function is called by a callback handler to retrieve uncommitted state + data from the browser. + + @param This A pointer to the EFI_FORM_BROWSER2_PROTOCOL + instance. + @param ResultsDataSize A pointer to the size of the buffer associated + with ResultsData. + @param ResultsData A string returned from an IFR browser or + equivalent. The results string will have no + routing information in them. + @param RetrieveData A BOOLEAN field which allows an agent to retrieve + (if RetrieveData = TRUE) data from the uncommitted + browser state information or set (if RetrieveData + = FALSE) data in the uncommitted browser state + information. + @param VariableGuid An optional field to indicate the target variable + GUID name to use. + @param VariableName An optional field to indicate the target + human-readable variable name. + + @retval EFI_SUCCESS The results have been distributed or are awaiting + distribution. + @retval EFI_BUFFER_TOO_SMALL The ResultsDataSize specified was too small to + contain the results data. + +**/ +EFI_STATUS +EFIAPI +BrowserCallback ( + IN CONST EFI_FORM_BROWSER2_PROTOCOL *This, + IN OUT UINTN *ResultsDataSize, + IN OUT EFI_STRING ResultsData, + IN BOOLEAN RetrieveData, + IN CONST EFI_GUID *VariableGuid, OPTIONAL + IN CONST CHAR16 *VariableName OPTIONAL + ) +{ + EFI_STATUS Status; + LIST_ENTRY *Link; + FORMSET_STORAGE *Storage; + FORM_BROWSER_FORMSET *FormSet; + BOOLEAN Found; + CHAR16 *ConfigResp; + CHAR16 *StrPtr; + UINTN BufferSize; + UINTN TmpSize; + + if (ResultsDataSize == NULL || ResultsData == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (gCurrentSelection == NULL) { + return EFI_NOT_READY; + } + + Storage = NULL; + ConfigResp = NULL; + FormSet = gCurrentSelection->FormSet; + + // + // Find target storage + // + Link = GetFirstNode (&FormSet->StorageListHead); + if (IsNull (&FormSet->StorageListHead, Link)) { + return EFI_UNSUPPORTED; + } + + if (VariableGuid != NULL) { + // + // Try to find target storage + // + Found = FALSE; + while (!IsNull (&FormSet->StorageListHead, Link)) { + Storage = FORMSET_STORAGE_FROM_LINK (Link); + Link = GetNextNode (&FormSet->StorageListHead, Link); + + if (CompareGuid (&Storage->Guid, (EFI_GUID *) VariableGuid)) { + if (Storage->Type == EFI_HII_VARSTORE_BUFFER) { + // + // Buffer storage require both GUID and Name + // + if (VariableName == NULL) { + return EFI_NOT_FOUND; + } + + if (StrCmp (Storage->Name, (CHAR16 *) VariableName) != 0) { + continue; + } + } + Found = TRUE; + break; + } + } + + if (!Found) { + return EFI_NOT_FOUND; + } + } else { + // + // GUID/Name is not specified, take the first storage in FormSet + // + Storage = FORMSET_STORAGE_FROM_LINK (Link); + } + + if (RetrieveData) { + // + // Skip if there is no RequestElement + // + if (Storage->ElementCount == 0) { + return EFI_SUCCESS; + } + + // + // Generate <ConfigResp> + // + Status = StorageToConfigResp (Storage, &ConfigResp); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Skip <ConfigHdr> and '&' to point to <ConfigBody> + // + StrPtr = ConfigResp + StrLen (Storage->ConfigHdr) + 1; + + BufferSize = StrSize (StrPtr); + if (*ResultsDataSize < BufferSize) { + *ResultsDataSize = BufferSize; + + gBS->FreePool (ConfigResp); + return EFI_BUFFER_TOO_SMALL; + } + + *ResultsDataSize = BufferSize; + CopyMem (ResultsData, StrPtr, BufferSize); + + gBS->FreePool (ConfigResp); + } else { + // + // Prepare <ConfigResp> + // + TmpSize = StrLen (ResultsData); + BufferSize = (TmpSize + StrLen (Storage->ConfigHdr) + 2) * sizeof (CHAR16); + ConfigResp = AllocateZeroPool (BufferSize); + ASSERT (ConfigResp != NULL); + + StrCpy (ConfigResp, Storage->ConfigHdr); + StrCat (ConfigResp, L"&"); + StrCat (ConfigResp, ResultsData); + + // + // Update Browser uncommited data + // + Status = ConfigRespToStorage (Storage, ConfigResp); + if (EFI_ERROR (Status)) { + return Status; + } + } + + return EFI_SUCCESS; +} + + +/** + Initialize Setup + + @param entry EFI_IMAGE_ENTRY_POINT) + + @retval EFI_SUCCESS Setup loaded. + @retval other Setup Error + +**/ +EFI_STATUS +EFIAPI +InitializeSetup ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + EFI_HANDLE HiiDriverHandle; + EFI_HII_PACKAGE_LIST_HEADER *PackageList; + + //@MT: EfiInitializeDriverLib (ImageHandle, SystemTable); + + // + // Locate required Hii relative protocols + // + Status = gBS->LocateProtocol ( + &gEfiHiiDatabaseProtocolGuid, + NULL, + (VOID **) &mHiiDatabase + ); + ASSERT_EFI_ERROR (Status); + + Status = gBS->LocateProtocol ( + &gEfiHiiStringProtocolGuid, + NULL, + (VOID **) &mHiiString + ); + ASSERT_EFI_ERROR (Status); + + Status = gBS->LocateProtocol ( + &gEfiHiiConfigRoutingProtocolGuid, + NULL, + (VOID **) &mHiiConfigRouting + ); + ASSERT_EFI_ERROR (Status); + + // + // Publish our HII data + // + Status = HiiLibCreateHiiDriverHandle (&HiiDriverHandle); + ASSERT_EFI_ERROR (Status); + + PackageList = PreparePackageList (1, &gSetupBrowserGuid, SetupBrowserStrings); + ASSERT (PackageList != NULL); + Status = mHiiDatabase->NewPackageList ( + mHiiDatabase, + PackageList, + HiiDriverHandle, + &gHiiHandle + ); + ASSERT_EFI_ERROR (Status); + + // + // Initialize Driver private data + // + gFirstIn = TRUE; + BannerData = AllocateZeroPool (sizeof (BANNER_DATA)); + ASSERT (BannerData != NULL); + + // + // Install FormBrowser2 protocol + // + mPrivateData.Handle = NULL; + Status = gBS->InstallProtocolInterface ( + &mPrivateData.Handle, + &gEfiFormBrowser2ProtocolGuid, + EFI_NATIVE_INTERFACE, + &mPrivateData.FormBrowser2 + ); + ASSERT_EFI_ERROR (Status); + + // + // Install Print protocol + // + Status = gBS->InstallProtocolInterface ( + &mPrivateData.Handle, + &gEfiPrintProtocolGuid, + EFI_NATIVE_INTERFACE, + &mPrivateData.Print + ); + + return Status; +} + + +/** + Create a new string in HII Package List. + + @param String The String to be added + @param HiiHandle The package list in the HII database to insert the + specified string. + + @return The output string. + +**/ +EFI_STRING_ID +NewString ( + IN CHAR16 *String, + IN EFI_HII_HANDLE HiiHandle + ) +{ + EFI_STRING_ID StringId; + EFI_STATUS Status; + + StringId = 0; + Status = IfrLibNewString (HiiHandle, &StringId, String); + ASSERT_EFI_ERROR (Status); + + return StringId; +} + + +/** + Delete a string from HII Package List. + + @param StringId Id of the string in HII database. + @param HiiHandle The HII package list handle. + + @retval EFI_SUCCESS The string was deleted successfully. + +**/ +EFI_STATUS +DeleteString ( + IN EFI_STRING_ID StringId, + IN EFI_HII_HANDLE HiiHandle + ) +{ + CHAR16 NullChar; + + NullChar = CHAR_NULL; + return IfrLibSetString (HiiHandle, StringId, &NullChar); +} + + +/** + Get the string based on the StringId and HII Package List Handle. + + @param Token The String's ID. + @param HiiHandle The package list in the HII database to search for + the specified string. + + @return The output string. + +**/ +CHAR16 * +GetToken ( + IN EFI_STRING_ID Token, + IN EFI_HII_HANDLE HiiHandle + ) +{ + EFI_STATUS Status; + CHAR16 *String; + UINTN BufferLength; + + // + // Set default string size assumption at no more than 256 bytes + // + BufferLength = 0x100; + String = AllocateZeroPool (BufferLength); + ASSERT (String != NULL); + + Status = IfrLibGetString (HiiHandle, Token, String, &BufferLength); + + if (Status == EFI_BUFFER_TOO_SMALL) { + gBS->FreePool (String); + String = AllocateZeroPool (BufferLength); + ASSERT (String != NULL); + + Status = IfrLibGetString (HiiHandle, Token, String, &BufferLength); + } + ASSERT_EFI_ERROR (Status); + + return String; +} + + +/** + Allocate new memory and then copy the Unicode string Source to Destination. + + @param Dest Location to copy string + @param Src String to copy + + @return NONE + +**/ +VOID +NewStringCpy ( + IN OUT CHAR16 **Dest, + IN CHAR16 *Src + ) +{ + SafeFreePool (*Dest); + *Dest = AllocateCopyPool (StrSize (Src), Src); + ASSERT (*Dest != NULL); +} + + +/** + Allocate new memory and concatinate Source on the end of Destination. + + @param Dest String to added to the end of. + @param Src String to concatinate. + + @return NONE + +**/ +VOID +NewStringCat ( + IN OUT CHAR16 **Dest, + IN CHAR16 *Src + ) +{ + CHAR16 *NewString; + UINTN TmpSize; + + if (*Dest == NULL) { + NewStringCpy (Dest, Src); + return; + } + + TmpSize = StrSize (*Dest); + NewString = AllocateZeroPool (TmpSize + StrSize (Src) - 1); + ASSERT (NewString != NULL); + + StrCpy (NewString, *Dest); + StrCat (NewString, Src); + + gBS->FreePool (*Dest); + *Dest = NewString; +} + + +/** + Synchronize Storage's Edit copy to Shadow copy. + + @param Storage The Storage to be synchronized. + + @return NONE + +**/ +VOID +SynchronizeStorage ( + IN FORMSET_STORAGE *Storage + ) +{ + LIST_ENTRY *Link; + NAME_VALUE_NODE *Node; + + switch (Storage->Type) { + case EFI_HII_VARSTORE_BUFFER: + CopyMem (Storage->Buffer, Storage->EditBuffer, Storage->Size); + break; + + case EFI_HII_VARSTORE_NAME_VALUE: + Link = GetFirstNode (&Storage->NameValueListHead); + while (!IsNull (&Storage->NameValueListHead, Link)) { + Node = NAME_VALUE_NODE_FROM_LINK (Link); + + NewStringCpy (&Node->Value, Node->EditValue); + + Link = GetNextNode (&Storage->NameValueListHead, Link); + } + break; + + case EFI_HII_VARSTORE_EFI_VARIABLE: + default: + break; + } +} + + +/** + Get Value for given Name from a NameValue Storage. + + @param Storage The NameValue Storage. + @param Name The Name. + @param Value The retured Value. + + @retval EFI_SUCCESS Value found for given Name. + @retval EFI_NOT_FOUND No such Name found in NameValue storage. + +**/ +EFI_STATUS +GetValueByName ( + IN FORMSET_STORAGE *Storage, + IN CHAR16 *Name, + IN OUT CHAR16 **Value + ) +{ + LIST_ENTRY *Link; + NAME_VALUE_NODE *Node; + + *Value = NULL; + + Link = GetFirstNode (&Storage->NameValueListHead); + while (!IsNull (&Storage->NameValueListHead, Link)) { + Node = NAME_VALUE_NODE_FROM_LINK (Link); + + if (StrCmp (Name, Node->Name) == 0) { + NewStringCpy (Value, Node->EditValue); + return EFI_SUCCESS; + } + + Link = GetNextNode (&Storage->NameValueListHead, Link); + } + + return EFI_NOT_FOUND; +} + + +/** + Set Value of given Name in a NameValue Storage. + + @param Storage The NameValue Storage. + @param Name The Name. + @param Value The Value to set. + + @retval EFI_SUCCESS Value found for given Name. + @retval EFI_NOT_FOUND No such Name found in NameValue storage. + +**/ +EFI_STATUS +SetValueByName ( + IN FORMSET_STORAGE *Storage, + IN CHAR16 *Name, + IN CHAR16 *Value + ) +{ + LIST_ENTRY *Link; + NAME_VALUE_NODE *Node; + + Link = GetFirstNode (&Storage->NameValueListHead); + while (!IsNull (&Storage->NameValueListHead, Link)) { + Node = NAME_VALUE_NODE_FROM_LINK (Link); + + if (StrCmp (Name, Node->Name) == 0) { + SafeFreePool (Node->EditValue); + Node->EditValue = AllocateCopyPool (StrSize (Value), Value); + ASSERT (Node->EditValue != NULL); + return EFI_SUCCESS; + } + + Link = GetNextNode (&Storage->NameValueListHead, Link); + } + + return EFI_NOT_FOUND; +} + + +/** + Convert setting of Buffer Storage or NameValue Storage to <ConfigResp>. + + @param Storage The Storage to be conveted. + @param ConfigResp The returned <ConfigResp>. + + @retval EFI_SUCCESS Convert success. + @retval EFI_INVALID_PARAMETER Incorrect storage type. + +**/ +EFI_STATUS +StorageToConfigResp ( + IN FORMSET_STORAGE *Storage, + IN CHAR16 **ConfigResp + ) +{ + EFI_STATUS Status; + EFI_STRING Progress; + LIST_ENTRY *Link; + NAME_VALUE_NODE *Node; + + Status = EFI_SUCCESS; + + switch (Storage->Type) { + case EFI_HII_VARSTORE_BUFFER: + Status = mHiiConfigRouting->BlockToConfig ( + mHiiConfigRouting, + Storage->ConfigRequest, + Storage->EditBuffer, + Storage->Size, + ConfigResp, + &Progress + ); + break; + + case EFI_HII_VARSTORE_NAME_VALUE: + *ConfigResp = NULL; + NewStringCat (ConfigResp, Storage->ConfigHdr); + + Link = GetFirstNode (&Storage->NameValueListHead); + while (!IsNull (&Storage->NameValueListHead, Link)) { + Node = NAME_VALUE_NODE_FROM_LINK (Link); + + NewStringCat (ConfigResp, L"&"); + NewStringCat (ConfigResp, Node->Name); + NewStringCat (ConfigResp, L"="); + NewStringCat (ConfigResp, Node->EditValue); + + Link = GetNextNode (&Storage->NameValueListHead, Link); + } + break; + + case EFI_HII_VARSTORE_EFI_VARIABLE: + default: + Status = EFI_INVALID_PARAMETER; + break; + } + + return Status; +} + + +/** + Convert <ConfigResp> to settings in Buffer Storage or NameValue Storage. + + @param Storage The Storage to receive the settings. + @param ConfigResp The <ConfigResp> to be converted. + + @retval EFI_SUCCESS Convert success. + @retval EFI_INVALID_PARAMETER Incorrect storage type. + +**/ +EFI_STATUS +ConfigRespToStorage ( + IN FORMSET_STORAGE *Storage, + IN CHAR16 *ConfigResp + ) +{ + EFI_STATUS Status; + EFI_STRING Progress; + UINTN BufferSize; + CHAR16 *StrPtr; + CHAR16 *Name; + CHAR16 *Value; + + Status = EFI_SUCCESS; + + switch (Storage->Type) { + case EFI_HII_VARSTORE_BUFFER: + BufferSize = Storage->Size; + Status = mHiiConfigRouting->ConfigToBlock ( + mHiiConfigRouting, + ConfigResp, + Storage->EditBuffer, + &BufferSize, + &Progress + ); + break; + + case EFI_HII_VARSTORE_NAME_VALUE: + StrPtr = StrStr (ConfigResp, L"&"); + while (StrPtr != NULL) { + // + // Skip '&' + // + StrPtr = StrPtr + 1; + Name = StrPtr; + StrPtr = StrStr (StrPtr, L"="); + if (StrPtr == NULL) { + break; + } + *StrPtr = 0; + + // + // Skip '=' + // + StrPtr = StrPtr + 1; + Value = StrPtr; + StrPtr = StrStr (StrPtr, L"&"); + if (StrPtr != NULL) { + *StrPtr = 0; + } + SetValueByName (Storage, Name, Value); + } + break; + + case EFI_HII_VARSTORE_EFI_VARIABLE: + default: + Status = EFI_INVALID_PARAMETER; + break; + } + + return Status; +} + + +/** + Get Question's current Value. + + @param FormSet FormSet data structure. + @param Form Form data structure. + @param Question Question to be initialized. + @param Cached TRUE: get from Edit copy FALSE: get from original + Storage + + @retval EFI_SUCCESS The function completed successfully. + +**/ +EFI_STATUS +GetQuestionValue ( + IN FORM_BROWSER_FORMSET *FormSet, + IN FORM_BROWSER_FORM *Form, + IN OUT FORM_BROWSER_STATEMENT *Question, + IN BOOLEAN Cached + ) +{ + EFI_STATUS Status; + BOOLEAN Enabled; + BOOLEAN Pending; + UINT8 *Dst; + UINTN StorageWidth; + EFI_TIME EfiTime; + FORMSET_STORAGE *Storage; + EFI_IFR_TYPE_VALUE *QuestionValue; + CHAR16 *ConfigRequest; + CHAR16 *Progress; + CHAR16 *Result; + CHAR16 *Value; + UINTN Length; + BOOLEAN IsBufferStorage; + BOOLEAN IsString; + + Status = EFI_SUCCESS; + + // + // Statement don't have storage, skip them + // + if (Question->QuestionId == 0) { + return Status; + } + + // + // Question value is provided by an Expression, evaluate it + // + if (Question->ValueExpression != NULL) { + Status = EvaluateExpression (FormSet, Form, Question->ValueExpression); + if (!EFI_ERROR (Status)) { + CopyMem (&Question->HiiValue, &Question->ValueExpression->Result, sizeof (EFI_HII_VALUE)); + } + return Status; + } + + // + // Question value is provided by RTC + // + Storage = Question->Storage; + QuestionValue = &Question->HiiValue.Value; + if (Storage == NULL) { + // + // It's a Question without storage, or RTC date/time + // + if (Question->Operand == EFI_IFR_DATE_OP || Question->Operand == EFI_IFR_TIME_OP) { + // + // Date and time define the same Flags bit + // + switch (Question->Flags & EFI_QF_DATE_STORAGE) { + case QF_DATE_STORAGE_TIME: + Status = gRT->GetTime (&EfiTime, NULL); + break; + + case QF_DATE_STORAGE_WAKEUP: + Status = gRT->GetWakeupTime (&Enabled, &Pending, &EfiTime); + break; + + case QF_DATE_STORAGE_NORMAL: + default: + // + // For date/time without storage + // + return EFI_SUCCESS; + } + + if (EFI_ERROR (Status)) { + return Status; + } + + if (Question->Operand == EFI_IFR_DATE_OP) { + QuestionValue->date.Year = EfiTime.Year; + QuestionValue->date.Month = EfiTime.Month; + QuestionValue->date.Day = EfiTime.Day; + } else { + QuestionValue->time.Hour = EfiTime.Hour; + QuestionValue->time.Minute = EfiTime.Minute; + QuestionValue->time.Second = EfiTime.Second; + } + } + + return EFI_SUCCESS; + } + + // + // Question value is provided by EFI variable + // + StorageWidth = Question->StorageWidth; + if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) { + if (Question->BufferValue != NULL) { + Dst = Question->BufferValue; + } else { + Dst = (UINT8 *) QuestionValue; + } + + Status = gRT->GetVariable ( + Question->VariableName, + &Storage->Guid, + NULL, + &StorageWidth, + Dst + ); + // + // Always return success, even this EFI variable doesn't exist + // + return EFI_SUCCESS; + } + + // + // Question Value is provided by Buffer Storage or NameValue Storage + // + if (Question->BufferValue != NULL) { + // + // This Question is password or orderedlist + // + Dst = Question->BufferValue; + } else { + // + // Other type of Questions + // + Dst = (UINT8 *) &Question->HiiValue.Value; + } + + IsBufferStorage = (BOOLEAN) ((Storage->Type == EFI_HII_VARSTORE_BUFFER) ? TRUE : FALSE); + IsString = (BOOLEAN) ((Question->HiiValue.Type == EFI_IFR_TYPE_STRING) ? TRUE : FALSE); + if (Cached) { + if (IsBufferStorage) { + // + // Copy from storage Edit buffer + // + CopyMem (Dst, Storage->EditBuffer + Question->VarStoreInfo.VarOffset, StorageWidth); + } else { + Status = GetValueByName (Storage, Question->VariableName, &Value); + if (EFI_ERROR (Status)) { + return Status; + } + + if (IsString) { + StrCpy ((CHAR16 *) Dst, Value); + } else { + Status = R8_HexStringToBuf (Dst, &StorageWidth, Value, NULL); + } + + gBS->FreePool (Value); + } + } else { + // + // Request current settings from Configuration Driver + // + if (FormSet->ConfigAccess == NULL) { + return EFI_NOT_FOUND; + } + + // + // <ConfigRequest> ::= <ConfigHdr> + <BlockName> || + // <ConfigHdr> + "&" + <VariableName> + // + if (IsBufferStorage) { + Length = StrLen (Storage->ConfigHdr); + Length += StrLen (Question->BlockName); + } else { + Length = StrLen (Storage->ConfigHdr); + Length += StrLen (Question->VariableName) + 1; + } + ConfigRequest = AllocateZeroPool ((Length + 1) * sizeof (CHAR16)); + ASSERT (ConfigRequest != NULL); + + StrCpy (ConfigRequest, Storage->ConfigHdr); + if (IsBufferStorage) { + StrCat (ConfigRequest, Question->BlockName); + } else { + StrCat (ConfigRequest, L"&"); + StrCat (ConfigRequest, Question->VariableName); + } + + Status = FormSet->ConfigAccess->ExtractConfig ( + FormSet->ConfigAccess, + ConfigRequest, + &Progress, + &Result + ); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Skip <ConfigRequest> + // + Value = Result + Length; + if (IsBufferStorage) { + // + // Skip "&VALUE" + // + Value = Value + 6; + } + if (*Value != '=') { + gBS->FreePool (Result); + return EFI_NOT_FOUND; + } + // + // Skip '=', point to value + // + Value = Value + 1; + if (!IsBufferStorage && IsString) { + StrCpy ((CHAR16 *) Dst, Value); + } else { + Status = R8_HexStringToBuf (Dst, &StorageWidth, Value, NULL); + if (EFI_ERROR (Status)) { + gBS->FreePool (Result); + return Status; + } + } + + // + // Synchronize Edit Buffer + // + if (IsBufferStorage) { + CopyMem (Storage->EditBuffer + Question->VarStoreInfo.VarOffset, Dst, StorageWidth); + } else { + SetValueByName (Storage, Question->VariableName, Value); + } + gBS->FreePool (Result); + } + + return Status; +} + + +/** + Save Question Value to edit copy(cached) or Storage(uncached). + + @param FormSet FormSet data structure. + @param Form Form data structure. + @param Question Pointer to the Question. + @param Cached TRUE: set to Edit copy FALSE: set to original + Storage + + @retval EFI_SUCCESS The function completed successfully. + +**/ +EFI_STATUS +SetQuestionValue ( + IN FORM_BROWSER_FORMSET *FormSet, + IN FORM_BROWSER_FORM *Form, + IN OUT FORM_BROWSER_STATEMENT *Question, + IN BOOLEAN Cached + ) +{ + EFI_STATUS Status; + BOOLEAN Enabled; + BOOLEAN Pending; + UINT8 *Src; + EFI_TIME EfiTime; + UINTN BufferLen; + UINTN StorageWidth; + FORMSET_STORAGE *Storage; + EFI_IFR_TYPE_VALUE *QuestionValue; + CHAR16 *ConfigResp; + CHAR16 *Progress; + CHAR16 *Value; + UINTN Length; + BOOLEAN IsBufferStorage; + BOOLEAN IsString; + + Status = EFI_SUCCESS; + + // + // Statement don't have storage, skip them + // + if (Question->QuestionId == 0) { + return Status; + } + + // + // If Question value is provided by an Expression, then it is read only + // + if (Question->ValueExpression != NULL) { + return Status; + } + + // + // Question value is provided by RTC + // + Storage = Question->Storage; + QuestionValue = &Question->HiiValue.Value; + if (Storage == NULL) { + // + // It's a Question without storage, or RTC date/time + // + if (Question->Operand == EFI_IFR_DATE_OP || Question->Operand == EFI_IFR_TIME_OP) { + // + // Date and time define the same Flags bit + // + switch (Question->Flags & EFI_QF_DATE_STORAGE) { + case QF_DATE_STORAGE_TIME: + Status = gRT->GetTime (&EfiTime, NULL); + break; + + case QF_DATE_STORAGE_WAKEUP: + Status = gRT->GetWakeupTime (&Enabled, &Pending, &EfiTime); + break; + + case QF_DATE_STORAGE_NORMAL: + default: + // + // For date/time without storage + // + return EFI_SUCCESS; + } + + if (EFI_ERROR (Status)) { + return Status; + } + + if (Question->Operand == EFI_IFR_DATE_OP) { + EfiTime.Year = QuestionValue->date.Year; + EfiTime.Month = QuestionValue->date.Month; + EfiTime.Day = QuestionValue->date.Day; + } else { + EfiTime.Hour = QuestionValue->time.Hour; + EfiTime.Minute = QuestionValue->time.Minute; + EfiTime.Second = QuestionValue->time.Second; + } + + if ((Question->Flags & EFI_QF_DATE_STORAGE) == QF_DATE_STORAGE_TIME) { + Status = gRT->SetTime (&EfiTime); + } else { + Status = gRT->SetWakeupTime (TRUE, &EfiTime); + } + } + + return Status; + } + + // + // Question value is provided by EFI variable + // + StorageWidth = Question->StorageWidth; + if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) { + if (Question->BufferValue != NULL) { + Src = Question->BufferValue; + } else { + Src = (UINT8 *) QuestionValue; + } + + Status = gRT->SetVariable ( + Question->VariableName, + &Storage->Guid, + Storage->Attributes, + StorageWidth, + Src + ); + return Status; + } + + // + // Question Value is provided by Buffer Storage or NameValue Storage + // + if (Question->BufferValue != NULL) { + Src = Question->BufferValue; + } else { + Src = (UINT8 *) &Question->HiiValue.Value; + } + + IsBufferStorage = (BOOLEAN) ((Storage->Type == EFI_HII_VARSTORE_BUFFER) ? TRUE : FALSE); + IsString = (BOOLEAN) ((Question->HiiValue.Type == EFI_IFR_TYPE_STRING) ? TRUE : FALSE); + if (IsBufferStorage) { + // + // Copy to storage edit buffer + // + CopyMem (Storage->EditBuffer + Question->VarStoreInfo.VarOffset, Src, StorageWidth); + } else { + if (IsString) { + Value = NULL; + NewStringCpy (&Value, (CHAR16 *) Src); + } else { + BufferLen = (StorageWidth * 2 + 1) * sizeof (CHAR16); + Value = AllocateZeroPool (BufferLen); + ASSERT (Value != NULL); + R8_BufToHexString (Value, &BufferLen, Src, StorageWidth); + } + + Status = SetValueByName (Storage, Question->VariableName, Value); + gBS->FreePool (Value); + } + + if (!Cached) { + // + // <ConfigResp> ::= <ConfigHdr> + <BlockName> + "&VALUE=" + "<HexCh>StorageWidth * 2" || + // <ConfigHdr> + "&" + <VariableName> + "=" + "<HexCh>StorageWidth * 2" + // + if (IsBufferStorage) { + Length = StrLen (Question->BlockName) + 7; + } else { + Length = StrLen (Question->VariableName) + 2; + } + if (!IsBufferStorage && IsString) { + Length += StrLen ((CHAR16 *) Src); + } else { + Length += (StorageWidth * 2); + } + ConfigResp = AllocateZeroPool ((StrLen (Storage->ConfigHdr) + Length + 1) * sizeof (CHAR16)); + ASSERT (ConfigResp != NULL); + + StrCpy (ConfigResp, Storage->ConfigHdr); + if (IsBufferStorage) { + StrCat (ConfigResp, Question->BlockName); + StrCat (ConfigResp, L"&VALUE="); + } else { + StrCat (ConfigResp, L"&"); + StrCat (ConfigResp, Question->VariableName); + StrCat (ConfigResp, L"="); + } + + Value = ConfigResp + StrLen (ConfigResp); + if (!IsBufferStorage && IsString) { + StrCpy (Value, (CHAR16 *) Src); + } else { + BufferLen = (StorageWidth * 2 + 1) * sizeof (CHAR16); + R8_BufToHexString (Value, &BufferLen, Src, StorageWidth); + } + + // + // Submit Question Value to Configuration Driver + // + if (FormSet->ConfigAccess != NULL) { + Status = FormSet->ConfigAccess->RouteConfig ( + FormSet->ConfigAccess, + ConfigResp, + &Progress + ); + if (EFI_ERROR (Status)) { + gBS->FreePool (ConfigResp); + return Status; + } + } + gBS->FreePool (ConfigResp); + + // + // Synchronize shadow Buffer + // + SynchronizeStorage (Storage); + } + + return Status; +} + + +/** + Perform inconsistent check for a Form. + + @param FormSet FormSet data structure. + @param Form Form data structure. + @param Question The Question to be validated. + @param Type Validation type: InConsistent or NoSubmit + + @retval EFI_SUCCESS Form validation pass. + @retval other Form validation failed. + +**/ +EFI_STATUS +ValidateQuestion ( + IN FORM_BROWSER_FORMSET *FormSet, + IN FORM_BROWSER_FORM *Form, + IN FORM_BROWSER_STATEMENT *Question, + IN UINTN Type + ) +{ + EFI_STATUS Status; + LIST_ENTRY *Link; + LIST_ENTRY *ListHead; + EFI_STRING PopUp; + EFI_INPUT_KEY Key; + FORM_EXPRESSION *Expression; + + if (Type == EFI_HII_EXPRESSION_INCONSISTENT_IF) { + ListHead = &Question->InconsistentListHead; + } else if (Type == EFI_HII_EXPRESSION_NO_SUBMIT_IF) { + ListHead = &Question->NoSubmitListHead; + } else { + return EFI_UNSUPPORTED; + } + + Link = GetFirstNode (ListHead); + while (!IsNull (ListHead, Link)) { + Expression = FORM_EXPRESSION_FROM_LINK (Link); + + // + // Evaluate the expression + // + Status = EvaluateExpression (FormSet, Form, Expression); + if (EFI_ERROR (Status)) { + return Status; + } + + if (Expression->Result.Value.b) { + // + // Condition meet, show up error message + // + if (Expression->Error != 0) { + PopUp = GetToken (Expression->Error, FormSet->HiiHandle); + do { + CreateDialog (4, TRUE, 0, NULL, &Key, gEmptyString, PopUp, gPressEnter, gEmptyString); + } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN); + gBS->FreePool (PopUp); + } + + return EFI_NOT_READY; + } + + Link = GetNextNode (ListHead, Link); + } + + return EFI_SUCCESS; +} + + +/** + Perform NoSubmit check for a Form. + + @param FormSet FormSet data structure. + @param Form Form data structure. + + @retval EFI_SUCCESS Form validation pass. + @retval other Form validation failed. + +**/ +EFI_STATUS +NoSubmitCheck ( + IN FORM_BROWSER_FORMSET *FormSet, + IN FORM_BROWSER_FORM *Form + ) +{ + EFI_STATUS Status; + LIST_ENTRY *Link; + FORM_BROWSER_STATEMENT *Question; + + Link = GetFirstNode (&Form->StatementListHead); + while (!IsNull (&Form->StatementListHead, Link)) { + Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link); + + Status = ValidateQuestion (FormSet, Form, Question, EFI_HII_EXPRESSION_NO_SUBMIT_IF); + if (EFI_ERROR (Status)) { + return Status; + } + + Link = GetNextNode (&Form->StatementListHead, Link); + } + + return EFI_SUCCESS; +} + + +/** + Submit a Form. + + @param FormSet FormSet data structure. + @param Form Form data structure. + + @retval EFI_SUCCESS The function completed successfully. + +**/ +EFI_STATUS +SubmitForm ( + IN FORM_BROWSER_FORMSET *FormSet, + IN FORM_BROWSER_FORM *Form + ) +{ + EFI_STATUS Status; + LIST_ENTRY *Link; + EFI_STRING ConfigResp; + EFI_STRING Progress; + FORMSET_STORAGE *Storage; + + // + // Validate the Form by NoSubmit check + // + Status = NoSubmitCheck (FormSet, Form); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Submit Buffer storage or Name/Value storage + // + Link = GetFirstNode (&FormSet->StorageListHead); + while (!IsNull (&FormSet->StorageListHead, Link)) { + Storage = FORMSET_STORAGE_FROM_LINK (Link); + Link = GetNextNode (&FormSet->StorageListHead, Link); + + if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) { + continue; + } + + // + // Skip if there is no RequestElement + // + if (Storage->ElementCount == 0) { + continue; + } + + // + // Prepare <ConfigResp> + // + Status = StorageToConfigResp (Storage, &ConfigResp); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Send <ConfigResp> to Configuration Driver + // + if (FormSet->ConfigAccess != NULL) { + Status = FormSet->ConfigAccess->RouteConfig ( + FormSet->ConfigAccess, + ConfigResp, + &Progress + ); + if (EFI_ERROR (Status)) { + gBS->FreePool (ConfigResp); + return Status; + } + } + gBS->FreePool (ConfigResp); + + // + // Config success, update storage shadow Buffer + // + SynchronizeStorage (Storage); + } + + gNvUpdateRequired = FALSE; + + return EFI_SUCCESS; +} + + +/** + Reset Question to its default value. + + @param FormSet FormSet data structure. + @param DefaultId The Class of the default. + + @retval EFI_SUCCESS Question is reset to default value. + +**/ +EFI_STATUS +GetQuestionDefault ( + IN FORM_BROWSER_FORMSET *FormSet, + IN FORM_BROWSER_FORM *Form, + IN FORM_BROWSER_STATEMENT *Question, + IN UINT16 DefaultId + ) +{ + EFI_STATUS Status; + LIST_ENTRY *Link; + QUESTION_DEFAULT *Default; + QUESTION_OPTION *Option; + EFI_HII_VALUE *HiiValue; + UINT8 Index; + + Status = EFI_SUCCESS; + + // + // Statement don't have storage, skip them + // + if (Question->QuestionId == 0) { + return Status; + } + + // + // There are three ways to specify default value for a Question: + // 1, use nested EFI_IFR_DEFAULT (highest priority) + // 2, set flags of EFI_ONE_OF_OPTION (provide Standard and Manufacturing default) + // 3, set flags of EFI_IFR_CHECKBOX (provide Standard and Manufacturing default) (lowest priority) + // + HiiValue = &Question->HiiValue; + + // + // EFI_IFR_DEFAULT has highest priority + // + if (!IsListEmpty (&Question->DefaultListHead)) { + Link = GetFirstNode (&Question->DefaultListHead); + while (!IsNull (&Question->DefaultListHead, Link)) { + Default = QUESTION_DEFAULT_FROM_LINK (Link); + + if (Default->DefaultId == DefaultId) { + if (Default->ValueExpression != NULL) { + // + // Default is provided by an Expression, evaluate it + // + Status = EvaluateExpression (FormSet, Form, Default->ValueExpression); + if (EFI_ERROR (Status)) { + return Status; + } + + CopyMem (HiiValue, &Default->ValueExpression->Result, sizeof (EFI_HII_VALUE)); + } else { + // + // Default value is embedded in EFI_IFR_DEFAULT + // + CopyMem (HiiValue, &Default->Value, sizeof (EFI_HII_VALUE)); + } + + return EFI_SUCCESS; + } + + Link = GetNextNode (&Question->DefaultListHead, Link); + } + } + + // + // EFI_ONE_OF_OPTION + // + if ((Question->Operand == EFI_IFR_ONE_OF_OP) && !IsListEmpty (&Question->OptionListHead)) { + if (DefaultId <= EFI_HII_DEFAULT_CLASS_MANUFACTURING) { + // + // OneOfOption could only provide Standard and Manufacturing default + // + Link = GetFirstNode (&Question->OptionListHead); + while (!IsNull (&Question->OptionListHead, Link)) { + Option = QUESTION_OPTION_FROM_LINK (Link); + + if (((DefaultId == EFI_HII_DEFAULT_CLASS_STANDARD) && (Option->Flags & EFI_IFR_OPTION_DEFAULT)) || + ((DefaultId == EFI_HII_DEFAULT_CLASS_MANUFACTURING) && (Option->Flags & EFI_IFR_OPTION_DEFAULT_MFG)) + ) { + CopyMem (HiiValue, &Option->Value, sizeof (EFI_HII_VALUE)); + + return EFI_SUCCESS; + } + + Link = GetNextNode (&Question->OptionListHead, Link); + } + } + } + + // + // EFI_IFR_CHECKBOX - lowest priority + // + if (Question->Operand == EFI_IFR_CHECKBOX_OP) { + if (DefaultId <= EFI_HII_DEFAULT_CLASS_MANUFACTURING) { + // + // Checkbox could only provide Standard and Manufacturing default + // + if (((DefaultId == EFI_HII_DEFAULT_CLASS_STANDARD) && (Question->Flags & EFI_IFR_CHECKBOX_DEFAULT)) || + ((DefaultId == EFI_HII_DEFAULT_CLASS_MANUFACTURING) && (Question->Flags & EFI_IFR_CHECKBOX_DEFAULT_MFG)) + ) { + HiiValue->Value.b = TRUE; + } else { + HiiValue->Value.b = FALSE; + } + + return EFI_SUCCESS; + } + } + + // + // For Questions without default + // + switch (Question->Operand) { + case EFI_IFR_NUMERIC_OP: + // + // Take minimal value as numeric's default value + // + HiiValue->Value.u64 = Question->Minimum; + break; + + case EFI_IFR_ONE_OF_OP: + // + // Take first oneof option as oneof's default value + // + Link = GetFirstNode (&Question->OptionListHead); + if (!IsNull (&Question->OptionListHead, Link)) { + Option = QUESTION_OPTION_FROM_LINK (Link); + CopyMem (HiiValue, &Option->Value, sizeof (EFI_HII_VALUE)); + } + break; + + case EFI_IFR_ORDERED_LIST_OP: + // + // Take option sequence in IFR as ordered list's default value + // + Index = 0; + Link = GetFirstNode (&Question->OptionListHead); + while (!IsNull (&Question->OptionListHead, Link)) { + Option = QUESTION_OPTION_FROM_LINK (Link); + + Question->BufferValue[Index] = Option->Value.Value.u8; + + Index++; + if (Index >= Question->MaxContainers) { + break; + } + + Link = GetNextNode (&Question->OptionListHead, Link); + } + break; + + default: + Status = EFI_NOT_FOUND; + break; + } + + return Status; +} + + +/** + Reset Questions in a Form to their default value. + + @param FormSet FormSet data structure. + @param Form The Form which to be reset. + @param DefaultId The Class of the default. + + @retval EFI_SUCCESS The function completed successfully. + +**/ +EFI_STATUS +ExtractFormDefault ( + IN FORM_BROWSER_FORMSET *FormSet, + IN FORM_BROWSER_FORM *Form, + IN UINT16 DefaultId + ) +{ + EFI_STATUS Status; + LIST_ENTRY *Link; + FORM_BROWSER_STATEMENT *Question; + + Link = GetFirstNode (&Form->StatementListHead); + while (!IsNull (&Form->StatementListHead, Link)) { + Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link); + Link = GetNextNode (&Form->StatementListHead, Link); + + // + // Reset Question to its default value + // + Status = GetQuestionDefault (FormSet, Form, Question, DefaultId); + if (EFI_ERROR (Status)) { + continue; + } + + // + // Synchronize Buffer storage's Edit buffer + // + if ((Question->Storage != NULL) && + (Question->Storage->Type != EFI_HII_VARSTORE_EFI_VARIABLE)) { + SetQuestionValue (FormSet, Form, Question, TRUE); + } + } + + return EFI_SUCCESS; +} + + +/** + Initialize Question's Edit copy from Storage. + + @param FormSet FormSet data structure. + @param Form Form data structure. + + @retval EFI_SUCCESS The function completed successfully. + +**/ +EFI_STATUS +LoadFormConfig ( + IN FORM_BROWSER_FORMSET *FormSet, + IN FORM_BROWSER_FORM *Form + ) +{ + EFI_STATUS Status; + LIST_ENTRY *Link; + FORM_BROWSER_STATEMENT *Question; + + Link = GetFirstNode (&Form->StatementListHead); + while (!IsNull (&Form->StatementListHead, Link)) { + Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link); + + // + // Initialize local copy of Value for each Question + // + Status = GetQuestionValue (FormSet, Form, Question, TRUE); + if (EFI_ERROR (Status)) { + return Status; + } + + Link = GetNextNode (&Form->StatementListHead, Link); + } + + return EFI_SUCCESS; +} + + +/** + Fill storage's edit copy with settings requested from Configuration Driver. + + @param FormSet FormSet data structure. + @param Storage Buffer Storage. + + @retval EFI_SUCCESS The function completed successfully. + +**/ +EFI_STATUS +LoadStorage ( + IN FORM_BROWSER_FORMSET *FormSet, + IN FORMSET_STORAGE *Storage + ) +{ + EFI_STATUS Status; + EFI_STRING Progress; + EFI_STRING Result; + CHAR16 *StrPtr; + + if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) { + return EFI_SUCCESS; + } + + if (FormSet->ConfigAccess == NULL) { + return EFI_NOT_FOUND; + } + + if (Storage->ElementCount == 0) { + // + // Skip if there is no RequestElement + // + return EFI_SUCCESS; + } + + // + // Request current settings from Configuration Driver + // + Status = FormSet->ConfigAccess->ExtractConfig ( + FormSet->ConfigAccess, + Storage->ConfigRequest, + &Progress, + &Result + ); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Convert Result from <ConfigAltResp> to <ConfigResp> + // + StrPtr = StrStr (Result, L"ALTCFG"); + if (StrPtr != NULL) { + *StrPtr = L'\0'; + } + + Status = ConfigRespToStorage (Storage, Result); + gBS->FreePool (Result); + return Status; +} + + +/** + Get current setting of Questions. + + @param FormSet FormSet data structure. + + @retval EFI_SUCCESS The function completed successfully. + +**/ +EFI_STATUS +InitializeCurrentSetting ( + IN OUT FORM_BROWSER_FORMSET *FormSet + ) +{ + LIST_ENTRY *Link; + FORMSET_STORAGE *Storage; + FORM_BROWSER_FORM *Form; + EFI_STATUS Status; + + // + // Extract default from IFR binary + // + Link = GetFirstNode (&FormSet->FormListHead); + while (!IsNull (&FormSet->FormListHead, Link)) { + Form = FORM_BROWSER_FORM_FROM_LINK (Link); + + Status = ExtractFormDefault (FormSet, Form, EFI_HII_DEFAULT_CLASS_STANDARD); + + Link = GetNextNode (&FormSet->FormListHead, Link); + } + + // + // Request current settings from Configuration Driver + // + Link = GetFirstNode (&FormSet->StorageListHead); + while (!IsNull (&FormSet->StorageListHead, Link)) { + Storage = FORMSET_STORAGE_FROM_LINK (Link); + + Status = LoadStorage (FormSet, Storage); + + // + // Now Edit Buffer is filled with default values(lower priority) and current + // settings(higher priority), sychronize it to shadow Buffer + // + if (!EFI_ERROR (Status)) { + SynchronizeStorage (Storage); + } + + Link = GetNextNode (&FormSet->StorageListHead, Link); + } + + return EFI_SUCCESS; +} + + +/** + Fetch the Ifr binary data of a FormSet. + + @param Handle PackageList Handle + @param FormSetGuid GUID of a formset. If not specified (NULL or zero + GUID), take the first FormSet found in package + list. + @param BinaryLength The length of the FormSet IFR binary. + @param BinaryData The buffer designed to receive the FormSet. + + @retval EFI_SUCCESS Buffer filled with the requested FormSet. + BufferLength was updated. + @retval EFI_INVALID_PARAMETER The handle is unknown. + @retval EFI_NOT_FOUND A form or FormSet on the requested handle cannot + be found with the requested FormId. + +**/ +EFI_STATUS +GetIfrBinaryData ( + IN EFI_HII_HANDLE Handle, + IN OUT EFI_GUID *FormSetGuid, + OUT UINTN *BinaryLength, + OUT UINT8 **BinaryData + ) +{ + EFI_STATUS Status; + EFI_HII_PACKAGE_LIST_HEADER *HiiPackageList; + UINTN BufferSize; + UINT8 *Package; + UINT8 *OpCodeData; + UINT32 Offset; + UINT32 Offset2; + BOOLEAN ReturnDefault; + UINT32 PackageListLength; + EFI_HII_PACKAGE_HEADER PackageHeader; + + OpCodeData = NULL; + Package = NULL; + ZeroMem (&PackageHeader, sizeof (EFI_HII_PACKAGE_HEADER));; + + // + // if FormSetGuid is NULL or zero GUID, return first FormSet in the package list + // + if (FormSetGuid == NULL || CompareGuid (FormSetGuid, &gZeroGuid)) { + ReturnDefault = TRUE; + } else { + ReturnDefault = FALSE; + } + + // + // Get HII PackageList + // + BufferSize = 0; + HiiPackageList = NULL; + Status = mHiiDatabase->ExportPackageLists (mHiiDatabase, Handle, &BufferSize, HiiPackageList); + if (Status == EFI_BUFFER_TOO_SMALL) { + HiiPackageList = AllocatePool (BufferSize); + ASSERT (HiiPackageList != NULL); + + Status = mHiiDatabase->ExportPackageLists (mHiiDatabase, Handle, &BufferSize, HiiPackageList); + } + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Get Form package from this HII package List + // + Offset = sizeof (EFI_HII_PACKAGE_LIST_HEADER); + Offset2 = 0; + CopyMem (&PackageListLength, &HiiPackageList->PackageLength, sizeof (UINT32)); + + while (Offset < PackageListLength) { + Package = ((UINT8 *) HiiPackageList) + Offset; + CopyMem (&PackageHeader, Package, sizeof (EFI_HII_PACKAGE_HEADER)); + + if (PackageHeader.Type == EFI_HII_PACKAGE_FORM) { + // + // Search FormSet in this Form Package + // + Offset2 = sizeof (EFI_HII_PACKAGE_HEADER); + while (Offset2 < PackageHeader.Length) { + OpCodeData = Package + Offset2; + + if (((EFI_IFR_OP_HEADER *) OpCodeData)->OpCode == EFI_IFR_FORM_SET_OP) { + // + // Check whether return default FormSet + // + if (ReturnDefault) { + break; + } + + // + // FormSet GUID is specified, check it + // + if (CompareGuid (FormSetGuid, (EFI_GUID *)(OpCodeData + sizeof (EFI_IFR_OP_HEADER)))) { + break; + } + } + + Offset2 += ((EFI_IFR_OP_HEADER *) OpCodeData)->Length; + } + + if (Offset2 < PackageHeader.Length) { + // + // Target formset found + // + break; + } + } + + Offset += PackageHeader.Length; + } + + if (Offset >= PackageListLength) { + // + // Form package not found in this Package List + // + gBS->FreePool (HiiPackageList); + return EFI_NOT_FOUND; + } + + if (ReturnDefault && FormSetGuid != NULL) { + // + // Return the default FormSet GUID + // + CopyMem (FormSetGuid, &((EFI_IFR_FORM_SET *) OpCodeData)->Guid, sizeof (EFI_GUID)); + } + + // + // To determine the length of a whole FormSet IFR binary, one have to parse all the Opcodes + // in this FormSet; So, here just simply copy the data from start of a FormSet to the end + // of the Form Package. + // + *BinaryLength = PackageHeader.Length - Offset2; + *BinaryData = AllocateCopyPool (*BinaryLength, OpCodeData); + + gBS->FreePool (HiiPackageList); + + if (*BinaryData == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + return EFI_SUCCESS; +} + + +/** + Initialize the internal data structure of a FormSet. + + @param Handle PackageList Handle + @param FormSetGuid GUID of a formset. If not specified (NULL or zero + GUID), take the first FormSet found in package + list. + @param FormSet FormSet data structure. + + @retval EFI_SUCCESS The function completed successfully. + @retval EFI_NOT_FOUND The specified FormSet could not be found. + +**/ +EFI_STATUS +InitializeFormSet ( + IN EFI_HII_HANDLE Handle, + IN OUT EFI_GUID *FormSetGuid, + OUT FORM_BROWSER_FORMSET *FormSet + ) +{ + EFI_STATUS Status; + EFI_HANDLE DriverHandle; + UINT16 Index; + + Status = GetIfrBinaryData (Handle, FormSetGuid, &FormSet->IfrBinaryLength, &FormSet->IfrBinaryData); + if (EFI_ERROR (Status)) { + return Status; + } + + FormSet->HiiHandle = Handle; + CopyMem (&FormSet->Guid, FormSetGuid, sizeof (EFI_GUID)); + + // + // Retrieve ConfigAccess Protocol associated with this HiiPackageList + // + Status = mHiiDatabase->GetPackageListHandle (mHiiDatabase, Handle, &DriverHandle); + if (EFI_ERROR (Status)) { + return Status; + } + FormSet->DriverHandle = DriverHandle; + Status = gBS->HandleProtocol ( + DriverHandle, + &gEfiHiiConfigAccessProtocolGuid, + (VOID **) &FormSet->ConfigAccess + ); + if (EFI_ERROR (Status)) { + // + // Configuration Driver don't attach ConfigAccess protocol to its HII package + // list, then there will be no configuration action required + // + FormSet->ConfigAccess = NULL; + } + + // + // Parse the IFR binary OpCodes + // + Status = ParseOpCodes (FormSet); + if (EFI_ERROR (Status)) { + return Status; + } + + gClassOfVfr = FormSet->SubClass; + if (gClassOfVfr == EFI_FRONT_PAGE_SUBCLASS) { + FrontPageHandle = FormSet->HiiHandle; + } + + // + // Match GUID to find out the function key setting. If match fail, use the default setting. + // + for (Index = 0; Index < sizeof (gFunctionKeySettingTable) / sizeof (FUNCTIION_KEY_SETTING); Index++) { + if (CompareGuid (&FormSet->Guid, &(gFunctionKeySettingTable[Index].FormSetGuid))) { + // + // Update the function key setting. + // + gFunctionKeySetting = gFunctionKeySettingTable[Index].KeySetting; + // + // Function key prompt can not be displayed if the function key has been disabled. + // + if ((gFunctionKeySetting & FUNCTION_ONE) != FUNCTION_ONE) { + gFunctionOneString = GetToken (STRING_TOKEN (EMPTY_STRING), gHiiHandle); + } + + if ((gFunctionKeySetting & FUNCTION_TWO) != FUNCTION_TWO) { + gFunctionTwoString = GetToken (STRING_TOKEN (EMPTY_STRING), gHiiHandle); + } + + if ((gFunctionKeySetting & FUNCTION_NINE) != FUNCTION_NINE) { + gFunctionNineString = GetToken (STRING_TOKEN (EMPTY_STRING), gHiiHandle); + } + + if ((gFunctionKeySetting & FUNCTION_TEN) != FUNCTION_TEN) { + gFunctionTenString = GetToken (STRING_TOKEN (EMPTY_STRING), gHiiHandle); + } + } + } + + return Status; +} |