mirror of
				https://git.proxmox.com/git/mirror_edk2
				synced 2025-10-31 05:28:13 +00:00 
			
		
		
		
	 94f3aae730
			
		
	
	
		94f3aae730
		
	
	
	
	
		
			
			Signed-off-by: Eric Dong <eric.dong@intel.com> Reviewed-by: Liming Gao <liming.gao@intel.com> git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@14280 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			4393 lines
		
	
	
		
			132 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			4393 lines
		
	
	
		
			132 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /** @file
 | |
| Entry and initialization module for the browser.
 | |
| 
 | |
| Copyright (c) 2007 - 2013, Intel Corporation. All rights reserved.<BR>
 | |
| 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.
 | |
| 
 | |
| **/
 | |
| 
 | |
| #include "Setup.h"
 | |
| 
 | |
| SETUP_DRIVER_PRIVATE_DATA  mPrivateData = {
 | |
|   SETUP_DRIVER_SIGNATURE,
 | |
|   NULL,
 | |
|   {
 | |
|     SendForm,
 | |
|     BrowserCallback
 | |
|   },
 | |
|   {
 | |
|     SetScope,
 | |
|     RegisterHotKey,
 | |
|     RegiserExitHandler,
 | |
|     SaveReminder
 | |
|   }
 | |
| };
 | |
| 
 | |
| EFI_HII_DATABASE_PROTOCOL         *mHiiDatabase;
 | |
| EFI_HII_STRING_PROTOCOL           *mHiiString;
 | |
| EFI_HII_CONFIG_ROUTING_PROTOCOL   *mHiiConfigRouting;
 | |
| EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL *mPathFromText;
 | |
| 
 | |
| UINTN           gBrowserContextCount = 0;
 | |
| LIST_ENTRY      gBrowserContextList = INITIALIZE_LIST_HEAD_VARIABLE (gBrowserContextList);
 | |
| LIST_ENTRY      gBrowserFormSetList = INITIALIZE_LIST_HEAD_VARIABLE (gBrowserFormSetList);
 | |
| LIST_ENTRY      gBrowserHotKeyList  = INITIALIZE_LIST_HEAD_VARIABLE (gBrowserHotKeyList);
 | |
| LIST_ENTRY      gBrowserStorageList  = INITIALIZE_LIST_HEAD_VARIABLE (gBrowserStorageList);
 | |
| 
 | |
| BANNER_DATA           *gBannerData;
 | |
| EFI_HII_HANDLE        gFrontPageHandle;
 | |
| UINTN                 gClassOfVfr;
 | |
| UINTN                 gFunctionKeySetting;
 | |
| BOOLEAN               gResetRequired;
 | |
| EFI_HII_HANDLE        gHiiHandle;
 | |
| UINT16                gDirection;
 | |
| EFI_SCREEN_DESCRIPTOR gScreenDimensions;
 | |
| BROWSER_SETTING_SCOPE gBrowserSettingScope = FormSetLevel;
 | |
| BOOLEAN               mBrowserScopeFirstSet = TRUE;
 | |
| EXIT_HANDLER          ExitHandlerFunction = NULL;
 | |
| UINTN                 gFooterHeight;
 | |
| 
 | |
| //
 | |
| // Browser Global Strings
 | |
| //
 | |
| CHAR16            *gSaveFailed;
 | |
| CHAR16            *gDiscardFailed;
 | |
| CHAR16            *gDefaultFailed;
 | |
| CHAR16            *gEnterString;
 | |
| CHAR16            *gEnterCommitString;
 | |
| CHAR16            *gEnterEscapeString;
 | |
| CHAR16            *gEscapeString;
 | |
| 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            *gSaveChanges;
 | |
| CHAR16            *gOptionMismatch;
 | |
| CHAR16            *gFormSuppress;
 | |
| CHAR16            *gProtocolNotFound;
 | |
| 
 | |
| CHAR16            *mUnknownString = L"!";
 | |
| 
 | |
| 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}
 | |
| };
 | |
| 
 | |
| FORM_BROWSER_FORMSET  *gOldFormSet = NULL;
 | |
| 
 | |
| 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
 | |
|   },
 | |
| };
 | |
| 
 | |
| /**
 | |
|   This is the routine which an external caller uses to direct the browser
 | |
|   where to obtain it's information.
 | |
| 
 | |
| 
 | |
|   @param This            The Form Browser protocol instanse.
 | |
|   @param Handles         A pointer to an array of Handles.  If HandleCount > 1 we
 | |
|                          display a list of the formsets for the handles specified.
 | |
|   @param HandleCount     The number of Handles specified in Handle.
 | |
|   @param 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.
 | |
|   @param 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.
 | |
|   @param ScreenDimensions Points to recommended form dimensions, including any non-content area, in
 | |
|                           characters.
 | |
|   @param ActionRequest   Points to the action recommended by the form.
 | |
| 
 | |
|   @retval  EFI_SUCCESS            The function completed successfully.
 | |
|   @retval  EFI_INVALID_PARAMETER  One of the parameters has an invalid value.
 | |
|   @retval  EFI_NOT_FOUND          No valid forms could be found to display.
 | |
| 
 | |
| **/
 | |
| 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
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                    Status;
 | |
|   UI_MENU_SELECTION             *Selection;
 | |
|   UINTN                         Index;
 | |
|   FORM_BROWSER_FORMSET          *FormSet;
 | |
|   LIST_ENTRY                    *Link;
 | |
| 
 | |
|   //
 | |
|   // Calculate total number of Register HotKeys. 
 | |
|   //
 | |
|   Index = 0;
 | |
|   Link  = GetFirstNode (&gBrowserHotKeyList);
 | |
|   while (!IsNull (&gBrowserHotKeyList, Link)) {
 | |
|     Link = GetNextNode (&gBrowserHotKeyList, Link);
 | |
|     Index ++;
 | |
|   }
 | |
|   //
 | |
|   // Show three HotKeys help information on one ROW.
 | |
|   //
 | |
|   gFooterHeight = FOOTER_HEIGHT + (Index / 3);
 | |
| 
 | |
|   //
 | |
|   // Clean the history menu list.
 | |
|   //
 | |
|   InitializeListHead (&gMenuList);
 | |
| 
 | |
|   //
 | |
|   // Save globals used by SendForm()
 | |
|   //
 | |
|   SaveBrowserContext ();
 | |
| 
 | |
|   gResetRequired = FALSE;
 | |
|   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)
 | |
|         ) {
 | |
|       Status = EFI_INVALID_PARAMETER;
 | |
|       goto Done;
 | |
|     } 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 +
 | |
|             gFooterHeight +
 | |
|             1
 | |
|           )
 | |
|         ) {
 | |
|         CopyMem (&gScreenDimensions, (VOID *) ScreenDimensions, sizeof (EFI_SCREEN_DESCRIPTOR));
 | |
|       } else {
 | |
|         Status = EFI_INVALID_PARAMETER;
 | |
|         goto Done;
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   gOptionBlockWidth = (CHAR16) ((gScreenDimensions.RightColumn - gScreenDimensions.LeftColumn) / 3);
 | |
|   gPromptBlockWidth = (CHAR16) (gOptionBlockWidth + LEFT_SKIPPED_COLUMNS);
 | |
|   gHelpBlockWidth   = (CHAR16) (gOptionBlockWidth - LEFT_SKIPPED_COLUMNS);
 | |
| 
 | |
|   //
 | |
|   // Initialize the strings for the browser, upon exit of the browser, the strings will be freed
 | |
|   //
 | |
|   InitializeBrowserStrings ();
 | |
| 
 | |
|   //
 | |
|   // Ensure we are in Text mode
 | |
|   //
 | |
|   gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));
 | |
| 
 | |
|   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;
 | |
|     } else {
 | |
|       CopyMem (&Selection->FormSetGuid, &gEfiHiiPlatformSetupFormsetGuid, sizeof (EFI_GUID));
 | |
|     }
 | |
| 
 | |
|     do {
 | |
|       FormSet = AllocateZeroPool (sizeof (FORM_BROWSER_FORMSET));
 | |
|       ASSERT (FormSet != NULL);
 | |
| 
 | |
|       //
 | |
|       // Initialize internal data structures of FormSet
 | |
|       //
 | |
|       Status = InitializeFormSet (Selection->Handle, &Selection->FormSetGuid, FormSet, TRUE);
 | |
|       if (EFI_ERROR (Status) || IsListEmpty (&FormSet->FormListHead)) {
 | |
|         DestroyFormSet (FormSet);
 | |
|         break;
 | |
|       }
 | |
|       Selection->FormSet = FormSet;
 | |
| 
 | |
|       //
 | |
|       // Try to find pre FormSet in the maintain backup list.
 | |
|       //
 | |
|       gOldFormSet = GetFormSetFromHiiHandle (Selection->Handle);
 | |
| 
 | |
|       //
 | |
|       // Display this formset
 | |
|       //
 | |
|       gCurrentSelection = Selection;
 | |
| 
 | |
|       Status = SetupBrowser (Selection);
 | |
| 
 | |
|       gCurrentSelection = NULL;
 | |
| 
 | |
|       if (EFI_ERROR (Status)) {
 | |
|         break;
 | |
|       }
 | |
| 
 | |
|     } while (Selection->Action == UI_ACTION_REFRESH_FORMSET);
 | |
| 
 | |
|     if (gOldFormSet != NULL) {
 | |
|       //
 | |
|       // If no data is changed, don't need to save current FormSet into the maintain list.
 | |
|       //
 | |
|       if (!IsNvUpdateRequired (gOldFormSet)) {
 | |
|         RemoveEntryList (&gOldFormSet->Link);
 | |
|         DestroyFormSet (gOldFormSet);
 | |
|       }
 | |
|       gOldFormSet = NULL;
 | |
|     }
 | |
| 
 | |
|     FreePool (Selection);
 | |
|   }
 | |
| 
 | |
|   if (ActionRequest != NULL) {
 | |
|     *ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;
 | |
|     if (gResetRequired) {
 | |
|       *ActionRequest = EFI_BROWSER_ACTION_REQUEST_RESET;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   FreeBrowserStrings ();
 | |
|   UiFreeMenuList(&gMenuList);
 | |
| 
 | |
|   gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));
 | |
|   gST->ConOut->ClearScreen (gST->ConOut);
 | |
| 
 | |
| Done:
 | |
|   //
 | |
|   // Restore globals used by SendForm()
 | |
|   //
 | |
|   RestoreBrowserContext ();
 | |
| 
 | |
