-/** @file
-Copyright (c) 2007 - 2008, 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
- },
-};
-
-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;
-
- //
- // 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 = HiiLibPreparePackageList (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 = HiiLibNewString (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 HiiLibSetString (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 = HiiLibGetString (HiiHandle, Token, String, &BufferLength);
-
- if (Status == EFI_BUFFER_TOO_SMALL) {
- gBS->FreePool (String);
- String = AllocateZeroPool (BufferLength);
- ASSERT (String != NULL);
-
- Status = HiiLibGetString (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) {
- //
- // Convert Config String to Unicode String, e.g "0041004200430044" => "ABCD"
- //
- Length = StorageWidth + sizeof (CHAR16);
- Status = ConfigStringToUnicode ((CHAR16 *) Dst, &Length, Value);
- } else {
- Status = 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) {
- //
- // Convert Config String to Unicode String, e.g "0041004200430044" => "ABCD"
- //
- Length = StorageWidth + sizeof (CHAR16);
- Status = ConfigStringToUnicode ((CHAR16 *) Dst, &Length, Value);
- } else {
- Status = 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) {
- //
- // Convert Unicode String to Config String, e.g. "ABCD" => "0041004200430044"
- //
- Value = NULL;
- BufferLen = ((StrLen ((CHAR16 *) Src) * 4) + 1) * sizeof (CHAR16);
- Value = AllocateZeroPool (BufferLen);
- ASSERT (Value != NULL);
- Status = UnicodeToConfigString (Value, &BufferLen, (CHAR16 *) Src);
- ASSERT_EFI_ERROR (Status);
- } else {
- BufferLen = StorageWidth * 2 + 1;
- Value = AllocateZeroPool (BufferLen * sizeof (CHAR16));
- ASSERT (Value != NULL);
- BufToHexString (Value, &BufferLen, Src, StorageWidth);
- ToLower (Value);
- }
-
- Status = SetValueByName (Storage, Question->VariableName, Value);
- gBS->FreePool (Value);
- }
-
- if (!Cached) {
- //
- // <ConfigResp> ::= <ConfigHdr> + <BlockName> + "&VALUE=" + "<HexCh>StorageWidth * 2" ||
- // <ConfigHdr> + "&" + <VariableName> + "=" + "<string>"
- //
- if (IsBufferStorage) {
- Length = StrLen (Question->BlockName) + 7;
- } else {
- Length = StrLen (Question->VariableName) + 2;
- }
- if (!IsBufferStorage && IsString) {
- Length += (StrLen ((CHAR16 *) Src) * 4);
- } 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) {
- //
- // Convert Unicode String to Config String, e.g. "ABCD" => "0041004200430044"
- //
- BufferLen = ((StrLen ((CHAR16 *) Src) * 4) + 1) * sizeof (CHAR16);
- Status = UnicodeToConfigString (Value, &BufferLen, (CHAR16 *) Src);
- ASSERT_EFI_ERROR (Status);
- } else {
- BufferLen = StorageWidth * 2 + 1;
- BufToHexString (Value, &BufferLen, Src, StorageWidth);
- ToLower (Value);
- }
-
- //
- // 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;
-}
+/** @file\r
+Entry and initialization module for the browser.\r
+\r
+Copyright (c) 2007 - 2012, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "Setup.h"\r
+\r
+SETUP_DRIVER_PRIVATE_DATA mPrivateData = {\r
+ SETUP_DRIVER_SIGNATURE,\r
+ NULL,\r
+ {\r
+ SendForm,\r
+ BrowserCallback\r
+ },\r
+ {\r
+ SetScope,\r
+ RegisterHotKey,\r
+ RegiserExitHandler,\r
+ SaveReminder\r
+ }\r
+};\r
+\r
+EFI_HII_DATABASE_PROTOCOL *mHiiDatabase;\r
+EFI_HII_STRING_PROTOCOL *mHiiString;\r
+EFI_HII_CONFIG_ROUTING_PROTOCOL *mHiiConfigRouting;\r
+\r
+UINTN gBrowserContextCount = 0;\r
+LIST_ENTRY gBrowserContextList = INITIALIZE_LIST_HEAD_VARIABLE (gBrowserContextList);\r
+LIST_ENTRY gBrowserFormSetList = INITIALIZE_LIST_HEAD_VARIABLE (gBrowserFormSetList);\r
+LIST_ENTRY gBrowserHotKeyList = INITIALIZE_LIST_HEAD_VARIABLE (gBrowserHotKeyList);\r
+\r
+BANNER_DATA *gBannerData;\r
+EFI_HII_HANDLE gFrontPageHandle;\r
+UINTN gClassOfVfr;\r
+UINTN gFunctionKeySetting;\r
+BOOLEAN gResetRequired;\r
+EFI_HII_HANDLE gHiiHandle;\r
+UINT16 gDirection;\r
+EFI_SCREEN_DESCRIPTOR gScreenDimensions;\r
+BROWSER_SETTING_SCOPE gBrowserSettingScope = FormSetLevel;\r
+BOOLEAN mBrowserScopeFirstSet = TRUE;\r
+EXIT_HANDLER ExitHandlerFunction = NULL;\r
+UINTN gFooterHeight;\r
+\r
+//\r
+// Browser Global Strings\r
+//\r
+CHAR16 *gSaveFailed;\r
+CHAR16 *gDiscardFailed;\r
+CHAR16 *gDefaultFailed;\r
+CHAR16 *gEnterString;\r
+CHAR16 *gEnterCommitString;\r
+CHAR16 *gEnterEscapeString;\r
+CHAR16 *gEscapeString;\r
+CHAR16 *gMoveHighlight;\r
+CHAR16 *gMakeSelection;\r
+CHAR16 *gDecNumericInput;\r
+CHAR16 *gHexNumericInput;\r
+CHAR16 *gToggleCheckBox;\r
+CHAR16 *gPromptForData;\r
+CHAR16 *gPromptForPassword;\r
+CHAR16 *gPromptForNewPassword;\r
+CHAR16 *gConfirmPassword;\r
+CHAR16 *gConfirmError;\r
+CHAR16 *gPassowordInvalid;\r
+CHAR16 *gPressEnter;\r
+CHAR16 *gEmptyString;\r
+CHAR16 *gAreYouSure;\r
+CHAR16 *gYesResponse;\r
+CHAR16 *gNoResponse;\r
+CHAR16 *gMiniString;\r
+CHAR16 *gPlusString;\r
+CHAR16 *gMinusString;\r
+CHAR16 *gAdjustNumber;\r
+CHAR16 *gSaveChanges;\r
+CHAR16 *gOptionMismatch;\r
+CHAR16 *gFormSuppress;\r
+\r
+CHAR16 *mUnknownString = L"!";\r
+\r
+CHAR16 gPromptBlockWidth;\r
+CHAR16 gOptionBlockWidth;\r
+CHAR16 gHelpBlockWidth;\r
+\r
+EFI_GUID gZeroGuid = {0, 0, 0, {0, 0, 0, 0, 0, 0, 0, 0}};\r
+EFI_GUID gSetupBrowserGuid = {\r
+ 0xab368524, 0xb60c, 0x495b, {0xa0, 0x9, 0x12, 0xe8, 0x5b, 0x1a, 0xea, 0x32}\r
+};\r
+\r
+FORM_BROWSER_FORMSET *gOldFormSet = NULL;\r
+\r
+FUNCTIION_KEY_SETTING gFunctionKeySettingTable[] = {\r
+ //\r
+ // Boot Manager\r
+ //\r
+ {\r
+ {\r
+ 0x847bc3fe,\r
+ 0xb974,\r
+ 0x446d,\r
+ {\r
+ 0x94,\r
+ 0x49,\r
+ 0x5a,\r
+ 0xd5,\r
+ 0x41,\r
+ 0x2e,\r
+ 0x99,\r
+ 0x3b\r
+ }\r
+ },\r
+ NONE_FUNCTION_KEY_SETTING\r
+ },\r
+ //\r
+ // Device Manager\r
+ //\r
+ {\r
+ {\r
+ 0x3ebfa8e6,\r
+ 0x511d,\r
+ 0x4b5b,\r
+ {\r
+ 0xa9,\r
+ 0x5f,\r
+ 0xfb,\r
+ 0x38,\r
+ 0x26,\r
+ 0xf,\r
+ 0x1c,\r
+ 0x27\r
+ }\r
+ },\r
+ NONE_FUNCTION_KEY_SETTING\r
+ },\r
+ //\r
+ // BMM FormSet.\r
+ //\r
+ {\r
+ {\r
+ 0x642237c7,\r
+ 0x35d4,\r
+ 0x472d,\r
+ {\r
+ 0x83,\r
+ 0x65,\r
+ 0x12,\r
+ 0xe0,\r
+ 0xcc,\r
+ 0xf2,\r
+ 0x7a,\r
+ 0x22\r
+ }\r
+ },\r
+ NONE_FUNCTION_KEY_SETTING\r
+ },\r
+ //\r
+ // BMM File Explorer FormSet.\r
+ //\r
+ {\r
+ {\r
+ 0x1f2d63e1,\r
+ 0xfebd,\r
+ 0x4dc7,\r
+ {\r
+ 0x9c,\r
+ 0xc5,\r
+ 0xba,\r
+ 0x2b,\r
+ 0x1c,\r
+ 0xef,\r
+ 0x9c,\r
+ 0x5b\r
+ }\r
+ },\r
+ NONE_FUNCTION_KEY_SETTING\r
+ },\r
+};\r
+\r
+/**\r
+ This is the routine which an external caller uses to direct the browser\r
+ where to obtain it's information.\r
+\r
+\r
+ @param This The Form Browser protocol instanse.\r
+ @param Handles A pointer to an array of Handles. If HandleCount > 1 we\r
+ display a list of the formsets for the handles specified.\r
+ @param HandleCount The number of Handles specified in Handle.\r
+ @param FormSetGuid This field points to the EFI_GUID which must match the Guid\r
+ field in the EFI_IFR_FORM_SET op-code for the specified\r
+ forms-based package. If FormSetGuid is NULL, then this\r
+ function will display the first found forms package.\r
+ @param FormId This field specifies which EFI_IFR_FORM to render as the first\r
+ displayable page. If this field has a value of 0x0000, then\r
+ the forms browser will render the specified forms in their encoded order.\r
+ @param ScreenDimensions Points to recommended form dimensions, including any non-content area, in\r
+ characters.\r
+ @param ActionRequest Points to the action recommended by the form.\r
+\r
+ @retval EFI_SUCCESS The function completed successfully.\r
+ @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.\r
+ @retval EFI_NOT_FOUND No valid forms could be found to display.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SendForm (\r
+ IN CONST EFI_FORM_BROWSER2_PROTOCOL *This,\r
+ IN EFI_HII_HANDLE *Handles,\r
+ IN UINTN HandleCount,\r
+ IN EFI_GUID *FormSetGuid, OPTIONAL\r
+ IN UINT16 FormId, OPTIONAL\r
+ IN CONST EFI_SCREEN_DESCRIPTOR *ScreenDimensions, OPTIONAL\r
+ OUT EFI_BROWSER_ACTION_REQUEST *ActionRequest OPTIONAL\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UI_MENU_SELECTION *Selection;\r
+ UINTN Index;\r
+ FORM_BROWSER_FORMSET *FormSet;\r
+ LIST_ENTRY *Link;\r
+\r
+ //\r
+ // Calculate total number of Register HotKeys. \r
+ //\r
+ Index = 0;\r
+ Link = GetFirstNode (&gBrowserHotKeyList);\r
+ while (!IsNull (&gBrowserHotKeyList, Link)) {\r
+ Link = GetNextNode (&gBrowserHotKeyList, Link);\r
+ Index ++;\r
+ }\r
+ //\r
+ // Show three HotKeys help information on one ROW.\r
+ //\r
+ gFooterHeight = FOOTER_HEIGHT + (Index / 3);\r
+\r
+ //\r
+ // Save globals used by SendForm()\r
+ //\r
+ SaveBrowserContext ();\r
+\r
+ gResetRequired = FALSE;\r
+ Status = EFI_SUCCESS;\r
+ ZeroMem (&gScreenDimensions, sizeof (EFI_SCREEN_DESCRIPTOR));\r
+\r
+ //\r
+ // Seed the dimensions in the global\r
+ //\r
+ gST->ConOut->QueryMode (\r
+ gST->ConOut,\r
+ gST->ConOut->Mode->Mode,\r
+ &gScreenDimensions.RightColumn,\r
+ &gScreenDimensions.BottomRow\r
+ );\r
+\r
+ if (ScreenDimensions != NULL) {\r
+ //\r
+ // Check local dimension vs. global dimension.\r
+ //\r
+ if ((gScreenDimensions.RightColumn < ScreenDimensions->RightColumn) ||\r
+ (gScreenDimensions.BottomRow < ScreenDimensions->BottomRow)\r
+ ) {\r
+ Status = EFI_INVALID_PARAMETER;\r
+ goto Done;\r
+ } else {\r
+ //\r
+ // Local dimension validation.\r
+ //\r
+ if ((ScreenDimensions->RightColumn > ScreenDimensions->LeftColumn) &&\r
+ (ScreenDimensions->BottomRow > ScreenDimensions->TopRow) &&\r
+ ((ScreenDimensions->RightColumn - ScreenDimensions->LeftColumn) > 2) &&\r
+ (\r
+ (ScreenDimensions->BottomRow - ScreenDimensions->TopRow) > STATUS_BAR_HEIGHT +\r
+ SCROLL_ARROW_HEIGHT *\r
+ 2 +\r
+ FRONT_PAGE_HEADER_HEIGHT +\r
+ gFooterHeight +\r
+ 1\r
+ )\r
+ ) {\r
+ CopyMem (&gScreenDimensions, (VOID *) ScreenDimensions, sizeof (EFI_SCREEN_DESCRIPTOR));\r
+ } else {\r
+ Status = EFI_INVALID_PARAMETER;\r
+ goto Done;\r
+ }\r
+ }\r
+ }\r
+\r
+ gOptionBlockWidth = (CHAR16) ((gScreenDimensions.RightColumn - gScreenDimensions.LeftColumn) / 3);\r
+ gPromptBlockWidth = (CHAR16) (gOptionBlockWidth + LEFT_SKIPPED_COLUMNS);\r
+ gHelpBlockWidth = (CHAR16) (gOptionBlockWidth - LEFT_SKIPPED_COLUMNS);\r
+\r
+ //\r
+ // Initialize the strings for the browser, upon exit of the browser, the strings will be freed\r
+ //\r
+ InitializeBrowserStrings ();\r
+\r
+ gFunctionKeySetting = ENABLE_FUNCTION_KEY_SETTING;\r
+\r
+ //\r
+ // Ensure we are in Text mode\r
+ //\r
+ gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));\r
+\r
+ for (Index = 0; Index < HandleCount; Index++) {\r
+ Selection = AllocateZeroPool (sizeof (UI_MENU_SELECTION));\r
+ ASSERT (Selection != NULL);\r
+\r
+ Selection->Handle = Handles[Index];\r
+ if (FormSetGuid != NULL) {\r
+ CopyMem (&Selection->FormSetGuid, FormSetGuid, sizeof (EFI_GUID));\r
+ Selection->FormId = FormId;\r
+ } else {\r
+ CopyMem (&Selection->FormSetGuid, &gEfiHiiPlatformSetupFormsetGuid, sizeof (EFI_GUID));\r
+ }\r
+\r
+ do {\r
+ FormSet = AllocateZeroPool (sizeof (FORM_BROWSER_FORMSET));\r
+ ASSERT (FormSet != NULL);\r
+\r
+ //\r
+ // Initialize internal data structures of FormSet\r
+ //\r
+ Status = InitializeFormSet (Selection->Handle, &Selection->FormSetGuid, FormSet, TRUE);\r
+ if (EFI_ERROR (Status) || IsListEmpty (&FormSet->FormListHead)) {\r
+ DestroyFormSet (FormSet);\r
+ break;\r
+ }\r
+ Selection->FormSet = FormSet;\r
+\r
+ //\r
+ // Try to find pre FormSet in the maintain backup list.\r
+ //\r
+ gOldFormSet = GetFormSetFromHiiHandle (Selection->Handle);\r
+\r
+ //\r
+ // Display this formset\r
+ //\r
+ gCurrentSelection = Selection;\r
+\r
+ Status = SetupBrowser (Selection);\r
+\r
+ gCurrentSelection = NULL;\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ break;\r
+ }\r
+\r
+ } while (Selection->Action == UI_ACTION_REFRESH_FORMSET);\r
+\r
+ if (gOldFormSet != NULL) {\r
+ //\r
+ // If no data is changed, don't need to save current FormSet into the maintain list.\r
+ //\r
+ if (!IsNvUpdateRequired (gOldFormSet)) {\r
+ RemoveEntryList (&gOldFormSet->Link);\r
+ DestroyFormSet (gOldFormSet);\r
+ }\r
+ gOldFormSet = NULL;\r
+ }\r
+\r
+ FreePool (Selection);\r
+ }\r
+\r
+ if (ActionRequest != NULL) {\r
+ *ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;\r
+ if (gResetRequired) {\r
+ *ActionRequest = EFI_BROWSER_ACTION_REQUEST_RESET;\r
+ }\r
+ }\r
+\r
+ FreeBrowserStrings ();\r
+\r
+ gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));\r
+ gST->ConOut->ClearScreen (gST->ConOut);\r
+\r
+Done:\r
+ //\r
+ // Restore globals used by SendForm()\r
+ //\r
+ RestoreBrowserContext ();\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ This function is called by a callback handler to retrieve uncommitted state\r
+ data from the browser.\r
+\r
+ @param This A pointer to the EFI_FORM_BROWSER2_PROTOCOL\r
+ instance.\r
+ @param ResultsDataSize A pointer to the size of the buffer associated\r
+ with ResultsData.\r
+ @param ResultsData A string returned from an IFR browser or\r
+ equivalent. The results string will have no\r
+ routing information in them.\r
+ @param RetrieveData A BOOLEAN field which allows an agent to retrieve\r
+ (if RetrieveData = TRUE) data from the uncommitted\r
+ browser state information or set (if RetrieveData\r
+ = FALSE) data in the uncommitted browser state\r
+ information.\r
+ @param VariableGuid An optional field to indicate the target variable\r
+ GUID name to use.\r
+ @param VariableName An optional field to indicate the target\r
+ human-readable variable name.\r
+\r
+ @retval EFI_SUCCESS The results have been distributed or are awaiting\r
+ distribution.\r
+ @retval EFI_BUFFER_TOO_SMALL The ResultsDataSize specified was too small to\r
+ contain the results data.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+BrowserCallback (\r
+ IN CONST EFI_FORM_BROWSER2_PROTOCOL *This,\r
+ IN OUT UINTN *ResultsDataSize,\r
+ IN OUT EFI_STRING ResultsData,\r
+ IN BOOLEAN RetrieveData,\r
+ IN CONST EFI_GUID *VariableGuid, OPTIONAL\r
+ IN CONST CHAR16 *VariableName OPTIONAL\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ LIST_ENTRY *Link;\r
+ FORMSET_STORAGE *Storage;\r
+ FORM_BROWSER_FORMSET *FormSet;\r
+ BOOLEAN Found;\r
+ CHAR16 *ConfigResp;\r
+ CHAR16 *StrPtr;\r
+ UINTN BufferSize;\r
+ UINTN TmpSize;\r
+\r
+ if (ResultsDataSize == NULL || ResultsData == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (gCurrentSelection == NULL) {\r
+ return EFI_NOT_READY;\r
+ }\r
+\r
+ Storage = NULL;\r
+ ConfigResp = NULL;\r
+ FormSet = gCurrentSelection->FormSet;\r
+\r
+ //\r
+ // Find target storage\r
+ //\r
+ Link = GetFirstNode (&FormSet->StorageListHead);\r
+ if (IsNull (&FormSet->StorageListHead, Link)) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ if (VariableGuid != NULL) {\r
+ //\r
+ // Try to find target storage\r
+ //\r
+ Found = FALSE;\r
+ while (!IsNull (&FormSet->StorageListHead, Link)) {\r
+ Storage = FORMSET_STORAGE_FROM_LINK (Link);\r
+ Link = GetNextNode (&FormSet->StorageListHead, Link);\r
+\r
+ if (CompareGuid (&Storage->Guid, (EFI_GUID *) VariableGuid)) {\r
+ if (Storage->Type == EFI_HII_VARSTORE_BUFFER ||\r
+ Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER) {\r
+ //\r
+ // Buffer storage require both GUID and Name\r
+ //\r
+ if (VariableName == NULL) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ if (StrCmp (Storage->Name, (CHAR16 *) VariableName) != 0) {\r
+ continue;\r
+ }\r
+ }\r
+ Found = TRUE;\r
+ break;\r
+ }\r
+ }\r
+\r
+ if (!Found) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+ } else {\r
+ //\r
+ // GUID/Name is not specified, take the first storage in FormSet\r
+ //\r
+ Storage = FORMSET_STORAGE_FROM_LINK (Link);\r
+ }\r
+\r
+ if (RetrieveData) {\r
+ //\r
+ // Skip if there is no RequestElement\r
+ //\r
+ if (Storage->ElementCount == 0) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ //\r
+ // Generate <ConfigResp>\r
+ //\r
+ Status = StorageToConfigResp (Storage, &ConfigResp, FALSE);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Skip <ConfigHdr> and '&' to point to <ConfigBody>\r
+ //\r
+ StrPtr = ConfigResp + StrLen (Storage->ConfigHdr) + 1;\r
+\r
+ BufferSize = StrSize (StrPtr);\r
+ if (*ResultsDataSize < BufferSize) {\r
+ *ResultsDataSize = BufferSize;\r
+\r
+ FreePool (ConfigResp);\r
+ return EFI_BUFFER_TOO_SMALL;\r
+ }\r
+\r
+ *ResultsDataSize = BufferSize;\r
+ CopyMem (ResultsData, StrPtr, BufferSize);\r
+\r
+ FreePool (ConfigResp);\r
+ } else {\r
+ //\r
+ // Prepare <ConfigResp>\r
+ //\r
+ TmpSize = StrLen (ResultsData);\r
+ BufferSize = (TmpSize + StrLen (Storage->ConfigHdr) + 2) * sizeof (CHAR16);\r
+ ConfigResp = AllocateZeroPool (BufferSize);\r
+ ASSERT (ConfigResp != NULL);\r
+\r
+ StrCpy (ConfigResp, Storage->ConfigHdr);\r
+ StrCat (ConfigResp, L"&");\r
+ StrCat (ConfigResp, ResultsData);\r
+\r
+ //\r
+ // Update Browser uncommited data\r
+ //\r
+ Status = ConfigRespToStorage (Storage, ConfigResp);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Notify function will remove the formset in the maintain list \r
+ once this formset is removed.\r
+ \r
+ Functions which are registered to receive notification of\r
+ database events have this prototype. The actual event is encoded\r
+ in NotifyType. The following table describes how PackageType,\r
+ PackageGuid, Handle, and Package are used for each of the\r
+ notification types.\r
+\r
+ @param PackageType Package type of the notification.\r
+\r
+ @param PackageGuid If PackageType is\r
+ EFI_HII_PACKAGE_TYPE_GUID, then this is\r
+ the pointer to the GUID from the Guid\r
+ field of EFI_HII_PACKAGE_GUID_HEADER.\r
+ Otherwise, it must be NULL.\r
+\r
+ @param Package Points to the package referred to by the\r
+ notification Handle The handle of the package\r
+ list which contains the specified package.\r
+\r
+ @param Handle The HII handle.\r
+\r
+ @param NotifyType The type of change concerning the\r
+ database. See\r
+ EFI_HII_DATABASE_NOTIFY_TYPE.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+FormsetRemoveNotify (\r
+ IN UINT8 PackageType,\r
+ IN CONST EFI_GUID *PackageGuid,\r
+ IN CONST EFI_HII_PACKAGE_HEADER *Package,\r
+ IN EFI_HII_HANDLE Handle,\r
+ IN EFI_HII_DATABASE_NOTIFY_TYPE NotifyType\r
+ )\r
+{\r
+ FORM_BROWSER_FORMSET *FormSet;\r
+\r
+ //\r
+ // Ignore the update for current using formset, which is handled by another notify function.\r
+ //\r
+ if (IsHiiHandleInBrowserContext (Handle)) {\r
+ return EFI_SUCCESS;\r
+ }\r
+ \r
+ //\r
+ // Remove the backup FormSet data when the Form Package is removed.\r
+ //\r
+ FormSet = GetFormSetFromHiiHandle (Handle);\r
+ if (FormSet != NULL) {\r
+ RemoveEntryList (&FormSet->Link);\r
+ DestroyFormSet (FormSet);\r
+ }\r
+ \r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Initialize Setup Browser driver.\r
+\r
+ @param ImageHandle The image handle.\r
+ @param SystemTable The system table.\r
+\r
+ @retval EFI_SUCCESS The Setup Browser module is initialized correctly..\r
+ @return Other value if failed to initialize the Setup Browser module.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+InitializeSetup (\r
+ IN EFI_HANDLE ImageHandle,\r
+ IN EFI_SYSTEM_TABLE *SystemTable\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_HANDLE NotifyHandle;\r
+ EFI_INPUT_KEY DefaultHotKey;\r
+ EFI_STRING HelpString;\r
+\r
+ //\r
+ // Locate required Hii relative protocols\r
+ //\r
+ Status = gBS->LocateProtocol (\r
+ &gEfiHiiDatabaseProtocolGuid,\r
+ NULL,\r
+ (VOID **) &mHiiDatabase\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ Status = gBS->LocateProtocol (\r
+ &gEfiHiiStringProtocolGuid,\r
+ NULL,\r
+ (VOID **) &mHiiString\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ Status = gBS->LocateProtocol (\r
+ &gEfiHiiConfigRoutingProtocolGuid,\r
+ NULL,\r
+ (VOID **) &mHiiConfigRouting\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ //\r
+ // Publish our HII data\r
+ //\r
+ gHiiHandle = HiiAddPackages (\r
+ &gSetupBrowserGuid,\r
+ ImageHandle,\r
+ SetupBrowserStrings,\r
+ NULL\r
+ );\r
+ ASSERT (gHiiHandle != NULL);\r
+\r
+ //\r
+ // Initialize Driver private data\r
+ //\r
+ gBannerData = AllocateZeroPool (sizeof (BANNER_DATA));\r
+ ASSERT (gBannerData != NULL);\r
+ \r
+ //\r
+ // Initialize generic help strings.\r
+ //\r
+ gSaveFailed = GetToken (STRING_TOKEN (SAVE_FAILED), gHiiHandle);\r
+ gDiscardFailed = GetToken (STRING_TOKEN (DISCARD_FAILED), gHiiHandle);\r
+ gDefaultFailed = GetToken (STRING_TOKEN (DEFAULT_FAILED), gHiiHandle);\r
+\r
+ //\r
+ // Install FormBrowser2 protocol\r
+ //\r
+ mPrivateData.Handle = NULL;\r
+ Status = gBS->InstallProtocolInterface (\r
+ &mPrivateData.Handle,\r
+ &gEfiFormBrowser2ProtocolGuid,\r
+ EFI_NATIVE_INTERFACE,\r
+ &mPrivateData.FormBrowser2\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ //\r
+ // Install default HotKey F10 for Save\r
+ //\r
+ DefaultHotKey.UnicodeChar = CHAR_NULL;\r
+ HelpString = GetToken (STRING_TOKEN (FUNCTION_TEN_STRING), gHiiHandle);\r
+ DefaultHotKey.ScanCode = SCAN_F10;\r
+ RegisterHotKey (&DefaultHotKey, BROWSER_ACTION_SUBMIT, 0, HelpString);\r
+ FreePool (HelpString);\r
+ //\r
+ // Install default HotKey F9 for Reset To Defaults\r
+ //\r
+ DefaultHotKey.ScanCode = SCAN_F9;\r
+ HelpString = GetToken (STRING_TOKEN (FUNCTION_NINE_STRING), gHiiHandle);\r
+ RegisterHotKey (&DefaultHotKey, BROWSER_ACTION_DEFAULT, EFI_HII_DEFAULT_CLASS_STANDARD, HelpString);\r
+ FreePool (HelpString);\r
+\r
+ //\r
+ // Install FormBrowserEx protocol\r
+ //\r
+ mPrivateData.Handle = NULL;\r
+ Status = gBS->InstallProtocolInterface (\r
+ &mPrivateData.Handle,\r
+ &gEfiFormBrowserExProtocolGuid,\r
+ EFI_NATIVE_INTERFACE,\r
+ &mPrivateData.FormBrowserEx\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ //\r
+ // Register notify for Form package remove\r
+ //\r
+ Status = mHiiDatabase->RegisterPackageNotify (\r
+ mHiiDatabase,\r
+ EFI_HII_PACKAGE_FORMS,\r
+ NULL,\r
+ FormsetRemoveNotify,\r
+ EFI_HII_DATABASE_NOTIFY_REMOVE_PACK,\r
+ &NotifyHandle\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Create a new string in HII Package List.\r
+\r
+ @param String The String to be added\r
+ @param HiiHandle The package list in the HII database to insert the\r
+ specified string.\r
+\r
+ @return The output string.\r
+\r
+**/\r
+EFI_STRING_ID\r
+NewString (\r
+ IN CHAR16 *String,\r
+ IN EFI_HII_HANDLE HiiHandle\r
+ )\r
+{\r
+ EFI_STRING_ID StringId;\r
+\r
+ StringId = HiiSetString (HiiHandle, 0, String, NULL);\r
+ ASSERT (StringId != 0);\r
+\r
+ return StringId;\r
+}\r
+\r
+\r
+/**\r
+ Delete a string from HII Package List.\r
+\r
+ @param StringId Id of the string in HII database.\r
+ @param HiiHandle The HII package list handle.\r
+\r
+ @retval EFI_SUCCESS The string was deleted successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+DeleteString (\r
+ IN EFI_STRING_ID StringId,\r
+ IN EFI_HII_HANDLE HiiHandle\r
+ )\r
+{\r
+ CHAR16 NullChar;\r
+\r
+ NullChar = CHAR_NULL;\r
+ HiiSetString (HiiHandle, StringId, &NullChar, NULL);\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ Get the string based on the StringId and HII Package List Handle.\r
+\r
+ @param Token The String's ID.\r
+ @param HiiHandle The package list in the HII database to search for\r
+ the specified string.\r
+\r
+ @return The output string.\r
+\r
+**/\r
+CHAR16 *\r
+GetToken (\r
+ IN EFI_STRING_ID Token,\r
+ IN EFI_HII_HANDLE HiiHandle\r
+ )\r
+{\r
+ EFI_STRING String;\r
+\r
+ if (HiiHandle == NULL) {\r
+ return NULL;\r
+ }\r
+\r
+ String = HiiGetString (HiiHandle, Token, NULL);\r
+ if (String == NULL) {\r
+ String = AllocateCopyPool (StrSize (mUnknownString), mUnknownString);\r
+ ASSERT (String != NULL);\r
+ }\r
+ return (CHAR16 *) String;\r
+}\r
+\r
+\r
+/**\r
+ Allocate new memory and then copy the Unicode string Source to Destination.\r
+\r
+ @param Dest Location to copy string\r
+ @param Src String to copy\r
+\r
+**/\r
+VOID\r
+NewStringCpy (\r
+ IN OUT CHAR16 **Dest,\r
+ IN CHAR16 *Src\r
+ )\r
+{\r
+ if (*Dest != NULL) {\r
+ FreePool (*Dest);\r
+ }\r
+ *Dest = AllocateCopyPool (StrSize (Src), Src);\r
+ ASSERT (*Dest != NULL);\r
+}\r
+\r
+\r
+/**\r
+ Allocate new memory and concatinate Source on the end of Destination.\r
+\r
+ @param Dest String to added to the end of.\r
+ @param Src String to concatinate.\r
+\r
+**/\r
+VOID\r
+NewStringCat (\r
+ IN OUT CHAR16 **Dest,\r
+ IN CHAR16 *Src\r
+ )\r
+{\r
+ CHAR16 *NewString;\r
+ UINTN TmpSize;\r
+\r
+ if (*Dest == NULL) {\r
+ NewStringCpy (Dest, Src);\r
+ return;\r
+ }\r
+\r
+ TmpSize = StrSize (*Dest);\r
+ NewString = AllocateZeroPool (TmpSize + StrSize (Src) - 1);\r
+ ASSERT (NewString != NULL);\r
+\r
+ StrCpy (NewString, *Dest);\r
+ StrCat (NewString, Src);\r
+\r
+ FreePool (*Dest);\r
+ *Dest = NewString;\r
+}\r
+\r
+\r
+/**\r
+ Synchronize or restore Storage's Edit copy and Shadow copy.\r
+\r
+ @param Storage The Storage to be synchronized.\r
+ @param SyncOrRestore Sync the buffer to editbuffer or Restore the \r
+ editbuffer to buffer\r
+ if TRUE, copy the editbuffer to the buffer.\r
+ if FALSE, copy the buffer to the editbuffer.\r
+\r
+**/\r
+VOID\r
+SynchronizeStorage (\r
+ IN FORMSET_STORAGE *Storage,\r
+ IN BOOLEAN SyncOrRestore\r
+ )\r
+{\r
+ LIST_ENTRY *Link;\r
+ NAME_VALUE_NODE *Node;\r
+\r
+ switch (Storage->Type) {\r
+ case EFI_HII_VARSTORE_BUFFER:\r
+ case EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER:\r
+ if (SyncOrRestore) {\r
+ CopyMem (Storage->Buffer, Storage->EditBuffer, Storage->Size);\r
+ } else {\r
+ CopyMem (Storage->EditBuffer, Storage->Buffer, Storage->Size);\r
+ }\r
+ break;\r
+\r
+ case EFI_HII_VARSTORE_NAME_VALUE:\r
+ Link = GetFirstNode (&Storage->NameValueListHead);\r
+ while (!IsNull (&Storage->NameValueListHead, Link)) {\r
+ Node = NAME_VALUE_NODE_FROM_LINK (Link);\r
+\r
+ if (SyncOrRestore) {\r
+ NewStringCpy (&Node->Value, Node->EditValue);\r
+ } else {\r
+ NewStringCpy (&Node->EditValue, Node->Value);\r
+ }\r
+\r
+ Link = GetNextNode (&Storage->NameValueListHead, Link);\r
+ }\r
+ break;\r
+\r
+ case EFI_HII_VARSTORE_EFI_VARIABLE:\r
+ default:\r
+ break;\r
+ }\r
+}\r
+\r
+\r
+/**\r
+ Get Value for given Name from a NameValue Storage.\r
+\r
+ @param Storage The NameValue Storage.\r
+ @param Name The Name.\r
+ @param Value The retured Value.\r
+ @param GetValueFrom Where to get source value, from EditValue or Value.\r
+\r
+ @retval EFI_SUCCESS Value found for given Name.\r
+ @retval EFI_NOT_FOUND No such Name found in NameValue storage.\r
+\r
+**/\r
+EFI_STATUS\r
+GetValueByName (\r
+ IN FORMSET_STORAGE *Storage,\r
+ IN CHAR16 *Name,\r
+ IN OUT CHAR16 **Value,\r
+ IN GET_SET_QUESTION_VALUE_WITH GetValueFrom\r
+ )\r
+{\r
+ LIST_ENTRY *Link;\r
+ NAME_VALUE_NODE *Node;\r
+\r
+ if (GetValueFrom != GetSetValueWithEditBuffer && GetValueFrom != GetSetValueWithBuffer) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ *Value = NULL;\r
+\r
+ Link = GetFirstNode (&Storage->NameValueListHead);\r
+ while (!IsNull (&Storage->NameValueListHead, Link)) {\r
+ Node = NAME_VALUE_NODE_FROM_LINK (Link);\r
+\r
+ if (StrCmp (Name, Node->Name) == 0) {\r
+ if (GetValueFrom == GetSetValueWithEditBuffer) {\r
+ NewStringCpy (Value, Node->EditValue);\r
+ } else {\r
+ NewStringCpy (Value, Node->Value);\r
+ }\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ Link = GetNextNode (&Storage->NameValueListHead, Link);\r
+ }\r
+\r
+ return EFI_NOT_FOUND;\r
+}\r
+\r
+\r
+/**\r
+ Set Value of given Name in a NameValue Storage.\r
+\r
+ @param Storage The NameValue Storage.\r
+ @param Name The Name.\r
+ @param Value The Value to set.\r
+ @param SetValueTo Whether update editValue or Value.\r
+\r
+ @retval EFI_SUCCESS Value found for given Name.\r
+ @retval EFI_NOT_FOUND No such Name found in NameValue storage.\r
+\r
+**/\r
+EFI_STATUS\r
+SetValueByName (\r
+ IN FORMSET_STORAGE *Storage,\r
+ IN CHAR16 *Name,\r
+ IN CHAR16 *Value,\r
+ IN GET_SET_QUESTION_VALUE_WITH SetValueTo\r
+ )\r
+{\r
+ LIST_ENTRY *Link;\r
+ NAME_VALUE_NODE *Node;\r
+ CHAR16 *Buffer;\r
+\r
+ if (SetValueTo != GetSetValueWithEditBuffer && SetValueTo != GetSetValueWithBuffer) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Link = GetFirstNode (&Storage->NameValueListHead);\r
+ while (!IsNull (&Storage->NameValueListHead, Link)) {\r
+ Node = NAME_VALUE_NODE_FROM_LINK (Link);\r
+\r
+ if (StrCmp (Name, Node->Name) == 0) {\r
+ if (SetValueTo == GetSetValueWithEditBuffer) {\r
+ Buffer = Node->EditValue;\r
+ } else {\r
+ Buffer = Node->Value;\r
+ }\r
+ if (Buffer != NULL) {\r
+ FreePool (Buffer);\r
+ }\r
+ Buffer = AllocateCopyPool (StrSize (Value), Value);\r
+ ASSERT (Buffer != NULL);\r
+ if (SetValueTo == GetSetValueWithEditBuffer) {\r
+ Node->EditValue = Buffer;\r
+ } else {\r
+ Node->Value = Buffer;\r
+ }\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ Link = GetNextNode (&Storage->NameValueListHead, Link);\r
+ }\r
+\r
+ return EFI_NOT_FOUND;\r
+}\r
+\r
+\r
+/**\r
+ Convert setting of Buffer Storage or NameValue Storage to <ConfigResp>.\r
+\r
+ @param Buffer The Storage to be conveted.\r
+ @param ConfigResp The returned <ConfigResp>.\r
+ @param SingleForm Whether update data for single form or formset level.\r
+\r
+ @retval EFI_SUCCESS Convert success.\r
+ @retval EFI_INVALID_PARAMETER Incorrect storage type.\r
+\r
+**/\r
+EFI_STATUS\r
+StorageToConfigResp (\r
+ IN VOID *Buffer,\r
+ IN CHAR16 **ConfigResp,\r
+ IN BOOLEAN SingleForm\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_STRING Progress;\r
+ LIST_ENTRY *Link;\r
+ NAME_VALUE_NODE *Node;\r
+ CHAR16 *ConfigRequest;\r
+ FORMSET_STORAGE *Storage;\r
+ FORM_BROWSER_CONFIG_REQUEST *ConfigInfo;\r
+\r
+ Status = EFI_SUCCESS;\r
+ if (SingleForm) {\r
+ ConfigInfo = (FORM_BROWSER_CONFIG_REQUEST *) Buffer;\r
+ Storage = ConfigInfo->Storage;\r
+ ConfigRequest = ConfigInfo->ConfigRequest;\r
+ } else {\r
+ Storage = (FORMSET_STORAGE *) Buffer;\r
+ ConfigRequest = Storage->ConfigRequest;\r
+ }\r
+\r
+ switch (Storage->Type) {\r
+ case EFI_HII_VARSTORE_BUFFER:\r
+ case EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER:\r
+ Status = mHiiConfigRouting->BlockToConfig (\r
+ mHiiConfigRouting,\r
+ ConfigRequest,\r
+ Storage->EditBuffer,\r
+ Storage->Size,\r
+ ConfigResp,\r
+ &Progress\r
+ );\r
+ break;\r
+\r
+ case EFI_HII_VARSTORE_NAME_VALUE:\r
+ *ConfigResp = NULL;\r
+ NewStringCat (ConfigResp, Storage->ConfigHdr);\r
+\r
+ Link = GetFirstNode (&Storage->NameValueListHead);\r
+ while (!IsNull (&Storage->NameValueListHead, Link)) {\r
+ Node = NAME_VALUE_NODE_FROM_LINK (Link);\r
+\r
+ if (StrStr (ConfigRequest, Node->Name) != NULL) {\r
+ NewStringCat (ConfigResp, L"&");\r
+ NewStringCat (ConfigResp, Node->Name);\r
+ NewStringCat (ConfigResp, L"=");\r
+ NewStringCat (ConfigResp, Node->EditValue);\r
+ }\r
+ Link = GetNextNode (&Storage->NameValueListHead, Link);\r
+ }\r
+ break;\r
+\r
+ case EFI_HII_VARSTORE_EFI_VARIABLE:\r
+ default:\r
+ Status = EFI_INVALID_PARAMETER;\r
+ break;\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Convert <ConfigResp> to settings in Buffer Storage or NameValue Storage.\r
+\r
+ @param Storage The Storage to receive the settings.\r
+ @param ConfigResp The <ConfigResp> to be converted.\r
+\r
+ @retval EFI_SUCCESS Convert success.\r
+ @retval EFI_INVALID_PARAMETER Incorrect storage type.\r
+\r
+**/\r
+EFI_STATUS\r
+ConfigRespToStorage (\r
+ IN FORMSET_STORAGE *Storage,\r
+ IN CHAR16 *ConfigResp\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_STRING Progress;\r
+ UINTN BufferSize;\r
+ CHAR16 *StrPtr;\r
+ CHAR16 *Name;\r
+ CHAR16 *Value;\r
+\r
+ Status = EFI_SUCCESS;\r
+\r
+ switch (Storage->Type) {\r
+ case EFI_HII_VARSTORE_BUFFER:\r
+ case EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER:\r
+ BufferSize = Storage->Size;\r
+ Status = mHiiConfigRouting->ConfigToBlock (\r
+ mHiiConfigRouting,\r
+ ConfigResp,\r
+ Storage->EditBuffer,\r
+ &BufferSize,\r
+ &Progress\r
+ );\r
+ break;\r
+\r
+ case EFI_HII_VARSTORE_NAME_VALUE:\r
+ StrPtr = StrStr (ConfigResp, L"PATH");\r
+ if (StrPtr == NULL) {\r
+ break;\r
+ }\r
+ StrPtr = StrStr (ConfigResp, L"&");\r
+ while (StrPtr != NULL) {\r
+ //\r
+ // Skip '&'\r
+ //\r
+ StrPtr = StrPtr + 1;\r
+ Name = StrPtr;\r
+ StrPtr = StrStr (StrPtr, L"=");\r
+ if (StrPtr == NULL) {\r
+ break;\r
+ }\r
+ *StrPtr = 0;\r
+\r
+ //\r
+ // Skip '='\r
+ //\r
+ StrPtr = StrPtr + 1;\r
+ Value = StrPtr;\r
+ StrPtr = StrStr (StrPtr, L"&");\r
+ if (StrPtr != NULL) {\r
+ *StrPtr = 0;\r
+ }\r
+ SetValueByName (Storage, Name, Value, GetSetValueWithEditBuffer);\r
+ }\r
+ break;\r
+\r
+ case EFI_HII_VARSTORE_EFI_VARIABLE:\r
+ default:\r
+ Status = EFI_INVALID_PARAMETER;\r
+ break;\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Get Question's current Value.\r
+\r
+ @param FormSet FormSet data structure.\r
+ @param Form Form data structure.\r
+ @param Question Question to be initialized.\r
+ @param GetValueFrom Where to get value, may from editbuffer, buffer or hii driver.\r
+\r
+ @retval EFI_SUCCESS The function completed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+GetQuestionValue (\r
+ IN FORM_BROWSER_FORMSET *FormSet,\r
+ IN FORM_BROWSER_FORM *Form,\r
+ IN OUT FORM_BROWSER_STATEMENT *Question,\r
+ IN GET_SET_QUESTION_VALUE_WITH GetValueFrom\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ BOOLEAN Enabled;\r
+ BOOLEAN Pending;\r
+ UINT8 *Dst;\r
+ UINTN StorageWidth;\r
+ EFI_TIME EfiTime;\r
+ FORMSET_STORAGE *Storage;\r
+ EFI_IFR_TYPE_VALUE *QuestionValue;\r
+ CHAR16 *ConfigRequest;\r
+ CHAR16 *Progress;\r
+ CHAR16 *Result;\r
+ CHAR16 *Value;\r
+ CHAR16 *StringPtr;\r
+ UINTN Length;\r
+ UINTN Index;\r
+ UINTN LengthStr;\r
+ BOOLEAN IsBufferStorage;\r
+ BOOLEAN IsString;\r
+ CHAR16 TemStr[5];\r
+ UINT8 DigitUint8;\r
+ UINT8 *TemBuffer;\r
+\r
+ Status = EFI_SUCCESS;\r
+ Value = NULL;\r
+ Result = NULL;\r
+\r
+ if (GetValueFrom >= GetSetValueWithMax) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ //\r
+ // Statement don't have storage, skip them\r
+ //\r
+ if (Question->QuestionId == 0) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Question value is provided by an Expression, evaluate it\r
+ //\r
+ if (Question->ValueExpression != NULL) {\r
+ Status = EvaluateExpression (FormSet, Form, Question->ValueExpression);\r
+ if (!EFI_ERROR (Status)) {\r
+ if (Question->ValueExpression->Result.Type == EFI_IFR_TYPE_BUFFER) {\r
+ ASSERT (Question->HiiValue.Type == EFI_IFR_TYPE_BUFFER && Question->HiiValue.Buffer != NULL);\r
+ if (Question->StorageWidth > Question->ValueExpression->Result.BufferLen) {\r
+ CopyMem (Question->HiiValue.Buffer, Question->ValueExpression->Result.Buffer, Question->ValueExpression->Result.BufferLen);\r
+ Question->HiiValue.BufferLen = Question->ValueExpression->Result.BufferLen;\r
+ } else {\r
+ CopyMem (Question->HiiValue.Buffer, Question->ValueExpression->Result.Buffer, Question->StorageWidth);\r
+ Question->HiiValue.BufferLen = Question->StorageWidth;\r
+ }\r
+ FreePool (Question->ValueExpression->Result.Buffer);\r
+ }\r
+ Question->HiiValue.Type = Question->ValueExpression->Result.Type;\r
+ CopyMem (&Question->HiiValue.Value, &Question->ValueExpression->Result.Value, sizeof (EFI_IFR_TYPE_VALUE)); \r
+ }\r
+ return Status;\r
+ }\r
+ \r
+ //\r
+ // Get question value by read expression.\r
+ //\r
+ if (Question->ReadExpression != NULL && Form->FormType == STANDARD_MAP_FORM_TYPE) {\r
+ Status = EvaluateExpression (FormSet, Form, Question->ReadExpression);\r
+ if (!EFI_ERROR (Status) && \r
+ ((Question->ReadExpression->Result.Type < EFI_IFR_TYPE_OTHER) || (Question->ReadExpression->Result.Type == EFI_IFR_TYPE_BUFFER))) {\r
+ //\r
+ // Only update question value to the valid result.\r
+ //\r
+ if (Question->ReadExpression->Result.Type == EFI_IFR_TYPE_BUFFER) {\r
+ ASSERT (Question->HiiValue.Type == EFI_IFR_TYPE_BUFFER && Question->HiiValue.Buffer != NULL);\r
+ if (Question->StorageWidth > Question->ReadExpression->Result.BufferLen) {\r
+ CopyMem (Question->HiiValue.Buffer, Question->ReadExpression->Result.Buffer, Question->ReadExpression->Result.BufferLen);\r
+ Question->HiiValue.BufferLen = Question->ReadExpression->Result.BufferLen;\r
+ } else {\r
+ CopyMem (Question->HiiValue.Buffer, Question->ReadExpression->Result.Buffer, Question->StorageWidth);\r
+ Question->HiiValue.BufferLen = Question->StorageWidth;\r
+ }\r
+ FreePool (Question->ReadExpression->Result.Buffer);\r
+ }\r
+ Question->HiiValue.Type = Question->ReadExpression->Result.Type;\r
+ CopyMem (&Question->HiiValue.Value, &Question->ReadExpression->Result.Value, sizeof (EFI_IFR_TYPE_VALUE)); \r
+ return EFI_SUCCESS;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Question value is provided by RTC\r
+ //\r
+ Storage = Question->Storage;\r
+ QuestionValue = &Question->HiiValue.Value;\r
+ if (Storage == NULL) {\r
+ //\r
+ // It's a Question without storage, or RTC date/time\r
+ //\r
+ if (Question->Operand == EFI_IFR_DATE_OP || Question->Operand == EFI_IFR_TIME_OP) {\r
+ //\r
+ // Date and time define the same Flags bit\r
+ //\r
+ switch (Question->Flags & EFI_QF_DATE_STORAGE) {\r
+ case QF_DATE_STORAGE_TIME:\r
+ Status = gRT->GetTime (&EfiTime, NULL);\r
+ break;\r
+\r
+ case QF_DATE_STORAGE_WAKEUP:\r
+ Status = gRT->GetWakeupTime (&Enabled, &Pending, &EfiTime);\r
+ break;\r
+\r
+ case QF_DATE_STORAGE_NORMAL:\r
+ default:\r
+ //\r
+ // For date/time without storage\r
+ //\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ if (Question->Operand == EFI_IFR_DATE_OP) {\r
+ QuestionValue->date.Year = EfiTime.Year;\r
+ QuestionValue->date.Month = EfiTime.Month;\r
+ QuestionValue->date.Day = EfiTime.Day;\r
+ } else {\r
+ QuestionValue->time.Hour = EfiTime.Hour;\r
+ QuestionValue->time.Minute = EfiTime.Minute;\r
+ QuestionValue->time.Second = EfiTime.Second;\r
+ }\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ //\r
+ // Question value is provided by EFI variable\r
+ //\r
+ StorageWidth = Question->StorageWidth;\r
+ if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {\r
+ if (Question->BufferValue != NULL) {\r
+ Dst = Question->BufferValue;\r
+ } else {\r
+ Dst = (UINT8 *) QuestionValue;\r
+ }\r
+\r
+ Status = gRT->GetVariable (\r
+ Question->VariableName,\r
+ &Storage->Guid,\r
+ NULL,\r
+ &StorageWidth,\r
+ Dst\r
+ );\r
+ //\r
+ // Always return success, even this EFI variable doesn't exist\r
+ //\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ //\r
+ // Question Value is provided by Buffer Storage or NameValue Storage\r
+ //\r
+ if (Question->BufferValue != NULL) {\r
+ //\r
+ // This Question is password or orderedlist\r
+ //\r
+ Dst = Question->BufferValue;\r
+ } else {\r
+ //\r
+ // Other type of Questions\r
+ //\r
+ Dst = (UINT8 *) &Question->HiiValue.Value;\r
+ }\r
+\r
+ if (Storage->Type == EFI_HII_VARSTORE_BUFFER || \r
+ Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER) {\r
+ IsBufferStorage = TRUE;\r
+ } else {\r
+ IsBufferStorage = FALSE;\r
+ }\r
+ IsString = (BOOLEAN) ((Question->HiiValue.Type == EFI_IFR_TYPE_STRING) ? TRUE : FALSE);\r
+ if (GetValueFrom == GetSetValueWithEditBuffer || GetValueFrom == GetSetValueWithBuffer ) {\r
+ if (IsBufferStorage) {\r
+ if (GetValueFrom == GetSetValueWithEditBuffer) {\r
+ //\r
+ // Copy from storage Edit buffer\r
+ //\r
+ CopyMem (Dst, Storage->EditBuffer + Question->VarStoreInfo.VarOffset, StorageWidth);\r
+ } else {\r
+ //\r
+ // Copy from storage Edit buffer\r
+ //\r
+ CopyMem (Dst, Storage->Buffer + Question->VarStoreInfo.VarOffset, StorageWidth);\r
+ }\r
+ } else {\r
+ Value = NULL;\r
+ Status = GetValueByName (Storage, Question->VariableName, &Value, GetValueFrom);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ ASSERT (Value != NULL);\r
+ LengthStr = StrLen (Value);\r
+ Status = EFI_SUCCESS;\r
+ if (IsString) {\r
+ //\r
+ // Convert Config String to Unicode String, e.g "0041004200430044" => "ABCD"\r
+ // Add string tail char L'\0' into Length\r
+ //\r
+ Length = StorageWidth + sizeof (CHAR16);\r
+ if (Length < ((LengthStr / 4 + 1) * 2)) {\r
+ Status = EFI_BUFFER_TOO_SMALL;\r
+ } else {\r
+ StringPtr = (CHAR16 *) Dst;\r
+ ZeroMem (TemStr, sizeof (TemStr));\r
+ for (Index = 0; Index < LengthStr; Index += 4) {\r
+ StrnCpy (TemStr, Value + Index, 4);\r
+ StringPtr[Index/4] = (CHAR16) StrHexToUint64 (TemStr);\r
+ }\r
+ //\r
+ // Add tailing L'\0' character\r
+ //\r
+ StringPtr[Index/4] = L'\0';\r
+ }\r
+ } else {\r
+ if (StorageWidth < ((LengthStr + 1) / 2)) {\r
+ Status = EFI_BUFFER_TOO_SMALL;\r
+ } else {\r
+ ZeroMem (TemStr, sizeof (TemStr));\r
+ for (Index = 0; Index < LengthStr; Index ++) {\r
+ TemStr[0] = Value[LengthStr - Index - 1];\r
+ DigitUint8 = (UINT8) StrHexToUint64 (TemStr);\r
+ if ((Index & 1) == 0) {\r
+ Dst [Index/2] = DigitUint8;\r
+ } else {\r
+ Dst [Index/2] = (UINT8) ((DigitUint8 << 4) + Dst [Index/2]);\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ FreePool (Value);\r
+ }\r
+ } else {\r
+ if (Storage->Type == EFI_HII_VARSTORE_BUFFER || Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) {\r
+ //\r
+ // Request current settings from Configuration Driver\r
+ //\r
+ if (FormSet->ConfigAccess == NULL) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ //\r
+ // <ConfigRequest> ::= <ConfigHdr> + <BlockName> ||\r
+ // <ConfigHdr> + "&" + <VariableName>\r
+ //\r
+ if (IsBufferStorage) {\r
+ Length = StrLen (Storage->ConfigHdr);\r
+ Length += StrLen (Question->BlockName);\r
+ } else {\r
+ Length = StrLen (Storage->ConfigHdr);\r
+ Length += StrLen (Question->VariableName) + 1;\r
+ }\r
+ ConfigRequest = AllocateZeroPool ((Length + 1) * sizeof (CHAR16));\r
+ ASSERT (ConfigRequest != NULL);\r
+\r
+ StrCpy (ConfigRequest, Storage->ConfigHdr);\r
+ if (IsBufferStorage) {\r
+ StrCat (ConfigRequest, Question->BlockName);\r
+ } else {\r
+ StrCat (ConfigRequest, L"&");\r
+ StrCat (ConfigRequest, Question->VariableName);\r
+ }\r
+\r
+ Status = FormSet->ConfigAccess->ExtractConfig (\r
+ FormSet->ConfigAccess,\r
+ ConfigRequest,\r
+ &Progress,\r
+ &Result\r
+ );\r
+ FreePool (ConfigRequest);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Skip <ConfigRequest>\r
+ //\r
+ if (IsBufferStorage) {\r
+ Value = StrStr (Result, L"&VALUE");\r
+ if (Value == NULL) {\r
+ FreePool (Result);\r
+ return EFI_NOT_FOUND;\r
+ }\r
+ //\r
+ // Skip "&VALUE"\r
+ //\r
+ Value = Value + 6;\r
+ } else {\r
+ Value = Result + Length;\r
+ }\r
+ if (*Value != '=') {\r
+ FreePool (Result);\r
+ return EFI_NOT_FOUND;\r
+ }\r
+ //\r
+ // Skip '=', point to value\r
+ //\r
+ Value = Value + 1;\r
+\r
+ //\r
+ // Suppress <AltResp> if any\r
+ //\r
+ StringPtr = Value;\r
+ while (*StringPtr != L'\0' && *StringPtr != L'&') {\r
+ StringPtr++;\r
+ }\r
+ *StringPtr = L'\0';\r
+\r
+ LengthStr = StrLen (Value);\r
+ Status = EFI_SUCCESS;\r
+ if (!IsBufferStorage && IsString) {\r
+ //\r
+ // Convert Config String to Unicode String, e.g "0041004200430044" => "ABCD"\r
+ // Add string tail char L'\0' into Length\r
+ //\r
+ Length = StorageWidth + sizeof (CHAR16);\r
+ if (Length < ((LengthStr / 4 + 1) * 2)) {\r
+ Status = EFI_BUFFER_TOO_SMALL;\r
+ } else {\r
+ StringPtr = (CHAR16 *) Dst;\r
+ ZeroMem (TemStr, sizeof (TemStr));\r
+ for (Index = 0; Index < LengthStr; Index += 4) {\r
+ StrnCpy (TemStr, Value + Index, 4);\r
+ StringPtr[Index/4] = (CHAR16) StrHexToUint64 (TemStr);\r
+ }\r
+ //\r
+ // Add tailing L'\0' character\r
+ //\r
+ StringPtr[Index/4] = L'\0';\r
+ }\r
+ } else {\r
+ if (StorageWidth < ((LengthStr + 1) / 2)) {\r
+ Status = EFI_BUFFER_TOO_SMALL;\r
+ } else {\r
+ ZeroMem (TemStr, sizeof (TemStr));\r
+ for (Index = 0; Index < LengthStr; Index ++) {\r
+ TemStr[0] = Value[LengthStr - Index - 1];\r
+ DigitUint8 = (UINT8) StrHexToUint64 (TemStr);\r
+ if ((Index & 1) == 0) {\r
+ Dst [Index/2] = DigitUint8;\r
+ } else {\r
+ Dst [Index/2] = (UINT8) ((DigitUint8 << 4) + Dst [Index/2]);\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ FreePool (Result);\r
+ return Status;\r
+ }\r
+ } else if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER) {\r
+ TemBuffer = NULL;\r
+ TemBuffer = AllocateZeroPool (Storage->Size);\r
+ if (TemBuffer == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ return Status;\r
+ }\r
+ Length = Storage->Size;\r
+ Status = gRT->GetVariable (\r
+ Storage->Name,\r
+ &Storage->Guid,\r
+ NULL,\r
+ &Length,\r
+ TemBuffer\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ FreePool (TemBuffer);\r
+ return Status;\r
+ }\r
+\r
+ CopyMem (Dst, TemBuffer + Question->VarStoreInfo.VarOffset, StorageWidth);\r
+\r
+ FreePool (TemBuffer);\r
+ }\r
+\r
+ //\r
+ // Synchronize Edit Buffer\r
+ //\r
+ if (IsBufferStorage) {\r
+ CopyMem (Storage->EditBuffer + Question->VarStoreInfo.VarOffset, Dst, StorageWidth);\r
+ } else {\r
+ SetValueByName (Storage, Question->VariableName, Value, GetSetValueWithEditBuffer);\r
+ }\r
+\r
+ if (Result != NULL) {\r
+ FreePool (Result);\r
+ }\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Save Question Value to edit copy(cached) or Storage(uncached).\r
+\r
+ @param FormSet FormSet data structure.\r
+ @param Form Form data structure.\r
+ @param Question Pointer to the Question.\r
+ @param SetValueTo Update the question value to editbuffer , buffer or hii driver.\r
+\r
+ @retval EFI_SUCCESS The function completed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+SetQuestionValue (\r
+ IN FORM_BROWSER_FORMSET *FormSet,\r
+ IN FORM_BROWSER_FORM *Form,\r
+ IN OUT FORM_BROWSER_STATEMENT *Question,\r
+ IN GET_SET_QUESTION_VALUE_WITH SetValueTo\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ BOOLEAN Enabled;\r
+ BOOLEAN Pending;\r
+ UINT8 *Src;\r
+ EFI_TIME EfiTime;\r
+ UINTN BufferLen;\r
+ UINTN StorageWidth;\r
+ FORMSET_STORAGE *Storage;\r
+ EFI_IFR_TYPE_VALUE *QuestionValue;\r
+ CHAR16 *ConfigResp;\r
+ CHAR16 *Progress;\r
+ CHAR16 *Value;\r
+ UINTN Length;\r
+ BOOLEAN IsBufferStorage;\r
+ BOOLEAN IsString;\r
+ UINT8 *TemBuffer;\r
+ CHAR16 *TemName;\r
+ CHAR16 *TemString;\r
+ UINTN Index;\r
+\r
+ Status = EFI_SUCCESS;\r
+\r
+ if (SetValueTo >= GetSetValueWithMax) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ //\r
+ // Statement don't have storage, skip them\r
+ //\r
+ if (Question->QuestionId == 0) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // If Question value is provided by an Expression, then it is read only\r
+ //\r
+ if (Question->ValueExpression != NULL) {\r
+ return Status;\r
+ }\r
+ \r
+ //\r
+ // Before set question value, evaluate its write expression.\r
+ //\r
+ if (Question->WriteExpression != NULL && Form->FormType == STANDARD_MAP_FORM_TYPE) {\r
+ Status = EvaluateExpression (FormSet, Form, Question->WriteExpression);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Question value is provided by RTC\r
+ //\r
+ Storage = Question->Storage;\r
+ QuestionValue = &Question->HiiValue.Value;\r
+ if (Storage == NULL) {\r
+ //\r
+ // It's a Question without storage, or RTC date/time\r
+ //\r
+ if (Question->Operand == EFI_IFR_DATE_OP || Question->Operand == EFI_IFR_TIME_OP) {\r
+ //\r
+ // Date and time define the same Flags bit\r
+ //\r
+ switch (Question->Flags & EFI_QF_DATE_STORAGE) {\r
+ case QF_DATE_STORAGE_TIME:\r
+ Status = gRT->GetTime (&EfiTime, NULL);\r
+ break;\r
+\r
+ case QF_DATE_STORAGE_WAKEUP:\r
+ Status = gRT->GetWakeupTime (&Enabled, &Pending, &EfiTime);\r
+ break;\r
+\r
+ case QF_DATE_STORAGE_NORMAL:\r
+ default:\r
+ //\r
+ // For date/time without storage\r
+ //\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ if (Question->Operand == EFI_IFR_DATE_OP) {\r
+ EfiTime.Year = QuestionValue->date.Year;\r
+ EfiTime.Month = QuestionValue->date.Month;\r
+ EfiTime.Day = QuestionValue->date.Day;\r
+ } else {\r
+ EfiTime.Hour = QuestionValue->time.Hour;\r
+ EfiTime.Minute = QuestionValue->time.Minute;\r
+ EfiTime.Second = QuestionValue->time.Second;\r
+ }\r
+\r
+ if ((Question->Flags & EFI_QF_DATE_STORAGE) == QF_DATE_STORAGE_TIME) {\r
+ Status = gRT->SetTime (&EfiTime);\r
+ } else {\r
+ Status = gRT->SetWakeupTime (TRUE, &EfiTime);\r
+ }\r
+ }\r
+\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Question value is provided by EFI variable\r
+ //\r
+ StorageWidth = Question->StorageWidth;\r
+ if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {\r
+ if (Question->BufferValue != NULL) {\r
+ Src = Question->BufferValue;\r
+ } else {\r
+ Src = (UINT8 *) QuestionValue;\r
+ }\r
+\r
+ Status = gRT->SetVariable (\r
+ Question->VariableName,\r
+ &Storage->Guid,\r
+ Storage->Attributes,\r
+ StorageWidth,\r
+ Src\r
+ );\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Question Value is provided by Buffer Storage or NameValue Storage\r
+ //\r
+ if (Question->BufferValue != NULL) {\r
+ Src = Question->BufferValue;\r
+ } else {\r
+ Src = (UINT8 *) &Question->HiiValue.Value;\r
+ }\r
+\r
+ if (Storage->Type == EFI_HII_VARSTORE_BUFFER || \r
+ Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER) {\r
+ IsBufferStorage = TRUE;\r
+ } else {\r
+ IsBufferStorage = FALSE;\r
+ }\r
+ IsString = (BOOLEAN) ((Question->HiiValue.Type == EFI_IFR_TYPE_STRING) ? TRUE : FALSE);\r
+\r
+ if (SetValueTo == GetSetValueWithEditBuffer || SetValueTo == GetSetValueWithBuffer) {\r
+ if (IsBufferStorage) {\r
+ if (SetValueTo == GetSetValueWithEditBuffer) {\r
+ //\r
+ // Copy to storage edit buffer\r
+ // \r
+ CopyMem (Storage->EditBuffer + Question->VarStoreInfo.VarOffset, Src, StorageWidth);\r
+ } else if (SetValueTo == GetSetValueWithBuffer) {\r
+ //\r
+ // Copy to storage edit buffer\r
+ // \r
+ CopyMem (Storage->Buffer + Question->VarStoreInfo.VarOffset, Src, StorageWidth);\r
+ }\r
+ } else {\r
+ if (IsString) {\r
+ //\r
+ // Allocate enough string buffer.\r
+ //\r
+ Value = NULL;\r
+ BufferLen = ((StrLen ((CHAR16 *) Src) * 4) + 1) * sizeof (CHAR16);\r
+ Value = AllocateZeroPool (BufferLen);\r
+ ASSERT (Value != NULL);\r
+ //\r
+ // Convert Unicode String to Config String, e.g. "ABCD" => "0041004200430044"\r
+ //\r
+ TemName = (CHAR16 *) Src;\r
+ TemString = Value;\r
+ for (; *TemName != L'\0'; TemName++) {\r
+ TemString += UnicodeValueToString (TemString, PREFIX_ZERO | RADIX_HEX, *TemName, 4);\r
+ }\r
+ } else {\r
+ BufferLen = StorageWidth * 2 + 1;\r
+ Value = AllocateZeroPool (BufferLen * sizeof (CHAR16));\r
+ ASSERT (Value != NULL);\r
+ //\r
+ // Convert Buffer to Hex String\r
+ //\r
+ TemBuffer = Src + StorageWidth - 1;\r
+ TemString = Value;\r
+ for (Index = 0; Index < StorageWidth; Index ++, TemBuffer --) {\r
+ TemString += UnicodeValueToString (TemString, PREFIX_ZERO | RADIX_HEX, *TemBuffer, 2);\r
+ }\r
+ }\r
+\r
+ Status = SetValueByName (Storage, Question->VariableName, Value, SetValueTo);\r
+ FreePool (Value);\r
+ }\r
+ } else if (SetValueTo == GetSetValueWithHiiDriver) {\r
+ if (Storage->Type == EFI_HII_VARSTORE_BUFFER || Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) {\r
+ //\r
+ // <ConfigResp> ::= <ConfigHdr> + <BlockName> + "&VALUE=" + "<HexCh>StorageWidth * 2" ||\r
+ // <ConfigHdr> + "&" + <VariableName> + "=" + "<string>"\r
+ //\r
+ if (IsBufferStorage) {\r
+ Length = StrLen (Question->BlockName) + 7;\r
+ } else {\r
+ Length = StrLen (Question->VariableName) + 2;\r
+ }\r
+ if (!IsBufferStorage && IsString) {\r
+ Length += (StrLen ((CHAR16 *) Src) * 4);\r
+ } else {\r
+ Length += (StorageWidth * 2);\r
+ }\r
+ ConfigResp = AllocateZeroPool ((StrLen (Storage->ConfigHdr) + Length + 1) * sizeof (CHAR16));\r
+ ASSERT (ConfigResp != NULL);\r
+\r
+ StrCpy (ConfigResp, Storage->ConfigHdr);\r
+ if (IsBufferStorage) {\r
+ StrCat (ConfigResp, Question->BlockName);\r
+ StrCat (ConfigResp, L"&VALUE=");\r
+ } else {\r
+ StrCat (ConfigResp, L"&");\r
+ StrCat (ConfigResp, Question->VariableName);\r
+ StrCat (ConfigResp, L"=");\r
+ }\r
+\r
+ Value = ConfigResp + StrLen (ConfigResp);\r
+\r
+ if (!IsBufferStorage && IsString) {\r
+ //\r
+ // Convert Unicode String to Config String, e.g. "ABCD" => "0041004200430044"\r
+ //\r
+ TemName = (CHAR16 *) Src;\r
+ TemString = Value;\r
+ for (; *TemName != L'\0'; TemName++) {\r
+ TemString += UnicodeValueToString (TemString, PREFIX_ZERO | RADIX_HEX, *TemName, 4);\r
+ }\r
+ } else {\r
+ //\r
+ // Convert Buffer to Hex String\r
+ //\r
+ TemBuffer = Src + StorageWidth - 1;\r
+ TemString = Value;\r
+ for (Index = 0; Index < StorageWidth; Index ++, TemBuffer --) {\r
+ TemString += UnicodeValueToString (TemString, PREFIX_ZERO | RADIX_HEX, *TemBuffer, 2);\r
+ }\r
+ }\r
+\r
+ //\r
+ // Convert to lower char.\r
+ //\r
+ for (TemString = Value; *Value != L'\0'; Value++) {\r
+ if (*Value >= L'A' && *Value <= L'Z') {\r
+ *Value = (CHAR16) (*Value - L'A' + L'a');\r
+ }\r
+ }\r
+\r
+ //\r
+ // Submit Question Value to Configuration Driver\r
+ //\r
+ if (FormSet->ConfigAccess != NULL) {\r
+ Status = FormSet->ConfigAccess->RouteConfig (\r
+ FormSet->ConfigAccess,\r
+ ConfigResp,\r
+ &Progress\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ FreePool (ConfigResp);\r
+ return Status;\r
+ }\r
+ }\r
+ FreePool (ConfigResp);\r
+ \r
+ } else if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER) {\r
+ TemBuffer = NULL;\r
+ TemBuffer = AllocateZeroPool(Storage->Size);\r
+ if (TemBuffer == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ return Status;\r
+ }\r
+ Length = Storage->Size;\r
+ Status = gRT->GetVariable (\r
+ Storage->Name,\r
+ &Storage->Guid,\r
+ NULL,\r
+ &Length,\r
+ TemBuffer\r
+ );\r
+\r
+ CopyMem (TemBuffer + Question->VarStoreInfo.VarOffset, Src, StorageWidth);\r
+ \r
+ Status = gRT->SetVariable (\r
+ Storage->Name,\r
+ &Storage->Guid,\r
+ Storage->Attributes,\r
+ Storage->Size,\r
+ TemBuffer\r
+ );\r
+ FreePool (TemBuffer);\r
+ if (EFI_ERROR (Status)){\r
+ return Status;\r
+ }\r
+ }\r
+ //\r
+ // Sync storage, from editbuffer to buffer.\r
+ //\r
+ CopyMem (Storage->Buffer + Question->VarStoreInfo.VarOffset, Src, StorageWidth);\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Perform inconsistent check for a Form.\r
+\r
+ @param FormSet FormSet data structure.\r
+ @param Form Form data structure.\r
+ @param Question The Question to be validated.\r
+ @param Type Validation type: InConsistent or NoSubmit\r
+\r
+ @retval EFI_SUCCESS Form validation pass.\r
+ @retval other Form validation failed.\r
+\r
+**/\r
+EFI_STATUS\r
+ValidateQuestion (\r
+ IN FORM_BROWSER_FORMSET *FormSet,\r
+ IN FORM_BROWSER_FORM *Form,\r
+ IN FORM_BROWSER_STATEMENT *Question,\r
+ IN UINTN Type\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ LIST_ENTRY *Link;\r
+ LIST_ENTRY *ListHead;\r
+ EFI_STRING PopUp;\r
+ EFI_INPUT_KEY Key;\r
+ FORM_EXPRESSION *Expression;\r
+\r
+ if (Type == EFI_HII_EXPRESSION_INCONSISTENT_IF) {\r
+ ListHead = &Question->InconsistentListHead;\r
+ } else if (Type == EFI_HII_EXPRESSION_NO_SUBMIT_IF) {\r
+ ListHead = &Question->NoSubmitListHead;\r
+ } else {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ Link = GetFirstNode (ListHead);\r
+ while (!IsNull (ListHead, Link)) {\r
+ Expression = FORM_EXPRESSION_FROM_LINK (Link);\r
+\r
+ //\r
+ // Evaluate the expression\r
+ //\r
+ Status = EvaluateExpression (FormSet, Form, Expression);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ if ((Expression->Result.Type == EFI_IFR_TYPE_BOOLEAN) && Expression->Result.Value.b) {\r
+ //\r
+ // Condition meet, show up error message\r
+ //\r
+ if (Expression->Error != 0) {\r
+ PopUp = GetToken (Expression->Error, FormSet->HiiHandle);\r
+ do {\r
+ CreateDialog (4, TRUE, 0, NULL, &Key, gEmptyString, PopUp, gPressEnter, gEmptyString);\r
+ } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
+ FreePool (PopUp);\r
+ }\r
+\r
+ return EFI_NOT_READY;\r
+ }\r
+\r
+ Link = GetNextNode (ListHead, Link);\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ Perform NoSubmit check for each Form in FormSet.\r
+\r
+ @param FormSet FormSet data structure.\r
+ @param CurrentForm Current input form data structure.\r
+\r
+ @retval EFI_SUCCESS Form validation pass.\r
+ @retval other Form validation failed.\r
+\r
+**/\r
+EFI_STATUS\r
+NoSubmitCheck (\r
+ IN FORM_BROWSER_FORMSET *FormSet,\r
+ IN FORM_BROWSER_FORM *CurrentForm\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ LIST_ENTRY *Link;\r
+ FORM_BROWSER_STATEMENT *Question;\r
+ FORM_BROWSER_FORM *Form;\r
+ LIST_ENTRY *LinkForm;\r
+\r
+ LinkForm = GetFirstNode (&FormSet->FormListHead);\r
+ while (!IsNull (&FormSet->FormListHead, LinkForm)) {\r
+ Form = FORM_BROWSER_FORM_FROM_LINK (LinkForm);\r
+ LinkForm = GetNextNode (&FormSet->FormListHead, LinkForm);\r
+\r
+ if (CurrentForm != NULL && CurrentForm != Form) {\r
+ continue;\r
+ }\r
+\r
+ Link = GetFirstNode (&Form->StatementListHead);\r
+ while (!IsNull (&Form->StatementListHead, Link)) {\r
+ Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link);\r
+\r
+ Status = ValidateQuestion (FormSet, Form, Question, EFI_HII_EXPRESSION_NO_SUBMIT_IF);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Link = GetNextNode (&Form->StatementListHead, Link);\r
+ }\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Fill storage's edit copy with settings requested from Configuration Driver.\r
+\r
+ @param FormSet FormSet data structure.\r
+ @param ConfigInfo The config info related to this form.\r
+ @param SyncOrRestore Sync the buffer to editbuffer or Restore the \r
+ editbuffer to buffer\r
+ if TRUE, copy the editbuffer to the buffer.\r
+ if FALSE, copy the buffer to the editbuffer.\r
+\r
+ @retval EFI_SUCCESS The function completed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+SynchronizeStorageForForm (\r
+ IN FORM_BROWSER_FORMSET *FormSet,\r
+ IN FORM_BROWSER_CONFIG_REQUEST *ConfigInfo,\r
+ IN BOOLEAN SyncOrRestore\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_STRING Progress;\r
+ EFI_STRING Result;\r
+ UINTN BufferSize;\r
+ LIST_ENTRY *Link;\r
+ NAME_VALUE_NODE *Node;\r
+ UINT8 *Src;\r
+ UINT8 *Dst;\r
+\r
+ Status = EFI_SUCCESS;\r
+ Result = NULL;\r
+ if (FormSet->ConfigAccess == NULL && ConfigInfo->Storage->Type != EFI_HII_VARSTORE_NAME_VALUE) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ if (ConfigInfo->ElementCount == 0) {\r
+ //\r
+ // Skip if there is no RequestElement\r
+ //\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ if (ConfigInfo->Storage->Type == EFI_HII_VARSTORE_BUFFER || \r
+ (ConfigInfo->Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER)) {\r
+ BufferSize = ConfigInfo->Storage->Size;\r
+\r
+ if (SyncOrRestore) {\r
+ Src = ConfigInfo->Storage->EditBuffer;\r
+ Dst = ConfigInfo->Storage->Buffer;\r
+ } else {\r
+ Src = ConfigInfo->Storage->Buffer;\r
+ Dst = ConfigInfo->Storage->EditBuffer;\r
+ }\r
+\r
+ Status = mHiiConfigRouting->BlockToConfig(\r
+ mHiiConfigRouting,\r
+ ConfigInfo->ConfigRequest,\r
+ Src,\r
+ BufferSize,\r
+ &Result,\r
+ &Progress\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Status = mHiiConfigRouting->ConfigToBlock (\r
+ mHiiConfigRouting,\r
+ Result,\r
+ Dst,\r
+ &BufferSize,\r
+ &Progress\r
+ );\r
+ if (Result != NULL) {\r
+ FreePool (Result);\r
+ }\r
+ } else if (ConfigInfo->Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) {\r
+ Link = GetFirstNode (&ConfigInfo->Storage->NameValueListHead);\r
+ while (!IsNull (&ConfigInfo->Storage->NameValueListHead, Link)) {\r
+ Node = NAME_VALUE_NODE_FROM_LINK (Link);\r
+\r
+ if (StrStr (ConfigInfo->ConfigRequest, Node->Name) != NULL) {\r
+ if (SyncOrRestore) {\r
+ NewStringCpy (&Node->Value, Node->EditValue);\r
+ } else {\r
+ NewStringCpy (&Node->EditValue, Node->Value);\r
+ }\r
+ }\r
+\r
+ Link = GetNextNode (&ConfigInfo->Storage->NameValueListHead, Link);\r
+ }\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ When discard the question value, call the callback function with Changed type\r
+ to inform the hii driver.\r
+\r
+ @param FormSet FormSet data structure.\r
+ @param Form Form data structure.\r
+\r
+**/\r
+VOID\r
+SendDiscardInfoToDriver (\r
+ IN FORM_BROWSER_FORMSET *FormSet,\r
+ IN FORM_BROWSER_FORM *Form\r
+ )\r
+{\r
+ LIST_ENTRY *Link;\r
+ FORM_BROWSER_STATEMENT *Question;\r
+ EFI_STATUS Status;\r
+ EFI_HII_VALUE HiiValue;\r
+ UINT8 *BufferValue;\r
+ BOOLEAN ValueChanged;\r
+ EFI_IFR_TYPE_VALUE *TypeValue;\r
+ EFI_BROWSER_ACTION_REQUEST ActionRequest;\r
+\r
+ ValueChanged = FALSE;\r
+ BufferValue = NULL;\r
+\r
+ if(!Form->NvUpdateRequired) {\r
+ return;\r
+ }\r
+\r
+ Link = GetFirstNode (&Form->StatementListHead);\r
+ while (!IsNull (&Form->StatementListHead, Link)) {\r
+ Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link);\r
+ Link = GetNextNode (&Form->StatementListHead, Link);\r
+\r
+ if (Question->Storage == NULL || Question->Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {\r
+ continue;\r
+ }\r
+\r
+ if (Question->Operand == EFI_IFR_PASSWORD_OP) {\r
+ continue;\r
+ }\r
+\r
+ if (Question->BufferValue != NULL) {\r
+ BufferValue = AllocateZeroPool (Question->StorageWidth);\r
+ ASSERT (BufferValue != NULL);\r
+ CopyMem (BufferValue, Question->BufferValue, Question->StorageWidth);\r
+ } else {\r
+ HiiValue.Type = Question->HiiValue.Type;\r
+ CopyMem (&HiiValue.Value, &Question->HiiValue.Value, sizeof (EFI_IFR_TYPE_VALUE));\r
+ }\r
+\r
+ Status = GetQuestionValue (FormSet, Form, Question, GetSetValueWithBuffer);\r
+ if (EFI_ERROR (Status)) {\r
+ if (BufferValue != NULL) {\r
+ FreePool (BufferValue);\r
+ BufferValue = NULL;\r
+ }\r
+ continue;\r
+ }\r
+\r
+ if (Question->BufferValue != NULL) {\r
+ if (CompareMem (BufferValue, Question->BufferValue, Question->StorageWidth)) {\r
+ ValueChanged = TRUE;\r
+ }\r
+ } else {\r
+ if (CompareMem (&HiiValue.Value, &Question->HiiValue.Value, sizeof (EFI_IFR_TYPE_VALUE))) {\r
+ ValueChanged = TRUE;\r
+ }\r
+ }\r
+\r
+ if (BufferValue != NULL) {\r
+ FreePool (BufferValue);\r
+ BufferValue = NULL;\r
+ }\r
+\r
+ if (!ValueChanged) {\r
+ continue;\r
+ }\r
+\r
+ ValueChanged = FALSE;\r
+\r
+ if (Question->HiiValue.Type == EFI_IFR_TYPE_BUFFER) {\r
+ TypeValue = (EFI_IFR_TYPE_VALUE *) Question->BufferValue;\r
+ } else {\r
+ TypeValue = &Question->HiiValue.Value;\r
+ }\r
+\r
+ ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;\r
+ FormSet->ConfigAccess->Callback (\r
+ FormSet->ConfigAccess,\r
+ EFI_BROWSER_ACTION_CHANGED,\r
+ Question->QuestionId,\r
+ Question->HiiValue.Type,\r
+ TypeValue,\r
+ &ActionRequest\r
+ );\r
+ }\r
+}\r
+\r
+/**\r
+ Discard data based on the input setting scope (Form, FormSet or System).\r
+\r
+ @param FormSet FormSet data structure.\r
+ @param Form Form data structure.\r
+ @param SettingScope Setting Scope for Discard action.\r
+\r
+ @retval EFI_SUCCESS The function completed successfully.\r
+ @retval EFI_UNSUPPORTED Unsupport SettingScope.\r
+\r
+**/\r
+EFI_STATUS\r
+DiscardForm (\r
+ IN FORM_BROWSER_FORMSET *FormSet,\r
+ IN FORM_BROWSER_FORM *Form,\r
+ IN BROWSER_SETTING_SCOPE SettingScope\r
+ )\r
+{\r
+ LIST_ENTRY *Link;\r
+ FORMSET_STORAGE *Storage;\r
+ FORM_BROWSER_CONFIG_REQUEST *ConfigInfo;\r
+ FORM_BROWSER_FORMSET *LocalFormSet;\r
+\r
+ //\r
+ // Check the supported setting level.\r
+ //\r
+ if (SettingScope >= MaxLevel) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ if (SettingScope == FormLevel && Form->NvUpdateRequired) {\r
+ ConfigInfo = NULL;\r
+ Link = GetFirstNode (&Form->ConfigRequestHead);\r
+ while (!IsNull (&Form->ConfigRequestHead, Link)) {\r
+ ConfigInfo = FORM_BROWSER_CONFIG_REQUEST_FROM_LINK (Link);\r
+ Link = GetNextNode (&Form->ConfigRequestHead, Link);\r
+\r
+ if (ConfigInfo->Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {\r
+ continue;\r
+ }\r
+\r
+ //\r
+ // Skip if there is no RequestElement\r
+ //\r
+ if (ConfigInfo->ElementCount == 0) {\r
+ continue;\r
+ }\r
+\r
+ //\r
+ // Prepare <ConfigResp>\r
+ //\r
+ SynchronizeStorageForForm(FormSet, ConfigInfo, FALSE);\r
+\r
+ //\r
+ // Call callback with Changed type to inform the driver.\r
+ //\r
+ SendDiscardInfoToDriver (FormSet, Form);\r
+ }\r
+\r
+ Form->NvUpdateRequired = FALSE;\r
+ } else if (SettingScope == FormSetLevel && IsNvUpdateRequired(FormSet)) {\r
+\r
+ //\r
+ // Discard Buffer storage or Name/Value storage\r
+ //\r
+ Link = GetFirstNode (&FormSet->StorageListHead);\r
+ while (!IsNull (&FormSet->StorageListHead, Link)) {\r
+ Storage = FORMSET_STORAGE_FROM_LINK (Link);\r
+ Link = GetNextNode (&FormSet->StorageListHead, Link);\r
+\r
+ if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {\r
+ continue;\r
+ }\r
+\r
+ //\r
+ // Skip if there is no RequestElement\r
+ //\r
+ if (Storage->ElementCount == 0) {\r
+ continue;\r
+ }\r
+\r
+ SynchronizeStorage(Storage, FALSE);\r
+ }\r
+\r
+ Link = GetFirstNode (&FormSet->FormListHead);\r
+ while (!IsNull (&FormSet->FormListHead, Link)) {\r
+ Form = FORM_BROWSER_FORM_FROM_LINK (Link);\r
+ Link = GetNextNode (&FormSet->FormListHead, Link);\r
+ \r
+ //\r
+ // Call callback with Changed type to inform the driver.\r
+ //\r
+ SendDiscardInfoToDriver (FormSet, Form);\r
+ }\r
+\r
+ UpdateNvInfoInForm (FormSet, FALSE); \r
+ } else if (SettingScope == SystemLevel) {\r
+ //\r
+ // System Level Discard.\r
+ //\r
+ \r
+ //\r
+ // Discard changed value for each FormSet in the maintain list.\r
+ //\r
+ Link = GetFirstNode (&gBrowserFormSetList);\r
+ while (!IsNull (&gBrowserFormSetList, Link)) {\r
+ LocalFormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link);\r
+ DiscardForm (LocalFormSet, NULL, FormSetLevel);\r
+ Link = GetNextNode (&gBrowserFormSetList, Link);\r
+ if (!IsHiiHandleInBrowserContext (LocalFormSet->HiiHandle)) {\r
+ //\r
+ // Remove maintain backup list after discard except for the current using FormSet.\r
+ //\r
+ RemoveEntryList (&LocalFormSet->Link);\r
+ DestroyFormSet (LocalFormSet);\r
+ }\r
+ }\r
+ }\r
+\r
+ return EFI_SUCCESS; \r
+}\r
+\r
+/**\r
+ Submit data based on the input Setting level (Form, FormSet or System).\r
+\r
+ @param FormSet FormSet data structure.\r
+ @param Form Form data structure.\r
+ @param SettingScope Setting Scope for Submit action.\r
+\r
+ @retval EFI_SUCCESS The function completed successfully.\r
+ @retval EFI_UNSUPPORTED Unsupport SettingScope.\r
+\r
+**/\r
+EFI_STATUS\r
+SubmitForm (\r
+ IN FORM_BROWSER_FORMSET *FormSet,\r
+ IN FORM_BROWSER_FORM *Form,\r
+ IN BROWSER_SETTING_SCOPE SettingScope\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ LIST_ENTRY *Link;\r
+ EFI_STRING ConfigResp;\r
+ EFI_STRING Progress;\r
+ FORMSET_STORAGE *Storage;\r
+ UINTN BufferSize;\r
+ UINT8 *TmpBuf; \r
+ FORM_BROWSER_FORMSET *LocalFormSet;\r
+ FORM_BROWSER_CONFIG_REQUEST *ConfigInfo;\r
+\r
+ //\r
+ // Check the supported setting level.\r
+ //\r
+ if (SettingScope >= MaxLevel) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ //\r
+ // Validate the Form by NoSubmit check\r
+ //\r
+ Status = EFI_SUCCESS;\r
+ if (SettingScope == FormLevel) {\r
+ Status = NoSubmitCheck (FormSet, Form);\r
+ } else if (SettingScope == FormSetLevel) {\r
+ Status = NoSubmitCheck (FormSet, NULL);\r
+ }\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ if (SettingScope == FormLevel && Form->NvUpdateRequired) {\r
+ ConfigInfo = NULL;\r
+ Link = GetFirstNode (&Form->ConfigRequestHead);\r
+ while (!IsNull (&Form->ConfigRequestHead, Link)) {\r
+ ConfigInfo = FORM_BROWSER_CONFIG_REQUEST_FROM_LINK (Link);\r
+ Link = GetNextNode (&Form->ConfigRequestHead, Link);\r
+\r
+ Storage = ConfigInfo->Storage;\r
+ if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {\r
+ continue;\r
+ }\r
+\r
+ //\r
+ // Skip if there is no RequestElement\r
+ //\r
+ if (ConfigInfo->ElementCount == 0) {\r
+ continue;\r
+ }\r
+\r
+ //\r
+ // 1. Prepare <ConfigResp>\r
+ //\r
+ Status = StorageToConfigResp (ConfigInfo, &ConfigResp, TRUE);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // 2. Set value to hii driver or efi variable.\r
+ //\r
+ if (Storage->Type == EFI_HII_VARSTORE_BUFFER || \r
+ Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) {\r
+ //\r
+ // Send <ConfigResp> to Configuration Driver\r
+ //\r
+ if (FormSet->ConfigAccess != NULL) {\r
+ Status = FormSet->ConfigAccess->RouteConfig (\r
+ FormSet->ConfigAccess,\r
+ ConfigResp,\r
+ &Progress\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ FreePool (ConfigResp);\r
+ return Status;\r
+ }\r
+ }\r
+ } else if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER) {\r
+ TmpBuf = NULL;\r
+ TmpBuf = AllocateZeroPool(Storage->Size);\r
+ if (TmpBuf == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ return Status;\r
+ }\r
+\r
+ BufferSize = Storage->Size;\r
+ Status = gRT->GetVariable (\r
+ Storage->Name,\r
+ &Storage->Guid,\r
+ NULL,\r
+ &BufferSize,\r
+ TmpBuf\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ FreePool (TmpBuf);\r
+ FreePool (ConfigResp);\r
+ return Status;\r
+ }\r
+ ASSERT (BufferSize == Storage->Size); \r
+ Status = mHiiConfigRouting->ConfigToBlock (\r
+ mHiiConfigRouting,\r
+ ConfigResp,\r
+ TmpBuf,\r
+ &BufferSize,\r
+ &Progress\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ FreePool (TmpBuf);\r
+ FreePool (ConfigResp);\r
+ return Status;\r
+ }\r
+\r
+ Status = gRT->SetVariable (\r
+ Storage->Name,\r
+ &Storage->Guid,\r
+ Storage->Attributes,\r
+ Storage->Size,\r
+ TmpBuf\r
+ );\r
+ FreePool (TmpBuf);\r
+ if (EFI_ERROR (Status)) {\r
+ FreePool (ConfigResp);\r
+ return Status;\r
+ }\r
+ }\r
+ FreePool (ConfigResp);\r
+ //\r
+ // 3. Config success, update storage shadow Buffer, only update the data belong to this form.\r
+ //\r
+ SynchronizeStorageForForm(FormSet, ConfigInfo, TRUE);\r
+ }\r
+\r
+ //\r
+ // 4. Update the NV flag.\r
+ // \r
+ Form->NvUpdateRequired = FALSE;\r
+ } else if (SettingScope == FormSetLevel && IsNvUpdateRequired(FormSet)) {\r
+ //\r
+ // Submit Buffer storage or Name/Value storage\r
+ //\r
+ Link = GetFirstNode (&FormSet->StorageListHead);\r
+ while (!IsNull (&FormSet->StorageListHead, Link)) {\r
+ Storage = FORMSET_STORAGE_FROM_LINK (Link);\r
+ Link = GetNextNode (&FormSet->StorageListHead, Link);\r
+\r
+ if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {\r
+ continue;\r
+ }\r
+\r
+ //\r
+ // Skip if there is no RequestElement\r
+ //\r
+ if (Storage->ElementCount == 0) {\r
+ continue;\r
+ }\r
+\r
+ //\r
+ // 1. Prepare <ConfigResp>\r
+ //\r
+ Status = StorageToConfigResp (Storage, &ConfigResp, FALSE);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ if (Storage->Type == EFI_HII_VARSTORE_BUFFER || \r
+ Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) {\r
+\r
+ //\r
+ // 2. Send <ConfigResp> to Configuration Driver\r
+ //\r
+ if (FormSet->ConfigAccess != NULL) {\r
+ Status = FormSet->ConfigAccess->RouteConfig (\r
+ FormSet->ConfigAccess,\r
+ ConfigResp,\r
+ &Progress\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ FreePool (ConfigResp);\r
+ return Status;\r
+ }\r
+ }\r
+ } else if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER) {\r
+ //\r
+ // 1&2. Set the edit data to the variable.\r
+ //\r
+ TmpBuf = NULL;\r
+ TmpBuf = AllocateZeroPool (Storage->Size);\r
+ if (TmpBuf == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ return Status;\r
+ } \r
+ BufferSize = Storage->Size;\r
+ Status = gRT->GetVariable (\r
+ Storage->Name,\r
+ &Storage->Guid,\r
+ NULL,\r
+ &BufferSize,\r
+ TmpBuf\r
+ );\r
+ ASSERT (BufferSize == Storage->Size); \r
+ Status = mHiiConfigRouting->ConfigToBlock (\r
+ mHiiConfigRouting,\r
+ ConfigResp,\r
+ TmpBuf,\r
+ &BufferSize,\r
+ &Progress\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ FreePool (TmpBuf);\r
+ FreePool (ConfigResp);\r
+ return Status;\r
+ }\r
+\r
+ Status = gRT->SetVariable (\r
+ Storage->Name,\r
+ &Storage->Guid,\r
+ Storage->Attributes,\r
+ Storage->Size,\r
+ TmpBuf\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ FreePool (TmpBuf);\r
+ FreePool (ConfigResp);\r
+ return Status;\r
+ }\r
+ FreePool (TmpBuf);\r
+ }\r
+ FreePool (ConfigResp);\r
+ //\r
+ // 3. Config success, update storage shadow Buffer\r
+ //\r
+ SynchronizeStorage (Storage, TRUE);\r
+ }\r
+\r
+ //\r
+ // 4. Update the NV flag.\r
+ // \r
+ UpdateNvInfoInForm (FormSet, FALSE);\r
+ } else if (SettingScope == SystemLevel) {\r
+ //\r
+ // System Level Save.\r
+ //\r
+\r
+ //\r
+ // Save changed value for each FormSet in the maintain list.\r
+ //\r
+ Link = GetFirstNode (&gBrowserFormSetList);\r
+ while (!IsNull (&gBrowserFormSetList, Link)) {\r
+ LocalFormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link);\r
+ SubmitForm (LocalFormSet, NULL, FormSetLevel);\r
+ Link = GetNextNode (&gBrowserFormSetList, Link);\r
+ if (!IsHiiHandleInBrowserContext (LocalFormSet->HiiHandle)) {\r
+ //\r
+ // Remove maintain backup list after save except for the current using FormSet.\r
+ //\r
+ RemoveEntryList (&LocalFormSet->Link);\r
+ DestroyFormSet (LocalFormSet);\r
+ }\r
+ }\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Get Question default value from AltCfg string.\r
+\r
+ @param FormSet The form set.\r
+ @param Question The question.\r
+ @param DefaultId The default Id.\r
+\r
+ @retval EFI_SUCCESS Question is reset to default value.\r
+\r
+**/\r
+EFI_STATUS\r
+GetDefaultValueFromAltCfg (\r
+ IN FORM_BROWSER_FORMSET *FormSet,\r
+ IN OUT FORM_BROWSER_STATEMENT *Question,\r
+ IN UINT16 DefaultId\r
+ )\r
+{\r
+ BOOLEAN IsBufferStorage;\r
+ BOOLEAN IsString; \r
+ UINTN Length;\r
+ FORMSET_STORAGE *Storage;\r
+ CHAR16 *ConfigRequest;\r
+ CHAR16 *Progress;\r
+ CHAR16 *Result;\r
+ CHAR16 *ConfigResp;\r
+ CHAR16 *Value;\r
+ CHAR16 *StringPtr;\r
+ UINTN LengthStr;\r
+ UINT8 *Dst;\r
+ CHAR16 TemStr[5];\r
+ UINTN Index;\r
+ UINT8 DigitUint8;\r
+ EFI_STATUS Status;\r
+\r
+ Status = EFI_NOT_FOUND;\r
+ Length = 0;\r
+ Dst = NULL;\r
+ ConfigRequest = NULL;\r
+ Result = NULL;\r
+ ConfigResp = NULL;\r
+ Value = NULL;\r
+ Storage = Question->Storage;\r
+\r
+ if ((Storage == NULL) || \r
+ (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) || \r
+ (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Question Value is provided by Buffer Storage or NameValue Storage\r
+ //\r
+ if (Question->BufferValue != NULL) {\r
+ //\r
+ // This Question is password or orderedlist\r
+ //\r
+ Dst = Question->BufferValue;\r
+ } else {\r
+ //\r
+ // Other type of Questions\r
+ //\r
+ Dst = (UINT8 *) &Question->HiiValue.Value;\r
+ }\r
+\r
+ IsBufferStorage = (BOOLEAN) ((Storage->Type == EFI_HII_VARSTORE_BUFFER) ? TRUE : FALSE);\r
+ IsString = (BOOLEAN) ((Question->HiiValue.Type == EFI_IFR_TYPE_STRING) ? TRUE : FALSE);\r
+\r
+ //\r
+ // <ConfigRequest> ::= <ConfigHdr> + <BlockName> ||\r
+ // <ConfigHdr> + "&" + <VariableName>\r
+ //\r
+ if (IsBufferStorage) {\r
+ Length = StrLen (Storage->ConfigHdr);\r
+ Length += StrLen (Question->BlockName);\r
+ } else {\r
+ Length = StrLen (Storage->ConfigHdr);\r
+ Length += StrLen (Question->VariableName) + 1;\r
+ }\r
+ ConfigRequest = AllocateZeroPool ((Length + 1) * sizeof (CHAR16));\r
+ ASSERT (ConfigRequest != NULL);\r
+\r
+ StrCpy (ConfigRequest, Storage->ConfigHdr);\r
+ if (IsBufferStorage) {\r
+ StrCat (ConfigRequest, Question->BlockName);\r
+ } else {\r
+ StrCat (ConfigRequest, L"&");\r
+ StrCat (ConfigRequest, Question->VariableName);\r
+ }\r
+\r
+ Status = FormSet->ConfigAccess->ExtractConfig (\r
+ FormSet->ConfigAccess,\r
+ ConfigRequest,\r
+ &Progress,\r
+ &Result\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ goto Done;\r
+ }\r
+\r
+ //\r
+ // Call ConfigRouting GetAltCfg(ConfigRoute, <ConfigResponse>, Guid, Name, DevicePath, AltCfgId, AltCfgResp)\r
+ // Get the default configuration string according to the default ID.\r
+ //\r
+ Status = mHiiConfigRouting->GetAltConfig (\r
+ mHiiConfigRouting,\r
+ Result,\r
+ &Storage->Guid,\r
+ Storage->Name,\r
+ NULL,\r
+ &DefaultId, // it can be NULL to get the current setting.\r
+ &ConfigResp\r
+ );\r
+ \r
+ //\r
+ // The required setting can't be found. So, it is not required to be validated and set.\r
+ //\r
+ if (EFI_ERROR (Status)) {\r
+ goto Done;\r
+ }\r
+\r
+ //\r
+ // Skip <ConfigRequest>\r
+ //\r
+ if (IsBufferStorage) {\r
+ Value = StrStr (ConfigResp, L"&VALUE");\r
+ ASSERT (Value != NULL);\r
+ //\r
+ // Skip "&VALUE"\r
+ //\r
+ Value = Value + 6;\r
+ } else {\r
+ Value = StrStr (ConfigResp, Question->VariableName);\r
+ ASSERT (Value != NULL);\r
+\r
+ Value = Value + StrLen (Question->VariableName);\r
+ }\r
+ if (*Value != '=') {\r
+ Status = EFI_NOT_FOUND;\r
+ goto Done;\r
+ }\r
+ //\r
+ // Skip '=', point to value\r
+ //\r
+ Value = Value + 1;\r
+\r
+ //\r
+ // Suppress <AltResp> if any\r
+ //\r
+ StringPtr = Value;\r
+ while (*StringPtr != L'\0' && *StringPtr != L'&') {\r
+ StringPtr++;\r
+ }\r
+ *StringPtr = L'\0';\r
+\r
+ LengthStr = StrLen (Value);\r
+ if (!IsBufferStorage && IsString) {\r
+ StringPtr = (CHAR16 *) Dst;\r
+ ZeroMem (TemStr, sizeof (TemStr));\r
+ for (Index = 0; Index < LengthStr; Index += 4) {\r
+ StrnCpy (TemStr, Value + Index, 4);\r
+ StringPtr[Index/4] = (CHAR16) StrHexToUint64 (TemStr);\r
+ }\r
+ //\r
+ // Add tailing L'\0' character\r
+ //\r
+ StringPtr[Index/4] = L'\0';\r
+ } else {\r
+ ZeroMem (TemStr, sizeof (TemStr));\r
+ for (Index = 0; Index < LengthStr; Index ++) {\r
+ TemStr[0] = Value[LengthStr - Index - 1];\r
+ DigitUint8 = (UINT8) StrHexToUint64 (TemStr);\r
+ if ((Index & 1) == 0) {\r
+ Dst [Index/2] = DigitUint8;\r
+ } else {\r
+ Dst [Index/2] = (UINT8) ((DigitUint8 << 4) + Dst [Index/2]);\r
+ }\r
+ }\r
+ }\r
+\r
+Done:\r
+ if (ConfigRequest != NULL){\r
+ FreePool (ConfigRequest);\r
+ }\r
+\r
+ if (ConfigResp != NULL) {\r
+ FreePool (ConfigResp);\r
+ }\r
+ \r
+ if (Result != NULL) {\r
+ FreePool (Result);\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Get default Id value used for browser.\r
+\r
+ @param DefaultId The default id value used by hii.\r
+\r
+ @retval Browser used default value.\r
+\r
+**/\r
+INTN\r
+GetDefaultIdForCallBack (\r
+ UINTN DefaultId\r
+ )\r
+{ \r
+ if (DefaultId == EFI_HII_DEFAULT_CLASS_STANDARD) {\r
+ return EFI_BROWSER_ACTION_DEFAULT_STANDARD;\r
+ } else if (DefaultId == EFI_HII_DEFAULT_CLASS_MANUFACTURING) {\r
+ return EFI_BROWSER_ACTION_DEFAULT_MANUFACTURING;\r
+ } else if (DefaultId == EFI_HII_DEFAULT_CLASS_SAFE) {\r
+ return EFI_BROWSER_ACTION_DEFAULT_SAFE;\r
+ } else if (DefaultId >= EFI_HII_DEFAULT_CLASS_PLATFORM_BEGIN && DefaultId < EFI_HII_DEFAULT_CLASS_PLATFORM_BEGIN + 0x1000) {\r
+ return EFI_BROWSER_ACTION_DEFAULT_PLATFORM + DefaultId - EFI_HII_DEFAULT_CLASS_PLATFORM_BEGIN;\r
+ } else if (DefaultId >= EFI_HII_DEFAULT_CLASS_HARDWARE_BEGIN && DefaultId < EFI_HII_DEFAULT_CLASS_HARDWARE_BEGIN + 0x1000) {\r
+ return EFI_BROWSER_ACTION_DEFAULT_HARDWARE + DefaultId - EFI_HII_DEFAULT_CLASS_HARDWARE_BEGIN;\r
+ } else if (DefaultId >= EFI_HII_DEFAULT_CLASS_FIRMWARE_BEGIN && DefaultId < EFI_HII_DEFAULT_CLASS_FIRMWARE_BEGIN + 0x1000) {\r
+ return EFI_BROWSER_ACTION_DEFAULT_FIRMWARE + DefaultId - EFI_HII_DEFAULT_CLASS_FIRMWARE_BEGIN;\r
+ } else {\r
+ return -1;\r
+ }\r
+}\r
+\r
+/**\r
+ Reset Question to its default value.\r
+\r
+ @param FormSet The form set.\r
+ @param Form The form.\r
+ @param Question The question.\r
+ @param DefaultId The Class of the default.\r
+\r
+ @retval EFI_SUCCESS Question is reset to default value.\r
+\r
+**/\r
+EFI_STATUS\r
+GetQuestionDefault (\r
+ IN FORM_BROWSER_FORMSET *FormSet,\r
+ IN FORM_BROWSER_FORM *Form,\r
+ IN FORM_BROWSER_STATEMENT *Question,\r
+ IN UINT16 DefaultId\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ LIST_ENTRY *Link;\r
+ QUESTION_DEFAULT *Default;\r
+ QUESTION_OPTION *Option;\r
+ EFI_HII_VALUE *HiiValue;\r
+ UINT8 Index;\r
+ EFI_STRING StrValue;\r
+ EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess;\r
+ EFI_BROWSER_ACTION_REQUEST ActionRequest;\r
+ INTN Action;\r
+\r
+ Status = EFI_NOT_FOUND;\r
+ StrValue = NULL;\r
+\r
+ //\r
+ // Statement don't have storage, skip them\r
+ //\r
+ if (Question->QuestionId == 0) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // There are Five ways to specify default value for a Question:\r
+ // 1, use call back function (highest priority)\r
+ // 2, use ExtractConfig function\r
+ // 3, use nested EFI_IFR_DEFAULT \r
+ // 4, set flags of EFI_ONE_OF_OPTION (provide Standard and Manufacturing default)\r
+ // 5, set flags of EFI_IFR_CHECKBOX (provide Standard and Manufacturing default) (lowest priority)\r
+ //\r
+ HiiValue = &Question->HiiValue;\r
+\r
+ //\r
+ // Get Question defaut value from call back function.\r
+ //\r
+ ConfigAccess = FormSet->ConfigAccess;\r
+ Action = GetDefaultIdForCallBack (DefaultId);\r
+ if ((Action > 0) && ((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) && (ConfigAccess != NULL)) {\r
+ ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;\r
+ Status = ConfigAccess->Callback (\r
+ ConfigAccess,\r
+ Action,\r
+ Question->QuestionId,\r
+ HiiValue->Type,\r
+ &HiiValue->Value,\r
+ &ActionRequest\r
+ );\r
+ if (!EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Get default value from altcfg string.\r
+ //\r
+ if (ConfigAccess != NULL) { \r
+ Status = GetDefaultValueFromAltCfg(FormSet, Question, DefaultId);\r
+ if (!EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ }\r
+\r
+ //\r
+ // EFI_IFR_DEFAULT has highest priority\r
+ //\r
+ if (!IsListEmpty (&Question->DefaultListHead)) {\r
+ Link = GetFirstNode (&Question->DefaultListHead);\r
+ while (!IsNull (&Question->DefaultListHead, Link)) {\r
+ Default = QUESTION_DEFAULT_FROM_LINK (Link);\r
+\r
+ if (Default->DefaultId == DefaultId) {\r
+ if (Default->ValueExpression != NULL) {\r
+ //\r
+ // Default is provided by an Expression, evaluate it\r
+ //\r
+ Status = EvaluateExpression (FormSet, Form, Default->ValueExpression);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ if (Default->ValueExpression->Result.Type == EFI_IFR_TYPE_BUFFER) {\r
+ ASSERT (HiiValue->Type == EFI_IFR_TYPE_BUFFER && Question->BufferValue != NULL);\r
+ if (Question->StorageWidth > Default->ValueExpression->Result.BufferLen) {\r
+ CopyMem (Question->HiiValue.Buffer, Default->ValueExpression->Result.Buffer, Default->ValueExpression->Result.BufferLen);\r
+ Question->HiiValue.BufferLen = Default->ValueExpression->Result.BufferLen;\r
+ } else {\r
+ CopyMem (Question->HiiValue.Buffer, Default->ValueExpression->Result.Buffer, Question->StorageWidth);\r
+ Question->HiiValue.BufferLen = Question->StorageWidth;\r
+ }\r
+ FreePool (Default->ValueExpression->Result.Buffer);\r
+ }\r
+ HiiValue->Type = Default->ValueExpression->Result.Type;\r
+ CopyMem (&HiiValue->Value, &Default->ValueExpression->Result.Value, sizeof (EFI_IFR_TYPE_VALUE)); \r
+ } else {\r
+ //\r
+ // Default value is embedded in EFI_IFR_DEFAULT\r
+ //\r
+ CopyMem (HiiValue, &Default->Value, sizeof (EFI_HII_VALUE));\r
+ }\r
+\r
+ if (HiiValue->Type == EFI_IFR_TYPE_STRING) {\r
+ StrValue = HiiGetString (FormSet->HiiHandle, HiiValue->Value.string, NULL);\r
+ if (StrValue == NULL) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+ if (Question->StorageWidth > StrSize (StrValue)) {\r
+ CopyMem (Question->BufferValue, StrValue, StrSize (StrValue));\r
+ } else {\r
+ CopyMem (Question->BufferValue, StrValue, Question->StorageWidth);\r
+ }\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ Link = GetNextNode (&Question->DefaultListHead, Link);\r
+ }\r
+ }\r
+\r
+ //\r
+ // EFI_ONE_OF_OPTION\r
+ //\r
+ if ((Question->Operand == EFI_IFR_ONE_OF_OP) && !IsListEmpty (&Question->OptionListHead)) {\r
+ if (DefaultId <= EFI_HII_DEFAULT_CLASS_MANUFACTURING) {\r
+ //\r
+ // OneOfOption could only provide Standard and Manufacturing default\r
+ //\r
+ Link = GetFirstNode (&Question->OptionListHead);\r
+ while (!IsNull (&Question->OptionListHead, Link)) {\r
+ Option = QUESTION_OPTION_FROM_LINK (Link);\r
+ Link = GetNextNode (&Question->OptionListHead, Link);\r
+\r
+ if ((Option->SuppressExpression != NULL) &&\r
+ EvaluateExpressionList(Option->SuppressExpression, FALSE, NULL, NULL) != ExpressFalse) {\r
+ continue;\r
+ }\r
+\r
+ if (((DefaultId == EFI_HII_DEFAULT_CLASS_STANDARD) && ((Option->Flags & EFI_IFR_OPTION_DEFAULT) != 0)) ||\r
+ ((DefaultId == EFI_HII_DEFAULT_CLASS_MANUFACTURING) && ((Option->Flags & EFI_IFR_OPTION_DEFAULT_MFG) != 0))\r
+ ) {\r
+ CopyMem (HiiValue, &Option->Value, sizeof (EFI_HII_VALUE));\r
+\r
+ return EFI_SUCCESS;\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ //\r
+ // EFI_IFR_CHECKBOX - lowest priority\r
+ //\r
+ if (Question->Operand == EFI_IFR_CHECKBOX_OP) {\r
+ if (DefaultId <= EFI_HII_DEFAULT_CLASS_MANUFACTURING) {\r
+ //\r
+ // Checkbox could only provide Standard and Manufacturing default\r
+ //\r
+ if (((DefaultId == EFI_HII_DEFAULT_CLASS_STANDARD) && ((Question->Flags & EFI_IFR_CHECKBOX_DEFAULT) != 0)) ||\r
+ ((DefaultId == EFI_HII_DEFAULT_CLASS_MANUFACTURING) && ((Question->Flags & EFI_IFR_CHECKBOX_DEFAULT_MFG) != 0))\r
+ ) {\r
+ HiiValue->Value.b = TRUE;\r
+ } else {\r
+ HiiValue->Value.b = FALSE;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+ }\r
+ }\r
+\r
+ //\r
+ // For Questions without default\r
+ //\r
+ Status = EFI_NOT_FOUND;\r
+ switch (Question->Operand) {\r
+ case EFI_IFR_NUMERIC_OP:\r
+ //\r
+ // Take minimum value as numeric default value\r
+ //\r
+ if ((HiiValue->Value.u64 < Question->Minimum) || (HiiValue->Value.u64 > Question->Maximum)) {\r
+ HiiValue->Value.u64 = Question->Minimum;\r
+ Status = EFI_SUCCESS;\r
+ }\r
+ break;\r
+\r
+ case EFI_IFR_ONE_OF_OP:\r
+ //\r
+ // Take first oneof option as oneof's default value\r
+ //\r
+ if (ValueToOption (Question, HiiValue) == NULL) {\r
+ Link = GetFirstNode (&Question->OptionListHead);\r
+ while (!IsNull (&Question->OptionListHead, Link)) {\r
+ Option = QUESTION_OPTION_FROM_LINK (Link);\r
+ Link = GetNextNode (&Question->OptionListHead, Link);\r
+\r
+ if ((Option->SuppressExpression != NULL) &&\r
+ EvaluateExpressionList(Option->SuppressExpression, FALSE, NULL, NULL) != ExpressFalse) {\r
+ continue;\r
+ }\r
+\r
+ CopyMem (HiiValue, &Option->Value, sizeof (EFI_HII_VALUE));\r
+ Status = EFI_SUCCESS;\r
+ break;\r
+ }\r
+ }\r
+ break;\r
+\r
+ case EFI_IFR_ORDERED_LIST_OP:\r
+ //\r
+ // Take option sequence in IFR as ordered list's default value\r
+ //\r
+ Index = 0;\r
+ Link = GetFirstNode (&Question->OptionListHead);\r
+ while (!IsNull (&Question->OptionListHead, Link)) {\r
+ Status = EFI_SUCCESS;\r
+ Option = QUESTION_OPTION_FROM_LINK (Link);\r
+ Link = GetNextNode (&Question->OptionListHead, Link);\r
+\r
+ if ((Option->SuppressExpression != NULL) &&\r
+ EvaluateExpressionList(Option->SuppressExpression, FALSE, NULL, NULL) != ExpressFalse) {\r
+ continue;\r
+ }\r
+\r
+ SetArrayData (Question->BufferValue, Question->ValueType, Index, Option->Value.Value.u64);\r
+\r
+ Index++;\r
+ if (Index >= Question->MaxContainers) {\r
+ break;\r
+ }\r
+ }\r
+ break;\r
+\r
+ default:\r
+ break;\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Reset Questions to their initial value or default value in a Form, Formset or System.\r
+\r
+ GetDefaultValueScope parameter decides which questions will reset \r
+ to its default value.\r
+\r
+ @param FormSet FormSet data structure.\r
+ @param Form Form data structure.\r
+ @param DefaultId The Class of the default.\r
+ @param SettingScope Setting Scope for Default action.\r
+ @param GetDefaultValueScope Get default value scope.\r
+ @param Storage Get default value only for this storage.\r
+ @param RetrieveValueFirst Whether call the retrieve call back to\r
+ get the initial value before get default\r
+ value.\r
+\r
+ @retval EFI_SUCCESS The function completed successfully.\r
+ @retval EFI_UNSUPPORTED Unsupport SettingScope.\r
+\r
+**/\r
+EFI_STATUS\r
+ExtractDefault (\r
+ IN FORM_BROWSER_FORMSET *FormSet,\r
+ IN FORM_BROWSER_FORM *Form,\r
+ IN UINT16 DefaultId,\r
+ IN BROWSER_SETTING_SCOPE SettingScope,\r
+ IN BROWSER_GET_DEFAULT_VALUE GetDefaultValueScope,\r
+ IN FORMSET_STORAGE *Storage OPTIONAL,\r
+ IN BOOLEAN RetrieveValueFirst\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ LIST_ENTRY *FormLink;\r
+ LIST_ENTRY *Link;\r
+ FORM_BROWSER_STATEMENT *Question;\r
+ FORM_BROWSER_FORMSET *BackUpFormSet;\r
+ FORM_BROWSER_FORMSET *LocalFormSet;\r
+ EFI_HII_HANDLE *HiiHandles;\r
+ UINTN Index;\r
+ EFI_GUID ZeroGuid;\r
+\r
+ Status = EFI_SUCCESS;\r
+\r
+ //\r
+ // Check the supported setting level.\r
+ //\r
+ if (SettingScope >= MaxLevel || GetDefaultValueScope >= GetDefaultForMax) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ if (GetDefaultValueScope == GetDefaultForStorage && Storage == NULL) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+ \r
+ if (SettingScope == FormLevel) {\r
+ //\r
+ // Extract Form default\r
+ //\r
+ Link = GetFirstNode (&Form->StatementListHead);\r
+ while (!IsNull (&Form->StatementListHead, Link)) {\r
+ Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link);\r
+ Link = GetNextNode (&Form->StatementListHead, Link);\r
+\r
+ //\r
+ // If get default value only for this storage, check the storage first.\r
+ //\r
+ if ((GetDefaultValueScope == GetDefaultForStorage) && (Question->Storage != Storage)) {\r
+ continue;\r
+ }\r
+\r
+ //\r
+ // If get default value only for no storage question, just skip the question which has storage.\r
+ //\r
+ if ((GetDefaultValueScope == GetDefaultForNoStorage) && (Question->Storage != NULL)) {\r
+ continue;\r
+ }\r
+\r
+ //\r
+ // If Question is disabled, don't reset it to default\r
+ //\r
+ if (Question->Expression != NULL) {\r
+ if (EvaluateExpressionList(Question->Expression, TRUE, FormSet, Form) == ExpressDisable) {\r
+ continue;\r
+ }\r
+ }\r
+\r
+ if (RetrieveValueFirst) {\r
+ //\r
+ // Call the Retrieve call back to get the initial question value.\r
+ //\r
+ Status = ProcessRetrieveForQuestion(FormSet->ConfigAccess, Question);\r
+ }\r
+\r
+ //\r
+ // If not request to get the initial value or get initial value fail, then get default value.\r
+ //\r
+ if (!RetrieveValueFirst || EFI_ERROR (Status)) {\r
+ Status = GetQuestionDefault (FormSet, Form, Question, DefaultId);\r
+ if (EFI_ERROR (Status)) {\r
+ continue;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Synchronize Buffer storage's Edit buffer\r
+ //\r
+ if ((Question->Storage != NULL) &&\r
+ (Question->Storage->Type != EFI_HII_VARSTORE_EFI_VARIABLE)) {\r
+ SetQuestionValue (FormSet, Form, Question, GetSetValueWithEditBuffer);\r
+ //\r
+ // Update Form NV flag.\r
+ //\r
+ Form->NvUpdateRequired = TRUE;\r
+ }\r
+ }\r
+ } else if (SettingScope == FormSetLevel) {\r
+ FormLink = GetFirstNode (&FormSet->FormListHead);\r
+ while (!IsNull (&FormSet->FormListHead, FormLink)) {\r
+ Form = FORM_BROWSER_FORM_FROM_LINK (FormLink);\r
+ ExtractDefault (FormSet, Form, DefaultId, FormLevel, GetDefaultValueScope, Storage, RetrieveValueFirst);\r
+ FormLink = GetNextNode (&FormSet->FormListHead, FormLink);\r
+ }\r
+ } else if (SettingScope == SystemLevel) {\r
+ //\r
+ // Open all FormSet by locate HII packages.\r
+ // Initiliaze the maintain FormSet to store default data as back up data.\r
+ //\r
+ BackUpFormSet = gOldFormSet;\r
+ gOldFormSet = NULL;\r
+\r
+ //\r
+ // Get all the Hii handles\r
+ //\r
+ HiiHandles = HiiGetHiiHandles (NULL);\r
+ ASSERT (HiiHandles != NULL);\r
+\r
+ //\r
+ // Search for formset of each class type\r
+ //\r
+ for (Index = 0; HiiHandles[Index] != NULL; Index++) {\r
+ //\r
+ // Check HiiHandles[Index] does exist in global maintain list. \r
+ //\r
+ if (GetFormSetFromHiiHandle (HiiHandles[Index]) != NULL) {\r
+ continue;\r
+ }\r
+ \r
+ //\r
+ // Initilize FormSet Setting\r
+ //\r
+ LocalFormSet = AllocateZeroPool (sizeof (FORM_BROWSER_FORMSET));\r
+ ASSERT (LocalFormSet != NULL);\r
+ ZeroMem (&ZeroGuid, sizeof (ZeroGuid));\r
+ Status = InitializeFormSet (HiiHandles[Index], &ZeroGuid, LocalFormSet, FALSE);\r
+ if (EFI_ERROR (Status) || IsListEmpty (&LocalFormSet->FormListHead)) {\r
+ DestroyFormSet (LocalFormSet);\r
+ continue;\r
+ }\r
+ Status = InitializeCurrentSetting (LocalFormSet);\r
+ if (EFI_ERROR (Status)) {\r
+ DestroyFormSet (LocalFormSet);\r
+ continue;\r
+ }\r
+ //\r
+ // Initilize Questions' Value\r
+ //\r
+ Status = LoadFormSetConfig (NULL, LocalFormSet);\r
+ if (EFI_ERROR (Status)) {\r
+ DestroyFormSet (LocalFormSet);\r
+ continue;\r
+ }\r
+\r
+ //\r
+ // Add FormSet into the maintain list.\r
+ //\r
+ InsertTailList (&gBrowserFormSetList, &LocalFormSet->Link);\r
+ }\r
+ \r
+ //\r
+ // Free resources, and restore gOldFormSet and gClassOfVfr\r
+ //\r
+ FreePool (HiiHandles);\r
+ gOldFormSet = BackUpFormSet;\r
+ \r
+ //\r
+ // Set Default Value for each FormSet in the maintain list.\r
+ //\r
+ Link = GetFirstNode (&gBrowserFormSetList);\r
+ while (!IsNull (&gBrowserFormSetList, Link)) {\r
+ LocalFormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link);\r
+ ExtractDefault (LocalFormSet, NULL, DefaultId, FormSetLevel, GetDefaultValueScope, Storage, RetrieveValueFirst);\r
+ Link = GetNextNode (&gBrowserFormSetList, Link);\r
+ }\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Initialize Question's Edit copy from Storage.\r
+\r
+ @param Selection Selection contains the information about \r
+ the Selection, form and formset to be displayed.\r
+ Selection action may be updated in retrieve callback.\r
+ If Selection is NULL, only initialize Question value.\r
+ @param FormSet FormSet data structure.\r
+ @param Form Form data structure.\r
+\r
+ @retval EFI_SUCCESS The function completed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+LoadFormConfig (\r
+ IN OUT UI_MENU_SELECTION *Selection,\r
+ IN FORM_BROWSER_FORMSET *FormSet,\r
+ IN FORM_BROWSER_FORM *Form\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ LIST_ENTRY *Link;\r
+ FORM_BROWSER_STATEMENT *Question;\r
+ UINT8 *BufferValue;\r
+ UINTN StorageWidth;\r
+ \r
+ Link = GetFirstNode (&Form->StatementListHead);\r
+ while (!IsNull (&Form->StatementListHead, Link)) {\r
+ Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link);\r
+\r
+ //\r
+ // Initialize local copy of Value for each Question\r
+ //\r
+ Status = GetQuestionValue (FormSet, Form, Question, GetSetValueWithEditBuffer);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ if ((Question->Operand == EFI_IFR_STRING_OP) || (Question->Operand == EFI_IFR_PASSWORD_OP)) {\r
+ HiiSetString (FormSet->HiiHandle, Question->HiiValue.Value.string, (CHAR16*)Question->BufferValue, NULL);\r
+ }\r
+\r
+ //\r
+ // Call the Retrieve call back function for all questions.\r
+ //\r
+ if ((FormSet->ConfigAccess != NULL) && (Selection != NULL) &&\r
+ ((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) == EFI_IFR_FLAG_CALLBACK)) {\r
+ //\r
+ // Check QuestionValue does exist.\r
+ //\r
+ StorageWidth = Question->StorageWidth;\r
+ if (Question->BufferValue != NULL) {\r
+ BufferValue = Question->BufferValue;\r
+ } else {\r
+ BufferValue = (UINT8 *) &Question->HiiValue.Value;\r
+ }\r
+\r
+ //\r
+ // For efivarstore storage, initial question value first.\r
+ //\r
+ if ((Question->Storage != NULL) && (Question->Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE)) {\r
+ Status = gRT->GetVariable (\r
+ Question->VariableName,\r
+ &Question->Storage->Guid,\r
+ NULL,\r
+ &StorageWidth,\r
+ BufferValue\r
+ );\r
+ }\r
+\r
+ Status = ProcessCallBackFunction(Selection, Question, EFI_BROWSER_ACTION_RETRIEVE, TRUE);\r
+ }\r
+\r
+ Link = GetNextNode (&Form->StatementListHead, Link);\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Initialize Question's Edit copy from Storage for the whole Formset.\r
+\r
+ @param Selection Selection contains the information about \r
+ the Selection, form and formset to be displayed.\r
+ Selection action may be updated in retrieve callback.\r
+ If Selection is NULL, only initialize Question value.\r
+ @param FormSet FormSet data structure.\r
+\r
+ @retval EFI_SUCCESS The function completed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+LoadFormSetConfig (\r
+ IN OUT UI_MENU_SELECTION *Selection,\r
+ IN FORM_BROWSER_FORMSET *FormSet\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ LIST_ENTRY *Link;\r
+ FORM_BROWSER_FORM *Form;\r
+\r
+ Link = GetFirstNode (&FormSet->FormListHead);\r
+ while (!IsNull (&FormSet->FormListHead, Link)) {\r
+ Form = FORM_BROWSER_FORM_FROM_LINK (Link);\r
+\r
+ //\r
+ // Initialize local copy of Value for each Form\r
+ //\r
+ Status = LoadFormConfig (Selection, FormSet, Form);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Link = GetNextNode (&FormSet->FormListHead, Link);\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Fill storage's edit copy with settings requested from Configuration Driver.\r
+\r
+ @param FormSet FormSet data structure.\r
+ @param Storage Buffer Storage.\r
+\r
+ @retval EFI_SUCCESS The function completed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+LoadStorage (\r
+ IN FORM_BROWSER_FORMSET *FormSet,\r
+ IN FORMSET_STORAGE *Storage\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_STRING Progress;\r
+ EFI_STRING Result;\r
+ CHAR16 *StrPtr;\r
+\r
+ if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER) {\r
+ Status = gRT->GetVariable (\r
+ Storage->Name,\r
+ &Storage->Guid,\r
+ NULL,\r
+ (UINTN*)&Storage->Size,\r
+ Storage->EditBuffer\r
+ );\r
+ return Status;\r
+ }\r
+\r
+ if (FormSet->ConfigAccess == NULL) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ if (Storage->ElementCount == 0) {\r
+ //\r
+ // Skip if there is no RequestElement\r
+ //\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ //\r
+ // Request current settings from Configuration Driver\r
+ //\r
+ Status = FormSet->ConfigAccess->ExtractConfig (\r
+ FormSet->ConfigAccess,\r
+ Storage->ConfigRequest,\r
+ &Progress,\r
+ &Result\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Convert Result from <ConfigAltResp> to <ConfigResp>\r
+ //\r
+ StrPtr = StrStr (Result, L"ALTCFG");\r
+ if (StrPtr != NULL) {\r
+ *StrPtr = L'\0';\r
+ }\r
+\r
+ Status = ConfigRespToStorage (Storage, Result);\r
+ FreePool (Result);\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Copy uncommitted data from source Storage to destination Storage.\r
+\r
+ @param Dst Target Storage for uncommitted data.\r
+ @param Src Source Storage for uncommitted data.\r
+\r
+ @retval EFI_SUCCESS The function completed successfully.\r
+ @retval EFI_INVALID_PARAMETER Source and destination Storage is not the same type.\r
+\r
+**/\r
+EFI_STATUS\r
+CopyStorage (\r
+ IN OUT FORMSET_STORAGE *Dst,\r
+ IN FORMSET_STORAGE *Src\r
+ )\r
+{\r
+ LIST_ENTRY *Link;\r
+ NAME_VALUE_NODE *Node;\r
+\r
+ if ((Dst->Type != Src->Type) || (Dst->Size != Src->Size)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ switch (Src->Type) {\r
+ case EFI_HII_VARSTORE_BUFFER:\r
+ case EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER:\r
+ CopyMem (Dst->EditBuffer, Src->EditBuffer, Src->Size);\r
+ CopyMem (Dst->Buffer, Src->Buffer, Src->Size);\r
+ break;\r
+\r
+ case EFI_HII_VARSTORE_NAME_VALUE:\r
+ Link = GetFirstNode (&Src->NameValueListHead);\r
+ while (!IsNull (&Src->NameValueListHead, Link)) {\r
+ Node = NAME_VALUE_NODE_FROM_LINK (Link);\r
+\r
+ SetValueByName (Dst, Node->Name, Node->EditValue, GetSetValueWithEditBuffer);\r
+ SetValueByName (Dst, Node->Name, Node->Value, GetSetValueWithBuffer);\r
+\r
+ Link = GetNextNode (&Src->NameValueListHead, Link);\r
+ }\r
+ break;\r
+\r
+ case EFI_HII_VARSTORE_EFI_VARIABLE:\r
+ default:\r
+ break;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Get old question value from the saved formset.\r
+\r
+ @param Statement The question which need to get old question value.\r
+ @param OldFormSet FormSet data structure saved in the list.\r
+\r
+**/\r
+VOID \r
+GetOldQuestionValue (\r
+ IN OUT FORM_BROWSER_STATEMENT *Statement,\r
+ IN FORM_BROWSER_FORMSET *OldFormSet\r
+ )\r
+{\r
+ LIST_ENTRY *FormLink;\r
+ LIST_ENTRY *Link;\r
+ FORM_BROWSER_STATEMENT *Question;\r
+ FORM_BROWSER_FORM *Form;\r
+\r
+ FormLink = GetFirstNode (&OldFormSet->FormListHead);\r
+ while (!IsNull (&OldFormSet->FormListHead, FormLink)) {\r
+ Form = FORM_BROWSER_FORM_FROM_LINK (FormLink);\r
+ FormLink = GetNextNode (&OldFormSet->FormListHead, FormLink);\r
+\r
+ Link = GetFirstNode (&Form->StatementListHead);\r
+ while (!IsNull (&Form->StatementListHead, Link)) {\r
+ Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link);\r
+ Link = GetNextNode (&Form->StatementListHead, Link);\r
+\r
+ if (Question->QuestionId != Statement->QuestionId) {\r
+ continue;\r
+ }\r
+\r
+ CopyMem (&Statement->HiiValue, &Question->HiiValue, sizeof (EFI_HII_VALUE));\r
+ return;\r
+ }\r
+ }\r
+}\r
+\r
+/**\r
+ Get old question value from the saved formset, all these questions not have\r
+ storage.\r
+\r
+ @param FormSet FormSet data structure which is used now.\r
+ @param OldFormSet FormSet data structure saved in the list.\r
+\r
+**/\r
+VOID\r
+CopyOldValueForNoStorageQst (\r
+ IN OUT FORM_BROWSER_FORMSET *FormSet,\r
+ IN FORM_BROWSER_FORMSET *OldFormSet\r
+ )\r
+{\r
+ LIST_ENTRY *FormLink;\r
+ LIST_ENTRY *Link;\r
+ FORM_BROWSER_STATEMENT *Question;\r
+ FORM_BROWSER_FORM *Form;\r
+\r
+ FormLink = GetFirstNode (&FormSet->FormListHead);\r
+ while (!IsNull (&FormSet->FormListHead, FormLink)) {\r
+ Form = FORM_BROWSER_FORM_FROM_LINK (FormLink);\r
+ FormLink = GetNextNode (&FormSet->FormListHead, FormLink);\r
+\r
+ Link = GetFirstNode (&Form->StatementListHead);\r
+ while (!IsNull (&Form->StatementListHead, Link)) {\r
+ Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link);\r
+ Link = GetNextNode (&Form->StatementListHead, Link);\r
+\r
+ if (Question->Storage == NULL) {\r
+ GetOldQuestionValue (Question, OldFormSet);\r
+ }\r
+ }\r
+ }\r
+}\r
+\r
+/**\r
+ Get current setting of Questions.\r
+\r
+ @param FormSet FormSet data structure.\r
+\r
+ @retval EFI_SUCCESS The function completed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+InitializeCurrentSetting (\r
+ IN OUT FORM_BROWSER_FORMSET *FormSet\r
+ )\r
+{\r
+ LIST_ENTRY *Link;\r
+ LIST_ENTRY *Link2;\r
+ FORMSET_STORAGE *Storage;\r
+ FORMSET_STORAGE *StorageSrc;\r
+ FORMSET_STORAGE *OldStorage;\r
+ FORM_BROWSER_FORM *Form;\r
+ FORM_BROWSER_FORM *Form2;\r
+ EFI_STATUS Status;\r
+\r
+ //\r
+ // Extract default from IFR binary for no storage questions.\r
+ // \r
+ ExtractDefault (FormSet, NULL, EFI_HII_DEFAULT_CLASS_STANDARD, FormSetLevel, GetDefaultForNoStorage, NULL, TRUE);\r
+\r
+ //\r
+ // Request current settings from Configuration Driver\r
+ //\r
+ Link = GetFirstNode (&FormSet->StorageListHead);\r
+ while (!IsNull (&FormSet->StorageListHead, Link)) {\r
+ Storage = FORMSET_STORAGE_FROM_LINK (Link);\r
+\r
+ OldStorage = NULL;\r
+ if (gOldFormSet != NULL) {\r
+ //\r
+ // Try to find the Storage in backup formset gOldFormSet\r
+ //\r
+ Link2 = GetFirstNode (&gOldFormSet->StorageListHead);\r
+ while (!IsNull (&gOldFormSet->StorageListHead, Link2)) {\r
+ StorageSrc = FORMSET_STORAGE_FROM_LINK (Link2);\r
+\r
+ if (StorageSrc->VarStoreId == Storage->VarStoreId) {\r
+ OldStorage = StorageSrc;\r
+ break;\r
+ }\r
+\r
+ Link2 = GetNextNode (&gOldFormSet->StorageListHead, Link2);\r
+ }\r
+ }\r
+\r
+ if (OldStorage == NULL) {\r
+ //\r
+ // Storage is not found in backup formset, request it from ConfigDriver\r
+ //\r
+ Status = LoadStorage (FormSet, Storage);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ //\r
+ // If get last time changed value failed, extract default from IFR binary\r
+ //\r
+ ExtractDefault (FormSet, NULL, EFI_HII_DEFAULT_CLASS_STANDARD, FormSetLevel, GetDefaultForStorage, Storage, TRUE);\r
+ //\r
+ // ExtractDefault will set the NV flag to TRUE, so need this function to clean the flag\r
+ // in current situation.\r
+ //\r
+ UpdateNvInfoInForm (FormSet, FALSE);\r
+ }\r
+\r
+ //\r
+ // Now Edit Buffer is filled with default values(lower priority) or current\r
+ // settings(higher priority), sychronize it to shadow Buffer\r
+ //\r
+ SynchronizeStorage (Storage, TRUE);\r
+ } else {\r
+ //\r
+ // Storage found in backup formset, use it\r
+ //\r
+ Status = CopyStorage (Storage, OldStorage);\r
+ }\r
+\r
+ Link = GetNextNode (&FormSet->StorageListHead, Link);\r
+ }\r
+\r
+ //\r
+ // If has old formset, get the old nv update status.\r
+ //\r
+ if (gOldFormSet != NULL) {\r
+ Link = GetFirstNode (&FormSet->FormListHead);\r
+ while (!IsNull (&FormSet->FormListHead, Link)) {\r
+ Form = FORM_BROWSER_FORM_FROM_LINK (Link);\r
+\r
+ Link2 = GetFirstNode (&gOldFormSet->FormListHead);\r
+ while (!IsNull (&gOldFormSet->FormListHead, Link2)) {\r
+ Form2 = FORM_BROWSER_FORM_FROM_LINK (Link2);\r
+\r
+ if (Form->FormId == Form2->FormId) {\r
+ Form->NvUpdateRequired = Form2->NvUpdateRequired;\r
+ break;\r
+ }\r
+\r
+ Link2 = GetNextNode (&gOldFormSet->FormListHead, Link2);\r
+ }\r
+ Link = GetNextNode (&FormSet->FormListHead, Link);\r
+ }\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ Fetch the Ifr binary data of a FormSet.\r
+\r
+ @param Handle PackageList Handle\r
+ @param FormSetGuid On input, GUID or class GUID of a formset. If not\r
+ specified (NULL or zero GUID), take the first\r
+ FormSet with class GUID EFI_HII_PLATFORM_SETUP_FORMSET_GUID\r
+ found in package list.\r
+ On output, GUID of the formset found(if not NULL).\r
+ @param BinaryLength The length of the FormSet IFR binary.\r
+ @param BinaryData The buffer designed to receive the FormSet.\r
+\r
+ @retval EFI_SUCCESS Buffer filled with the requested FormSet.\r
+ BufferLength was updated.\r
+ @retval EFI_INVALID_PARAMETER The handle is unknown.\r
+ @retval EFI_NOT_FOUND A form or FormSet on the requested handle cannot\r
+ be found with the requested FormId.\r
+\r
+**/\r
+EFI_STATUS\r
+GetIfrBinaryData (\r
+ IN EFI_HII_HANDLE Handle,\r
+ IN OUT EFI_GUID *FormSetGuid,\r
+ OUT UINTN *BinaryLength,\r
+ OUT UINT8 **BinaryData\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_HII_PACKAGE_LIST_HEADER *HiiPackageList;\r
+ UINTN BufferSize;\r
+ UINT8 *Package;\r
+ UINT8 *OpCodeData;\r
+ UINT32 Offset;\r
+ UINT32 Offset2;\r
+ UINT32 PackageListLength;\r
+ EFI_HII_PACKAGE_HEADER PackageHeader;\r
+ UINT8 Index;\r
+ UINT8 NumberOfClassGuid;\r
+ BOOLEAN ClassGuidMatch;\r
+ EFI_GUID *ClassGuid;\r
+ EFI_GUID *ComparingGuid;\r
+\r
+ OpCodeData = NULL;\r
+ Package = NULL;\r
+ ZeroMem (&PackageHeader, sizeof (EFI_HII_PACKAGE_HEADER));\r
+\r
+ //\r
+ // if FormSetGuid is NULL or zero GUID, return first Setup FormSet in the package list\r
+ //\r
+ if (FormSetGuid == NULL) {\r
+ ComparingGuid = &gZeroGuid;\r
+ } else {\r
+ ComparingGuid = FormSetGuid;\r
+ }\r
+\r
+ //\r
+ // Get HII PackageList\r
+ //\r
+ BufferSize = 0;\r
+ HiiPackageList = NULL;\r
+ Status = mHiiDatabase->ExportPackageLists (mHiiDatabase, Handle, &BufferSize, HiiPackageList);\r
+ if (Status == EFI_BUFFER_TOO_SMALL) {\r
+ HiiPackageList = AllocatePool (BufferSize);\r
+ ASSERT (HiiPackageList != NULL);\r
+\r
+ Status = mHiiDatabase->ExportPackageLists (mHiiDatabase, Handle, &BufferSize, HiiPackageList);\r
+ }\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ ASSERT (HiiPackageList != NULL);\r
+\r
+ //\r
+ // Get Form package from this HII package List\r
+ //\r
+ Offset = sizeof (EFI_HII_PACKAGE_LIST_HEADER);\r
+ Offset2 = 0;\r
+ CopyMem (&PackageListLength, &HiiPackageList->PackageLength, sizeof (UINT32));\r
+\r
+ ClassGuidMatch = FALSE;\r
+ while (Offset < PackageListLength) {\r
+ Package = ((UINT8 *) HiiPackageList) + Offset;\r
+ CopyMem (&PackageHeader, Package, sizeof (EFI_HII_PACKAGE_HEADER));\r
+\r
+ if (PackageHeader.Type == EFI_HII_PACKAGE_FORMS) {\r
+ //\r
+ // Search FormSet in this Form Package\r
+ //\r
+ Offset2 = sizeof (EFI_HII_PACKAGE_HEADER);\r
+ while (Offset2 < PackageHeader.Length) {\r
+ OpCodeData = Package + Offset2;\r
+\r
+ if (((EFI_IFR_OP_HEADER *) OpCodeData)->OpCode == EFI_IFR_FORM_SET_OP) {\r
+ //\r
+ // Try to compare against formset GUID\r
+ //\r
+ if (CompareGuid (FormSetGuid, &gZeroGuid) || \r
+ CompareGuid (ComparingGuid, (EFI_GUID *)(OpCodeData + sizeof (EFI_IFR_OP_HEADER)))) {\r
+ break;\r
+ }\r
+\r
+ if (((EFI_IFR_OP_HEADER *) OpCodeData)->Length > OFFSET_OF (EFI_IFR_FORM_SET, Flags)) {\r
+ //\r
+ // Try to compare against formset class GUID\r
+ //\r
+ NumberOfClassGuid = (UINT8) (((EFI_IFR_FORM_SET *) OpCodeData)->Flags & 0x3);\r
+ ClassGuid = (EFI_GUID *) (OpCodeData + sizeof (EFI_IFR_FORM_SET));\r
+ for (Index = 0; Index < NumberOfClassGuid; Index++) {\r
+ if (CompareGuid (ComparingGuid, ClassGuid + Index)) {\r
+ ClassGuidMatch = TRUE;\r
+ break;\r
+ }\r
+ }\r
+ if (ClassGuidMatch) {\r
+ break;\r
+ }\r
+ } else if (ComparingGuid == &gEfiHiiPlatformSetupFormsetGuid) {\r
+ ClassGuidMatch = TRUE;\r
+ break;\r
+ }\r
+ }\r
+\r
+ Offset2 += ((EFI_IFR_OP_HEADER *) OpCodeData)->Length;\r
+ }\r
+\r
+ if (Offset2 < PackageHeader.Length) {\r
+ //\r
+ // Target formset found\r
+ //\r
+ break;\r
+ }\r
+ }\r
+\r
+ Offset += PackageHeader.Length;\r
+ }\r
+\r
+ if (Offset >= PackageListLength) {\r
+ //\r
+ // Form package not found in this Package List\r
+ //\r
+ FreePool (HiiPackageList);\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ if (FormSetGuid != NULL) {\r
+ //\r
+ // Return the FormSet GUID\r
+ //\r
+ CopyMem (FormSetGuid, &((EFI_IFR_FORM_SET *) OpCodeData)->Guid, sizeof (EFI_GUID));\r
+ }\r
+\r
+ //\r
+ // To determine the length of a whole FormSet IFR binary, one have to parse all the Opcodes\r
+ // in this FormSet; So, here just simply copy the data from start of a FormSet to the end\r
+ // of the Form Package.\r
+ //\r
+ *BinaryLength = PackageHeader.Length - Offset2;\r
+ *BinaryData = AllocateCopyPool (*BinaryLength, OpCodeData);\r
+\r
+ FreePool (HiiPackageList);\r
+\r
+ if (*BinaryData == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ Initialize the internal data structure of a FormSet.\r
+\r
+ @param Handle PackageList Handle\r
+ @param FormSetGuid On input, GUID or class GUID of a formset. If not\r
+ specified (NULL or zero GUID), take the first\r
+ FormSet with class GUID EFI_HII_PLATFORM_SETUP_FORMSET_GUID\r
+ found in package list.\r
+ On output, GUID of the formset found(if not NULL).\r
+ @param FormSet FormSet data structure.\r
+ @param UpdateGlobalVar Whether need to update the global variable.\r
+\r
+ @retval EFI_SUCCESS The function completed successfully.\r
+ @retval EFI_NOT_FOUND The specified FormSet could not be found.\r
+\r
+**/\r
+EFI_STATUS\r
+InitializeFormSet (\r
+ IN EFI_HII_HANDLE Handle,\r
+ IN OUT EFI_GUID *FormSetGuid,\r
+ OUT FORM_BROWSER_FORMSET *FormSet,\r
+ IN BOOLEAN UpdateGlobalVar \r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_HANDLE DriverHandle;\r
+ UINT16 Index;\r
+\r
+ Status = GetIfrBinaryData (Handle, FormSetGuid, &FormSet->IfrBinaryLength, &FormSet->IfrBinaryData);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ FormSet->Signature = FORM_BROWSER_FORMSET_SIGNATURE;\r
+ FormSet->HiiHandle = Handle;\r
+ CopyMem (&FormSet->Guid, FormSetGuid, sizeof (EFI_GUID));\r
+\r
+ //\r
+ // Retrieve ConfigAccess Protocol associated with this HiiPackageList\r
+ //\r
+ Status = mHiiDatabase->GetPackageListHandle (mHiiDatabase, Handle, &DriverHandle);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ FormSet->DriverHandle = DriverHandle;\r
+ Status = gBS->HandleProtocol (\r
+ DriverHandle,\r
+ &gEfiHiiConfigAccessProtocolGuid,\r
+ (VOID **) &FormSet->ConfigAccess\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ //\r
+ // Configuration Driver don't attach ConfigAccess protocol to its HII package\r
+ // list, then there will be no configuration action required\r
+ //\r
+ FormSet->ConfigAccess = NULL;\r
+ }\r
+\r
+ //\r
+ // Parse the IFR binary OpCodes\r
+ //\r
+ Status = ParseOpCodes (FormSet);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ // \r
+ // If not need to update the global variable, just return.\r
+ //\r
+ if (!UpdateGlobalVar) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Set VFR type by FormSet SubClass field\r
+ //\r
+ gClassOfVfr = FORMSET_CLASS_PLATFORM_SETUP;\r
+ if (FormSet->SubClass == EFI_FRONT_PAGE_SUBCLASS) {\r
+ gClassOfVfr = FORMSET_CLASS_FRONT_PAGE;\r
+ }\r
+ \r
+ //\r
+ // Set VFR type by FormSet class guid\r
+ //\r
+ for (Index = 0; Index < 3; Index ++) {\r
+ if (CompareGuid (&FormSet->ClassGuid[Index], &gEfiHiiPlatformSetupFormsetGuid)) {\r
+ gClassOfVfr |= FORMSET_CLASS_PLATFORM_SETUP;\r
+ break;\r
+ }\r
+ }\r
+\r
+ if ((gClassOfVfr & FORMSET_CLASS_FRONT_PAGE) == FORMSET_CLASS_FRONT_PAGE) {\r
+ gFrontPageHandle = FormSet->HiiHandle;\r
+ gFunctionKeySetting = NONE_FUNCTION_KEY_SETTING;\r
+ }\r
+\r
+ //\r
+ // Match GUID to find out the function key setting. If match fail, use the default setting.\r
+ //\r
+ for (Index = 0; Index < sizeof (gFunctionKeySettingTable) / sizeof (FUNCTIION_KEY_SETTING); Index++) {\r
+ if (CompareGuid (&FormSet->Guid, &(gFunctionKeySettingTable[Index].FormSetGuid))) {\r
+ //\r
+ // Update the function key setting.\r
+ //\r
+ gFunctionKeySetting = gFunctionKeySettingTable[Index].KeySetting;\r
+ }\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ Save globals used by previous call to SendForm(). SendForm() may be called from \r
+ HiiConfigAccess.Callback(), this will cause SendForm() be reentried.\r
+ So, save globals of previous call to SendForm() and restore them upon exit.\r
+\r
+**/\r
+VOID\r
+SaveBrowserContext (\r
+ VOID\r
+ )\r
+{\r
+ BROWSER_CONTEXT *Context;\r
+\r
+ gBrowserContextCount++;\r
+ if (gBrowserContextCount == 1) {\r
+ //\r
+ // This is not reentry of SendForm(), no context to save\r
+ //\r
+ return;\r
+ }\r
+\r
+ Context = AllocatePool (sizeof (BROWSER_CONTEXT));\r
+ ASSERT (Context != NULL);\r
+\r
+ Context->Signature = BROWSER_CONTEXT_SIGNATURE;\r
+\r
+ //\r
+ // Save FormBrowser context\r
+ //\r
+ Context->BannerData = gBannerData;\r
+ Context->ClassOfVfr = gClassOfVfr;\r
+ Context->FunctionKeySetting = gFunctionKeySetting;\r
+ Context->ResetRequired = gResetRequired;\r
+ Context->Direction = gDirection;\r
+ Context->EnterString = gEnterString;\r
+ Context->EnterCommitString = gEnterCommitString;\r
+ Context->EnterEscapeString = gEnterEscapeString;\r
+ Context->EscapeString = gEscapeString;\r
+ Context->MoveHighlight = gMoveHighlight;\r
+ Context->MakeSelection = gMakeSelection;\r
+ Context->DecNumericInput = gDecNumericInput;\r
+ Context->HexNumericInput = gHexNumericInput;\r
+ Context->ToggleCheckBox = gToggleCheckBox;\r
+ Context->PromptForData = gPromptForData;\r
+ Context->PromptForPassword = gPromptForPassword;\r
+ Context->PromptForNewPassword = gPromptForNewPassword;\r
+ Context->ConfirmPassword = gConfirmPassword;\r
+ Context->ConfirmError = gConfirmError;\r
+ Context->PassowordInvalid = gPassowordInvalid;\r
+ Context->PressEnter = gPressEnter;\r
+ Context->EmptyString = gEmptyString;\r
+ Context->AreYouSure = gAreYouSure;\r
+ Context->YesResponse = gYesResponse;\r
+ Context->NoResponse = gNoResponse;\r
+ Context->MiniString = gMiniString;\r
+ Context->PlusString = gPlusString;\r
+ Context->MinusString = gMinusString;\r
+ Context->AdjustNumber = gAdjustNumber;\r
+ Context->SaveChanges = gSaveChanges;\r
+ Context->OptionMismatch = gOptionMismatch;\r
+ Context->FormSuppress = gFormSuppress;\r
+ Context->PromptBlockWidth = gPromptBlockWidth;\r
+ Context->OptionBlockWidth = gOptionBlockWidth;\r
+ Context->HelpBlockWidth = gHelpBlockWidth;\r
+ Context->OldFormSet = gOldFormSet;\r
+ Context->MenuRefreshHead = gMenuRefreshHead;\r
+\r
+ CopyMem (&Context->ScreenDimensions, &gScreenDimensions, sizeof (gScreenDimensions));\r
+ CopyMem (&Context->MenuOption, &gMenuOption, sizeof (gMenuOption));\r
+\r
+ //\r
+ // Insert to FormBrowser context list\r
+ //\r
+ InsertHeadList (&gBrowserContextList, &Context->Link);\r
+}\r
+\r
+\r
+/**\r
+ Restore globals used by previous call to SendForm().\r
+\r
+**/\r
+VOID\r
+RestoreBrowserContext (\r
+ VOID\r
+ )\r
+{\r
+ LIST_ENTRY *Link;\r
+ BROWSER_CONTEXT *Context;\r
+\r
+ ASSERT (gBrowserContextCount != 0);\r
+ gBrowserContextCount--;\r
+ if (gBrowserContextCount == 0) {\r
+ //\r
+ // This is not reentry of SendForm(), no context to restore\r
+ //\r
+ return;\r
+ }\r
+\r
+ ASSERT (!IsListEmpty (&gBrowserContextList));\r
+\r
+ Link = GetFirstNode (&gBrowserContextList);\r
+ Context = BROWSER_CONTEXT_FROM_LINK (Link);\r
+\r
+ //\r
+ // Restore FormBrowser context\r
+ //\r
+ gBannerData = Context->BannerData;\r
+ gClassOfVfr = Context->ClassOfVfr;\r
+ gFunctionKeySetting = Context->FunctionKeySetting;\r
+ gResetRequired = Context->ResetRequired;\r
+ gDirection = Context->Direction;\r
+ gEnterString = Context->EnterString;\r
+ gEnterCommitString = Context->EnterCommitString;\r
+ gEnterEscapeString = Context->EnterEscapeString;\r
+ gEscapeString = Context->EscapeString;\r
+ gMoveHighlight = Context->MoveHighlight;\r
+ gMakeSelection = Context->MakeSelection;\r
+ gDecNumericInput = Context->DecNumericInput;\r
+ gHexNumericInput = Context->HexNumericInput;\r
+ gToggleCheckBox = Context->ToggleCheckBox;\r
+ gPromptForData = Context->PromptForData;\r
+ gPromptForPassword = Context->PromptForPassword;\r
+ gPromptForNewPassword = Context->PromptForNewPassword;\r
+ gConfirmPassword = Context->ConfirmPassword;\r
+ gConfirmError = Context->ConfirmError;\r
+ gPassowordInvalid = Context->PassowordInvalid;\r
+ gPressEnter = Context->PressEnter;\r
+ gEmptyString = Context->EmptyString;\r
+ gAreYouSure = Context->AreYouSure;\r
+ gYesResponse = Context->YesResponse;\r
+ gNoResponse = Context->NoResponse;\r
+ gMiniString = Context->MiniString;\r
+ gPlusString = Context->PlusString;\r
+ gMinusString = Context->MinusString;\r
+ gAdjustNumber = Context->AdjustNumber;\r
+ gSaveChanges = Context->SaveChanges;\r
+ gOptionMismatch = Context->OptionMismatch;\r
+ gFormSuppress = Context->FormSuppress;\r
+ gPromptBlockWidth = Context->PromptBlockWidth;\r
+ gOptionBlockWidth = Context->OptionBlockWidth;\r
+ gHelpBlockWidth = Context->HelpBlockWidth;\r
+ gOldFormSet = Context->OldFormSet;\r
+ gMenuRefreshHead = Context->MenuRefreshHead;\r
+\r
+ CopyMem (&gScreenDimensions, &Context->ScreenDimensions, sizeof (gScreenDimensions));\r
+ CopyMem (&gMenuOption, &Context->MenuOption, sizeof (gMenuOption));\r
+\r
+ //\r
+ // Remove from FormBrowser context list\r
+ //\r
+ RemoveEntryList (&Context->Link);\r
+ gBS->FreePool (Context);\r
+}\r
+\r
+/**\r
+ Find the matched FormSet context in the backup maintain list based on HiiHandle.\r
+ \r
+ @param Handle The Hii Handle.\r
+ \r
+ @return the found FormSet context. If no found, NULL will return.\r
+\r
+**/\r
+FORM_BROWSER_FORMSET * \r
+GetFormSetFromHiiHandle (\r
+ EFI_HII_HANDLE Handle\r
+ )\r
+{\r
+ LIST_ENTRY *Link;\r
+ FORM_BROWSER_FORMSET *FormSet;\r
+\r
+ Link = GetFirstNode (&gBrowserFormSetList);\r
+ while (!IsNull (&gBrowserFormSetList, Link)) {\r
+ FormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link);\r
+ if (FormSet->HiiHandle == Handle) {\r
+ return FormSet;\r
+ }\r
+ Link = GetNextNode (&gBrowserFormSetList, Link);\r
+ }\r
+ \r
+ return NULL;\r
+}\r
+\r
+/**\r
+ Check whether the input HII handle is the FormSet that is being used.\r
+ \r
+ @param Handle The Hii Handle.\r
+ \r
+ @retval TRUE HII handle is being used.\r
+ @retval FALSE HII handle is not being used.\r
+\r
+**/\r
+BOOLEAN\r
+IsHiiHandleInBrowserContext (\r
+ EFI_HII_HANDLE Handle\r
+ )\r
+{\r
+ LIST_ENTRY *Link;\r
+ BROWSER_CONTEXT *Context;\r
+\r
+ //\r
+ // HiiHandle is Current FormSet.\r
+ //\r
+ if ((gOldFormSet != NULL) && (gOldFormSet->HiiHandle == Handle)) {\r
+ return TRUE;\r
+ }\r
+\r
+ //\r
+ // Check whether HiiHandle is in BrowserContext.\r
+ //\r
+ Link = GetFirstNode (&gBrowserContextList);\r
+ while (!IsNull (&gBrowserContextList, Link)) {\r
+ Context = BROWSER_CONTEXT_FROM_LINK (Link);\r
+ if (Context->OldFormSet->HiiHandle == Handle) {\r
+ //\r
+ // HiiHandle is in BrowserContext\r
+ //\r
+ return TRUE;\r
+ }\r
+ Link = GetNextNode (&gBrowserContextList, Link);\r
+ }\r
+ \r
+ return FALSE;\r
+}\r
+\r
+/**\r
+ Find the registered HotKey based on KeyData.\r
+ \r
+ @param[in] KeyData A pointer to a buffer that describes the keystroke\r
+ information for the hot key.\r
+\r
+ @return The registered HotKey context. If no found, NULL will return.\r
+**/\r
+BROWSER_HOT_KEY *\r
+GetHotKeyFromRegisterList (\r
+ IN EFI_INPUT_KEY *KeyData\r
+ )\r
+{\r
+ LIST_ENTRY *Link;\r
+ BROWSER_HOT_KEY *HotKey;\r
+\r
+ Link = GetFirstNode (&gBrowserHotKeyList);\r
+ while (!IsNull (&gBrowserHotKeyList, Link)) {\r
+ HotKey = BROWSER_HOT_KEY_FROM_LINK (Link);\r
+ if (HotKey->KeyData->ScanCode == KeyData->ScanCode) {\r
+ return HotKey;\r
+ }\r
+ Link = GetNextNode (&gBrowserHotKeyList, Link);\r
+ }\r
+ \r
+ return NULL;\r
+}\r
+\r
+/**\r
+ Configure what scope the hot key will impact.\r
+ All hot keys have the same scope. The mixed hot keys with the different level are not supported.\r
+ If no scope is set, the default scope will be FormSet level.\r
+ After all registered hot keys are removed, previous Scope can reset to another level.\r
+ \r
+ @param[in] Scope Scope level to be set. \r
+ \r
+ @retval EFI_SUCCESS Scope is set correctly.\r
+ @retval EFI_INVALID_PARAMETER Scope is not the valid value specified in BROWSER_SETTING_SCOPE. \r
+ @retval EFI_UNSPPORTED Scope level is different from current one that the registered hot keys have.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SetScope (\r
+ IN BROWSER_SETTING_SCOPE Scope\r
+ )\r
+{\r
+ if (Scope >= MaxLevel) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ \r
+ //\r
+ // When no hot key registered in system or on the first setting,\r
+ // Scope can be set.\r
+ //\r
+ if (mBrowserScopeFirstSet || IsListEmpty (&gBrowserHotKeyList)) {\r
+ gBrowserSettingScope = Scope;\r
+ mBrowserScopeFirstSet = FALSE;\r
+ } else if (Scope != gBrowserSettingScope) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Register the hot key with its browser action, or unregistered the hot key.\r
+ Only support hot key that is not printable character (control key, function key, etc.).\r
+ If the action value is zero, the hot key will be unregistered if it has been registered.\r
+ If the same hot key has been registered, the new action and help string will override the previous ones.\r
+ \r
+ @param[in] KeyData A pointer to a buffer that describes the keystroke\r
+ information for the hot key. Its type is EFI_INPUT_KEY to \r
+ be supported by all ConsoleIn devices.\r
+ @param[in] Action Action value that describes what action will be trigged when the hot key is pressed. \r
+ @param[in] DefaultId Specifies the type of defaults to retrieve, which is only for DEFAULT action.\r
+ @param[in] HelpString Help string that describes the hot key information.\r
+ Its value may be NULL for the unregistered hot key.\r
+ \r
+ @retval EFI_SUCCESS Hot key is registered or unregistered.\r
+ @retval EFI_INVALID_PARAMETER KeyData is NULL or HelpString is NULL on register.\r
+ @retval EFI_NOT_FOUND KeyData is not found to be unregistered.\r
+ @retval EFI_UNSUPPORTED Key represents a printable character. It is conflicted with Browser.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+RegisterHotKey (\r
+ IN EFI_INPUT_KEY *KeyData,\r
+ IN UINT32 Action,\r
+ IN UINT16 DefaultId,\r
+ IN EFI_STRING HelpString OPTIONAL\r
+ )\r
+{\r
+ BROWSER_HOT_KEY *HotKey;\r
+\r
+ //\r
+ // Check input parameters.\r
+ //\r
+ if (KeyData == NULL || KeyData->UnicodeChar != CHAR_NULL || \r
+ (Action != BROWSER_ACTION_UNREGISTER && HelpString == NULL)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ //\r
+ // Check whether the input KeyData is in BrowserHotKeyList.\r
+ //\r
+ HotKey = GetHotKeyFromRegisterList (KeyData);\r
+ \r
+ //\r
+ // Unregister HotKey\r
+ //\r
+ if (Action == BROWSER_ACTION_UNREGISTER) {\r
+ if (HotKey != NULL) {\r
+ //\r
+ // The registered HotKey is found. \r
+ // Remove it from List, and free its resource.\r
+ //\r
+ RemoveEntryList (&HotKey->Link);\r
+ FreePool (HotKey->KeyData);\r
+ FreePool (HotKey->HelpString);\r
+ return EFI_SUCCESS;\r
+ } else {\r
+ //\r
+ // The registered HotKey is not found. \r
+ //\r
+ return EFI_NOT_FOUND;\r
+ }\r
+ }\r
+ \r
+ //\r
+ // Register HotKey into List.\r
+ //\r
+ if (HotKey == NULL) {\r
+ //\r
+ // Create new Key, and add it into List.\r
+ //\r
+ HotKey = AllocateZeroPool (sizeof (BROWSER_HOT_KEY));\r
+ ASSERT (HotKey != NULL);\r
+ HotKey->Signature = BROWSER_HOT_KEY_SIGNATURE;\r
+ HotKey->KeyData = AllocateCopyPool (sizeof (EFI_INPUT_KEY), KeyData);\r
+ InsertTailList (&gBrowserHotKeyList, &HotKey->Link);\r
+ }\r
+\r
+ //\r
+ // Fill HotKey information.\r
+ //\r
+ HotKey->Action = Action;\r
+ HotKey->DefaultId = DefaultId;\r
+ if (HotKey->HelpString != NULL) {\r
+ FreePool (HotKey->HelpString);\r
+ }\r
+ HotKey->HelpString = AllocateCopyPool (StrSize (HelpString), HelpString);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Register Exit handler function. \r
+ When more than one handler function is registered, the latter one will override the previous one. \r
+ When NULL handler is specified, the previous Exit handler will be unregistered. \r
+ \r
+ @param[in] Handler Pointer to handler function. \r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+RegiserExitHandler (\r
+ IN EXIT_HANDLER Handler\r
+ )\r
+{\r
+ ExitHandlerFunction = Handler;\r
+ return;\r
+}\r
+\r
+/**\r
+ Create reminder to let user to choose save or discard the changed browser data.\r
+ Caller can use it to actively check the changed browser data.\r
+\r
+ @retval BROWSER_NO_CHANGES No browser data is changed.\r
+ @retval BROWSER_SAVE_CHANGES The changed browser data is saved.\r
+ @retval BROWSER_DISCARD_CHANGES The changed browser data is discard.\r
+\r
+**/\r
+UINT32\r
+EFIAPI\r
+SaveReminder (\r
+ VOID\r
+ )\r
+{\r
+ LIST_ENTRY *Link;\r
+ FORM_BROWSER_FORMSET *FormSet;\r
+ BOOLEAN IsDataChanged;\r
+ UINT32 DataSavedAction;\r
+ CHAR16 *YesResponse;\r
+ CHAR16 *NoResponse;\r
+ CHAR16 *EmptyString;\r
+ CHAR16 *ChangeReminderString;\r
+ CHAR16 *SaveConfirmString;\r
+ EFI_INPUT_KEY Key;\r
+\r
+ DataSavedAction = BROWSER_NO_CHANGES;\r
+ IsDataChanged = FALSE;\r
+ Link = GetFirstNode (&gBrowserFormSetList);\r
+ while (!IsNull (&gBrowserFormSetList, Link)) {\r
+ FormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link);\r
+ if (IsNvUpdateRequired (FormSet)) {\r
+ IsDataChanged = TRUE;\r
+ break;\r
+ }\r
+ Link = GetNextNode (&gBrowserFormSetList, Link);\r
+ }\r
+ \r
+ //\r
+ // No data is changed. No save is required. \r
+ //\r
+ if (!IsDataChanged) {\r
+ return DataSavedAction;\r
+ }\r
+ \r
+ //\r
+ // If data is changed, prompt user\r
+ //\r
+ gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);\r
+\r
+ YesResponse = GetToken (STRING_TOKEN (ARE_YOU_SURE_YES), gHiiHandle);\r
+ ASSERT (YesResponse != NULL);\r
+ NoResponse = GetToken (STRING_TOKEN (ARE_YOU_SURE_NO), gHiiHandle);\r
+ ASSERT (NoResponse != NULL);\r
+ EmptyString = GetToken (STRING_TOKEN (EMPTY_STRING), gHiiHandle);\r
+ ChangeReminderString = GetToken (STRING_TOKEN (CHANGE_REMINDER), gHiiHandle);\r
+ SaveConfirmString = GetToken (STRING_TOKEN (SAVE_CONFIRM), gHiiHandle);\r
+\r
+ do {\r
+ CreateDialog (4, TRUE, 0, NULL, &Key, EmptyString, ChangeReminderString, SaveConfirmString, EmptyString);\r
+ } while\r
+ (((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) != (NoResponse[0] | UPPER_LOWER_CASE_OFFSET)) &&\r
+ ((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) != (YesResponse[0] | UPPER_LOWER_CASE_OFFSET))\r
+ );\r
+\r
+ //\r
+ // If the user hits the YesResponse key\r
+ //\r
+ if ((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) == (YesResponse[0] | UPPER_LOWER_CASE_OFFSET)) {\r
+ SubmitForm (NULL, NULL, SystemLevel);\r
+ DataSavedAction = BROWSER_SAVE_CHANGES;\r
+ } else {\r
+ DiscardForm (NULL, NULL, SystemLevel);\r
+ DataSavedAction = BROWSER_DISCARD_CHANGES;\r
+ gResetRequired = FALSE;\r
+ }\r
+\r
+ FreePool (YesResponse);\r
+ FreePool (NoResponse);\r
+ FreePool (EmptyString);\r
+ FreePool (SaveConfirmString);\r
+ FreePool (ChangeReminderString);\r
+\r
+ return DataSavedAction;\r
+}\r