|   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->BrowserStorage->Guid, (EFI_GUID *) VariableGuid)) {
 | |
|         if (Storage->BrowserStorage->Type == EFI_HII_VARSTORE_BUFFER ||
 | |
|             Storage->BrowserStorage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER) {
 | |
|           //
 | |
|           // Buffer storage require both GUID and Name
 | |
|           //
 | |
|           if (VariableName == NULL) {
 | |
|             return EFI_NOT_FOUND;
 | |
|           }
 | |
| 
 | |
|           if (StrCmp (Storage->BrowserStorage->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->BrowserStorage, &ConfigResp, Storage->ConfigRequest);
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       return Status;
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // Skip <ConfigHdr> and '&' to point to <ConfigBody>
 | |
|     //
 | |
|     StrPtr = ConfigResp + StrLen (Storage->BrowserStorage->ConfigHdr) + 1;
 | |
| 
 | |
|     BufferSize = StrSize (StrPtr);
 | |
|     if (*ResultsDataSize < BufferSize) {
 | |
|       *ResultsDataSize = BufferSize;
 | |
| 
 | |
|       FreePool (ConfigResp);
 | |
|       return EFI_BUFFER_TOO_SMALL;
 | |
|     }
 | |
| 
 | |
|     *ResultsDataSize = BufferSize;
 | |
|     CopyMem (ResultsData, StrPtr, BufferSize);
 | |
| 
 | |
|     FreePool (ConfigResp);
 | |
|   } else {
 | |
|     //
 | |
|     // Prepare <ConfigResp>
 | |
|     //
 | |
|     TmpSize = StrLen (ResultsData);
 | |
|     BufferSize = (TmpSize + StrLen (Storage->BrowserStorage->ConfigHdr) + 2) * sizeof (CHAR16);
 | |
|     ConfigResp = AllocateZeroPool (BufferSize);
 | |
|     ASSERT (ConfigResp != NULL);
 | |
| 
 | |
|     StrCpy (ConfigResp, Storage->BrowserStorage->ConfigHdr);
 | |
|     StrCat (ConfigResp, L"&");
 | |
|     StrCat (ConfigResp, ResultsData);
 | |
| 
 | |
|     //
 | |
|     // Update Browser uncommited data
 | |
|     //
 | |
|     Status = ConfigRespToStorage (Storage->BrowserStorage, ConfigResp);
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       return Status;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Initialize Setup Browser driver.
 | |
| 
 | |
|   @param ImageHandle     The image handle.
 | |
|   @param SystemTable     The system table.
 | |
| 
 | |
|   @retval EFI_SUCCESS    The Setup Browser module is initialized correctly..
 | |
|   @return Other value if failed to initialize the Setup Browser module.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| InitializeSetup (
 | |
|   IN EFI_HANDLE           ImageHandle,
 | |
|   IN EFI_SYSTEM_TABLE     *SystemTable
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                  Status;
 | |
|   EFI_INPUT_KEY               DefaultHotKey;
 | |
|   EFI_STRING                  HelpString;
 | |
| 
 | |
|   //
 | |
|   // 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);
 | |
| 
 | |
|   Status = gBS->LocateProtocol (
 | |
|                   &gEfiDevicePathFromTextProtocolGuid,
 | |
|                   NULL,
 | |
|                   (VOID **) &mPathFromText
 | |
|                   );
 | |
| 
 | |
|   //
 | |
|   // Publish our HII data
 | |
|   //
 | |
|   gHiiHandle = HiiAddPackages (
 | |
|                  &gSetupBrowserGuid,
 | |
|                  ImageHandle,
 | |
|                  SetupBrowserStrings,
 | |
|                  NULL
 | |
|                  );
 | |
|   ASSERT (gHiiHandle != NULL);
 | |
| 
 | |
|   //
 | |
|   // Initialize Driver private data
 | |
|   //
 | |
|   gBannerData = AllocateZeroPool (sizeof (BANNER_DATA));
 | |
|   ASSERT (gBannerData != NULL);
 | |
|   
 | |
|   //
 | |
|   // Initialize generic help strings.
 | |
|   //
 | |
|   gSaveFailed    = GetToken (STRING_TOKEN (SAVE_FAILED), gHiiHandle);
 | |
|   gDiscardFailed = GetToken (STRING_TOKEN (DISCARD_FAILED), gHiiHandle);
 | |
|   gDefaultFailed = GetToken (STRING_TOKEN (DEFAULT_FAILED), gHiiHandle);
 | |
| 
 | |
|   //
 | |
|   // Install FormBrowser2 protocol
 | |
|   //
 | |
|   mPrivateData.Handle = NULL;
 | |
|   Status = gBS->InstallProtocolInterface (
 | |
|                   &mPrivateData.Handle,
 | |
|                   &gEfiFormBrowser2ProtocolGuid,
 | |
|                   EFI_NATIVE_INTERFACE,
 | |
|                   &mPrivateData.FormBrowser2
 | |
|                   );
 | |
|   ASSERT_EFI_ERROR (Status);
 | |
| 
 | |
|   //
 | |
|   // Install default HotKey F10 for Save
 | |
|   //
 | |
|   DefaultHotKey.UnicodeChar = CHAR_NULL;
 | |
|   HelpString             = GetToken (STRING_TOKEN (FUNCTION_TEN_STRING), gHiiHandle);
 | |
|   DefaultHotKey.ScanCode = SCAN_F10;
 | |
|   RegisterHotKey (&DefaultHotKey, BROWSER_ACTION_SUBMIT, 0, HelpString);
 | |
|   FreePool (HelpString);
 | |
|   //
 | |
|   // Install default HotKey F9 for Reset To Defaults
 | |
|   //
 | |
|   DefaultHotKey.ScanCode    = SCAN_F9;
 | |
|   HelpString                = GetToken (STRING_TOKEN (FUNCTION_NINE_STRING), gHiiHandle);
 | |
|   RegisterHotKey (&DefaultHotKey, BROWSER_ACTION_DEFAULT, EFI_HII_DEFAULT_CLASS_STANDARD, HelpString);
 | |
|   FreePool (HelpString);
 | |
| 
 | |
|   //
 | |
|   // Install FormBrowserEx protocol
 | |
|   //
 | |
|   mPrivateData.Handle = NULL;
 | |
|   Status = gBS->InstallProtocolInterface (
 | |
|                   &mPrivateData.Handle,
 | |
|                   &gEfiFormBrowserExProtocolGuid,
 | |
|                   EFI_NATIVE_INTERFACE,
 | |
|                   &mPrivateData.FormBrowserEx
 | |
|                   );
 | |
|   ASSERT_EFI_ERROR (Status);
 | |
| 
 | |
|   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;
 | |
| 
 | |
|   StringId = HiiSetString (HiiHandle, 0, String, NULL);
 | |
|   ASSERT (StringId != 0);
 | |
| 
 | |
|   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;
 | |
|   HiiSetString (HiiHandle, StringId, &NullChar, NULL);
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   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_STRING  String;
 | |
| 
 | |
|   if (HiiHandle == NULL) {
 | |
|     return NULL;
 | |
|   }
 | |
| 
 | |
|   String = HiiGetString (HiiHandle, Token, NULL);
 | |
|   if (String == NULL) {
 | |
|     String = AllocateCopyPool (StrSize (mUnknownString), mUnknownString);
 | |
|     ASSERT (String != NULL);
 | |
|   }
 | |
|   return (CHAR16 *) String;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Allocate new memory and then copy the Unicode string Source to Destination.
 | |
| 
 | |
|   @param  Dest                   Location to copy string
 | |
|   @param  Src                    String to copy
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| NewStringCpy (
 | |
|   IN OUT CHAR16       **Dest,
 | |
|   IN CHAR16           *Src
 | |
|   )
 | |
| {
 | |
|   if (*Dest != NULL) {
 | |
|     FreePool (*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.
 | |
| 
 | |
| **/
 | |
| 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);
 | |
| 
 | |
|   FreePool (*Dest);
 | |
|   *Dest = NewString;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Synchronize or restore Storage's Edit copy and Shadow copy.
 | |
| 
 | |
|   @param  Storage          The Storage to be synchronized.
 | |
|   @param  SyncOrRestore    Sync the buffer to editbuffer or Restore  the 
 | |
|                            editbuffer to buffer
 | |
|                            if TRUE, copy the editbuffer to the buffer.
 | |
|                            if FALSE, copy the buffer to the editbuffer.
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| SynchronizeStorage (
 | |
|   IN BROWSER_STORAGE         *Storage,
 | |
|   IN BOOLEAN                 SyncOrRestore
 | |
|   )
 | |
| {
 | |
|   LIST_ENTRY              *Link;
 | |
|   NAME_VALUE_NODE         *Node;
 | |
| 
 | |
|   switch (Storage->Type) {
 | |
|   case EFI_HII_VARSTORE_BUFFER:
 | |
|   case EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER:
 | |
|     if (SyncOrRestore) {
 | |
|       CopyMem (Storage->Buffer, Storage->EditBuffer, Storage->Size);
 | |
|     } else {
 | |
|       CopyMem (Storage->EditBuffer, Storage->Buffer, 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);
 | |
| 
 | |
|       if (SyncOrRestore) {
 | |
|         NewStringCpy (&Node->Value, Node->EditValue);
 | |
|       } else {
 | |
|         NewStringCpy (&Node->EditValue, Node->Value);
 | |
|       }
 | |
| 
 | |
|       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.
 | |
|   @param  GetValueFrom           Where to get source value, from EditValue or Value.
 | |
| 
 | |
|   @retval EFI_SUCCESS            Value found for given Name.
 | |
|   @retval EFI_NOT_FOUND          No such Name found in NameValue storage.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| GetValueByName (
 | |
|   IN BROWSER_STORAGE             *Storage,
 | |
|   IN CHAR16                      *Name,
 | |
|   IN OUT CHAR16                  **Value,
 | |
|   IN GET_SET_QUESTION_VALUE_WITH GetValueFrom
 | |
|   )
 | |
| {
 | |
|   LIST_ENTRY              *Link;
 | |
|   NAME_VALUE_NODE         *Node;
 | |
| 
 | |
|   if (GetValueFrom != GetSetValueWithEditBuffer && GetValueFrom != GetSetValueWithBuffer) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   *Value = NULL;
 | |
| 
 | |
|   Link = GetFirstNode (&Storage->NameValueListHead);
 | |
|   while (!IsNull (&Storage->NameValueListHead, Link)) {
 | |
|     Node = NAME_VALUE_NODE_FROM_LINK (Link);
 | |
| 
 | |
|     if (StrCmp (Name, Node->Name) == 0) {
 | |
|       if (GetValueFrom == GetSetValueWithEditBuffer) {
 | |
|         NewStringCpy (Value, Node->EditValue);
 | |
|       } else {
 | |
|         NewStringCpy (Value, Node->Value);
 | |
|       }
 | |
|       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.
 | |
|   @param  SetValueTo             Whether update editValue or Value.
 | |
| 
 | |
|   @retval EFI_SUCCESS            Value found for given Name.
 | |
|   @retval EFI_NOT_FOUND          No such Name found in NameValue storage.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| SetValueByName (
 | |
|   IN BROWSER_STORAGE         *Storage,
 | |
|   IN CHAR16                  *Name,
 | |
|   IN CHAR16                  *Value,
 | |
|   IN GET_SET_QUESTION_VALUE_WITH SetValueTo
 | |
|   )
 | |
| {
 | |
|   LIST_ENTRY              *Link;
 | |
|   NAME_VALUE_NODE         *Node;
 | |
|   CHAR16                  *Buffer;
 | |
| 
 | |
|   if (SetValueTo != GetSetValueWithEditBuffer && SetValueTo != GetSetValueWithBuffer) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   Link = GetFirstNode (&Storage->NameValueListHead);
 | |
|   while (!IsNull (&Storage->NameValueListHead, Link)) {
 | |
|     Node = NAME_VALUE_NODE_FROM_LINK (Link);
 | |
| 
 | |
|     if (StrCmp (Name, Node->Name) == 0) {
 | |
|       if (SetValueTo == GetSetValueWithEditBuffer) {
 | |
|         Buffer = Node->EditValue;
 | |
|       } else {
 | |
|         Buffer = Node->Value;
 | |
|       }
 | |
|       if (Buffer != NULL) {
 | |
|         FreePool (Buffer);
 | |
|       }
 | |
|       Buffer = AllocateCopyPool (StrSize (Value), Value);
 | |
|       ASSERT (Buffer != NULL);
 | |
|       if (SetValueTo == GetSetValueWithEditBuffer) {
 | |
|         Node->EditValue = Buffer;
 | |
|       } else {
 | |
|         Node->Value = Buffer;
 | |
|       }
 | |
|       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>.
 | |
|   @param  ConfigRequest          The ConfigRequest string.
 | |
| 
 | |
|   @retval EFI_SUCCESS            Convert success.
 | |
|   @retval EFI_INVALID_PARAMETER  Incorrect storage type.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| StorageToConfigResp (
 | |
|   IN BROWSER_STORAGE         *Storage,
 | |
|   IN CHAR16                  **ConfigResp,
 | |
|   IN CHAR16                  *ConfigRequest
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS              Status;
 | |
|   EFI_STRING              Progress;
 | |
|   LIST_ENTRY              *Link;
 | |
|   NAME_VALUE_NODE         *Node;
 | |
| 
 | |
|   Status = EFI_SUCCESS;
 | |
| 
 | |
|   switch (Storage->Type) {
 | |
|   case EFI_HII_VARSTORE_BUFFER:
 | |
|   case EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER:
 | |
|     Status = mHiiConfigRouting->BlockToConfig (
 | |
|                                   mHiiConfigRouting,
 | |
|                                   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);
 | |
| 
 | |
|       if (StrStr (ConfigRequest, Node->Name) != NULL) {
 | |
|         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 BROWSER_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:
 | |
|   case EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER:
 | |
|     BufferSize = Storage->Size;
 | |
|     Status = mHiiConfigRouting->ConfigToBlock (
 | |
|                                   mHiiConfigRouting,
 | |
|                                   ConfigResp,
 | |
|                                   Storage->EditBuffer,
 | |
|                                   &BufferSize,
 | |
|                                   &Progress
 | |
|                                   );
 | |
|     break;
 | |
| 
 | |
|   case EFI_HII_VARSTORE_NAME_VALUE:
 | |
|     StrPtr = StrStr (ConfigResp, L"PATH");
 | |
|     if (StrPtr == NULL) {
 | |
|       break;
 | |
|     }
 | |
|     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, GetSetValueWithEditBuffer);
 | |
|     }
 | |
|     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  GetValueFrom           Where to get value, may from editbuffer, buffer or hii driver.
 | |
| 
 | |
|   @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 GET_SET_QUESTION_VALUE_WITH      GetValueFrom
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS          Status;
 | |
|   BOOLEAN             Enabled;
 | |
|   BOOLEAN             Pending;
 | |
|   UINT8               *Dst;
 | |
|   UINTN               StorageWidth;
 | |
|   EFI_TIME            EfiTime;
 | |
|   BROWSER_STORAGE     *Storage;
 | |
|   EFI_IFR_TYPE_VALUE  *QuestionValue;
 | |
|   CHAR16              *ConfigRequest;
 | |
|   CHAR16              *Progress;
 | |
|   CHAR16              *Result;
 | |
|   CHAR16              *Value;
 | |
|   CHAR16              *StringPtr;
 | |
|   UINTN               Length;
 | |
|   UINTN               Index;
 | |
|   UINTN               LengthStr;
 | |
|   BOOLEAN             IsBufferStorage;
 | |
|   BOOLEAN             IsString;
 | |
|   CHAR16              TemStr[5];
 | |
|   UINT8               DigitUint8;
 | |
|   UINT8               *TemBuffer;
 | |
| 
 | |
|   Status = EFI_SUCCESS;
 | |
|   Value  = NULL;
 | |
|   Result = NULL;
 | |
| 
 | |
|   if (GetValueFrom >= GetSetValueWithMax) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // 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)) {
 | |
|       if (Question->ValueExpression->Result.Type == EFI_IFR_TYPE_BUFFER) {
 | |
|         ASSERT (Question->HiiValue.Type == EFI_IFR_TYPE_BUFFER && Question->HiiValue.Buffer != NULL);
 | |
|         if (Question->StorageWidth > Question->ValueExpression->Result.BufferLen) {
 | |
|           CopyMem (Question->HiiValue.Buffer, Question->ValueExpression->Result.Buffer, Question->ValueExpression->Result.BufferLen);
 | |
|           Question->HiiValue.BufferLen = Question->ValueExpression->Result.BufferLen;
 | |
|         } else {
 | |
|           CopyMem (Question->HiiValue.Buffer, Question->ValueExpression->Result.Buffer, Question->StorageWidth);
 | |
|           Question->HiiValue.BufferLen = Question->StorageWidth;
 | |
|         }
 | |
|         FreePool (Question->ValueExpression->Result.Buffer);
 | |
|       }
 | |
|       Question->HiiValue.Type = Question->ValueExpression->Result.Type;
 | |
|       CopyMem (&Question->HiiValue.Value, &Question->ValueExpression->Result.Value, sizeof (EFI_IFR_TYPE_VALUE));      
 | |
|     }
 | |
|     return Status;
 | |
|   }
 | |
|   
 | |
|   //
 | |
|   // Get question value by read expression.
 | |
|   //
 | |
|   if (Question->ReadExpression != NULL && Form->FormType == STANDARD_MAP_FORM_TYPE) {
 | |
|     Status = EvaluateExpression (FormSet, Form, Question->ReadExpression);
 | |
|     if (!EFI_ERROR (Status) && 
 | |
|       ((Question->ReadExpression->Result.Type < EFI_IFR_TYPE_OTHER) || (Question->ReadExpression->Result.Type == EFI_IFR_TYPE_BUFFER))) {
 | |
|       //
 | |
|       // Only update question value to the valid result.
 | |
|       //
 | |
|       if (Question->ReadExpression->Result.Type == EFI_IFR_TYPE_BUFFER) {
 | |
|         ASSERT (Question->HiiValue.Type == EFI_IFR_TYPE_BUFFER && Question->HiiValue.Buffer != NULL);
 | |
|         if (Question->StorageWidth > Question->ReadExpression->Result.BufferLen) {
 | |
|           CopyMem (Question->HiiValue.Buffer, Question->ReadExpression->Result.Buffer, Question->ReadExpression->Result.BufferLen);
 | |
|           Question->HiiValue.BufferLen = Question->ReadExpression->Result.BufferLen;
 | |
|         } else {
 | |
|           CopyMem (Question->HiiValue.Buffer, Question->ReadExpression->Result.Buffer, Question->StorageWidth);
 | |
|           Question->HiiValue.BufferLen = Question->StorageWidth;
 | |
|         }
 | |
|         FreePool (Question->ReadExpression->Result.Buffer);
 | |
|       }
 | |
|       Question->HiiValue.Type = Question->ReadExpression->Result.Type;
 | |
|       CopyMem (&Question->HiiValue.Value, &Question->ReadExpression->Result.Value, sizeof (EFI_IFR_TYPE_VALUE));       
 | |
|       return EFI_SUCCESS;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // 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;
 | |
|   }
 | |
| 
 | |
|   if (Storage->Type == EFI_HII_VARSTORE_BUFFER || 
 | |
|       Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER) {
 | |
|     IsBufferStorage = TRUE;
 | |
|   } else {
 | |
|     IsBufferStorage = FALSE;
 | |
|   }
 | |
|   IsString = (BOOLEAN) ((Question->HiiValue.Type == EFI_IFR_TYPE_STRING) ?  TRUE : FALSE);
 | |
|   if (GetValueFrom == GetSetValueWithEditBuffer || GetValueFrom == GetSetValueWithBuffer ) {
 | |
|     if (IsBufferStorage) {
 | |
|       if (GetValueFrom == GetSetValueWithEditBuffer) {
 | |
|         //
 | |
|         // Copy from storage Edit buffer
 | |
|         //
 | |
|         CopyMem (Dst, Storage->EditBuffer + Question->VarStoreInfo.VarOffset, StorageWidth);
 | |
|       } else {
 | |
|         //
 | |
|         // Copy from storage Edit buffer
 | |
|         //
 | |
|         CopyMem (Dst, Storage->Buffer + Question->VarStoreInfo.VarOffset, StorageWidth);
 | |
|       }
 | |
|     } else {
 | |
|       Value = NULL;
 | |
|       Status = GetValueByName (Storage, Question->VariableName, &Value, GetValueFrom);
 | |
|       if (EFI_ERROR (Status)) {
 | |
|         return Status;
 | |
|       }
 | |
| 
 | |
|       ASSERT (Value != NULL);
 | |
|       LengthStr = StrLen (Value);
 | |
|       Status    = EFI_SUCCESS;
 | |
|       if (IsString) {
 | |
|         //
 | |
|         // Convert Config String to Unicode String, e.g "0041004200430044" => "ABCD"
 | |
|         // Add string tail char L'\0' into Length
 | |
|         //
 | |
|         Length    = StorageWidth + sizeof (CHAR16);
 | |
|         if (Length < ((LengthStr / 4 + 1) * 2)) {
 | |
|           Status = EFI_BUFFER_TOO_SMALL;
 | |
|         } else {
 | |
|           StringPtr = (CHAR16 *) Dst;
 | |
|           ZeroMem (TemStr, sizeof (TemStr));
 | |
|           for (Index = 0; Index < LengthStr; Index += 4) {
 | |
|             StrnCpy (TemStr, Value + Index, 4);
 | |
|             StringPtr[Index/4] = (CHAR16) StrHexToUint64 (TemStr);
 | |
|           }
 | |
|           //
 | |
|           // Add tailing L'\0' character
 | |
|           //
 | |
|           StringPtr[Index/4] = L'\0';
 | |
|         }
 | |
|       } else {
 | |
|         if (StorageWidth < ((LengthStr + 1) / 2)) {
 | |
|           Status = EFI_BUFFER_TOO_SMALL;
 | |
|         } else {
 | |
|           ZeroMem (TemStr, sizeof (TemStr));
 | |
|           for (Index = 0; Index < LengthStr; Index ++) {
 | |
|             TemStr[0] = Value[LengthStr - Index - 1];
 | |
|             DigitUint8 = (UINT8) StrHexToUint64 (TemStr);
 | |
|             if ((Index & 1) == 0) {
 | |
|               Dst [Index/2] = DigitUint8;
 | |
|             } else {
 | |
|               Dst [Index/2] = (UINT8) ((DigitUint8 << 4) + Dst [Index/2]);
 | |
|             }
 | |
|           }
 | |
|         }
 | |
|       }
 | |
| 
 | |
|       FreePool (Value);
 | |
|     }
 | |
|   } else {
 | |
|     if (Storage->Type == EFI_HII_VARSTORE_BUFFER || Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) {
 | |
|       //
 | |
|       // 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
 | |
|                                         );
 | |
|       FreePool (ConfigRequest);
 | |
|       if (EFI_ERROR (Status)) {
 | |
|         return Status;
 | |
|       }
 | |
| 
 | |
|       //
 | |
|       // Skip <ConfigRequest>
 | |
|       //
 | |
|       if (IsBufferStorage) {
 | |
|         Value = StrStr (Result, L"&VALUE");
 | |
|         if (Value == NULL) {
 | |
|           FreePool (Result);
 | |
|           return EFI_NOT_FOUND;
 | |
|         }
 | |
|         //
 | |
|         // Skip "&VALUE"
 | |
|         //
 | |
|         Value = Value + 6;
 | |
|       } else {
 | |
|         Value = Result + Length;
 | |
|       }
 | |
|       if (*Value != '=') {
 | |
|         FreePool (Result);
 | |
|         return EFI_NOT_FOUND;
 | |
|       }
 | |
|       //
 | |
|       // Skip '=', point to value
 | |
|       //
 | |
|       Value = Value + 1;
 | |
| 
 | |
|       //
 | |
|       // Suppress <AltResp> if any
 | |
|       //
 | |
|       StringPtr = Value;
 | |
|       while (*StringPtr != L'\0' && *StringPtr != L'&') {
 | |
|         StringPtr++;
 | |
|       }
 | |
|       *StringPtr = L'\0';
 | |
| 
 | |
|       LengthStr = StrLen (Value);
 | |
|       Status    = EFI_SUCCESS;
 | |
|       if (!IsBufferStorage && IsString) {
 | |
|         //
 | |
|         // Convert Config String to Unicode String, e.g "0041004200430044" => "ABCD"
 | |
|         // Add string tail char L'\0' into Length
 | |
|         //
 | |
|         Length    = StorageWidth + sizeof (CHAR16);
 | |
|         if (Length < ((LengthStr / 4 + 1) * 2)) {
 | |
|           Status = EFI_BUFFER_TOO_SMALL;
 | |
|         } else {
 | |
|           StringPtr = (CHAR16 *) Dst;
 | |
|           ZeroMem (TemStr, sizeof (TemStr));
 | |
|           for (Index = 0; Index < LengthStr; Index += 4) {
 | |
|             StrnCpy (TemStr, Value + Index, 4);
 | |
|             StringPtr[Index/4] = (CHAR16) StrHexToUint64 (TemStr);
 | |
|           }
 | |
|           //
 | |
|           // Add tailing L'\0' character
 | |
|           //
 | |
|           StringPtr[Index/4] = L'\0';
 | |
|         }
 | |
|       } else {
 | |
|         if (StorageWidth < ((LengthStr + 1) / 2)) {
 | |
|           Status = EFI_BUFFER_TOO_SMALL;
 | |
|         } else {
 | |
|           ZeroMem (TemStr, sizeof (TemStr));
 | |
|           for (Index = 0; Index < LengthStr; Index ++) {
 | |
|             TemStr[0] = Value[LengthStr - Index - 1];
 | |
|             DigitUint8 = (UINT8) StrHexToUint64 (TemStr);
 | |
|             if ((Index & 1) == 0) {
 | |
|               Dst [Index/2] = DigitUint8;
 | |
|             } else {
 | |
|               Dst [Index/2] = (UINT8) ((DigitUint8 << 4) + Dst [Index/2]);
 | |
|             }
 | |
|           }
 | |
|         }
 | |
|       }
 | |
| 
 | |
|       if (EFI_ERROR (Status)) {
 | |
|         FreePool (Result);
 | |
|         return Status;
 | |
|       }
 | |
|     } else if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER) {
 | |
|       TemBuffer = NULL;
 | |
|       TemBuffer = AllocateZeroPool (Storage->Size);
 | |
|       if (TemBuffer == NULL) {
 | |
|         Status = EFI_OUT_OF_RESOURCES;
 | |
|         return Status;
 | |
|       }
 | |
|       Length = Storage->Size;
 | |
|       Status = gRT->GetVariable (
 | |
|                        Storage->Name,
 | |
|                        &Storage->Guid,
 | |
|                        NULL,
 | |
|                        &Length,
 | |
|                        TemBuffer
 | |
|                        );
 | |
|       if (EFI_ERROR (Status)) {
 | |
|         FreePool (TemBuffer);
 | |
|         return Status;
 | |
|       }
 | |
| 
 | |
|       CopyMem (Dst, TemBuffer + Question->VarStoreInfo.VarOffset, StorageWidth);
 | |
| 
 | |
|       FreePool (TemBuffer);
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // Synchronize Edit Buffer
 | |
|     //
 | |
|     if (IsBufferStorage) {
 | |
|       CopyMem (Storage->EditBuffer + Question->VarStoreInfo.VarOffset, Dst, StorageWidth);
 | |
|     } else {
 | |
|       SetValueByName (Storage, Question->VariableName, Value, GetSetValueWithEditBuffer);
 | |
|     }
 | |
| 
 | |
|     if (Result != NULL) {
 | |
|       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  SetValueTo             Update the question value to editbuffer , buffer or hii driver.
 | |
| 
 | |
|   @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 GET_SET_QUESTION_VALUE_WITH      SetValueTo
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS          Status;
 | |
|   BOOLEAN             Enabled;
 | |
|   BOOLEAN             Pending;
 | |
|   UINT8               *Src;
 | |
|   EFI_TIME            EfiTime;
 | |
|   UINTN               BufferLen;
 | |
|   UINTN               StorageWidth;
 | |
|   BROWSER_STORAGE     *Storage;
 | |
|   EFI_IFR_TYPE_VALUE  *QuestionValue;
 | |
|   CHAR16              *ConfigResp;
 | |
|   CHAR16              *Progress;
 | |
|   CHAR16              *Value;
 | |
|   UINTN               Length;
 | |
|   BOOLEAN             IsBufferStorage;
 | |
|   BOOLEAN             IsString;
 | |
|   UINT8               *TemBuffer;
 | |
|   CHAR16              *TemName;
 | |
|   CHAR16              *TemString;
 | |
|   UINTN               Index;
 | |
| 
 | |
|   Status = EFI_SUCCESS;
 | |
| 
 | |
|   if (SetValueTo >= GetSetValueWithMax) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // 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;
 | |
|   }
 | |
|   
 | |
|   //
 | |
|   // Before set question value, evaluate its write expression.
 | |
|   //
 | |
|   if (Question->WriteExpression != NULL && Form->FormType == STANDARD_MAP_FORM_TYPE) {
 | |
|     Status = EvaluateExpression (FormSet, Form, Question->WriteExpression);
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       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;
 | |
|   }
 | |
| 
 | |
|   if (Storage->Type == EFI_HII_VARSTORE_BUFFER || 
 | |
|       Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER) {
 | |
|     IsBufferStorage = TRUE;
 | |
|   } else {
 | |
|     IsBufferStorage = FALSE;
 | |
|   }
 | |
|   IsString = (BOOLEAN) ((Question->HiiValue.Type == EFI_IFR_TYPE_STRING) ?  TRUE : FALSE);
 | |
| 
 | |
|   if (SetValueTo == GetSetValueWithEditBuffer || SetValueTo == GetSetValueWithBuffer) {
 | |
|     if (IsBufferStorage) {
 | |
|       if (SetValueTo == GetSetValueWithEditBuffer) {
 | |
|         //
 | |
|         // Copy to storage edit buffer
 | |
|         //      
 | |
|         CopyMem (Storage->EditBuffer + Question->VarStoreInfo.VarOffset, Src, StorageWidth);
 | |
|       } else if (SetValueTo == GetSetValueWithBuffer) {
 | |
|         //
 | |
|         // Copy to storage edit buffer
 | |
|         //     
 | |
|         CopyMem (Storage->Buffer + Question->VarStoreInfo.VarOffset, Src, StorageWidth);
 | |
|       }
 | |
|     } else {
 | |
|       if (IsString) {
 | |
|         //
 | |
|         // Allocate enough string buffer.
 | |
|         //
 | |
|         Value = NULL;
 | |
|         BufferLen = ((StrLen ((CHAR16 *) Src) * 4) + 1) * sizeof (CHAR16);
 | |
|         Value = AllocateZeroPool (BufferLen);
 | |
|         ASSERT (Value != NULL);
 | |
|         //
 | |
|         // Convert Unicode String to Config String, e.g. "ABCD" => "0041004200430044"
 | |
|         //
 | |
|         TemName = (CHAR16 *) Src;
 | |
|         TemString = Value;
 | |
|         for (; *TemName != L'\0'; TemName++) {
 | |
|           TemString += UnicodeValueToString (TemString, PREFIX_ZERO | RADIX_HEX, *TemName, 4);
 | |
|         }
 | |
|       } else {
 | |
|         BufferLen = StorageWidth * 2 + 1;
 | |
|         Value = AllocateZeroPool (BufferLen * sizeof (CHAR16));
 | |
|         ASSERT (Value != NULL);
 | |
|         //
 | |
|         // Convert Buffer to Hex String
 | |
|         //
 | |
|         TemBuffer = Src + StorageWidth - 1;
 | |
|         TemString = Value;
 | |
|         for (Index = 0; Index < StorageWidth; Index ++, TemBuffer --) {
 | |
|           TemString += UnicodeValueToString (TemString, PREFIX_ZERO | RADIX_HEX, *TemBuffer, 2);
 | |
|         }
 | |
|       }
 | |
| 
 | |
|       Status = SetValueByName (Storage, Question->VariableName, Value, SetValueTo);
 | |
|       FreePool (Value);
 | |
|     }
 | |
|   } else if (SetValueTo == GetSetValueWithHiiDriver) {
 | |
|     if (Storage->Type == EFI_HII_VARSTORE_BUFFER || Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) {
 | |
|       //
 | |
|       // <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"
 | |
|         //
 | |
|         TemName = (CHAR16 *) Src;
 | |
|         TemString = Value;
 | |
|         for (; *TemName != L'\0'; TemName++) {
 | |
|           TemString += UnicodeValueToString (TemString, PREFIX_ZERO | RADIX_HEX, *TemName, 4);
 | |
|         }
 | |
|       } else {
 | |
|         //
 | |
|         // Convert Buffer to Hex String
 | |
|         //
 | |
|         TemBuffer = Src + StorageWidth - 1;
 | |
|         TemString = Value;
 | |
|         for (Index = 0; Index < StorageWidth; Index ++, TemBuffer --) {
 | |
|           TemString += UnicodeValueToString (TemString, PREFIX_ZERO | RADIX_HEX, *TemBuffer, 2);
 | |
|         }
 | |
|       }
 | |
| 
 | |
|       //
 | |
|       // Convert to lower char.
 | |
|       //
 | |
|       for (TemString = Value; *Value != L'\0'; Value++) {
 | |
|         if (*Value >= L'A' && *Value <= L'Z') {
 | |
|           *Value = (CHAR16) (*Value - L'A' + L'a');
 | |
|         }
 | |
|       }
 | |
| 
 | |
|       //
 | |
|       // Submit Question Value to Configuration Driver
 | |
|       //
 | |
|       if (FormSet->ConfigAccess != NULL) {
 | |
|         Status = FormSet->ConfigAccess->RouteConfig (
 | |
|                                           FormSet->ConfigAccess,
 | |
|                                           ConfigResp,
 | |
|                                           &Progress
 | |
|                                           );
 | |
|         if (EFI_ERROR (Status)) {
 | |
|           FreePool (ConfigResp);
 | |
|           return Status;
 | |
|         }
 | |
|       }
 | |
|       FreePool (ConfigResp);
 | |
|       
 | |
|     } else if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER) {
 | |
|       TemBuffer = NULL;
 | |
|       TemBuffer = AllocateZeroPool(Storage->Size);
 | |
|       if (TemBuffer == NULL) {
 | |
|         Status = EFI_OUT_OF_RESOURCES;
 | |
|         return Status;
 | |
|       }
 | |
|       Length = Storage->Size;
 | |
|       Status = gRT->GetVariable (
 | |
|                        Storage->Name,
 | |
|                        &Storage->Guid,
 | |
|                        NULL,
 | |
|                        &Length,
 | |
|                        TemBuffer
 | |
|                        );
 | |
| 
 | |
|       CopyMem (TemBuffer + Question->VarStoreInfo.VarOffset, Src, StorageWidth);
 | |
|       
 | |
|       Status = gRT->SetVariable (
 | |
|                        Storage->Name,
 | |
|                        &Storage->Guid,
 | |
|                        Storage->Attributes,
 | |
|                        Storage->Size,
 | |
|                        TemBuffer
 | |
|                        );
 | |
|       FreePool (TemBuffer);
 | |
|       if (EFI_ERROR (Status)){
 | |
|         return Status;
 | |
|       }
 | |
|     }
 | |
|     //
 | |
|     // Sync storage, from editbuffer to buffer.
 | |
|     //
 | |
|     CopyMem (Storage->Buffer + Question->VarStoreInfo.VarOffset, Src, StorageWidth);
 | |
|   }
 | |
| 
 | |
|   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.Type == EFI_IFR_TYPE_BOOLEAN) && 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);
 | |
|         FreePool (PopUp);
 | |
|       }
 | |
| 
 | |
|       return EFI_NOT_READY;
 | |
|     }
 | |
| 
 | |
|     Link = GetNextNode (ListHead, Link);
 | |
|   }
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Perform NoSubmit check for each Form in FormSet.
 | |
| 
 | |
|   @param  FormSet                FormSet data structure.
 | |
|   @param  CurrentForm            Current input 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               *CurrentForm
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS              Status;
 | |
|   LIST_ENTRY              *Link;
 | |
|   FORM_BROWSER_STATEMENT  *Question;
 | |
|   FORM_BROWSER_FORM       *Form;
 | |
|   LIST_ENTRY              *LinkForm;
 | |
| 
 | |
|   LinkForm = GetFirstNode (&FormSet->FormListHead);
 | |
|   while (!IsNull (&FormSet->FormListHead, LinkForm)) {
 | |
|     Form = FORM_BROWSER_FORM_FROM_LINK (LinkForm);
 | |
|     LinkForm = GetNextNode (&FormSet->FormListHead, LinkForm);
 | |
| 
 | |
|     if (CurrentForm != NULL && CurrentForm != Form) {
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
|     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;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Fill storage's edit copy with settings requested from Configuration Driver.
 | |
| 
 | |
|   @param  FormSet                FormSet data structure.
 | |
|   @param  ConfigInfo             The config info related to this form.
 | |
|   @param  SyncOrRestore          Sync the buffer to editbuffer or Restore  the 
 | |
|                                  editbuffer to buffer
 | |
|                                  if TRUE, copy the editbuffer to the buffer.
 | |
|                                  if FALSE, copy the buffer to the editbuffer.
 | |
| 
 | |
|   @retval EFI_SUCCESS            The function completed successfully.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| SynchronizeStorageForForm (
 | |
|   IN FORM_BROWSER_FORMSET        *FormSet,
 | |
|   IN FORM_BROWSER_CONFIG_REQUEST *ConfigInfo,
 | |
|   IN BOOLEAN                     SyncOrRestore
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS              Status;
 | |
|   EFI_STRING              Progress;
 | |
|   EFI_STRING              Result;
 | |
|   UINTN                   BufferSize;
 | |
|   LIST_ENTRY              *Link;
 | |
|   NAME_VALUE_NODE         *Node;
 | |
|   UINT8                   *Src;
 | |
|   UINT8                   *Dst;
 | |
| 
 | |
|   Status = EFI_SUCCESS;
 | |
|   Result = NULL;
 | |
|   if (FormSet->ConfigAccess == NULL && ConfigInfo->Storage->Type != EFI_HII_VARSTORE_NAME_VALUE) {
 | |
|     return EFI_NOT_FOUND;
 | |
|   }
 | |
| 
 | |
|   if (ConfigInfo->ElementCount == 0) {
 | |
|     //
 | |
|     // Skip if there is no RequestElement
 | |
|     //
 | |
|     return EFI_SUCCESS;
 | |
|   }
 | |
| 
 | |
|   if (ConfigInfo->Storage->Type == EFI_HII_VARSTORE_BUFFER || 
 | |
|       (ConfigInfo->Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER)) {
 | |
|     BufferSize = ConfigInfo->Storage->Size;
 | |
| 
 | |
|     if (SyncOrRestore) {
 | |
|       Src = ConfigInfo->Storage->EditBuffer;
 | |
|       Dst = ConfigInfo->Storage->Buffer;
 | |
|     } else {
 | |
|       Src = ConfigInfo->Storage->Buffer;
 | |
|       Dst = ConfigInfo->Storage->EditBuffer;
 | |
|     }
 | |
| 
 | |
|     Status = mHiiConfigRouting->BlockToConfig(
 | |
|                                   mHiiConfigRouting,
 | |
|                                   ConfigInfo->ConfigRequest,
 | |
|                                   Src,
 | |
|                                   BufferSize,
 | |
|                                   &Result,
 | |
|                                   &Progress
 | |
|                                   );
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       return Status;
 | |
|     }
 | |
| 
 | |
|     Status = mHiiConfigRouting->ConfigToBlock (
 | |
|                                   mHiiConfigRouting,
 | |
|                                   Result,
 | |
|                                   Dst,
 | |
|                                   &BufferSize,
 | |
|                                   &Progress
 | |
|                                   );
 | |
|     if (Result != NULL) {
 | |
|       FreePool (Result);
 | |
|     }
 | |
|   } else if (ConfigInfo->Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) {
 | |
|     Link = GetFirstNode (&ConfigInfo->Storage->NameValueListHead);
 | |
|     while (!IsNull (&ConfigInfo->Storage->NameValueListHead, Link)) {
 | |
|       Node = NAME_VALUE_NODE_FROM_LINK (Link);
 | |
| 
 | |
|       if (StrStr (ConfigInfo->ConfigRequest, Node->Name) != NULL) {
 | |
|         if (SyncOrRestore) {
 | |
|           NewStringCpy (&Node->Value, Node->EditValue);
 | |
|         } else {
 | |
|           NewStringCpy (&Node->EditValue, Node->Value);
 | |
|         }
 | |
|       }
 | |
| 
 | |
|       Link = GetNextNode (&ConfigInfo->Storage->NameValueListHead, Link);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   When discard the question value, call the callback function with Changed type
 | |
|   to inform the hii driver.
 | |
| 
 | |
|   @param  FormSet                FormSet data structure.
 | |
|   @param  Form                   Form data structure.
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| SendDiscardInfoToDriver (
 | |
|   IN FORM_BROWSER_FORMSET             *FormSet,
 | |
|   IN FORM_BROWSER_FORM                *Form
 | |
|   )
 | |
| {
 | |
|   LIST_ENTRY                  *Link;
 | |
|   FORM_BROWSER_STATEMENT      *Question;
 | |
|   EFI_STATUS                  Status;
 | |
|   EFI_HII_VALUE               HiiValue;
 | |
|   UINT8                       *BufferValue;
 | |
|   BOOLEAN                     ValueChanged;
 | |
|   EFI_IFR_TYPE_VALUE          *TypeValue;
 | |
|   EFI_BROWSER_ACTION_REQUEST  ActionRequest;
 | |
| 
 | |
|   ValueChanged = FALSE;
 | |
|   BufferValue  = NULL;
 | |
| 
 | |
|   if(!Form->NvUpdateRequired) {
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   Link = GetFirstNode (&Form->StatementListHead);
 | |
|   while (!IsNull (&Form->StatementListHead, Link)) {
 | |
|     Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link);
 | |
|     Link = GetNextNode (&Form->StatementListHead, Link);
 | |
| 
 | |
|     if (Question->Storage == NULL || Question->Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
|     if (Question->Operand == EFI_IFR_PASSWORD_OP) {
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
|     if (Question->BufferValue != NULL) {
 | |
|       BufferValue = AllocateZeroPool (Question->StorageWidth);
 | |
|       ASSERT (BufferValue != NULL);
 | |
|       CopyMem (BufferValue, Question->BufferValue, Question->StorageWidth);
 | |
|     } else {
 | |
|       HiiValue.Type = Question->HiiValue.Type;
 | |
|       CopyMem (&HiiValue.Value, &Question->HiiValue.Value, sizeof (EFI_IFR_TYPE_VALUE));
 | |
|     }
 | |
| 
 | |
|     Status = GetQuestionValue (FormSet, Form, Question, GetSetValueWithBuffer);
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       if (BufferValue != NULL) {
 | |
|         FreePool (BufferValue);
 | |
|         BufferValue = NULL;
 | |
|       }
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
|     if (Question->BufferValue != NULL) {
 | |
|       if (CompareMem (BufferValue, Question->BufferValue, Question->StorageWidth)) {
 | |
|         ValueChanged = TRUE;
 | |
|       }
 | |
|     } else {
 | |
|       if (CompareMem (&HiiValue.Value, &Question->HiiValue.Value, sizeof (EFI_IFR_TYPE_VALUE))) {
 | |
|         ValueChanged = TRUE;
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     if (BufferValue != NULL) {
 | |
|       FreePool (BufferValue);
 | |
|       BufferValue = NULL;
 | |
|     }
 | |
| 
 | |
|     if (!ValueChanged) {
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
|     ValueChanged = FALSE;
 | |
| 
 | |
|     if (Question->HiiValue.Type == EFI_IFR_TYPE_BUFFER) {
 | |
|       TypeValue = (EFI_IFR_TYPE_VALUE *) Question->BufferValue;
 | |
|     } else {
 | |
|       TypeValue = &Question->HiiValue.Value;
 | |
|     }
 | |
| 
 | |
|     ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;
 | |
|     FormSet->ConfigAccess->Callback (
 | |
|                              FormSet->ConfigAccess,
 | |
|                              EFI_BROWSER_ACTION_CHANGED,
 | |
|                              Question->QuestionId,
 | |
|                              Question->HiiValue.Type,
 | |
|                              TypeValue,
 | |
|                              &ActionRequest
 | |
|                              );
 | |
|   }
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Validate the FormSet. If the formset is not validate, remove it from the list.
 | |
| 
 | |
|   @param  FormSet                The input FormSet which need to validate.
 | |
| 
 | |
|   @retval TRUE                   The handle is validate.
 | |
|   @retval FALSE                  The handle is invalidate.
 | |
| 
 | |
| **/
 | |
| BOOLEAN
 | |
| ValidateFormSet (
 | |
|   FORM_BROWSER_FORMSET    *FormSet
 | |
|   )
 | |
| {
 | |
|   EFI_HII_HANDLE          *HiiHandles;
 | |
|   UINTN                   Index;
 | |
|   BOOLEAN                 Find;
 | |
| 
 | |
|   ASSERT (FormSet != NULL);
 | |
|   Find = FALSE;
 | |
|   //
 | |
|   // Get all the Hii handles
 | |
|   //
 | |
|   HiiHandles = HiiGetHiiHandles (NULL);
 | |
|   ASSERT (HiiHandles != NULL);
 | |
| 
 | |
|   //
 | |
|   // Search for formset of each class type
 | |
|   //
 | |
|   for (Index = 0; HiiHandles[Index] != NULL; Index++) {
 | |
|     if (HiiHandles[Index] == FormSet->HiiHandle) {
 | |
|       Find = TRUE;
 | |
|       break;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if (!Find) {
 | |
|     RemoveEntryList (&FormSet->Link);
 | |
|     DestroyFormSet (FormSet);
 | |
|   }
 | |
| 
 | |
|   FreePool (HiiHandles);
 | |
| 
 | |
|   return Find;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Discard data based on the input setting scope (Form, FormSet or System).
 | |
| 
 | |
|   @param  FormSet                FormSet data structure.
 | |
|   @param  Form                   Form data structure.
 | |
|   @param  SettingScope           Setting Scope for Discard action.
 | |
| 
 | |
|   @retval EFI_SUCCESS            The function completed successfully.
 | |
|   @retval EFI_UNSUPPORTED        Unsupport SettingScope.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| DiscardForm (
 | |
|   IN FORM_BROWSER_FORMSET             *FormSet,
 | |
|   IN FORM_BROWSER_FORM                *Form,
 | |
|   IN BROWSER_SETTING_SCOPE            SettingScope
 | |
|   )
 | |
| {
 | |
|   LIST_ENTRY                   *Link;
 | |
|   FORMSET_STORAGE              *Storage;
 | |
|   FORM_BROWSER_CONFIG_REQUEST  *ConfigInfo;
 | |
|   FORM_BROWSER_FORMSET    *LocalFormSet;
 | |
| 
 | |
|   //
 | |
|   // Check the supported setting level.
 | |
|   //
 | |
|   if (SettingScope >= MaxLevel) {
 | |
|     return EFI_UNSUPPORTED;
 | |
|   }
 | |
| 
 | |
|   if (SettingScope == FormLevel && Form->NvUpdateRequired) {
 | |
|     ConfigInfo = NULL;
 | |
|     Link = GetFirstNode (&Form->ConfigRequestHead);
 | |
|     while (!IsNull (&Form->ConfigRequestHead, Link)) {
 | |
|       ConfigInfo = FORM_BROWSER_CONFIG_REQUEST_FROM_LINK (Link);
 | |
|       Link = GetNextNode (&Form->ConfigRequestHead, Link);
 | |
| 
 | |
|       if (ConfigInfo->Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {
 | |
|         continue;
 | |
|       }
 | |
| 
 | |
|       //
 | |
|       // Skip if there is no RequestElement
 | |
|       //
 | |
|       if (ConfigInfo->ElementCount == 0) {
 | |
|         continue;
 | |
|       }
 | |
| 
 | |
|       //
 | |
|       // Prepare <ConfigResp>
 | |
|       //
 | |
|       SynchronizeStorageForForm(FormSet, ConfigInfo, FALSE);
 | |
| 
 | |
|       //
 | |
|       // Call callback with Changed type to inform the driver.
 | |
|       //
 | |
|       SendDiscardInfoToDriver (FormSet, Form);
 | |
|     }
 | |
| 
 | |
|     Form->NvUpdateRequired = FALSE;
 | |
|   } else if (SettingScope == FormSetLevel && IsNvUpdateRequired(FormSet)) {
 | |
| 
 | |
|     //
 | |
|     // Discard 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->BrowserStorage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {
 | |
|         continue;
 | |
|       }
 | |
| 
 | |
|       //
 | |
|       // Skip if there is no RequestElement
 | |
|       //
 | |
|       if (Storage->ElementCount == 0) {
 | |
|         continue;
 | |
|       }
 | |
| 
 | |
|       SynchronizeStorage(Storage->BrowserStorage, FALSE);
 | |
|     }
 | |
| 
 | |
|     Link = GetFirstNode (&FormSet->FormListHead);
 | |
|     while (!IsNull (&FormSet->FormListHead, Link)) {
 | |
|       Form = FORM_BROWSER_FORM_FROM_LINK (Link);
 | |
|       Link = GetNextNode (&FormSet->FormListHead, Link);
 | |
|       
 | |
|       //
 | |
|       // Call callback with Changed type to inform the driver.
 | |
|       //
 | |
|       SendDiscardInfoToDriver (FormSet, Form);
 | |
|     }
 | |
| 
 | |
|     UpdateNvInfoInForm (FormSet, FALSE);   
 | |
|   } else if (SettingScope == SystemLevel) {
 | |
|     //
 | |
|     // System Level Discard.
 | |
|     //
 | |
|     
 | |
|     //
 | |
|     // Discard changed value for each FormSet in the maintain list.
 | |
|     //
 | |
|     Link = GetFirstNode (&gBrowserFormSetList);
 | |
|     while (!IsNull (&gBrowserFormSetList, Link)) {
 | |
|       LocalFormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link);
 | |
|       Link = GetNextNode (&gBrowserFormSetList, Link);
 | |
|       if (!ValidateFormSet(LocalFormSet)) {
 | |
|         continue;
 | |
|       }
 | |
|       DiscardForm (LocalFormSet, NULL, FormSetLevel);
 | |
|       if (!IsHiiHandleInBrowserContext (LocalFormSet->HiiHandle)) {
 | |
|         //
 | |
|         // Remove maintain backup list after discard except for the current using FormSet.
 | |
|         //
 | |
|         RemoveEntryList (&LocalFormSet->Link);
 | |
|         DestroyFormSet (LocalFormSet);
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return EFI_SUCCESS;  
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Submit data based on the input Setting level (Form, FormSet or System).
 | |
| 
 | |
|   @param  FormSet                FormSet data structure.
 | |
|   @param  Form                   Form data structure.
 | |
|   @param  SettingScope           Setting Scope for Submit action.
 | |
| 
 | |
|   @retval EFI_SUCCESS            The function completed successfully.
 | |
|   @retval EFI_UNSUPPORTED        Unsupport SettingScope.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| SubmitForm (
 | |
|   IN FORM_BROWSER_FORMSET             *FormSet,
 | |
|   IN FORM_BROWSER_FORM                *Form,
 | |
|   IN BROWSER_SETTING_SCOPE            SettingScope
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS              Status;
 | |
|   LIST_ENTRY              *Link;
 | |
|   EFI_STRING              ConfigResp;
 | |
|   EFI_STRING              Progress;
 | |
|   BROWSER_STORAGE         *Storage;
 | |
|   FORMSET_STORAGE         *FormSetStorage;
 | |
|   UINTN                   BufferSize;
 | |
|   UINT8                   *TmpBuf;  
 | |
|   FORM_BROWSER_FORMSET    *LocalFormSet;
 | |
|   FORM_BROWSER_CONFIG_REQUEST  *ConfigInfo;
 | |
| 
 | |
|   //
 | |
|   // Check the supported setting level.
 | |
|   //
 | |
|   if (SettingScope >= MaxLevel) {
 | |
|     return EFI_UNSUPPORTED;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Validate the Form by NoSubmit check
 | |
|   //
 | |
|   Status = EFI_SUCCESS;
 | |
|   if (SettingScope == FormLevel) {
 | |
|     Status = NoSubmitCheck (FormSet, Form);
 | |
|   } else if (SettingScope == FormSetLevel) {
 | |
|     Status = NoSubmitCheck (FormSet, NULL);
 | |
|   }
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   if (SettingScope == FormLevel && Form->NvUpdateRequired) {
 | |
|     ConfigInfo = NULL;
 | |
|     Link = GetFirstNode (&Form->ConfigRequestHead);
 | |
|     while (!IsNull (&Form->ConfigRequestHead, Link)) {
 | |
|       ConfigInfo = FORM_BROWSER_CONFIG_REQUEST_FROM_LINK (Link);
 | |
|       Link = GetNextNode (&Form->ConfigRequestHead, Link);
 | |
| 
 | |
|       Storage = ConfigInfo->Storage;
 | |
|       if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {
 | |
|         continue;
 | |
|       }
 | |
| 
 | |
|       //
 | |
|       // Skip if there is no RequestElement
 | |
|       //
 | |
|       if (ConfigInfo->ElementCount == 0) {
 | |
|         continue;
 | |
|       }
 | |
| 
 | |
|       //
 | |
|       // 1. Prepare <ConfigResp>
 | |
|       //
 | |
|       Status = StorageToConfigResp (ConfigInfo->Storage, &ConfigResp, ConfigInfo->ConfigRequest);
 | |
|       if (EFI_ERROR (Status)) {
 | |
|         return Status;
 | |
|       }
 | |
| 
 | |
|       //
 | |
|       // 2. Set value to hii driver or efi variable.
 | |
|       //
 | |
|       if (Storage->Type == EFI_HII_VARSTORE_BUFFER || 
 | |
|           Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) {
 | |
|         //
 | |
|         // Send <ConfigResp> to Configuration Driver
 | |
|         //
 | |
|         if (FormSet->ConfigAccess != NULL) {
 | |
|           Status = FormSet->ConfigAccess->RouteConfig (
 | |
|                                             FormSet->ConfigAccess,
 | |
|                                             ConfigResp,
 | |
|                                             &Progress
 | |
|                                             );
 | |
|           if (EFI_ERROR (Status)) {
 | |
|             FreePool (ConfigResp);
 | |
|             return Status;
 | |
|           }
 | |
|         }
 | |
|       } else if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER) {
 | |
|         TmpBuf = NULL;
 | |
|         TmpBuf = AllocateZeroPool(Storage->Size);
 | |
|         if (TmpBuf == NULL) {
 | |
|           Status = EFI_OUT_OF_RESOURCES;
 | |
|           return Status;
 | |
|         }
 | |
| 
 | |
|         BufferSize = Storage->Size;
 | |
|         Status = gRT->GetVariable (
 | |
|                          Storage->Name,
 | |
|                          &Storage->Guid,
 | |
|                          NULL,
 | |
|                          &BufferSize,
 | |
|                          TmpBuf
 | |
|                          );
 | |
|         if (EFI_ERROR (Status)) {
 | |
|           FreePool (TmpBuf);
 | |
|           FreePool (ConfigResp);
 | |
|           return Status;
 | |
|         }
 | |
|         ASSERT (BufferSize == Storage->Size);      
 | |
|         Status = mHiiConfigRouting->ConfigToBlock (
 | |
|                                       mHiiConfigRouting,
 | |
|                                       ConfigResp,
 | |
|                                       TmpBuf,
 | |
|                                       &BufferSize,
 | |
|                                       &Progress
 | |
|                                       );
 | |
|         if (EFI_ERROR (Status)) {
 | |
|           FreePool (TmpBuf);
 | |
|           FreePool (ConfigResp);
 | |
|           return Status;
 | |
|         }
 | |
| 
 | |
|         Status = gRT->SetVariable (
 | |
|                          Storage->Name,
 | |
|                          &Storage->Guid,
 | |
|                          Storage->Attributes,
 | |
|                          Storage->Size,
 | |
|                          TmpBuf
 | |
|                          );
 | |
|         FreePool (TmpBuf);
 | |
|         if (EFI_ERROR (Status)) {
 | |
|           FreePool (ConfigResp);
 | |
|           return Status;
 | |
|         }
 | |
|       }
 | |
|       FreePool (ConfigResp);
 | |
|       //
 | |
|       // 3. Config success, update storage shadow Buffer, only update the data belong to this form.
 | |
|       //
 | |
|       SynchronizeStorageForForm(FormSet, ConfigInfo, TRUE);
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // 4. Update the NV flag.
 | |
|     // 
 | |
|     Form->NvUpdateRequired = FALSE;
 | |
|   } else if (SettingScope == FormSetLevel && IsNvUpdateRequired(FormSet)) {
 | |
|     //
 | |
|     // Submit Buffer storage or Name/Value storage
 | |
|     //
 | |
|     Link = GetFirstNode (&FormSet->StorageListHead);
 | |
|     while (!IsNull (&FormSet->StorageListHead, Link)) {
 | |
|       FormSetStorage = (FORMSET_STORAGE_FROM_LINK (Link));
 | |
|       Storage        = FormSetStorage->BrowserStorage;
 | |
|       Link = GetNextNode (&FormSet->StorageListHead, Link);
 | |
| 
 | |
|       if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {
 | |
|         continue;
 | |
|       }
 | |
| 
 | |
|       //
 | |
|       // Skip if there is no RequestElement
 | |
|       //
 | |
|       if (FormSetStorage->ElementCount == 0) {
 | |
|         continue;
 | |
|       }
 | |
| 
 | |
|       //
 | |
|       // 1. Prepare <ConfigResp>
 | |
|       //
 | |
|       Status = StorageToConfigResp (Storage, &ConfigResp, FormSetStorage->ConfigRequest);
 | |
|       if (EFI_ERROR (Status)) {
 | |
|         return Status;
 | |
|       }
 | |
| 
 | |
|       if (Storage->Type == EFI_HII_VARSTORE_BUFFER || 
 | |
|           Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) {
 | |
| 
 | |
|         //
 | |
|         // 2. Send <ConfigResp> to Configuration Driver
 | |
|         //
 | |
|         if (FormSet->ConfigAccess != NULL) {
 | |
|           Status = FormSet->ConfigAccess->RouteConfig (
 | |
|                                             FormSet->ConfigAccess,
 | |
|                                             ConfigResp,
 | |
|                                             &Progress
 | |
|                                             );
 | |
|           if (EFI_ERROR (Status)) {
 | |
|             FreePool (ConfigResp);
 | |
|             return Status;
 | |
|           }
 | |
|         }
 | |
|       } else if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER) {
 | |
|         //
 | |
|         // 1&2. Set the edit data to the variable.
 | |
|         //
 | |
|         TmpBuf = NULL;
 | |
|         TmpBuf = AllocateZeroPool (Storage->Size);
 | |
|         if (TmpBuf == NULL) {
 | |
|           Status = EFI_OUT_OF_RESOURCES;
 | |
|           return Status;
 | |
|         }        
 | |
|         BufferSize = Storage->Size;
 | |
|         Status = gRT->GetVariable (
 | |
|                        Storage->Name,
 | |
|                        &Storage->Guid,
 | |
|                        NULL,
 | |
|                        &BufferSize,
 | |
|                        TmpBuf
 | |
|                        );
 | |
|         ASSERT (BufferSize == Storage->Size);      
 | |
|         Status = mHiiConfigRouting->ConfigToBlock (
 | |
|                                       mHiiConfigRouting,
 | |
|                                       ConfigResp,
 | |
|                                       TmpBuf,
 | |
|                                       &BufferSize,
 | |
|                                       &Progress
 | |
|                                       );
 | |
|         if (EFI_ERROR (Status)) {
 | |
|           FreePool (TmpBuf);
 | |
|           FreePool (ConfigResp);
 | |
|           return Status;
 | |
|         }
 | |
| 
 | |
|         Status = gRT->SetVariable (
 | |
|                          Storage->Name,
 | |
|                          &Storage->Guid,
 | |
|                          Storage->Attributes,
 | |
|                          Storage->Size,
 | |
|                          TmpBuf
 | |
|                          );
 | |
|         if (EFI_ERROR (Status)) {
 | |
|           FreePool (TmpBuf);
 | |
|           FreePool (ConfigResp);
 | |
|           return Status;
 | |
|         }
 | |
|         FreePool (TmpBuf);
 | |
|       }
 | |
|       FreePool (ConfigResp);
 | |
|       //
 | |
|       // 3. Config success, update storage shadow Buffer
 | |
|       //
 | |
|       SynchronizeStorage (Storage, TRUE);
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // 4. Update the NV flag.
 | |
|     // 
 | |
|     UpdateNvInfoInForm (FormSet, FALSE);
 | |
|   } else if (SettingScope == SystemLevel) {
 | |
|     //
 | |
|     // System Level Save.
 | |
|     //
 | |
| 
 | |
|     //
 | |
|     // Save changed value for each FormSet in the maintain list.
 | |
|     //
 | |
|     Link = GetFirstNode (&gBrowserFormSetList);
 | |
|     while (!IsNull (&gBrowserFormSetList, Link)) {
 | |
|       LocalFormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link);
 | |
|       Link = GetNextNode (&gBrowserFormSetList, Link);
 | |
|       if (!ValidateFormSet(LocalFormSet)) {
 | |
|         continue;
 | |
|       }
 | |
|       SubmitForm (LocalFormSet, NULL, FormSetLevel);
 | |
|       if (!IsHiiHandleInBrowserContext (LocalFormSet->HiiHandle)) {
 | |
|         //
 | |
|         // Remove maintain backup list after save except for the current using FormSet.
 | |
|         //
 | |
|         RemoveEntryList (&LocalFormSet->Link);
 | |
|         DestroyFormSet (LocalFormSet);
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Get Question default value from AltCfg string.
 | |
| 
 | |
|   @param  FormSet                The form set.
 | |
|   @param  Question               The question.
 | |
|   @param  DefaultId              The default Id.
 | |
| 
 | |
|   @retval EFI_SUCCESS            Question is reset to default value.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| GetDefaultValueFromAltCfg (
 | |
|   IN     FORM_BROWSER_FORMSET             *FormSet,
 | |
|   IN OUT FORM_BROWSER_STATEMENT           *Question,
 | |
|   IN     UINT16                           DefaultId
 | |
|   )
 | |
| {
 | |
|   BOOLEAN             IsBufferStorage;
 | |
|   BOOLEAN             IsString;  
 | |
|   UINTN               Length;
 | |
|   BROWSER_STORAGE     *Storage;
 | |
|   CHAR16              *ConfigRequest;
 | |
|   CHAR16              *Progress;
 | |
|   CHAR16              *Result;
 | |
|   CHAR16              *ConfigResp;
 | |
|   CHAR16              *Value;
 | |
|   CHAR16              *StringPtr;
 | |
|   UINTN               LengthStr;
 | |
|   UINT8               *Dst;
 | |
|   CHAR16              TemStr[5];
 | |
|   UINTN               Index;
 | |
|   UINT8               DigitUint8;
 | |
|   EFI_STATUS          Status;
 | |
| 
 | |
|   Status        = EFI_NOT_FOUND;
 | |
|   Length        = 0;
 | |
|   Dst           = NULL;
 | |
|   ConfigRequest = NULL;
 | |
|   Result        = NULL;
 | |
|   ConfigResp    = NULL;
 | |
|   Value         = NULL;
 | |
|   Storage       = Question->Storage;
 | |
| 
 | |
|   if ((Storage == NULL) || 
 | |
|       (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) || 
 | |
|       (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER)) {
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // 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);
 | |
| 
 | |
|   //
 | |
|   // <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)) {
 | |
|     goto Done;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Call ConfigRouting GetAltCfg(ConfigRoute, <ConfigResponse>, Guid, Name, DevicePath, AltCfgId, AltCfgResp)
 | |
|   //    Get the default configuration string according to the default ID.
 | |
|   //
 | |
|   Status = mHiiConfigRouting->GetAltConfig (
 | |
|                                 mHiiConfigRouting,
 | |
|                                 Result,
 | |
|                                 &Storage->Guid,
 | |
|                                 Storage->Name,
 | |
|                                 NULL,
 | |
|                                 &DefaultId,  // it can be NULL to get the current setting.
 | |
|                                 &ConfigResp
 | |
|                               );
 | |
|   
 | |
|   //
 | |
|   // The required setting can't be found. So, it is not required to be validated and set.
 | |
|   //
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     goto Done;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Skip <ConfigRequest>
 | |
|   //
 | |
|   if (IsBufferStorage) {
 | |
|     Value = StrStr (ConfigResp, L"&VALUE");
 | |
|     ASSERT (Value != NULL);
 | |
|     //
 | |
|     // Skip "&VALUE"
 | |
|     //
 | |
|     Value = Value + 6;
 | |
|   } else {
 | |
|     Value = StrStr (ConfigResp, Question->VariableName);
 | |
|     ASSERT (Value != NULL);
 | |
| 
 | |
|     Value = Value + StrLen (Question->VariableName);
 | |
|   }
 | |
|   if (*Value != '=') {
 | |
|     Status = EFI_NOT_FOUND;
 | |
|     goto Done;
 | |
|   }
 | |
|   //
 | |
|   // Skip '=', point to value
 | |
|   //
 | |
|   Value = Value + 1;
 | |
| 
 | |
|   //
 | |
|   // Suppress <AltResp> if any
 | |
|   //
 | |
|   StringPtr = Value;
 | |
|   while (*StringPtr != L'\0' && *StringPtr != L'&') {
 | |
|     StringPtr++;
 | |
|   }
 | |
|   *StringPtr = L'\0';
 | |
| 
 | |
|   LengthStr = StrLen (Value);
 | |
|   if (!IsBufferStorage && IsString) {
 | |
|     StringPtr = (CHAR16 *) Dst;
 | |
|     ZeroMem (TemStr, sizeof (TemStr));
 | |
|     for (Index = 0; Index < LengthStr; Index += 4) {
 | |
|       StrnCpy (TemStr, Value + Index, 4);
 | |
|       StringPtr[Index/4] = (CHAR16) StrHexToUint64 (TemStr);
 | |
|     }
 | |
|     //
 | |
|     // Add tailing L'\0' character
 | |
|     //
 | |
|     StringPtr[Index/4] = L'\0';
 | |
|   } else {
 | |
|     ZeroMem (TemStr, sizeof (TemStr));
 | |
|     for (Index = 0; Index < LengthStr; Index ++) {
 | |
|       TemStr[0] = Value[LengthStr - Index - 1];
 | |
|       DigitUint8 = (UINT8) StrHexToUint64 (TemStr);
 | |
|       if ((Index & 1) == 0) {
 | |
|         Dst [Index/2] = DigitUint8;
 | |
|       } else {
 | |
|         Dst [Index/2] = (UINT8) ((DigitUint8 << 4) + Dst [Index/2]);
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
| Done:
 | |
|   if (ConfigRequest != NULL){
 | |
|     FreePool (ConfigRequest);
 | |
|   }
 | |
| 
 | |
|   if (ConfigResp != NULL) {
 | |
|     FreePool (ConfigResp);
 | |
|   }
 | |
|   
 | |
|   if (Result != NULL) {
 | |
|     FreePool (Result);
 | |
|   }
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Get default Id value used for browser.
 | |
| 
 | |
|   @param  DefaultId              The default id value used by hii.
 | |
| 
 | |
|   @retval Browser used default value.
 | |
| 
 | |
| **/
 | |
| INTN
 | |
| GetDefaultIdForCallBack (
 | |
|   UINTN DefaultId
 | |
|   )
 | |
| { 
 | |
|   if (DefaultId == EFI_HII_DEFAULT_CLASS_STANDARD) {
 | |
|     return EFI_BROWSER_ACTION_DEFAULT_STANDARD;
 | |
|   } else if (DefaultId == EFI_HII_DEFAULT_CLASS_MANUFACTURING) {
 | |
|     return EFI_BROWSER_ACTION_DEFAULT_MANUFACTURING;
 | |
|   } else if (DefaultId == EFI_HII_DEFAULT_CLASS_SAFE) {
 | |
|     return EFI_BROWSER_ACTION_DEFAULT_SAFE;
 | |
|   } else if (DefaultId >= EFI_HII_DEFAULT_CLASS_PLATFORM_BEGIN && DefaultId < EFI_HII_DEFAULT_CLASS_PLATFORM_BEGIN + 0x1000) {
 | |
|     return EFI_BROWSER_ACTION_DEFAULT_PLATFORM + DefaultId - EFI_HII_DEFAULT_CLASS_PLATFORM_BEGIN;
 | |
|   } else if (DefaultId >= EFI_HII_DEFAULT_CLASS_HARDWARE_BEGIN && DefaultId < EFI_HII_DEFAULT_CLASS_HARDWARE_BEGIN + 0x1000) {
 | |
|     return EFI_BROWSER_ACTION_DEFAULT_HARDWARE + DefaultId - EFI_HII_DEFAULT_CLASS_HARDWARE_BEGIN;
 | |
|   } else if (DefaultId >= EFI_HII_DEFAULT_CLASS_FIRMWARE_BEGIN && DefaultId < EFI_HII_DEFAULT_CLASS_FIRMWARE_BEGIN + 0x1000) {
 | |
|     return EFI_BROWSER_ACTION_DEFAULT_FIRMWARE + DefaultId - EFI_HII_DEFAULT_CLASS_FIRMWARE_BEGIN;
 | |
|   } else {
 | |
|     return -1;
 | |
|   }
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Reset Question to its default value.
 | |
| 
 | |
|   @param  FormSet                The form set.
 | |
|   @param  Form                   The form.
 | |
|   @param  Question               The question.
 | |
|   @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;
 | |
|   EFI_STRING              StrValue;
 | |
|   EFI_HII_CONFIG_ACCESS_PROTOCOL  *ConfigAccess;
 | |
|   EFI_BROWSER_ACTION_REQUEST      ActionRequest;
 | |
|   INTN                            Action;
 | |
| 
 | |
|   Status   = EFI_NOT_FOUND;
 | |
|   StrValue = NULL;
 | |
| 
 | |
|   //
 | |
|   // Statement don't have storage, skip them
 | |
|   //
 | |
|   if (Question->QuestionId == 0) {
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // There are Five ways to specify default value for a Question:
 | |
|   //  1, use call back function (highest priority)
 | |
|   //  2, use ExtractConfig function
 | |
|   //  3, use nested EFI_IFR_DEFAULT 
 | |
|   //  4, set flags of EFI_ONE_OF_OPTION (provide Standard and Manufacturing default)
 | |
|   //  5, set flags of EFI_IFR_CHECKBOX (provide Standard and Manufacturing default) (lowest priority)
 | |
|   //
 | |
|   HiiValue = &Question->HiiValue;
 | |
| 
 | |
|   //
 | |
|   // Get Question defaut value from call back function.
 | |
|   //
 | |
|   ConfigAccess = FormSet->ConfigAccess;
 | |
|   Action = GetDefaultIdForCallBack (DefaultId);
 | |
|   if ((Action > 0) && ((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) && (ConfigAccess != NULL)) {
 | |
|     ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;
 | |
|     Status = ConfigAccess->Callback (
 | |
|                              ConfigAccess,
 | |
|                              Action,
 | |
|                              Question->QuestionId,
 | |
|                              HiiValue->Type,
 | |
|                              &HiiValue->Value,
 | |
|                              &ActionRequest
 | |
|                              );
 | |
|     if (!EFI_ERROR (Status)) {
 | |
|       return Status;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Get default value from altcfg string.
 | |
|   //
 | |
|   if (ConfigAccess != NULL) {  
 | |
|     Status = GetDefaultValueFromAltCfg(FormSet, Question, DefaultId);
 | |
|     if (!EFI_ERROR (Status)) {
 | |
|         return Status;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // 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;
 | |
|           }
 | |
| 
 | |
|           if (Default->ValueExpression->Result.Type == EFI_IFR_TYPE_BUFFER) {
 | |
|             ASSERT (HiiValue->Type == EFI_IFR_TYPE_BUFFER && Question->BufferValue != NULL);
 | |
|             if (Question->StorageWidth > Default->ValueExpression->Result.BufferLen) {
 | |
|               CopyMem (Question->HiiValue.Buffer, Default->ValueExpression->Result.Buffer, Default->ValueExpression->Result.BufferLen);
 | |
|               Question->HiiValue.BufferLen = Default->ValueExpression->Result.BufferLen;
 | |
|             } else {
 | |
|               CopyMem (Question->HiiValue.Buffer, Default->ValueExpression->Result.Buffer, Question->StorageWidth);
 | |
|               Question->HiiValue.BufferLen = Question->StorageWidth;
 | |
|             }
 | |
|             FreePool (Default->ValueExpression->Result.Buffer);
 | |
|           }
 | |
|           HiiValue->Type = Default->ValueExpression->Result.Type;
 | |
|           CopyMem (&HiiValue->Value, &Default->ValueExpression->Result.Value, sizeof (EFI_IFR_TYPE_VALUE));       
 | |
|         } else {
 | |
|           //
 | |
|           // Default value is embedded in EFI_IFR_DEFAULT
 | |
|           //
 | |
|           CopyMem (HiiValue, &Default->Value, sizeof (EFI_HII_VALUE));
 | |
|         }
 | |
| 
 | |
|         if (HiiValue->Type == EFI_IFR_TYPE_STRING) {
 | |
|           StrValue = HiiGetString (FormSet->HiiHandle, HiiValue->Value.string, NULL);
 | |
|           if (StrValue == NULL) {
 | |
|             return EFI_NOT_FOUND;
 | |
|           }
 | |
|           if (Question->StorageWidth > StrSize (StrValue)) {
 | |
|             CopyMem (Question->BufferValue, StrValue, StrSize (StrValue));
 | |
|           } else {
 | |
|             CopyMem (Question->BufferValue, StrValue, Question->StorageWidth);
 | |
|           }
 | |
|         }
 | |
| 
 | |
|         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);
 | |
|         Link = GetNextNode (&Question->OptionListHead, Link);
 | |
| 
 | |
|         if ((Option->SuppressExpression != NULL) &&
 | |
|             EvaluateExpressionList(Option->SuppressExpression, FALSE, NULL, NULL) != ExpressFalse) {
 | |
|           continue;
 | |
|         }
 | |
| 
 | |
|         if (((DefaultId == EFI_HII_DEFAULT_CLASS_STANDARD) && ((Option->Flags & EFI_IFR_OPTION_DEFAULT) != 0)) ||
 | |
|             ((DefaultId == EFI_HII_DEFAULT_CLASS_MANUFACTURING) && ((Option->Flags & EFI_IFR_OPTION_DEFAULT_MFG) != 0))
 | |
|            ) {
 | |
|           CopyMem (HiiValue, &Option->Value, sizeof (EFI_HII_VALUE));
 | |
| 
 | |
|           return EFI_SUCCESS;
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // 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) != 0)) ||
 | |
|           ((DefaultId == EFI_HII_DEFAULT_CLASS_MANUFACTURING) && ((Question->Flags & EFI_IFR_CHECKBOX_DEFAULT_MFG) != 0))
 | |
|          ) {
 | |
|         HiiValue->Value.b = TRUE;
 | |
|       } else {
 | |
|         HiiValue->Value.b = FALSE;
 | |
|       }
 | |
| 
 | |
|       return EFI_SUCCESS;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // For Questions without default
 | |
|   //
 | |
|   Status = EFI_NOT_FOUND;
 | |
|   switch (Question->Operand) {
 | |
|   case EFI_IFR_NUMERIC_OP:
 | |
|     //
 | |
|     // Take minimum value as numeric default value
 | |
|     //
 | |
|     if ((HiiValue->Value.u64 < Question->Minimum) || (HiiValue->Value.u64 > Question->Maximum)) {
 | |
|       HiiValue->Value.u64 = Question->Minimum;
 | |
|       Status = EFI_SUCCESS;
 | |
|     }
 | |
|     break;
 | |
| 
 | |
|   case EFI_IFR_ONE_OF_OP:
 | |
|     //
 | |
|     // Take first oneof option as oneof's default value
 | |
|     //
 | |
|     if (ValueToOption (Question, HiiValue) == NULL) {
 | |
|       Link = GetFirstNode (&Question->OptionListHead);
 | |
|       while (!IsNull (&Question->OptionListHead, Link)) {
 | |
|         Option = QUESTION_OPTION_FROM_LINK (Link);
 | |
|         Link = GetNextNode (&Question->OptionListHead, Link);
 | |
| 
 | |
|         if ((Option->SuppressExpression != NULL) &&
 | |
|             EvaluateExpressionList(Option->SuppressExpression, FALSE, NULL, NULL) != ExpressFalse) {
 | |
|           continue;
 | |
|         }
 | |
| 
 | |
|         CopyMem (HiiValue, &Option->Value, sizeof (EFI_HII_VALUE));
 | |
|         Status = EFI_SUCCESS;
 | |
|         break;
 | |
|       }
 | |
|     }
 | |
|     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)) {
 | |
|       Status = EFI_SUCCESS;
 | |
|       Option = QUESTION_OPTION_FROM_LINK (Link);
 | |
|       Link = GetNextNode (&Question->OptionListHead, Link);
 | |
| 
 | |
|       if ((Option->SuppressExpression != NULL) &&
 | |
|           EvaluateExpressionList(Option->SuppressExpression, FALSE, NULL, NULL) != ExpressFalse) {
 | |
|         continue;
 | |
|       }
 | |
| 
 | |
|       SetArrayData (Question->BufferValue, Question->ValueType, Index, Option->Value.Value.u64);
 | |
| 
 | |
|       Index++;
 | |
|       if (Index >= Question->MaxContainers) {
 | |
|         break;
 | |
|       }
 | |
|     }
 | |
|     break;
 | |
| 
 | |
|   default:
 | |
|     break;
 | |
|   }
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Reset Questions to their initial value or default value in a Form, Formset or System.
 | |
| 
 | |
|   GetDefaultValueScope parameter decides which questions will reset 
 | |
|   to its default value.
 | |
| 
 | |
|   @param  FormSet                FormSet data structure.
 | |
|   @param  Form                   Form data structure.
 | |
|   @param  DefaultId              The Class of the default.
 | |
|   @param  SettingScope           Setting Scope for Default action.
 | |
|   @param  GetDefaultValueScope   Get default value scope.
 | |
|   @param  Storage                Get default value only for this storage.
 | |
|   @param  RetrieveValueFirst     Whether call the retrieve call back to
 | |
|                                  get the initial value before get default
 | |
|                                  value.
 | |
| 
 | |
|   @retval EFI_SUCCESS            The function completed successfully.
 | |
|   @retval EFI_UNSUPPORTED        Unsupport SettingScope.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| ExtractDefault (
 | |
|   IN FORM_BROWSER_FORMSET             *FormSet,
 | |
|   IN FORM_BROWSER_FORM                *Form,
 | |
|   IN UINT16                           DefaultId,
 | |
|   IN BROWSER_SETTING_SCOPE            SettingScope,
 | |
|   IN BROWSER_GET_DEFAULT_VALUE        GetDefaultValueScope,
 | |
|   IN BROWSER_STORAGE                  *Storage OPTIONAL,
 | |
|   IN BOOLEAN                          RetrieveValueFirst
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS              Status;
 | |
|   LIST_ENTRY              *FormLink;
 | |
|   LIST_ENTRY              *Link;
 | |
|   FORM_BROWSER_STATEMENT  *Question;
 | |
|   FORM_BROWSER_FORMSET    *BackUpFormSet;
 | |
|   FORM_BROWSER_FORMSET    *LocalFormSet;
 | |
|   EFI_HII_HANDLE          *HiiHandles;
 | |
|   UINTN                   Index;
 | |
|   EFI_GUID                ZeroGuid;
 | |
| 
 | |
|   Status = EFI_SUCCESS;
 | |
| 
 | |
|   //
 | |
|   // Check the supported setting level.
 | |
|   //
 | |
|   if (SettingScope >= MaxLevel || GetDefaultValueScope >= GetDefaultForMax) {
 | |
|     return EFI_UNSUPPORTED;
 | |
|   }
 | |
| 
 | |
|   if (GetDefaultValueScope == GetDefaultForStorage && Storage == NULL) {
 | |
|     return EFI_UNSUPPORTED;
 | |
|   }
 | |
|   
 | |
|   if (SettingScope == FormLevel) {
 | |
|     //
 | |
|     // Extract Form default
 | |
|     //
 | |
|     Link = GetFirstNode (&Form->StatementListHead);
 | |
|     while (!IsNull (&Form->StatementListHead, Link)) {
 | |
|       Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link);
 | |
|       Link = GetNextNode (&Form->StatementListHead, Link);
 | |
| 
 | |
|       //
 | |
|       // If get default value only for this storage, check the storage first.
 | |
|       //
 | |
|       if ((GetDefaultValueScope == GetDefaultForStorage) && (Question->Storage != Storage)) {
 | |
|         continue;
 | |
|       }
 | |
| 
 | |
|       //
 | |
|       // If get default value only for no storage question, just skip the question which has storage.
 | |
|       //
 | |
|       if ((GetDefaultValueScope == GetDefaultForNoStorage) && (Question->Storage != NULL)) {
 | |
|         continue;
 | |
|       }
 | |
| 
 | |
|       //
 | |
|       // If Question is disabled, don't reset it to default
 | |
|       //
 | |
|       if (Question->Expression != NULL) {
 | |
|         if (EvaluateExpressionList(Question->Expression, TRUE, FormSet, Form) == ExpressDisable) {
 | |
|           continue;
 | |
|         }
 | |
|       }
 | |
| 
 | |
|       if (RetrieveValueFirst) {
 | |
|         //
 | |
|         // Call the Retrieve call back to get the initial question value.
 | |
|         //
 | |
|         Status = ProcessRetrieveForQuestion(FormSet->ConfigAccess, Question);
 | |
|       }
 | |
| 
 | |
|       //
 | |
|       // If not request to get the initial value or get initial value fail, then get default value.
 | |
|       //
 | |
|       if (!RetrieveValueFirst || EFI_ERROR (Status)) {
 | |
|         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, GetSetValueWithEditBuffer);
 | |
|         //
 | |
|         // Update Form NV flag.
 | |
|         //
 | |
|         Form->NvUpdateRequired = TRUE;
 | |
|       }
 | |
|     }
 | |
|   } else if (SettingScope == FormSetLevel) {
 | |
|     FormLink = GetFirstNode (&FormSet->FormListHead);
 | |
|     while (!IsNull (&FormSet->FormListHead, FormLink)) {
 | |
|       Form = FORM_BROWSER_FORM_FROM_LINK (FormLink);
 | |
|       ExtractDefault (FormSet, Form, DefaultId, FormLevel, GetDefaultValueScope, Storage, RetrieveValueFirst);
 | |
|       FormLink = GetNextNode (&FormSet->FormListHead, FormLink);
 | |
|     }
 | |
|   } else if (SettingScope == SystemLevel) {
 | |
|     //
 | |
|     // Open all FormSet by locate HII packages.
 | |
|     // Initiliaze the maintain FormSet to store default data as back up data.
 | |
|     //
 | |
|     BackUpFormSet    = gOldFormSet;
 | |
|     gOldFormSet      = NULL;
 | |
| 
 | |
|     //
 | |
|     // Get all the Hii handles
 | |
|     //
 | |
|     HiiHandles = HiiGetHiiHandles (NULL);
 | |
|     ASSERT (HiiHandles != NULL);
 | |
| 
 | |
|     //
 | |
|     // Search for formset of each class type
 | |
|     //
 | |
|     for (Index = 0; HiiHandles[Index] != NULL; Index++) {
 | |
|       //
 | |
|       // Check HiiHandles[Index] does exist in global maintain list. 
 | |
|       //
 | |
|       if (GetFormSetFromHiiHandle (HiiHandles[Index]) != NULL) {
 | |
|         continue;
 | |
|       }
 | |
|       
 | |
|       //
 | |
|       // Initilize FormSet Setting
 | |
|       //
 | |
|       LocalFormSet = AllocateZeroPool (sizeof (FORM_BROWSER_FORMSET));
 | |
|       ASSERT (LocalFormSet != NULL);
 | |
|       ZeroMem (&ZeroGuid, sizeof (ZeroGuid));
 | |
|       Status = InitializeFormSet (HiiHandles[Index], &ZeroGuid, LocalFormSet, FALSE);
 | |
|       if (EFI_ERROR (Status) || IsListEmpty (&LocalFormSet->FormListHead)) {
 | |
|         DestroyFormSet (LocalFormSet);
 | |
|         continue;
 | |
|       }
 | |
|       Status = InitializeCurrentSetting (LocalFormSet);
 | |
|       if (EFI_ERROR (Status)) {
 | |
|         DestroyFormSet (LocalFormSet);
 | |
|         continue;
 | |
|       }
 | |
|       //
 | |
|       // Initilize Questions' Value
 | |
|       //
 | |
|       Status = LoadFormSetConfig (NULL, LocalFormSet);
 | |
|       if (EFI_ERROR (Status)) {
 | |
|         DestroyFormSet (LocalFormSet);
 | |
|         continue;
 | |
|       }
 | |
| 
 | |
|       //
 | |
|       // Add FormSet into the maintain list.
 | |
|       //
 | |
|       InsertTailList (&gBrowserFormSetList, &LocalFormSet->Link);
 | |
|     }
 | |
|     
 | |
|     //
 | |
|     // Free resources, and restore gOldFormSet and gClassOfVfr
 | |
|     //
 | |
|     FreePool (HiiHandles);
 | |
|     gOldFormSet = BackUpFormSet;
 | |
|        
 | |
|     //
 | |
|     // Set Default Value for each FormSet in the maintain list.
 | |
|     //
 | |
|     Link = GetFirstNode (&gBrowserFormSetList);
 | |
|     while (!IsNull (&gBrowserFormSetList, Link)) {
 | |
|       LocalFormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link);
 | |
|       Link = GetNextNode (&gBrowserFormSetList, Link);
 | |
|       if (!ValidateFormSet(LocalFormSet)) {
 | |
|         continue;
 | |
|       }
 | |
|       ExtractDefault (LocalFormSet, NULL, DefaultId, FormSetLevel, GetDefaultValueScope, Storage, RetrieveValueFirst);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Initialize Question's Edit copy from Storage.
 | |
| 
 | |
|   @param  Selection              Selection contains the information about 
 | |
|                                  the Selection, form and formset to be displayed.
 | |
|                                  Selection action may be updated in retrieve callback.
 | |
|                                  If Selection is NULL, only initialize Question value.
 | |
|   @param  FormSet                FormSet data structure.
 | |
|   @param  Form                   Form data structure.
 | |
| 
 | |
|   @retval EFI_SUCCESS            The function completed successfully.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| LoadFormConfig (
 | |
|   IN OUT UI_MENU_SELECTION    *Selection,
 | |
|   IN FORM_BROWSER_FORMSET     *FormSet,
 | |
|   IN FORM_BROWSER_FORM        *Form
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                  Status;
 | |
|   LIST_ENTRY                  *Link;
 | |
|   FORM_BROWSER_STATEMENT      *Question;
 | |
|   UINT8                       *BufferValue;
 | |
|   UINTN                       StorageWidth;
 | |
|   
 | |
|   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, GetSetValueWithEditBuffer);
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       return Status;
 | |
|     }
 | |
| 
 | |
|     if ((Question->Operand == EFI_IFR_STRING_OP) || (Question->Operand == EFI_IFR_PASSWORD_OP)) {
 | |
|       HiiSetString (FormSet->HiiHandle, Question->HiiValue.Value.string, (CHAR16*)Question->BufferValue, NULL);
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // Call the Retrieve call back function for all questions.
 | |
|     //
 | |
|     if ((FormSet->ConfigAccess != NULL) && (Selection != NULL) &&
 | |
|         ((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) == EFI_IFR_FLAG_CALLBACK)) {
 | |
|       //
 | |
|       // Check QuestionValue does exist.
 | |
|       //
 | |
|       StorageWidth = Question->StorageWidth;
 | |
|       if (Question->BufferValue != NULL) {
 | |
|         BufferValue  = Question->BufferValue;
 | |
|       } else {
 | |
|         BufferValue = (UINT8 *) &Question->HiiValue.Value;
 | |
|       }
 | |
| 
 | |
|       //
 | |
|       // For efivarstore storage, initial question value first.
 | |
|       //
 | |
|       if ((Question->Storage != NULL) && (Question->Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE)) {
 | |
|         Status = gRT->GetVariable (
 | |
|                          Question->VariableName,
 | |
|                          &Question->Storage->Guid,
 | |
|                          NULL,
 | |
|                          &StorageWidth,
 | |
|                          BufferValue
 | |
|                          );
 | |
|       }
 | |
| 
 | |
|       Status = ProcessCallBackFunction(Selection, Question, EFI_BROWSER_ACTION_RETRIEVE, TRUE);
 | |
|     }
 | |
| 
 | |
|     Link = GetNextNode (&Form->StatementListHead, Link);
 | |
|   }
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Initialize Question's Edit copy from Storage for the whole Formset.
 | |
| 
 | |
|   @param  Selection              Selection contains the information about 
 | |
|                                  the Selection, form and formset to be displayed.
 | |
|                                  Selection action may be updated in retrieve callback.
 | |
|                                  If Selection is NULL, only initialize Question value.
 | |
|   @param  FormSet                FormSet data structure.
 | |
| 
 | |
|   @retval EFI_SUCCESS            The function completed successfully.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| LoadFormSetConfig (
 | |
|   IN OUT UI_MENU_SELECTION    *Selection,
 | |
|   IN     FORM_BROWSER_FORMSET *FormSet
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS            Status;
 | |
|   LIST_ENTRY            *Link;
 | |
|   FORM_BROWSER_FORM     *Form;
 | |
| 
 | |
|   Link = GetFirstNode (&FormSet->FormListHead);
 | |
|   while (!IsNull (&FormSet->FormListHead, Link)) {
 | |
|     Form = FORM_BROWSER_FORM_FROM_LINK (Link);
 | |
| 
 | |
|     //
 | |
|     // Initialize local copy of Value for each Form
 | |
|     //
 | |
|     Status = LoadFormConfig (Selection, FormSet, Form);
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       return Status;
 | |
|     }
 | |
| 
 | |
|     Link = GetNextNode (&FormSet->FormListHead, 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->BrowserStorage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {
 | |
|     return EFI_SUCCESS;
 | |
|   }
 | |
| 
 | |
|   if (Storage->BrowserStorage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER) {
 | |
|     Status = gRT->GetVariable (
 | |
|                      Storage->BrowserStorage->Name,
 | |
|                      &Storage->BrowserStorage->Guid,
 | |
|                      NULL,
 | |
|                      (UINTN*)&Storage->BrowserStorage->Size,
 | |
|                      Storage->BrowserStorage->EditBuffer
 | |
|                      );
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   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"&GUID=");
 | |
|   if (StrPtr != NULL) {
 | |
|     *StrPtr = L'\0';
 | |
|   }
 | |
| 
 | |
|   Status = ConfigRespToStorage (Storage->BrowserStorage, Result);
 | |
|   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;
 | |
|   LIST_ENTRY              *Link2;
 | |
|   FORMSET_STORAGE         *Storage;
 | |
|   FORMSET_STORAGE         *StorageSrc;
 | |
|   FORMSET_STORAGE         *OldStorage;
 | |
|   FORM_BROWSER_FORM       *Form;
 | |
|   FORM_BROWSER_FORM       *Form2;
 | |
|   EFI_STATUS              Status;
 | |
| 
 | |
|   //
 | |
|   // Extract default from IFR binary for no storage questions.
 | |
|   //  
 | |
|   ExtractDefault (FormSet, NULL, EFI_HII_DEFAULT_CLASS_STANDARD, FormSetLevel, GetDefaultForNoStorage, NULL, TRUE);
 | |
| 
 | |
|   //
 | |
|   // Request current settings from Configuration Driver
 | |
|   //
 | |
|   Link = GetFirstNode (&FormSet->StorageListHead);
 | |
|   while (!IsNull (&FormSet->StorageListHead, Link)) {
 | |
|     Storage = FORMSET_STORAGE_FROM_LINK (Link);
 | |
| 
 | |
|     OldStorage = NULL;
 | |
|     if (gOldFormSet != NULL) {
 | |
|       //
 | |
|       // Try to find the Storage in backup formset gOldFormSet
 | |
|       //
 | |
|       Link2 = GetFirstNode (&gOldFormSet->StorageListHead);
 | |
|       while (!IsNull (&gOldFormSet->StorageListHead, Link2)) {
 | |
|         StorageSrc = FORMSET_STORAGE_FROM_LINK (Link2);
 | |
| 
 | |
|         if (StorageSrc->VarStoreId == Storage->VarStoreId) {
 | |
|           OldStorage = StorageSrc;
 | |
|           break;
 | |
|         }
 | |
| 
 | |
|         Link2 = GetNextNode (&gOldFormSet->StorageListHead, Link2);
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // Storage is not found in backup formset and current global storage not has other driver used,
 | |
|     // request it from ConfigDriver
 | |
|     //
 | |
|     if (OldStorage == NULL && Storage->BrowserStorage->ReferenceCount == 1) {
 | |
|       Status = LoadStorage (FormSet, Storage);
 | |
| 
 | |
|       if (EFI_ERROR (Status)) {
 | |
|         //
 | |
|         // If get last time changed value failed, extract default from IFR binary
 | |
|         //
 | |
|         ExtractDefault (FormSet, NULL, EFI_HII_DEFAULT_CLASS_STANDARD, FormSetLevel, GetDefaultForStorage, Storage->BrowserStorage, TRUE);
 | |
|         //
 | |
|         // ExtractDefault will set the NV flag to TRUE, so need this function to clean the flag
 | |
|         // in current situation.
 | |
|         //
 | |
|         UpdateNvInfoInForm (FormSet, FALSE);
 | |
|       }
 | |
| 
 | |
|       //
 | |
|       // Now Edit Buffer is filled with default values(lower priority) or current
 | |
|       // settings(higher priority), sychronize it to shadow Buffer
 | |
|       //
 | |
|       SynchronizeStorage (Storage->BrowserStorage, TRUE);
 | |
|     }
 | |
| 
 | |
|     Link = GetNextNode (&FormSet->StorageListHead, Link);
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // If has old formset, get the old nv update status.
 | |
|   //
 | |
|   if (gOldFormSet != NULL) {
 | |
|     Link = GetFirstNode (&FormSet->FormListHead);
 | |
|     while (!IsNull (&FormSet->FormListHead, Link)) {
 | |
|       Form = FORM_BROWSER_FORM_FROM_LINK (Link);
 | |
| 
 | |
|       Link2 = GetFirstNode (&gOldFormSet->FormListHead);
 | |
|       while (!IsNull (&gOldFormSet->FormListHead, Link2)) {
 | |
|         Form2 = FORM_BROWSER_FORM_FROM_LINK (Link2);
 | |
| 
 | |
|         if (Form->FormId == Form2->FormId) {
 | |
|           Form->NvUpdateRequired = Form2->NvUpdateRequired;
 | |
|           break;
 | |
|         }
 | |
| 
 | |
|         Link2 = GetNextNode (&gOldFormSet->FormListHead, Link2);
 | |
|       }
 | |
|       Link = GetNextNode (&FormSet->FormListHead, Link);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Fetch the Ifr binary data of a FormSet.
 | |
| 
 | |
|   @param  Handle                 PackageList Handle
 | |
|   @param  FormSetGuid            On input, GUID or class GUID of a formset. If not
 | |
|                                  specified (NULL or zero GUID), take the first
 | |
|                                  FormSet with class GUID EFI_HII_PLATFORM_SETUP_FORMSET_GUID
 | |
|                                  found in package list.
 | |
|                                  On output, GUID of the formset found(if not NULL).
 | |
|   @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;
 | |
|   UINT32                       PackageListLength;
 | |
|   EFI_HII_PACKAGE_HEADER       PackageHeader;
 | |
|   UINT8                        Index;
 | |
|   UINT8                        NumberOfClassGuid;
 | |
|   BOOLEAN                      ClassGuidMatch;
 | |
|   EFI_GUID                     *ClassGuid;
 | |
|   EFI_GUID                     *ComparingGuid;
 | |
| 
 | |
|   OpCodeData = NULL;
 | |
|   Package = NULL;
 | |
|   ZeroMem (&PackageHeader, sizeof (EFI_HII_PACKAGE_HEADER));
 | |
| 
 | |
|   //
 | |
|   // if FormSetGuid is NULL or zero GUID, return first Setup FormSet in the package list
 | |
|   //
 | |
|   if (FormSetGuid == NULL) {
 | |
|     ComparingGuid = &gZeroGuid;
 | |
|   } else {
 | |
|     ComparingGuid = FormSetGuid;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // 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;
 | |
|   }
 | |
|   ASSERT (HiiPackageList != NULL);
 | |
| 
 | |
|   //
 | |
|   // Get Form package from this HII package List
 | |
|   //
 | |
|   Offset = sizeof (EFI_HII_PACKAGE_LIST_HEADER);
 | |
|   Offset2 = 0;
 | |
|   CopyMem (&PackageListLength, &HiiPackageList->PackageLength, sizeof (UINT32));
 | |
| 
 | |
|   ClassGuidMatch = FALSE;
 | |
|   while (Offset < PackageListLength) {
 | |
|     Package = ((UINT8 *) HiiPackageList) + Offset;
 | |
|     CopyMem (&PackageHeader, Package, sizeof (EFI_HII_PACKAGE_HEADER));
 | |
| 
 | |
|     if (PackageHeader.Type == EFI_HII_PACKAGE_FORMS) {
 | |
|       //
 | |
|       // 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) {
 | |
|           //
 | |
|           // Try to compare against formset GUID
 | |
|           //
 | |
|           if (CompareGuid (FormSetGuid, &gZeroGuid) || 
 | |
|               CompareGuid (ComparingGuid, (EFI_GUID *)(OpCodeData + sizeof (EFI_IFR_OP_HEADER)))) {
 | |
|             break;
 | |
|           }
 | |
| 
 | |
|           if (((EFI_IFR_OP_HEADER *) OpCodeData)->Length > OFFSET_OF (EFI_IFR_FORM_SET, Flags)) {
 | |
|             //
 | |
|             // Try to compare against formset class GUID
 | |
|             //
 | |
|             NumberOfClassGuid = (UINT8) (((EFI_IFR_FORM_SET *) OpCodeData)->Flags & 0x3);
 | |
|             ClassGuid         = (EFI_GUID *) (OpCodeData + sizeof (EFI_IFR_FORM_SET));
 | |
|             for (Index = 0; Index < NumberOfClassGuid; Index++) {
 | |
|               if (CompareGuid (ComparingGuid, ClassGuid + Index)) {
 | |
|                 ClassGuidMatch = TRUE;
 | |
|                 break;
 | |
|               }
 | |
|             }
 | |
|             if (ClassGuidMatch) {
 | |
|               break;
 | |
|             }
 | |
|           } else if (ComparingGuid == &gEfiHiiPlatformSetupFormsetGuid) {
 | |
|             ClassGuidMatch = TRUE;
 | |
|             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
 | |
|     //
 | |
|     FreePool (HiiPackageList);
 | |
|     return EFI_NOT_FOUND;
 | |
|   }
 | |
| 
 | |
|   if (FormSetGuid != NULL) {
 | |
|     //
 | |
|     // Return the 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);
 | |
| 
 | |
|   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            On input, GUID or class GUID of a formset. If not
 | |
|                                  specified (NULL or zero GUID), take the first
 | |
|                                  FormSet with class GUID EFI_HII_PLATFORM_SETUP_FORMSET_GUID
 | |
|                                  found in package list.
 | |
|                                  On output, GUID of the formset found(if not NULL).
 | |
|   @param  FormSet                FormSet data structure.
 | |
|   @param  UpdateGlobalVar        Whether need to update the global variable.
 | |
| 
 | |
|   @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,
 | |
|   IN  BOOLEAN                          UpdateGlobalVar                   
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                Status;
 | |
|   EFI_HANDLE                DriverHandle;
 | |
|   UINT16                    Index;
 | |
| 
 | |
|   Status = GetIfrBinaryData (Handle, FormSetGuid, &FormSet->IfrBinaryLength, &FormSet->IfrBinaryData);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   FormSet->Signature = FORM_BROWSER_FORMSET_SIGNATURE;
 | |
|   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;
 | |
|   }
 | |
| 
 | |
|   // 
 | |
|   // If not need to update the global variable, just return.
 | |
|   //
 | |
|   if (!UpdateGlobalVar) {
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Set VFR type by FormSet SubClass field
 | |
|   //
 | |
|   gClassOfVfr = FORMSET_CLASS_PLATFORM_SETUP;
 | |
|   if (FormSet->SubClass == EFI_FRONT_PAGE_SUBCLASS) {
 | |
|     gClassOfVfr = FORMSET_CLASS_FRONT_PAGE;
 | |
|   }
 | |
|   
 | |
|   //
 | |
|   // Set VFR type by FormSet class guid
 | |
|   //
 | |
|   for (Index = 0; Index < 3; Index ++) {
 | |
|     if (CompareGuid (&FormSet->ClassGuid[Index], &gEfiHiiPlatformSetupFormsetGuid)) {
 | |
|       gClassOfVfr |= FORMSET_CLASS_PLATFORM_SETUP;
 | |
|       break;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   gFunctionKeySetting = ENABLE_FUNCTION_KEY_SETTING;
 | |
| 
 | |
|   if ((gClassOfVfr & FORMSET_CLASS_FRONT_PAGE) == FORMSET_CLASS_FRONT_PAGE) {
 | |
|     gFrontPageHandle = FormSet->HiiHandle;
 | |
|     gFunctionKeySetting = NONE_FUNCTION_KEY_SETTING;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // 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;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Save globals used by previous call to SendForm(). SendForm() may be called from 
 | |
|   HiiConfigAccess.Callback(), this will cause SendForm() be reentried.
 | |
|   So, save globals of previous call to SendForm() and restore them upon exit.
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| SaveBrowserContext (
 | |
|   VOID
 | |
|   )
 | |
| {
 | |
|   BROWSER_CONTEXT  *Context;
 | |
| 
 | |
|   gBrowserContextCount++;
 | |
|   if (gBrowserContextCount == 1) {
 | |
|     //
 | |
|     // This is not reentry of SendForm(), no context to save
 | |
|     //
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   Context = AllocatePool (sizeof (BROWSER_CONTEXT));
 | |
|   ASSERT (Context != NULL);
 | |
| 
 | |
|   Context->Signature = BROWSER_CONTEXT_SIGNATURE;
 | |
| 
 | |
|   //
 | |
|   // Save FormBrowser context
 | |
|   //
 | |
|   Context->BannerData           = gBannerData;
 | |
|   Context->ClassOfVfr           = gClassOfVfr;
 | |
|   Context->FunctionKeySetting   = gFunctionKeySetting;
 | |
|   Context->ResetRequired        = gResetRequired;
 | |
|   Context->Direction            = gDirection;
 | |
|   Context->EnterString          = gEnterString;
 | |
|   Context->EnterCommitString    = gEnterCommitString;
 | |
|   Context->EnterEscapeString    = gEnterEscapeString;
 | |
|   Context->EscapeString         = gEscapeString;
 | |
|   Context->MoveHighlight        = gMoveHighlight;
 | |
|   Context->MakeSelection        = gMakeSelection;
 | |
|   Context->DecNumericInput      = gDecNumericInput;
 | |
|   Context->HexNumericInput      = gHexNumericInput;
 | |
|   Context->ToggleCheckBox       = gToggleCheckBox;
 | |
|   Context->PromptForData        = gPromptForData;
 | |
|   Context->PromptForPassword    = gPromptForPassword;
 | |
|   Context->PromptForNewPassword = gPromptForNewPassword;
 | |
|   Context->ConfirmPassword      = gConfirmPassword;
 | |
|   Context->ConfirmError         = gConfirmError;
 | |
|   Context->PassowordInvalid     = gPassowordInvalid;
 | |
|   Context->PressEnter           = gPressEnter;
 | |
|   Context->EmptyString          = gEmptyString;
 | |
|   Context->AreYouSure           = gAreYouSure;
 | |
|   Context->YesResponse          = gYesResponse;
 | |
|   Context->NoResponse           = gNoResponse;
 | |
|   Context->MiniString           = gMiniString;
 | |
|   Context->PlusString           = gPlusString;
 | |
|   Context->MinusString          = gMinusString;
 | |
|   Context->AdjustNumber         = gAdjustNumber;
 | |
|   Context->SaveChanges          = gSaveChanges;
 | |
|   Context->OptionMismatch       = gOptionMismatch;
 | |
|   Context->FormSuppress         = gFormSuppress;
 | |
|   Context->PromptBlockWidth     = gPromptBlockWidth;
 | |
|   Context->OptionBlockWidth     = gOptionBlockWidth;
 | |
|   Context->HelpBlockWidth       = gHelpBlockWidth;
 | |
|   Context->OldFormSet           = gOldFormSet;
 | |
|   Context->MenuRefreshHead      = gMenuRefreshHead;
 | |
|   Context->ProtocolNotFound     = gProtocolNotFound;
 | |
| 
 | |
|   CopyMem (&Context->ScreenDimensions, &gScreenDimensions, sizeof (gScreenDimensions));
 | |
|   CopyMem (&Context->MenuOption, &gMenuOption, sizeof (gMenuOption));
 | |
| 
 | |
|   //
 | |
|   // Insert to FormBrowser context list
 | |
|   //
 | |
|   InsertHeadList (&gBrowserContextList, &Context->Link);
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Restore globals used by previous call to SendForm().
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| RestoreBrowserContext (
 | |
|   VOID
 | |
|   )
 | |
| {
 | |
|   LIST_ENTRY       *Link;
 | |
|   BROWSER_CONTEXT  *Context;
 | |
| 
 | |
|   ASSERT (gBrowserContextCount != 0);
 | |
|   gBrowserContextCount--;
 | |
|   if (gBrowserContextCount == 0) {
 | |
|     //
 | |
|     // This is not reentry of SendForm(), no context to restore
 | |
|     //
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   ASSERT (!IsListEmpty (&gBrowserContextList));
 | |
| 
 | |
|   Link = GetFirstNode (&gBrowserContextList);
 | |
|   Context = BROWSER_CONTEXT_FROM_LINK (Link);
 | |
| 
 | |
|   //
 | |
|   // Restore FormBrowser context
 | |
|   //
 | |
|   gBannerData           = Context->BannerData;
 | |
|   gClassOfVfr           = Context->ClassOfVfr;
 | |
|   gFunctionKeySetting   = Context->FunctionKeySetting;
 | |
|   gResetRequired        = Context->ResetRequired;
 | |
|   gDirection            = Context->Direction;
 | |
|   gEnterString          = Context->EnterString;
 | |
|   gEnterCommitString    = Context->EnterCommitString;
 | |
|   gEnterEscapeString    = Context->EnterEscapeString;
 | |
|   gEscapeString         = Context->EscapeString;
 | |
|   gMoveHighlight        = Context->MoveHighlight;
 | |
|   gMakeSelection        = Context->MakeSelection;
 | |
|   gDecNumericInput      = Context->DecNumericInput;
 | |
|   gHexNumericInput      = Context->HexNumericInput;
 | |
|   gToggleCheckBox       = Context->ToggleCheckBox;
 | |
|   gPromptForData        = Context->PromptForData;
 | |
|   gPromptForPassword    = Context->PromptForPassword;
 | |
|   gPromptForNewPassword = Context->PromptForNewPassword;
 | |
|   gConfirmPassword      = Context->ConfirmPassword;
 | |
|   gConfirmError         = Context->ConfirmError;
 | |
|   gPassowordInvalid     = Context->PassowordInvalid;
 | |
|   gPressEnter           = Context->PressEnter;
 | |
|   gEmptyString          = Context->EmptyString;
 | |
|   gAreYouSure           = Context->AreYouSure;
 | |
|   gYesResponse          = Context->YesResponse;
 | |
|   gNoResponse           = Context->NoResponse;
 | |
|   gMiniString           = Context->MiniString;
 | |
|   gPlusString           = Context->PlusString;
 | |
|   gMinusString          = Context->MinusString;
 | |
|   gAdjustNumber         = Context->AdjustNumber;
 | |
|   gSaveChanges          = Context->SaveChanges;
 | |
|   gOptionMismatch       = Context->OptionMismatch;
 | |
|   gFormSuppress         = Context->FormSuppress;
 | |
|   gPromptBlockWidth     = Context->PromptBlockWidth;
 | |
|   gOptionBlockWidth     = Context->OptionBlockWidth;
 | |
|   gHelpBlockWidth       = Context->HelpBlockWidth;
 | |
|   gOldFormSet           = Context->OldFormSet;
 | |
|   gMenuRefreshHead      = Context->MenuRefreshHead;
 | |
|   gProtocolNotFound     = Context->ProtocolNotFound;
 | |
| 
 | |
|   CopyMem (&gScreenDimensions, &Context->ScreenDimensions, sizeof (gScreenDimensions));
 | |
|   CopyMem (&gMenuOption, &Context->MenuOption, sizeof (gMenuOption));
 | |
| 
 | |
|   //
 | |
|   // Remove from FormBrowser context list
 | |
|   //
 | |
|   RemoveEntryList (&Context->Link);
 | |
|   gBS->FreePool (Context);
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Find the matched FormSet context in the backup maintain list based on HiiHandle.
 | |
|   
 | |
|   @param Handle  The Hii Handle.
 | |
|   
 | |
|   @return the found FormSet context. If no found, NULL will return.
 | |
| 
 | |
| **/
 | |
| FORM_BROWSER_FORMSET * 
 | |
| GetFormSetFromHiiHandle (
 | |
|   EFI_HII_HANDLE Handle
 | |
|   )
 | |
| {
 | |
|   LIST_ENTRY           *Link;
 | |
|   FORM_BROWSER_FORMSET *FormSet;
 | |
| 
 | |
|   Link = GetFirstNode (&gBrowserFormSetList);
 | |
|   while (!IsNull (&gBrowserFormSetList, Link)) {
 | |
|     FormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link);
 | |
|     Link = GetNextNode (&gBrowserFormSetList, Link);
 | |
|     if (!ValidateFormSet(FormSet)) {
 | |
|       continue;
 | |
|     }
 | |
|     if (FormSet->HiiHandle == Handle) {
 | |
|       return FormSet;
 | |
|     }
 | |
|   }
 | |
|   
 | |
|   return NULL;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Check whether the input HII handle is the FormSet that is being used.
 | |
|   
 | |
|   @param Handle  The Hii Handle.
 | |
|   
 | |
|   @retval TRUE   HII handle is being used.
 | |
|   @retval FALSE  HII handle is not being used.
 | |
| 
 | |
| **/
 | |
| BOOLEAN
 | |
| IsHiiHandleInBrowserContext (
 | |
|   EFI_HII_HANDLE Handle
 | |
|   )
 | |
| {
 | |
|   LIST_ENTRY       *Link;
 | |
|   BROWSER_CONTEXT  *Context;
 | |
| 
 | |
|   //
 | |
|   // HiiHandle is Current FormSet.
 | |
|   //
 | |
|   if ((gOldFormSet != NULL) && (gOldFormSet->HiiHandle == Handle)) {
 | |
|     return TRUE;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Check whether HiiHandle is in BrowserContext.
 | |
|   //
 | |
|   Link = GetFirstNode (&gBrowserContextList);
 | |
|   while (!IsNull (&gBrowserContextList, Link)) {
 | |
|     Context = BROWSER_CONTEXT_FROM_LINK (Link);
 | |
|     if (Context->OldFormSet->HiiHandle == Handle) {
 | |
|       //
 | |
|       // HiiHandle is in BrowserContext
 | |
|       //
 | |
|       return TRUE;
 | |
|     }
 | |
|     Link = GetNextNode (&gBrowserContextList, Link);
 | |
|   }
 | |
|   
 | |
|   return FALSE;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Find the registered HotKey based on KeyData.
 | |
|   
 | |
|   @param[in] KeyData     A pointer to a buffer that describes the keystroke
 | |
|                          information for the hot key.
 | |
| 
 | |
|   @return The registered HotKey context. If no found, NULL will return.
 | |
| **/
 | |
| BROWSER_HOT_KEY *
 | |
| GetHotKeyFromRegisterList (
 | |
|   IN EFI_INPUT_KEY *KeyData
 | |
|   )
 | |
| {
 | |
|   LIST_ENTRY       *Link;
 | |
|   BROWSER_HOT_KEY  *HotKey;
 | |
| 
 | |
|   Link = GetFirstNode (&gBrowserHotKeyList);
 | |
|   while (!IsNull (&gBrowserHotKeyList, Link)) {
 | |
|     HotKey = BROWSER_HOT_KEY_FROM_LINK (Link);
 | |
|     if (HotKey->KeyData->ScanCode == KeyData->ScanCode) {
 | |
|       return HotKey;
 | |
|     }
 | |
|     Link = GetNextNode (&gBrowserHotKeyList, Link);
 | |
|   }
 | |
|   
 | |
|   return NULL;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Configure what scope the hot key will impact.
 | |
|   All hot keys have the same scope. The mixed hot keys with the different level are not supported.
 | |
|   If no scope is set, the default scope will be FormSet level.
 | |
|   After all registered hot keys are removed, previous Scope can reset to another level.
 | |
|   
 | |
|   @param[in] Scope               Scope level to be set. 
 | |
|   
 | |
|   @retval EFI_SUCCESS            Scope is set correctly.
 | |
|   @retval EFI_INVALID_PARAMETER  Scope is not the valid value specified in BROWSER_SETTING_SCOPE. 
 | |
|   @retval EFI_UNSPPORTED         Scope level is different from current one that the registered hot keys have.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| SetScope (
 | |
|   IN BROWSER_SETTING_SCOPE Scope
 | |
|   )
 | |
| {
 | |
|   if (Scope >= MaxLevel) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
|   
 | |
|   //
 | |
|   // When no hot key registered in system or on the first setting,
 | |
|   // Scope can be set.
 | |
|   //
 | |
|   if (mBrowserScopeFirstSet || IsListEmpty (&gBrowserHotKeyList)) {
 | |
|     gBrowserSettingScope  = Scope;
 | |
|     mBrowserScopeFirstSet = FALSE;
 | |
|   } else if (Scope != gBrowserSettingScope) {
 | |
|     return EFI_UNSUPPORTED;
 | |
|   }
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Register the hot key with its browser action, or unregistered the hot key.
 | |
|   Only support hot key that is not printable character (control key, function key, etc.).
 | |
|   If the action value is zero, the hot key will be unregistered if it has been registered.
 | |
|   If the same hot key has been registered, the new action and help string will override the previous ones.
 | |
|   
 | |
|   @param[in] KeyData     A pointer to a buffer that describes the keystroke
 | |
|                          information for the hot key. Its type is EFI_INPUT_KEY to 
 | |
|                          be supported by all ConsoleIn devices.
 | |
|   @param[in] Action      Action value that describes what action will be trigged when the hot key is pressed. 
 | |
|   @param[in] DefaultId   Specifies the type of defaults to retrieve, which is only for DEFAULT action.
 | |
|   @param[in] HelpString  Help string that describes the hot key information.
 | |
|                          Its value may be NULL for the unregistered hot key.
 | |
|   
 | |
|   @retval EFI_SUCCESS            Hot key is registered or unregistered.
 | |
|   @retval EFI_INVALID_PARAMETER  KeyData is NULL or HelpString is NULL on register.
 | |
|   @retval EFI_NOT_FOUND          KeyData is not found to be unregistered.
 | |
|   @retval EFI_UNSUPPORTED        Key represents a printable character. It is conflicted with Browser.
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| RegisterHotKey (
 | |
|   IN EFI_INPUT_KEY *KeyData,
 | |
|   IN UINT32        Action,
 | |
|   IN UINT16        DefaultId,
 | |
|   IN EFI_STRING    HelpString OPTIONAL
 | |
|   )
 | |
| {
 | |
|   BROWSER_HOT_KEY  *HotKey;
 | |
| 
 | |
|   //
 | |
|   // Check input parameters.
 | |
|   //
 | |
|   if (KeyData == NULL || KeyData->UnicodeChar != CHAR_NULL || 
 | |
|      (Action != BROWSER_ACTION_UNREGISTER && HelpString == NULL)) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Check whether the input KeyData is in BrowserHotKeyList.
 | |
|   //
 | |
|   HotKey = GetHotKeyFromRegisterList (KeyData);
 | |
|   
 | |
|   //
 | |
|   // Unregister HotKey
 | |
|   //
 | |
|   if (Action == BROWSER_ACTION_UNREGISTER) {
 | |
|     if (HotKey != NULL) {
 | |
|       //
 | |
|       // The registered HotKey is found.  
 | |
|       // Remove it from List, and free its resource.
 | |
|       //
 | |
|       RemoveEntryList (&HotKey->Link);
 | |
|       FreePool (HotKey->KeyData);
 | |
|       FreePool (HotKey->HelpString);
 | |
|       return EFI_SUCCESS;
 | |
|     } else {
 | |
|       //
 | |
|       // The registered HotKey is not found. 
 | |
|       //
 | |
|       return EFI_NOT_FOUND;
 | |
|     }
 | |
|   }
 | |
|   
 | |
|   //
 | |
|   // Register HotKey into List.
 | |
|   //
 | |
|   if (HotKey == NULL) {
 | |
|     //
 | |
|     // Create new Key, and add it into List.
 | |
|     //
 | |
|     HotKey = AllocateZeroPool (sizeof (BROWSER_HOT_KEY));
 | |
|     ASSERT (HotKey != NULL);
 | |
|     HotKey->Signature = BROWSER_HOT_KEY_SIGNATURE;
 | |
|     HotKey->KeyData   = AllocateCopyPool (sizeof (EFI_INPUT_KEY), KeyData);
 | |
|     InsertTailList (&gBrowserHotKeyList, &HotKey->Link);
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Fill HotKey information.
 | |
|   //
 | |
|   HotKey->Action     = Action;
 | |
|   HotKey->DefaultId  = DefaultId;
 | |
|   if (HotKey->HelpString != NULL) {
 | |
|     FreePool (HotKey->HelpString);
 | |
|   }
 | |
|   HotKey->HelpString = AllocateCopyPool (StrSize (HelpString), HelpString);
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Register Exit handler function. 
 | |
|   When more than one handler function is registered, the latter one will override the previous one. 
 | |
|   When NULL handler is specified, the previous Exit handler will be unregistered. 
 | |
|   
 | |
|   @param[in] Handler      Pointer to handler function. 
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| EFIAPI
 | |
| RegiserExitHandler (
 | |
|   IN EXIT_HANDLER Handler
 | |
|   )
 | |
| {
 | |
|   ExitHandlerFunction = Handler;
 | |
|   return;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Create reminder to let user to choose save or discard the changed browser data.
 | |
|   Caller can use it to actively check the changed browser data.
 | |
| 
 | |
|   @retval BROWSER_NO_CHANGES       No browser data is changed.
 | |
|   @retval BROWSER_SAVE_CHANGES     The changed browser data is saved.
 | |
|   @retval BROWSER_DISCARD_CHANGES  The changed browser data is discard.
 | |
| 
 | |
| **/
 | |
| UINT32
 | |
| EFIAPI
 | |
| SaveReminder (
 | |
|   VOID
 | |
|   )
 | |
| {
 | |
|   LIST_ENTRY              *Link;
 | |
|   FORM_BROWSER_FORMSET    *FormSet;
 | |
|   BOOLEAN                 IsDataChanged;
 | |
|   UINT32                  DataSavedAction;
 | |
|   CHAR16                  *YesResponse;
 | |
|   CHAR16                  *NoResponse;
 | |
|   CHAR16                  *EmptyString;
 | |
|   CHAR16                  *ChangeReminderString;
 | |
|   CHAR16                  *SaveConfirmString;
 | |
|   EFI_INPUT_KEY           Key;
 | |
| 
 | |
|   DataSavedAction  = BROWSER_NO_CHANGES;
 | |
|   IsDataChanged    = FALSE;
 | |
|   Link = GetFirstNode (&gBrowserFormSetList);
 | |
|   while (!IsNull (&gBrowserFormSetList, Link)) {
 | |
|     FormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link);
 | |
|     Link = GetNextNode (&gBrowserFormSetList, Link);
 | |
|     if (!ValidateFormSet(FormSet)) {
 | |
|       continue;
 | |
|     }
 | |
|     if (IsNvUpdateRequired (FormSet)) {
 | |
|       IsDataChanged = TRUE;
 | |
|       break;
 | |
|     }
 | |
|   }
 | |
|   
 | |
|   //
 | |
|   // No data is changed. No save is required. 
 | |
|   //
 | |
|   if (!IsDataChanged) {
 | |
|     return DataSavedAction;
 | |
|   }
 | |
|   
 | |
|   //
 | |
|   // If data is changed, prompt user
 | |
|   //
 | |
|   gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
 | |
| 
 | |
|   YesResponse          = GetToken (STRING_TOKEN (ARE_YOU_SURE_YES), gHiiHandle);
 | |
|   ASSERT (YesResponse != NULL);
 | |
|   NoResponse           = GetToken (STRING_TOKEN (ARE_YOU_SURE_NO), gHiiHandle);
 | |
|   ASSERT (NoResponse  != NULL);
 | |
|   EmptyString          = GetToken (STRING_TOKEN (EMPTY_STRING), gHiiHandle);
 | |
|   ChangeReminderString = GetToken (STRING_TOKEN (CHANGE_REMINDER), gHiiHandle);
 | |
|   SaveConfirmString    = GetToken (STRING_TOKEN (SAVE_CONFIRM), gHiiHandle);
 | |
| 
 | |
|   do {
 | |
|     CreateDialog (4, TRUE, 0, NULL, &Key, EmptyString, ChangeReminderString, SaveConfirmString, EmptyString);
 | |
|   } while
 | |
|   (((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) != (NoResponse[0] | UPPER_LOWER_CASE_OFFSET)) &&
 | |
|    ((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) != (YesResponse[0] | UPPER_LOWER_CASE_OFFSET))
 | |
|   );
 | |
| 
 | |
|   //
 | |
|   // If the user hits the YesResponse key
 | |
|   //
 | |
|   if ((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) == (YesResponse[0] | UPPER_LOWER_CASE_OFFSET)) {
 | |
|     SubmitForm (NULL, NULL, SystemLevel);
 | |
|     DataSavedAction = BROWSER_SAVE_CHANGES;
 | |
|   } else {
 | |
|     DiscardForm (NULL, NULL, SystemLevel);
 | |
|     DataSavedAction = BROWSER_DISCARD_CHANGES;
 | |
|     gResetRequired  = FALSE;
 | |
|   }
 | |
| 
 | |
|   FreePool (YesResponse);
 | |
|   FreePool (NoResponse);
 | |
|   FreePool (EmptyString);
 | |
|   FreePool (SaveConfirmString);
 | |
|   FreePool (ChangeReminderString);
 | |
| 
 | |
|   return DataSavedAction;
 | |
| }
 |