| /** @file | |
| Entry and initialization module for the browser. | |
| Copyright (c) 2007 - 2016, 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 | |
| }, | |
| { | |
| BROWSER_EXTENSION2_VERSION_1_1, | |
| SetScope, | |
| RegisterHotKey, | |
| RegiserExitHandler, | |
| IsBrowserDataModified, | |
| ExecuteAction, | |
| {NULL,NULL}, | |
| {NULL,NULL}, | |
| IsResetRequired | |
| } | |
| }; | |
| EFI_HII_DATABASE_PROTOCOL *mHiiDatabase; | |
| EFI_HII_CONFIG_ROUTING_PROTOCOL *mHiiConfigRouting; | |
| EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL *mPathFromText; | |
| EDKII_FORM_DISPLAY_ENGINE_PROTOCOL *mFormDisplay; | |
| 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); | |
| LIST_ENTRY gBrowserSaveFailFormSetList = INITIALIZE_LIST_HEAD_VARIABLE (gBrowserSaveFailFormSetList); | |
| BOOLEAN mSystemSubmit = FALSE; | |
| BOOLEAN gResetRequired; | |
| BOOLEAN gExitRequired; | |
| BOOLEAN gFlagReconnect; | |
| BOOLEAN gCallbackReconnect; | |
| BROWSER_SETTING_SCOPE gBrowserSettingScope = FormSetLevel; | |
| BOOLEAN mBrowserScopeFirstSet = TRUE; | |
| EXIT_HANDLER ExitHandlerFunction = NULL; | |
| FORM_BROWSER_FORMSET *mSystemLevelFormSet; | |
| // | |
| // Browser Global Strings | |
| // | |
| CHAR16 *gEmptyString; | |
| CHAR16 *mUnknownString = L"!"; | |
| extern EFI_GUID mCurrentFormSetGuid; | |
| extern EFI_HII_HANDLE mCurrentHiiHandle; | |
| extern UINT16 mCurrentFormId; | |
| extern FORM_DISPLAY_ENGINE_FORM gDisplayFormData; | |
| /** | |
| Create a menu with specified formset GUID and form ID, and add it as a child | |
| of the given parent menu. | |
| @param HiiHandle Hii handle related to this formset. | |
| @param FormSetGuid The Formset Guid of menu to be added. | |
| @param FormId The Form ID of menu to be added. | |
| @param QuestionId The question id of this menu to be added. | |
| @return A pointer to the newly added menu or NULL if memory is insufficient. | |
| **/ | |
| FORM_ENTRY_INFO * | |
| UiAddMenuList ( | |
| IN EFI_HII_HANDLE HiiHandle, | |
| IN EFI_GUID *FormSetGuid, | |
| IN UINT16 FormId, | |
| IN UINT16 QuestionId | |
| ) | |
| { | |
| FORM_ENTRY_INFO *MenuList; | |
| MenuList = AllocateZeroPool (sizeof (FORM_ENTRY_INFO)); | |
| if (MenuList == NULL) { | |
| return NULL; | |
| } | |
| MenuList->Signature = FORM_ENTRY_INFO_SIGNATURE; | |
| MenuList->HiiHandle = HiiHandle; | |
| CopyMem (&MenuList->FormSetGuid, FormSetGuid, sizeof (EFI_GUID)); | |
| MenuList->FormId = FormId; | |
| MenuList->QuestionId = QuestionId; | |
| // | |
| // If parent is not specified, it is the root Form of a Formset | |
| // | |
| InsertTailList (&mPrivateData.FormBrowserEx2.FormViewHistoryHead, &MenuList->Link); | |
| return MenuList; | |
| } | |
| /** | |
| Return the form id for the input hiihandle and formset. | |
| @param HiiHandle HiiHandle for FormSet. | |
| @param FormSetGuid The Formset GUID of the menu to search. | |
| @return First form's id for this form set. | |
| **/ | |
| EFI_FORM_ID | |
| GetFirstFormId ( | |
| IN EFI_HII_HANDLE HiiHandle, | |
| IN EFI_GUID *FormSetGuid | |
| ) | |
| { | |
| LIST_ENTRY *Link; | |
| FORM_BROWSER_FORM *Form; | |
| Link = GetFirstNode (&gCurrentSelection->FormSet->FormListHead); | |
| Form = FORM_BROWSER_FORM_FROM_LINK (Link); | |
| return Form->FormId; | |
| } | |
| /** | |
| Search Menu with given FormSetGuid and FormId in all cached menu list. | |
| @param HiiHandle HiiHandle for FormSet. | |
| @param FormSetGuid The Formset GUID of the menu to search. | |
| @param FormId The Form ID of menu to search. | |
| @return A pointer to menu found or NULL if not found. | |
| **/ | |
| FORM_ENTRY_INFO * | |
| UiFindMenuList ( | |
| IN EFI_HII_HANDLE HiiHandle, | |
| IN EFI_GUID *FormSetGuid, | |
| IN UINT16 FormId | |
| ) | |
| { | |
| LIST_ENTRY *Link; | |
| FORM_ENTRY_INFO *MenuList; | |
| FORM_ENTRY_INFO *RetMenu; | |
| EFI_FORM_ID FirstFormId; | |
| RetMenu = NULL; | |
| Link = GetFirstNode (&mPrivateData.FormBrowserEx2.FormViewHistoryHead); | |
| while (!IsNull (&mPrivateData.FormBrowserEx2.FormViewHistoryHead, Link)) { | |
| MenuList = FORM_ENTRY_INFO_FROM_LINK (Link); | |
| Link = GetNextNode (&mPrivateData.FormBrowserEx2.FormViewHistoryHead, Link); | |
| // | |
| // If already find the menu, free the menus behind it. | |
| // | |
| if (RetMenu != NULL) { | |
| RemoveEntryList (&MenuList->Link); | |
| FreePool (MenuList); | |
| continue; | |
| } | |
| // | |
| // Find the same FromSet. | |
| // | |
| if (MenuList->HiiHandle == HiiHandle) { | |
| if (CompareGuid (&MenuList->FormSetGuid, &gZeroGuid)) { | |
| // | |
| // FormSetGuid is not specified. | |
| // | |
| RetMenu = MenuList; | |
| } else if (CompareGuid (&MenuList->FormSetGuid, FormSetGuid)) { | |
| if (MenuList->FormId == FormId) { | |
| RetMenu = MenuList; | |
| } else if (FormId == 0 || MenuList->FormId == 0 ) { | |
| FirstFormId = GetFirstFormId (HiiHandle, FormSetGuid); | |
| if ((FormId == 0 && FirstFormId == MenuList->FormId) || (MenuList->FormId ==0 && FirstFormId == FormId)) { | |
| RetMenu = MenuList; | |
| } | |
| } | |
| } | |
| } | |
| } | |
| return RetMenu; | |
| } | |
| /** | |
| Find parent menu for current menu. | |
| @param CurrentMenu Current Menu | |
| @param SettingLevel Whether find parent menu in Form Level or Formset level. | |
| In form level, just find the parent menu; | |
| In formset level, find the parent menu which has different | |
| formset guid value. | |
| @retval The parent menu for current menu. | |
| **/ | |
| FORM_ENTRY_INFO * | |
| UiFindParentMenu ( | |
| IN FORM_ENTRY_INFO *CurrentMenu, | |
| IN BROWSER_SETTING_SCOPE SettingLevel | |
| ) | |
| { | |
| FORM_ENTRY_INFO *ParentMenu; | |
| LIST_ENTRY *Link; | |
| ASSERT (SettingLevel == FormLevel || SettingLevel == FormSetLevel); | |
| if (CurrentMenu == NULL) { | |
| return NULL; | |
| } | |
| ParentMenu = NULL; | |
| Link = &CurrentMenu->Link; | |
| while (Link->BackLink != &mPrivateData.FormBrowserEx2.FormViewHistoryHead) { | |
| ParentMenu = FORM_ENTRY_INFO_FROM_LINK (Link->BackLink); | |
| if (SettingLevel == FormLevel) { | |
| // | |
| // For FormLevel, just find the parent menu, return. | |
| // | |
| break; | |
| } | |
| if (!CompareGuid (&CurrentMenu->FormSetGuid, &ParentMenu->FormSetGuid)) { | |
| // | |
| // For SystemLevel, must find the menu which has different formset. | |
| // | |
| break; | |
| } | |
| Link = Link->BackLink; | |
| } | |
| // | |
| // Not find the parent menu, just return NULL. | |
| // | |
| if (Link->BackLink == &mPrivateData.FormBrowserEx2.FormViewHistoryHead) { | |
| return NULL; | |
| } | |
| return ParentMenu; | |
| } | |
| /** | |
| Free Menu list linked list. | |
| @param MenuListHead One Menu list point in the menu list. | |
| **/ | |
| VOID | |
| UiFreeMenuList ( | |
| LIST_ENTRY *MenuListHead | |
| ) | |
| { | |
| FORM_ENTRY_INFO *MenuList; | |
| while (!IsListEmpty (MenuListHead)) { | |
| MenuList = FORM_ENTRY_INFO_FROM_LINK (MenuListHead->ForwardLink); | |
| RemoveEntryList (&MenuList->Link); | |
| FreePool (MenuList); | |
| } | |
| } | |
| /** | |
| Copy current Menu list to the new menu list. | |
| @param NewMenuListHead New create Menu list. | |
| @param CurrentMenuListHead Current Menu list. | |
| **/ | |
| VOID | |
| UiCopyMenuList ( | |
| OUT LIST_ENTRY *NewMenuListHead, | |
| IN LIST_ENTRY *CurrentMenuListHead | |
| ) | |
| { | |
| LIST_ENTRY *Link; | |
| FORM_ENTRY_INFO *MenuList; | |
| FORM_ENTRY_INFO *NewMenuEntry; | |
| // | |
| // If new menu list not empty, free it first. | |
| // | |
| UiFreeMenuList (NewMenuListHead); | |
| Link = GetFirstNode (CurrentMenuListHead); | |
| while (!IsNull (CurrentMenuListHead, Link)) { | |
| MenuList = FORM_ENTRY_INFO_FROM_LINK (Link); | |
| Link = GetNextNode (CurrentMenuListHead, Link); | |
| NewMenuEntry = AllocateZeroPool (sizeof (FORM_ENTRY_INFO)); | |
| ASSERT (NewMenuEntry != NULL); | |
| NewMenuEntry->Signature = FORM_ENTRY_INFO_SIGNATURE; | |
| NewMenuEntry->HiiHandle = MenuList->HiiHandle; | |
| CopyMem (&NewMenuEntry->FormSetGuid, &MenuList->FormSetGuid, sizeof (EFI_GUID)); | |
| NewMenuEntry->FormId = MenuList->FormId; | |
| NewMenuEntry->QuestionId = MenuList->QuestionId; | |
| InsertTailList (NewMenuListHead, &NewMenuEntry->Link); | |
| } | |
| } | |
| /** | |
| Load all hii formset to the browser. | |
| **/ | |
| VOID | |
| LoadAllHiiFormset ( | |
| VOID | |
| ) | |
| { | |
| FORM_BROWSER_FORMSET *LocalFormSet; | |
| EFI_HII_HANDLE *HiiHandles; | |
| UINTN Index; | |
| EFI_GUID ZeroGuid; | |
| EFI_STATUS Status; | |
| FORM_BROWSER_FORMSET *OldFormset; | |
| OldFormset = mSystemLevelFormSet; | |
| // | |
| // 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); | |
| mSystemLevelFormSet = LocalFormSet; | |
| ZeroMem (&ZeroGuid, sizeof (ZeroGuid)); | |
| Status = InitializeFormSet (HiiHandles[Index], &ZeroGuid, LocalFormSet); | |
| if (EFI_ERROR (Status) || IsListEmpty (&LocalFormSet->FormListHead)) { | |
| DestroyFormSet (LocalFormSet); | |
| continue; | |
| } | |
| InitializeCurrentSetting (LocalFormSet); | |
| // | |
| // Initilize Questions' Value | |
| // | |
| Status = LoadFormSetConfig (NULL, LocalFormSet); | |
| if (EFI_ERROR (Status)) { | |
| DestroyFormSet (LocalFormSet); | |
| continue; | |
| } | |
| } | |
| // | |
| // Free resources, and restore gOldFormSet and gClassOfVfr | |
| // | |
| FreePool (HiiHandles); | |
| mSystemLevelFormSet = OldFormset; | |
| } | |
| /** | |
| Pop up the error info. | |
| @param BrowserStatus The input browser status. | |
| @param HiiHandle The Hiihandle for this opcode. | |
| @param OpCode The opcode use to get the erro info and timeout value. | |
| @param ErrorString Error string used by BROWSER_NO_SUBMIT_IF. | |
| **/ | |
| UINT32 | |
| PopupErrorMessage ( | |
| IN UINT32 BrowserStatus, | |
| IN EFI_HII_HANDLE HiiHandle, | |
| IN EFI_IFR_OP_HEADER *OpCode, OPTIONAL | |
| IN CHAR16 *ErrorString | |
| ) | |
| { | |
| FORM_DISPLAY_ENGINE_STATEMENT *Statement; | |
| USER_INPUT UserInputData; | |
| Statement = NULL; | |
| if (OpCode != NULL) { | |
| Statement = AllocateZeroPool (sizeof(FORM_DISPLAY_ENGINE_STATEMENT)); | |
| ASSERT (Statement != NULL); | |
| Statement->OpCode = OpCode; | |
| gDisplayFormData.HighLightedStatement = Statement; | |
| } | |
| // | |
| // Used to compatible with old display engine. | |
| // New display engine not use this field. | |
| // | |
| gDisplayFormData.ErrorString = ErrorString; | |
| gDisplayFormData.BrowserStatus = BrowserStatus; | |
| if (HiiHandle != NULL) { | |
| gDisplayFormData.HiiHandle = HiiHandle; | |
| } | |
| mFormDisplay->FormDisplay (&gDisplayFormData, &UserInputData); | |
| gDisplayFormData.BrowserStatus = BROWSER_SUCCESS; | |
| gDisplayFormData.ErrorString = NULL; | |
| if (OpCode != NULL) { | |
| FreePool (Statement); | |
| } | |
| return UserInputData.Action; | |
| } | |
| /** | |
| 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; | |
| FORM_ENTRY_INFO *MenuList; | |
| BOOLEAN RetVal; | |
| // | |
| // If EDKII_FORM_DISPLAY_ENGINE_PROTOCOL not found, return EFI_UNSUPPORTED. | |
| // | |
| if (mFormDisplay == NULL) { | |
| DEBUG ((DEBUG_ERROR, "Fatal Error! EDKII_FORM_DISPLAY_ENGINE_PROTOCOL not found!")); | |
| return EFI_UNSUPPORTED; | |
| } | |
| // | |
| // Save globals used by SendForm() | |
| // | |
| SaveBrowserContext (); | |
| gFlagReconnect = FALSE; | |
| gResetRequired = FALSE; | |
| gExitRequired = FALSE; | |
| gCallbackReconnect = FALSE; | |
| Status = EFI_SUCCESS; | |
| gEmptyString = L""; | |
| gDisplayFormData.ScreenDimensions = (EFI_SCREEN_DESCRIPTOR *) ScreenDimensions; | |
| 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); | |
| // | |
| // Validate the HiiHandle | |
| // if validate failed, find the first validate parent HiiHandle. | |
| // | |
| if (!ValidateHiiHandle(Selection->Handle)) { | |
| FindNextMenu (Selection, FormSetLevel); | |
| } | |
| // | |
| // Initialize internal data structures of FormSet | |
| // | |
| Status = InitializeFormSet (Selection->Handle, &Selection->FormSetGuid, FormSet); | |
| if (EFI_ERROR (Status) || IsListEmpty (&FormSet->FormListHead)) { | |
| DestroyFormSet (FormSet); | |
| break; | |
| } | |
| Selection->FormSet = FormSet; | |
| mSystemLevelFormSet = FormSet; | |
| // | |
| // Display this formset | |
| // | |
| gCurrentSelection = Selection; | |
| Status = SetupBrowser (Selection); | |
| gCurrentSelection = NULL; | |
| mSystemLevelFormSet = NULL; | |
| if (gFlagReconnect || gCallbackReconnect) { | |
| RetVal = ReconnectController (FormSet->DriverHandle); | |
| if (!RetVal) { | |
| PopupErrorMessage(BROWSER_RECONNECT_FAIL, NULL, NULL, NULL); | |
| } | |
| gFlagReconnect = FALSE; | |
| gCallbackReconnect = FALSE; | |
| } | |
| // | |
| // If no data is changed, don't need to save current FormSet into the maintain list. | |
| // | |
| if (!IsNvUpdateRequiredForFormSet (FormSet)) { | |
| CleanBrowserStorage(FormSet); | |
| RemoveEntryList (&FormSet->Link); | |
| DestroyFormSet (FormSet); | |
| } | |
| if (EFI_ERROR (Status)) { | |
| break; | |
| } | |
| } while (Selection->Action == UI_ACTION_REFRESH_FORMSET); | |
| FreePool (Selection); | |
| } | |
| if (ActionRequest != NULL) { | |
| *ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE; | |
| if (gResetRequired) { | |
| *ActionRequest = EFI_BROWSER_ACTION_REQUEST_RESET; | |
| } | |
| } | |
| mFormDisplay->ExitDisplay(); | |
| // | |
| // Clear the menu history data. | |
| // | |
| while (!IsListEmpty (&mPrivateData.FormBrowserEx2.FormViewHistoryHead)) { | |
| MenuList = FORM_ENTRY_INFO_FROM_LINK (mPrivateData.FormBrowserEx2.FormViewHistoryHead.ForwardLink); | |
| RemoveEntryList (&MenuList->Link); | |
| FreePool (MenuList); | |
| } | |
| // | |
| // Restore globals used by SendForm() | |
| // | |
| RestoreBrowserContext (); | |
| return Status; | |
| } | |
| /** | |
| Get or set data to the storage. | |
| @param ResultsDataSize The size of the buffer associatedwith 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 Storage The pointer to the storage. | |
| @retval EFI_SUCCESS The results have been distributed or are awaiting | |
| distribution. | |
| **/ | |
| EFI_STATUS | |
| ProcessStorage ( | |
| IN OUT UINTN *ResultsDataSize, | |
| IN OUT EFI_STRING *ResultsData, | |
| IN BOOLEAN RetrieveData, | |
| IN BROWSER_STORAGE *Storage | |
| ) | |
| { | |
| CHAR16 *ConfigResp; | |
| EFI_STATUS Status; | |
| CHAR16 *StrPtr; | |
| UINTN BufferSize; | |
| UINTN TmpSize; | |
| UINTN MaxLen; | |
| FORMSET_STORAGE *BrowserStorage; | |
| if (RetrieveData) { | |
| // | |
| // Generate <ConfigResp> | |
| // | |
| Status = StorageToConfigResp (Storage, &ConfigResp, Storage->ConfigRequest, TRUE); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| // | |
| // Skip <ConfigHdr> and '&' to point to <ConfigBody> when first copy the configbody. | |
| // Also need to consider add "\0" at first time. | |
| // | |
| StrPtr = StrStr (ConfigResp, L"PATH"); | |
| ASSERT (StrPtr != NULL); | |
| StrPtr = StrStr (StrPtr, L"&"); | |
| StrPtr += 1; | |
| BufferSize = StrSize (StrPtr); | |
| // | |
| // Copy the data if the input buffer is bigger enough. | |
| // | |
| if (*ResultsDataSize >= BufferSize) { | |
| StrCpyS (*ResultsData, *ResultsDataSize / sizeof (CHAR16), StrPtr); | |
| } | |
| *ResultsDataSize = BufferSize; | |
| FreePool (ConfigResp); | |
| } else { | |
| // | |
| // Prepare <ConfigResp> | |
| // | |
| BrowserStorage = GetFstStgFromBrsStg (Storage); | |
| ASSERT (BrowserStorage != NULL); | |
| TmpSize = StrLen (*ResultsData); | |
| BufferSize = (TmpSize + StrLen (BrowserStorage->ConfigHdr) + 2) * sizeof (CHAR16); | |
| MaxLen = BufferSize / sizeof (CHAR16); | |
| ConfigResp = AllocateZeroPool (BufferSize); | |
| ASSERT (ConfigResp != NULL); | |
| StrCpyS (ConfigResp, MaxLen, BrowserStorage->ConfigHdr); | |
| StrCatS (ConfigResp, MaxLen, L"&"); | |
| StrCatS (ConfigResp, MaxLen, *ResultsData); | |
| // | |
| // Update Browser uncommited data | |
| // | |
| Status = ConfigRespToStorage (Storage, ConfigResp); | |
| FreePool (ConfigResp); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| } | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| This routine called this service in the browser to retrieve or set certain uncommitted | |
| state information that resides in the open formsets. | |
| @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; | |
| BROWSER_STORAGE *Storage; | |
| FORMSET_STORAGE *FormsetStorage; | |
| UINTN TotalSize; | |
| BOOLEAN Found; | |
| if (ResultsDataSize == NULL || ResultsData == NULL) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| TotalSize = *ResultsDataSize; | |
| Storage = NULL; | |
| Found = FALSE; | |
| Status = EFI_SUCCESS; | |
| if (VariableGuid != NULL) { | |
| // | |
| // Try to find target storage in the current formset. | |
| // | |
| Link = GetFirstNode (&gBrowserStorageList); | |
| while (!IsNull (&gBrowserStorageList, Link)) { | |
| Storage = BROWSER_STORAGE_FROM_LINK (Link); | |
| Link = GetNextNode (&gBrowserStorageList, Link); | |
| // | |
| // Check the current storage. | |
| // | |
| if (!CompareGuid (&Storage->Guid, (EFI_GUID *) VariableGuid)) { | |
| continue; | |
| } | |
| if (Storage->Type == EFI_HII_VARSTORE_BUFFER || | |
| Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER) { | |
| // | |
| // Buffer storage require both GUID and Name | |
| // | |
| if (VariableName == NULL) { | |
| return EFI_NOT_FOUND; | |
| } | |
| if (StrCmp (Storage->Name, (CHAR16 *) VariableName) != 0) { | |
| continue; | |
| } | |
| } | |
| if (Storage->Type == EFI_HII_VARSTORE_NAME_VALUE || | |
| Storage->Type == EFI_HII_VARSTORE_BUFFER) { | |
| if (mSystemLevelFormSet == NULL || mSystemLevelFormSet->HiiHandle == NULL) { | |
| return EFI_NOT_FOUND; | |
| } | |
| if (Storage->HiiHandle != mSystemLevelFormSet->HiiHandle) { | |
| continue; | |
| } | |
| } | |
| Status = ProcessStorage (&TotalSize, &ResultsData, RetrieveData, Storage); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER) { | |
| ConfigRequestAdjust (Storage, ResultsData, TRUE); | |
| } | |
| // | |
| // Different formsets may have same varstore, so here just set the flag | |
| // not exit the circle. | |
| // | |
| Found = TRUE; | |
| break; | |
| } | |
| if (!Found) { | |
| return EFI_NOT_FOUND; | |
| } | |
| } else { | |
| // | |
| // GUID/Name is not specified, take the first storage in FormSet | |
| // | |
| if (mSystemLevelFormSet == NULL) { | |
| return EFI_NOT_READY; | |
| } | |
| // | |
| // Generate <ConfigResp> | |
| // | |
| Link = GetFirstNode (&mSystemLevelFormSet->StorageListHead); | |
| if (IsNull (&mSystemLevelFormSet->StorageListHead, Link)) { | |
| return EFI_UNSUPPORTED; | |
| } | |
| FormsetStorage = FORMSET_STORAGE_FROM_LINK (Link); | |
| Status = ProcessStorage (&TotalSize, &ResultsData, RetrieveData, FormsetStorage->BrowserStorage); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| } | |
| if (RetrieveData) { | |
| Status = TotalSize <= *ResultsDataSize ? EFI_SUCCESS : EFI_BUFFER_TOO_SMALL; | |
| *ResultsDataSize = TotalSize; | |
| } | |
| return Status; | |
| } | |
| /** | |
| Callback function for SimpleTextInEx protocol install events | |
| @param Event the event that is signaled. | |
| @param Context not used here. | |
| **/ | |
| VOID | |
| EFIAPI | |
| FormDisplayCallback ( | |
| IN EFI_EVENT Event, | |
| IN VOID *Context | |
| ) | |
| { | |
| if (mFormDisplay != NULL) { | |
| return; | |
| } | |
| gBS->LocateProtocol ( | |
| &gEdkiiFormDisplayEngineProtocolGuid, | |
| NULL, | |
| (VOID **) &mFormDisplay | |
| ); | |
| } | |
| /** | |
| 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; | |
| VOID *Registration; | |
| // | |
| // Locate required Hii relative protocols | |
| // | |
| Status = gBS->LocateProtocol ( | |
| &gEfiHiiDatabaseProtocolGuid, | |
| NULL, | |
| (VOID **) &mHiiDatabase | |
| ); | |
| ASSERT_EFI_ERROR (Status); | |
| Status = gBS->LocateProtocol ( | |
| &gEfiHiiConfigRoutingProtocolGuid, | |
| NULL, | |
| (VOID **) &mHiiConfigRouting | |
| ); | |
| ASSERT_EFI_ERROR (Status); | |
| Status = gBS->LocateProtocol ( | |
| &gEfiDevicePathFromTextProtocolGuid, | |
| NULL, | |
| (VOID **) &mPathFromText | |
| ); | |
| // | |
| // Install FormBrowser2 protocol | |
| // | |
| mPrivateData.Handle = NULL; | |
| Status = gBS->InstallProtocolInterface ( | |
| &mPrivateData.Handle, | |
| &gEfiFormBrowser2ProtocolGuid, | |
| EFI_NATIVE_INTERFACE, | |
| &mPrivateData.FormBrowser2 | |
| ); | |
| ASSERT_EFI_ERROR (Status); | |
| // | |
| // Install FormBrowserEx2 protocol | |
| // | |
| InitializeListHead (&mPrivateData.FormBrowserEx2.FormViewHistoryHead); | |
| InitializeListHead (&mPrivateData.FormBrowserEx2.OverrideQestListHead); | |
| mPrivateData.Handle = NULL; | |
| Status = gBS->InstallProtocolInterface ( | |
| &mPrivateData.Handle, | |
| &gEdkiiFormBrowserEx2ProtocolGuid, | |
| EFI_NATIVE_INTERFACE, | |
| &mPrivateData.FormBrowserEx2 | |
| ); | |
| ASSERT_EFI_ERROR (Status); | |
| Status = gBS->InstallProtocolInterface ( | |
| &mPrivateData.Handle, | |
| &gEfiFormBrowserExProtocolGuid, | |
| EFI_NATIVE_INTERFACE, | |
| &mPrivateData.FormBrowserEx | |
| ); | |
| ASSERT_EFI_ERROR (Status); | |
| InitializeDisplayFormData (); | |
| Status = gBS->LocateProtocol ( | |
| &gEdkiiFormDisplayEngineProtocolGuid, | |
| NULL, | |
| (VOID **) &mFormDisplay | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| EfiCreateProtocolNotifyEvent ( | |
| &gEdkiiFormDisplayEngineProtocolGuid, | |
| TPL_CALLBACK, | |
| FormDisplayCallback, | |
| NULL, | |
| &Registration | |
| ); | |
| } | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| 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 MaxLen; | |
| if (*Dest == NULL) { | |
| NewStringCpy (Dest, Src); | |
| return; | |
| } | |
| MaxLen = ( StrSize (*Dest) + StrSize (Src) - 1) / sizeof (CHAR16); | |
| NewString = AllocateZeroPool (MaxLen * sizeof (CHAR16)); | |
| ASSERT (NewString != NULL); | |
| StrCpyS (NewString, MaxLen, *Dest); | |
| StrCatS (NewString, MaxLen, Src); | |
| FreePool (*Dest); | |
| *Dest = NewString; | |
| } | |
| /** | |
| 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. | |
| @param ReturnNode The node use the input name. | |
| @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, | |
| OUT NAME_VALUE_NODE **ReturnNode | |
| ) | |
| { | |
| 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; | |
| } | |
| if (ReturnNode != NULL) { | |
| *ReturnNode = Node; | |
| } | |
| 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. | |
| @param GetEditBuf Get the data from editbuffer or buffer. | |
| @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, | |
| IN BOOLEAN GetEditBuf | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| EFI_STRING Progress; | |
| LIST_ENTRY *Link; | |
| NAME_VALUE_NODE *Node; | |
| UINT8 *SourceBuf; | |
| FORMSET_STORAGE *FormsetStorage; | |
| Status = EFI_SUCCESS; | |
| switch (Storage->Type) { | |
| case EFI_HII_VARSTORE_BUFFER: | |
| case EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER: | |
| SourceBuf = GetEditBuf ? Storage->EditBuffer : Storage->Buffer; | |
| Status = mHiiConfigRouting->BlockToConfig ( | |
| mHiiConfigRouting, | |
| ConfigRequest, | |
| SourceBuf, | |
| Storage->Size, | |
| ConfigResp, | |
| &Progress | |
| ); | |
| break; | |
| case EFI_HII_VARSTORE_NAME_VALUE: | |
| *ConfigResp = NULL; | |
| FormsetStorage = GetFstStgFromBrsStg(Storage); | |
| ASSERT (FormsetStorage != NULL); | |
| NewStringCat (ConfigResp, FormsetStorage->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"="); | |
| if (GetEditBuf) { | |
| NewStringCat (ConfigResp, Node->EditValue); | |
| } else { | |
| NewStringCat (ConfigResp, Node->Value); | |
| } | |
| } | |
| 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, NULL); | |
| } | |
| break; | |
| case EFI_HII_VARSTORE_EFI_VARIABLE: | |
| default: | |
| Status = EFI_INVALID_PARAMETER; | |
| break; | |
| } | |
| return Status; | |
| } | |
| /** | |
| Convert the buffer value to HiiValue. | |
| @param Question The question. | |
| @param Value Unicode buffer save the question value. | |
| @retval Status whether convert the value success. | |
| **/ | |
| EFI_STATUS | |
| BufferToValue ( | |
| IN OUT FORM_BROWSER_STATEMENT *Question, | |
| IN CHAR16 *Value | |
| ) | |
| { | |
| CHAR16 *StringPtr; | |
| BOOLEAN IsBufferStorage; | |
| CHAR16 *DstBuf; | |
| CHAR16 TempChar; | |
| UINTN LengthStr; | |
| UINT8 *Dst; | |
| CHAR16 TemStr[5]; | |
| UINTN Index; | |
| UINT8 DigitUint8; | |
| BOOLEAN IsString; | |
| UINTN Length; | |
| EFI_STATUS Status; | |
| IsString = (BOOLEAN) ((Question->HiiValue.Type == EFI_IFR_TYPE_STRING) ? TRUE : FALSE); | |
| if (Question->Storage->Type == EFI_HII_VARSTORE_BUFFER || | |
| Question->Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER) { | |
| IsBufferStorage = TRUE; | |
| } else { | |
| IsBufferStorage = FALSE; | |
| } | |
| // | |
| // 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; | |
| } | |
| // | |
| // Temp cut at the end of this section, end with '\0' or '&'. | |
| // | |
| StringPtr = Value; | |
| while (*StringPtr != L'\0' && *StringPtr != L'&') { | |
| StringPtr++; | |
| } | |
| TempChar = *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 = Question->StorageWidth + sizeof (CHAR16); | |
| if (Length < ((LengthStr / 4 + 1) * 2)) { | |
| Status = EFI_BUFFER_TOO_SMALL; | |
| } else { | |
| DstBuf = (CHAR16 *) Dst; | |
| ZeroMem (TemStr, sizeof (TemStr)); | |
| for (Index = 0; Index < LengthStr; Index += 4) { | |
| StrnCpyS (TemStr, sizeof (TemStr) / sizeof (CHAR16), Value + Index, 4); | |
| DstBuf[Index/4] = (CHAR16) StrHexToUint64 (TemStr); | |
| } | |
| // | |
| // Add tailing L'\0' character | |
| // | |
| DstBuf[Index/4] = L'\0'; | |
| } | |
| } else { | |
| if (Question->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]); | |
| } | |
| } | |
| } | |
| } | |
| *StringPtr = TempChar; | |
| 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; | |
| FORMSET_STORAGE *FormsetStorage; | |
| EFI_IFR_TYPE_VALUE *QuestionValue; | |
| CHAR16 *ConfigRequest; | |
| CHAR16 *Progress; | |
| CHAR16 *Result; | |
| CHAR16 *Value; | |
| UINTN Length; | |
| BOOLEAN IsBufferStorage; | |
| UINTN MaxLen; | |
| Status = EFI_SUCCESS; | |
| Value = NULL; | |
| Result = NULL; | |
| if (GetValueFrom >= GetSetValueWithMax) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| // | |
| // 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)) { | |
| if (Question->Operand == EFI_IFR_DATE_OP){ | |
| QuestionValue->date.Year = 0xff; | |
| QuestionValue->date.Month = 0xff; | |
| QuestionValue->date.Day = 0xff; | |
| } else { | |
| QuestionValue->time.Hour = 0xff; | |
| QuestionValue->time.Minute = 0xff; | |
| QuestionValue->time.Second = 0xff; | |
| } | |
| return EFI_SUCCESS; | |
| } | |
| 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; | |
| } | |
| 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); | |
| Status = BufferToValue (Question, Value); | |
| FreePool (Value); | |
| } | |
| } else { | |
| FormsetStorage = GetFstStgFromVarId(FormSet, Question->VarStoreId); | |
| ASSERT (FormsetStorage != NULL); | |
| // | |
| // <ConfigRequest> ::= <ConfigHdr> + <BlockName> || | |
| // <ConfigHdr> + "&" + <VariableName> | |
| // | |
| if (IsBufferStorage) { | |
| Length = StrLen (FormsetStorage->ConfigHdr); | |
| Length += StrLen (Question->BlockName); | |
| } else { | |
| Length = StrLen (FormsetStorage->ConfigHdr); | |
| Length += StrLen (Question->VariableName) + 1; | |
| } | |
| // Allocate buffer include '\0' | |
| MaxLen = Length + 1; | |
| ConfigRequest = AllocateZeroPool (MaxLen * sizeof (CHAR16)); | |
| ASSERT (ConfigRequest != NULL); | |
| StrCpyS (ConfigRequest, MaxLen, FormsetStorage->ConfigHdr); | |
| if (IsBufferStorage) { | |
| StrCatS (ConfigRequest, MaxLen, Question->BlockName); | |
| } else { | |
| StrCatS (ConfigRequest, MaxLen, L"&"); | |
| StrCatS (ConfigRequest, MaxLen, Question->VariableName); | |
| } | |
| // | |
| // Request current settings from Configuration Driver | |
| // | |
| Status = mHiiConfigRouting->ExtractConfig ( | |
| mHiiConfigRouting, | |
| 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; | |
| Status = BufferToValue (Question, Value); | |
| if (EFI_ERROR (Status)) { | |
| FreePool (Result); | |
| return Status; | |
| } | |
| // | |
| // Synchronize Edit Buffer | |
| // | |
| if (IsBufferStorage) { | |
| CopyMem (Storage->EditBuffer + Question->VarStoreInfo.VarOffset, Dst, StorageWidth); | |
| } else { | |
| SetValueByName (Storage, Question->VariableName, Value, GetSetValueWithEditBuffer, NULL); | |
| } | |
| 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; | |
| FORMSET_STORAGE *FormsetStorage; | |
| 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; | |
| NAME_VALUE_NODE *Node; | |
| UINTN MaxLen; | |
| Status = EFI_SUCCESS; | |
| Node = NULL; | |
| if (SetValueTo >= GetSetValueWithMax) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| // | |
| // 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, &Node); | |
| FreePool (Value); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| } | |
| } else if (SetValueTo == GetSetValueWithHiiDriver) { | |
| // | |
| // <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); | |
| } | |
| FormsetStorage = GetFstStgFromVarId(FormSet, Question->VarStoreId); | |
| ASSERT (FormsetStorage != NULL); | |
| MaxLen = StrLen (FormsetStorage->ConfigHdr) + Length + 1; | |
| ConfigResp = AllocateZeroPool (MaxLen * sizeof (CHAR16)); | |
| ASSERT (ConfigResp != NULL); | |
| StrCpyS (ConfigResp, MaxLen, FormsetStorage->ConfigHdr); | |
| if (IsBufferStorage) { | |
| StrCatS (ConfigResp, MaxLen, Question->BlockName); | |
| StrCatS (ConfigResp, MaxLen, L"&VALUE="); | |
| } else { | |
| StrCatS (ConfigResp, MaxLen, L"&"); | |
| StrCatS (ConfigResp, MaxLen, Question->VariableName); | |
| StrCatS (ConfigResp, MaxLen, 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 | |
| // | |
| Status = mHiiConfigRouting->RouteConfig ( | |
| mHiiConfigRouting, | |
| ConfigResp, | |
| &Progress | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| FreePool (ConfigResp); | |
| return Status; | |
| } | |
| FreePool (ConfigResp); | |
| // | |
| // Sync storage, from editbuffer to buffer. | |
| // | |
| CopyMem (Storage->Buffer + Question->VarStoreInfo.VarOffset, Src, StorageWidth); | |
| } | |
| return Status; | |
| } | |
| /** | |
| Perform nosubmitif 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: 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; | |
| FORM_EXPRESSION *Expression; | |
| UINT32 BrowserStatus; | |
| CHAR16 *ErrorStr; | |
| BrowserStatus = BROWSER_SUCCESS; | |
| ErrorStr = NULL; | |
| switch (Type) { | |
| case EFI_HII_EXPRESSION_INCONSISTENT_IF: | |
| ListHead = &Question->InconsistentListHead; | |
| break; | |
| case EFI_HII_EXPRESSION_WARNING_IF: | |
| ListHead = &Question->WarningListHead; | |
| break; | |
| case EFI_HII_EXPRESSION_NO_SUBMIT_IF: | |
| ListHead = &Question->NoSubmitListHead; | |
| break; | |
| default: | |
| ASSERT (FALSE); | |
| 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 (IsTrue (&Expression->Result)) { | |
| switch (Type) { | |
| case EFI_HII_EXPRESSION_INCONSISTENT_IF: | |
| BrowserStatus = BROWSER_INCONSISTENT_IF; | |
| break; | |
| case EFI_HII_EXPRESSION_WARNING_IF: | |
| BrowserStatus = BROWSER_WARNING_IF; | |
| break; | |
| case EFI_HII_EXPRESSION_NO_SUBMIT_IF: | |
| BrowserStatus = BROWSER_NO_SUBMIT_IF; | |
| // | |
| // This code only used to compatible with old display engine, | |
| // New display engine will not use this field. | |
| // | |
| if (Expression->Error != 0) { | |
| ErrorStr = GetToken (Expression->Error, FormSet->HiiHandle); | |
| } | |
| break; | |
| default: | |
| ASSERT (FALSE); | |
| break; | |
| } | |
| if (!((Type == EFI_HII_EXPRESSION_NO_SUBMIT_IF) && mSystemSubmit)) { | |
| // | |
| // If in system submit process and for no_submit_if check, not popup this error message. | |
| // Will process this fail again later in not system submit process. | |
| // | |
| PopupErrorMessage(BrowserStatus, FormSet->HiiHandle, Expression->OpCode, ErrorStr); | |
| } | |
| if (ErrorStr != NULL) { | |
| FreePool (ErrorStr); | |
| } | |
| if (Type == EFI_HII_EXPRESSION_WARNING_IF) { | |
| return EFI_SUCCESS; | |
| } else { | |
| return EFI_NOT_READY; | |
| } | |
| } | |
| Link = GetNextNode (ListHead, Link); | |
| } | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Perform question check. | |
| If one question has more than one check, process form high priority to low. | |
| Only one error info will be popup. | |
| @param FormSet FormSet data structure. | |
| @param Form Form data structure. | |
| @param Question The Question to be validated. | |
| @retval EFI_SUCCESS Form validation pass. | |
| @retval other Form validation failed. | |
| **/ | |
| EFI_STATUS | |
| ValueChangedValidation ( | |
| IN FORM_BROWSER_FORMSET *FormSet, | |
| IN FORM_BROWSER_FORM *Form, | |
| IN FORM_BROWSER_STATEMENT *Question | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| Status = EFI_SUCCESS; | |
| // | |
| // Do the inconsistentif check. | |
| // | |
| if (!IsListEmpty (&Question->InconsistentListHead)) { | |
| Status = ValidateQuestion (FormSet, Form, Question, EFI_HII_EXPRESSION_INCONSISTENT_IF); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| } | |
| // | |
| // Do the warningif check. | |
| // | |
| if (!IsListEmpty (&Question->WarningListHead)) { | |
| Status = ValidateQuestion (FormSet, Form, Question, EFI_HII_EXPRESSION_WARNING_IF); | |
| } | |
| return Status; | |
| } | |
| /** | |
| Perform NoSubmit check for each Form in FormSet. | |
| @param FormSet FormSet data structure. | |
| @param CurrentForm Current input form data structure. | |
| @param Statement The statement for this check. | |
| @retval EFI_SUCCESS Form validation pass. | |
| @retval other Form validation failed. | |
| **/ | |
| EFI_STATUS | |
| NoSubmitCheck ( | |
| IN FORM_BROWSER_FORMSET *FormSet, | |
| IN OUT FORM_BROWSER_FORM **CurrentForm, | |
| OUT FORM_BROWSER_STATEMENT **Statement | |
| ) | |
| { | |
| 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)) { | |
| if (*CurrentForm == NULL) { | |
| *CurrentForm = Form; | |
| } | |
| if (Statement != NULL) { | |
| *Statement = Question; | |
| } | |
| return Status; | |
| } | |
| Link = GetNextNode (&Form->StatementListHead, Link); | |
| } | |
| } | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Fill storage's edit copy with settings requested from Configuration Driver. | |
| @param Storage The storage which need to sync. | |
| @param ConfigRequest The config request string which used to sync storage. | |
| @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 | |
| SynchronizeStorage ( | |
| OUT BROWSER_STORAGE *Storage, | |
| IN CHAR16 *ConfigRequest, | |
| 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 (Storage->Type == EFI_HII_VARSTORE_BUFFER || | |
| (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER)) { | |
| BufferSize = Storage->Size; | |
| if (SyncOrRestore) { | |
| Src = Storage->EditBuffer; | |
| Dst = Storage->Buffer; | |
| } else { | |
| Src = Storage->Buffer; | |
| Dst = Storage->EditBuffer; | |
| } | |
| if (ConfigRequest != NULL) { | |
| Status = mHiiConfigRouting->BlockToConfig( | |
| mHiiConfigRouting, | |
| 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 { | |
| CopyMem (Dst, Src, BufferSize); | |
| } | |
| } else if (Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) { | |
| Link = GetFirstNode (&Storage->NameValueListHead); | |
| while (!IsNull (&Storage->NameValueListHead, Link)) { | |
| Node = NAME_VALUE_NODE_FROM_LINK (Link); | |
| if ((ConfigRequest != NULL && StrStr (ConfigRequest, Node->Name) != NULL) || | |
| (ConfigRequest == NULL)) { | |
| if (SyncOrRestore) { | |
| NewStringCpy (&Node->Value, Node->EditValue); | |
| } else { | |
| NewStringCpy (&Node->EditValue, Node->Value); | |
| } | |
| } | |
| Link = GetNextNode (&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_IFR_TYPE_VALUE *TypeValue; | |
| EFI_BROWSER_ACTION_REQUEST ActionRequest; | |
| if (FormSet->ConfigAccess == NULL) { | |
| 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->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != EFI_IFR_FLAG_CALLBACK) { | |
| continue; | |
| } | |
| if (Question->Operand == EFI_IFR_PASSWORD_OP) { | |
| continue; | |
| } | |
| if (!Question->ValueChanged) { | |
| continue; | |
| } | |
| // | |
| // Restore the question value before call the CHANGED callback type. | |
| // | |
| GetQuestionValue (FormSet, Form, Question, GetSetValueWithEditBuffer); | |
| if (Question->Operand == EFI_IFR_STRING_OP){ | |
| HiiSetString (FormSet->HiiHandle, Question->HiiValue.Value.string, (CHAR16*)Question->BufferValue, NULL); | |
| } | |
| 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 | |
| ); | |
| } | |
| } | |
| /** | |
| When submit the question value, call the callback function with Submitted type | |
| to inform the hii driver. | |
| @param FormSet FormSet data structure. | |
| @param Form Form data structure. | |
| **/ | |
| VOID | |
| SubmitCallbackForForm ( | |
| IN FORM_BROWSER_FORMSET *FormSet, | |
| IN FORM_BROWSER_FORM *Form | |
| ) | |
| { | |
| LIST_ENTRY *Link; | |
| FORM_BROWSER_STATEMENT *Question; | |
| EFI_IFR_TYPE_VALUE *TypeValue; | |
| EFI_BROWSER_ACTION_REQUEST ActionRequest; | |
| if (FormSet->ConfigAccess == NULL) { | |
| 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->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != EFI_IFR_FLAG_CALLBACK) { | |
| continue; | |
| } | |
| if (Question->Operand == EFI_IFR_PASSWORD_OP) { | |
| continue; | |
| } | |
| 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_SUBMITTED, | |
| Question->QuestionId, | |
| Question->HiiValue.Type, | |
| TypeValue, | |
| &ActionRequest | |
| ); | |
| } | |
| } | |
| /** | |
| When value set Success, call the submit callback function. | |
| @param FormSet FormSet data structure. | |
| @param Form Form data structure. | |
| **/ | |
| VOID | |
| SubmitCallback ( | |
| IN FORM_BROWSER_FORMSET *FormSet, | |
| IN FORM_BROWSER_FORM *Form | |
| ) | |
| { | |
| FORM_BROWSER_FORM *CurrentForm; | |
| LIST_ENTRY *Link; | |
| if (Form != NULL) { | |
| SubmitCallbackForForm(FormSet, Form); | |
| return; | |
| } | |
| Link = GetFirstNode (&FormSet->FormListHead); | |
| while (!IsNull (&FormSet->FormListHead, Link)) { | |
| CurrentForm = FORM_BROWSER_FORM_FROM_LINK (Link); | |
| Link = GetNextNode (&FormSet->FormListHead, Link); | |
| SubmitCallbackForForm(FormSet, CurrentForm); | |
| } | |
| } | |
| /** | |
| Validate the HiiHandle. | |
| @param HiiHandle The input HiiHandle which need to validate. | |
| @retval TRUE The handle is validate. | |
| @retval FALSE The handle is invalidate. | |
| **/ | |
| BOOLEAN | |
| ValidateHiiHandle ( | |
| EFI_HII_HANDLE HiiHandle | |
| ) | |
| { | |
| EFI_HII_HANDLE *HiiHandles; | |
| UINTN Index; | |
| BOOLEAN Find; | |
| if (HiiHandle == NULL) { | |
| return FALSE; | |
| } | |
| Find = FALSE; | |
| HiiHandles = HiiGetHiiHandles (NULL); | |
| ASSERT (HiiHandles != NULL); | |
| for (Index = 0; HiiHandles[Index] != NULL; Index++) { | |
| if (HiiHandles[Index] == HiiHandle) { | |
| Find = TRUE; | |
| break; | |
| } | |
| } | |
| FreePool (HiiHandles); | |
| return Find; | |
| } | |
| /** | |
| 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 | |
| ) | |
| { | |
| BOOLEAN Find; | |
| ASSERT (FormSet != NULL); | |
| Find = ValidateHiiHandle(FormSet->HiiHandle); | |
| // | |
| // Should not remove the formset which is being used. | |
| // | |
| if (!Find && (FormSet != gCurrentSelection->FormSet)) { | |
| CleanBrowserStorage(FormSet); | |
| RemoveEntryList (&FormSet->Link); | |
| DestroyFormSet (FormSet); | |
| } | |
| return Find; | |
| } | |
| /** | |
| Check whether need to enable the reset flag in form level. | |
| Also clean all ValueChanged flag in question. | |
| @param SetFlag Whether need to set the Reset Flag. | |
| @param FormSet FormSet data structure. | |
| @param Form Form data structure. | |
| **/ | |
| VOID | |
| UpdateFlagForForm ( | |
| IN BOOLEAN SetFlag, | |
| IN FORM_BROWSER_FORMSET *FormSet, | |
| IN FORM_BROWSER_FORM *Form | |
| ) | |
| { | |
| LIST_ENTRY *Link; | |
| FORM_BROWSER_STATEMENT *Question; | |
| BOOLEAN OldValue; | |
| Link = GetFirstNode (&Form->StatementListHead); | |
| while (!IsNull (&Form->StatementListHead, Link)) { | |
| Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link); | |
| Link = GetNextNode (&Form->StatementListHead, Link); | |
| if (!Question->ValueChanged) { | |
| continue; | |
| } | |
| OldValue = Question->ValueChanged; | |
| // | |
| // Compare the buffer and editbuffer data to see whether the data has been saved. | |
| // | |
| Question->ValueChanged = IsQuestionValueChanged(FormSet, Form, Question, GetSetValueWithBothBuffer); | |
| // | |
| // Only the changed data has been saved, then need to set the reset flag. | |
| // | |
| if (SetFlag && OldValue && !Question->ValueChanged) { | |
| if ((Question->QuestionFlags & EFI_IFR_FLAG_RESET_REQUIRED) != 0) { | |
| gResetRequired = TRUE; | |
| } | |
| if ((Question->QuestionFlags & EFI_IFR_FLAG_RECONNECT_REQUIRED) != 0) { | |
| gFlagReconnect = TRUE; | |
| } | |
| } | |
| } | |
| } | |
| /** | |
| Check whether need to enable the reset flag. | |
| Also clean ValueChanged flag for all statements. | |
| Form level or formset level, only one. | |
| @param SetFlag Whether need to set the Reset Flag. | |
| @param FormSet FormSet data structure. | |
| @param Form Form data structure. | |
| **/ | |
| VOID | |
| ValueChangeResetFlagUpdate ( | |
| IN BOOLEAN SetFlag, | |
| IN FORM_BROWSER_FORMSET *FormSet, | |
| IN FORM_BROWSER_FORM *Form | |
| ) | |
| { | |
| FORM_BROWSER_FORM *CurrentForm; | |
| LIST_ENTRY *Link; | |
| if (Form != NULL) { | |
| UpdateFlagForForm(SetFlag, FormSet, Form); | |
| return; | |
| } | |
| Link = GetFirstNode (&FormSet->FormListHead); | |
| while (!IsNull (&FormSet->FormListHead, Link)) { | |
| CurrentForm = FORM_BROWSER_FORM_FROM_LINK (Link); | |
| Link = GetNextNode (&FormSet->FormListHead, Link); | |
| UpdateFlagForForm(SetFlag, FormSet, CurrentForm); | |
| } | |
| } | |
| /** | |
| Base on the return Progress string to find the form. | |
| Base on the first return Offset/Width (Name) string to find the form | |
| which keep this string. | |
| @param FormSet FormSet data structure. | |
| @param Storage Storage which has this Progress string. | |
| @param Progress The Progress string which has the first fail string. | |
| @param RetForm The return form for this progress string. | |
| @param RetQuestion The return question for the error progress string. | |
| @retval TRUE Find the error form and statement for this error progress string. | |
| @retval FALSE Not find the error form. | |
| **/ | |
| BOOLEAN | |
| FindQuestionFromProgress ( | |
| IN FORM_BROWSER_FORMSET *FormSet, | |
| IN BROWSER_STORAGE *Storage, | |
| IN EFI_STRING Progress, | |
| OUT FORM_BROWSER_FORM **RetForm, | |
| OUT FORM_BROWSER_STATEMENT **RetQuestion | |
| ) | |
| { | |
| LIST_ENTRY *Link; | |
| LIST_ENTRY *LinkStorage; | |
| LIST_ENTRY *LinkStatement; | |
| FORM_BROWSER_CONFIG_REQUEST *ConfigInfo; | |
| FORM_BROWSER_FORM *Form; | |
| EFI_STRING EndStr; | |
| FORM_BROWSER_STATEMENT *Statement; | |
| ASSERT ((*Progress == '&') || (*Progress == 'G')); | |
| ConfigInfo = NULL; | |
| *RetForm = NULL; | |
| *RetQuestion = NULL; | |
| // | |
| // Skip the first "&" or the ConfigHdr part. | |
| // | |
| if (*Progress == '&') { | |
| Progress++; | |
| } else { | |
| // | |
| // Prepare the "NAME" or "OFFSET=0x####&WIDTH=0x####" string. | |
| // | |
| if (Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) { | |
| // | |
| // For Name/Value type, Skip the ConfigHdr part. | |
| // | |
| EndStr = StrStr (Progress, L"PATH="); | |
| ASSERT (EndStr != NULL); | |
| while (*EndStr != '&') { | |
| EndStr++; | |
| } | |
| *EndStr = '\0'; | |
| } else { | |
| // | |
| // For Buffer type, Skip the ConfigHdr part. | |
| // | |
| EndStr = StrStr (Progress, L"&OFFSET="); | |
| ASSERT (EndStr != NULL); | |
| *EndStr = '\0'; | |
| } | |
| Progress = EndStr + 1; | |
| } | |
| // | |
| // Prepare the "NAME" or "OFFSET=0x####&WIDTH=0x####" string. | |
| // | |
| if (Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) { | |
| // | |
| // For Name/Value type, the data is "&Fred=16&George=16&Ron=12" formset, | |
| // here, just keep the "Fred" string. | |
| // | |
| EndStr = StrStr (Progress, L"="); | |
| ASSERT (EndStr != NULL); | |
| *EndStr = '\0'; | |
| } else { | |
| // | |
| // For Buffer type, the data is "OFFSET=0x####&WIDTH=0x####&VALUE=0x####", | |
| // here, just keep the "OFFSET=0x####&WIDTH=0x####" string. | |
| // | |
| EndStr = StrStr (Progress, L"&VALUE="); | |
| ASSERT (EndStr != NULL); | |
| *EndStr = '\0'; | |
| } | |
| // | |
| // Search in the form list. | |
| // | |
| Link = GetFirstNode (&FormSet->FormListHead); | |
| while (!IsNull (&FormSet->FormListHead, Link)) { | |
| Form = FORM_BROWSER_FORM_FROM_LINK (Link); | |
| Link = GetNextNode (&FormSet->FormListHead, Link); | |
| // | |
| // Search in the ConfigReqeust list in this form. | |
| // | |
| LinkStorage = GetFirstNode (&Form->ConfigRequestHead); | |
| while (!IsNull (&Form->ConfigRequestHead, LinkStorage)) { | |
| ConfigInfo = FORM_BROWSER_CONFIG_REQUEST_FROM_LINK (LinkStorage); | |
| LinkStorage = GetNextNode (&Form->ConfigRequestHead, LinkStorage); | |
| if (Storage != ConfigInfo->Storage) { | |
| continue; | |
| } | |
| if (StrStr (ConfigInfo->ConfigRequest, Progress) != NULL) { | |
| // | |
| // Find the OffsetWidth string in this form. | |
| // | |
| *RetForm = Form; | |
| break; | |
| } | |
| } | |
| if (*RetForm != NULL) { | |
| LinkStatement = GetFirstNode (&Form->StatementListHead); | |
| while (!IsNull (&Form->StatementListHead, LinkStatement)) { | |
| Statement = FORM_BROWSER_STATEMENT_FROM_LINK (LinkStatement); | |
| LinkStatement = GetNextNode (&Form->StatementListHead, LinkStatement); | |
| if (Statement->BlockName != NULL && StrStr (Statement->BlockName, Progress) != NULL) { | |
| *RetQuestion = Statement; | |
| break; | |
| } | |
| if (Statement->VariableName != NULL && StrStr (Statement->VariableName, Progress) != NULL) { | |
| *RetQuestion = Statement; | |
| break; | |
| } | |
| } | |
| } | |
| if (*RetForm != NULL) { | |
| break; | |
| } | |
| } | |
| // | |
| // restore the OffsetWidth string to the original format. | |
| // | |
| if (Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) { | |
| *EndStr = '='; | |
| } else { | |
| *EndStr = '&'; | |
| } | |
| return (BOOLEAN) (*RetForm != NULL); | |
| } | |
| /** | |
| Popup an save error info and get user input. | |
| @param TitleId The form title id. | |
| @param HiiHandle The hii handle for this package. | |
| @retval UINT32 The user select option for the save fail. | |
| BROWSER_ACTION_DISCARD or BROWSER_ACTION_JUMP_TO_FORMSET | |
| **/ | |
| UINT32 | |
| ConfirmSaveFail ( | |
| IN EFI_STRING_ID TitleId, | |
| IN EFI_HII_HANDLE HiiHandle | |
| ) | |
| { | |
| CHAR16 *FormTitle; | |
| CHAR16 *StringBuffer; | |
| UINT32 RetVal; | |
| FormTitle = GetToken (TitleId, HiiHandle); | |
| StringBuffer = AllocateZeroPool (256 * sizeof (CHAR16)); | |
| ASSERT (StringBuffer != NULL); | |
| UnicodeSPrint ( | |
| StringBuffer, | |
| 24 * sizeof (CHAR16) + StrSize (FormTitle), | |
| L"Submit Fail For Form: %s.", | |
| FormTitle | |
| ); | |
| RetVal = PopupErrorMessage(BROWSER_SUBMIT_FAIL, NULL, NULL, StringBuffer); | |
| FreePool (StringBuffer); | |
| FreePool (FormTitle); | |
| return RetVal; | |
| } | |
| /** | |
| Popup an NO_SUBMIT_IF error info and get user input. | |
| @param TitleId The form title id. | |
| @param HiiHandle The hii handle for this package. | |
| @retval UINT32 The user select option for the save fail. | |
| BROWSER_ACTION_DISCARD or BROWSER_ACTION_JUMP_TO_FORMSET | |
| **/ | |
| UINT32 | |
| ConfirmNoSubmitFail ( | |
| IN EFI_STRING_ID TitleId, | |
| IN EFI_HII_HANDLE HiiHandle | |
| ) | |
| { | |
| CHAR16 *FormTitle; | |
| CHAR16 *StringBuffer; | |
| UINT32 RetVal; | |
| FormTitle = GetToken (TitleId, HiiHandle); | |
| StringBuffer = AllocateZeroPool (256 * sizeof (CHAR16)); | |
| ASSERT (StringBuffer != NULL); | |
| UnicodeSPrint ( | |
| StringBuffer, | |
| 24 * sizeof (CHAR16) + StrSize (FormTitle), | |
| L"NO_SUBMIT_IF error For Form: %s.", | |
| FormTitle | |
| ); | |
| RetVal = PopupErrorMessage(BROWSER_SUBMIT_FAIL_NO_SUBMIT_IF, NULL, NULL, StringBuffer); | |
| FreePool (StringBuffer); | |
| FreePool (FormTitle); | |
| return RetVal; | |
| } | |
| /** | |
| 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; | |
| FORM_BROWSER_FORMSET *OldFormSet; | |
| // | |
| // Check the supported setting level. | |
| // | |
| if (SettingScope >= MaxLevel) { | |
| return EFI_UNSUPPORTED; | |
| } | |
| if (SettingScope == FormLevel && IsNvUpdateRequiredForForm (Form)) { | |
| 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> | |
| // | |
| SynchronizeStorage(ConfigInfo->Storage, ConfigInfo->ConfigRequest, FALSE); | |
| // | |
| // Call callback with Changed type to inform the driver. | |
| // | |
| SendDiscardInfoToDriver (FormSet, Form); | |
| } | |
| ValueChangeResetFlagUpdate (FALSE, FormSet, Form); | |
| } else if (SettingScope == FormSetLevel && IsNvUpdateRequiredForFormSet (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, Storage->ConfigRequest, 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); | |
| } | |
| ValueChangeResetFlagUpdate(FALSE, FormSet, NULL); | |
| } else if (SettingScope == SystemLevel) { | |
| // | |
| // System Level Discard. | |
| // | |
| OldFormSet = mSystemLevelFormSet; | |
| // | |
| // 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; | |
| } | |
| mSystemLevelFormSet = LocalFormSet; | |
| DiscardForm (LocalFormSet, NULL, FormSetLevel); | |
| if (!IsHiiHandleInBrowserContext (LocalFormSet->HiiHandle)) { | |
| // | |
| // Remove maintain backup list after discard except for the current using FormSet. | |
| // | |
| CleanBrowserStorage(LocalFormSet); | |
| RemoveEntryList (&LocalFormSet->Link); | |
| DestroyFormSet (LocalFormSet); | |
| } | |
| } | |
| mSystemLevelFormSet = OldFormSet; | |
| } | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Submit data for a form. | |
| @param FormSet FormSet data structure. | |
| @param Form Form data structure. | |
| @retval EFI_SUCCESS The function completed successfully. | |
| @retval EFI_UNSUPPORTED Unsupport SettingScope. | |
| **/ | |
| EFI_STATUS | |
| SubmitForForm ( | |
| IN FORM_BROWSER_FORMSET *FormSet, | |
| IN FORM_BROWSER_FORM *Form | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| LIST_ENTRY *Link; | |
| EFI_STRING ConfigResp; | |
| EFI_STRING Progress; | |
| BROWSER_STORAGE *Storage; | |
| FORM_BROWSER_CONFIG_REQUEST *ConfigInfo; | |
| if (!IsNvUpdateRequiredForForm (Form)) { | |
| return EFI_SUCCESS; | |
| } | |
| Status = NoSubmitCheck (FormSet, &Form, NULL); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| 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, TRUE); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| // | |
| // 2. Set value to hii config routine protocol. | |
| // | |
| Status = mHiiConfigRouting->RouteConfig ( | |
| mHiiConfigRouting, | |
| ConfigResp, | |
| &Progress | |
| ); | |
| FreePool (ConfigResp); | |
| if (EFI_ERROR (Status)) { | |
| InsertTailList (&gBrowserSaveFailFormSetList, &ConfigInfo->SaveFailLink); | |
| continue; | |
| } | |
| // | |
| // 3. Config success, update storage shadow Buffer, only update the data belong to this form. | |
| // | |
| SynchronizeStorage (ConfigInfo->Storage, ConfigInfo->ConfigRequest, TRUE); | |
| } | |
| // | |
| // 4. Process the save failed storage. | |
| // | |
| if (!IsListEmpty (&gBrowserSaveFailFormSetList)) { | |
| if (ConfirmSaveFail (Form->FormTitle, FormSet->HiiHandle) == BROWSER_ACTION_DISCARD) { | |
| Link = GetFirstNode (&gBrowserSaveFailFormSetList); | |
| while (!IsNull (&gBrowserSaveFailFormSetList, Link)) { | |
| ConfigInfo = FORM_BROWSER_CONFIG_REQUEST_FROM_SAVE_FAIL_LINK (Link); | |
| Link = GetNextNode (&gBrowserSaveFailFormSetList, Link); | |
| SynchronizeStorage(ConfigInfo->Storage, ConfigInfo->ConfigRequest, FALSE); | |
| Status = EFI_SUCCESS; | |
| } | |
| } else { | |
| Status = EFI_UNSUPPORTED; | |
| } | |
| // | |
| // Free Form save fail list. | |
| // | |
| while (!IsListEmpty (&gBrowserSaveFailFormSetList)) { | |
| Link = GetFirstNode (&gBrowserSaveFailFormSetList); | |
| ConfigInfo = FORM_BROWSER_CONFIG_REQUEST_FROM_SAVE_FAIL_LINK (Link); | |
| RemoveEntryList (&ConfigInfo->SaveFailLink); | |
| } | |
| } | |
| // | |
| // 5. Update the NV flag. | |
| // | |
| ValueChangeResetFlagUpdate(TRUE, FormSet, Form); | |
| // | |
| // 6 Call callback with Submitted type to inform the driver. | |
| // | |
| SubmitCallback (FormSet, Form); | |
| return Status; | |
| } | |
| /** | |
| Submit data for a formset. | |
| @param FormSet FormSet data structure. | |
| @param SkipProcessFail Whether skip to process the save failed storage. | |
| If submit formset is called when do system level save, | |
| set this value to true and process the failed formset | |
| together. | |
| if submit formset is called when do formset level save, | |
| set the value to false and process the failed storage | |
| right after process all storages for this formset. | |
| @retval EFI_SUCCESS The function completed successfully. | |
| @retval EFI_UNSUPPORTED Unsupport SettingScope. | |
| **/ | |
| EFI_STATUS | |
| SubmitForFormSet ( | |
| IN FORM_BROWSER_FORMSET *FormSet, | |
| IN BOOLEAN SkipProcessFail | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| LIST_ENTRY *Link; | |
| EFI_STRING ConfigResp; | |
| EFI_STRING Progress; | |
| BROWSER_STORAGE *Storage; | |
| FORMSET_STORAGE *FormSetStorage; | |
| FORM_BROWSER_FORM *Form; | |
| BOOLEAN HasInserted; | |
| FORM_BROWSER_STATEMENT *Question; | |
| HasInserted = FALSE; | |
| if (!IsNvUpdateRequiredForFormSet (FormSet)) { | |
| return EFI_SUCCESS; | |
| } | |
| Form = NULL; | |
| Status = NoSubmitCheck (FormSet, &Form, &Question); | |
| if (EFI_ERROR (Status)) { | |
| if (SkipProcessFail) { | |
| // | |
| // Process NO_SUBMIT check first, so insert it at head. | |
| // | |
| FormSet->SaveFailForm = Form; | |
| FormSet->SaveFailStatement = Question; | |
| InsertHeadList (&gBrowserSaveFailFormSetList, &FormSet->SaveFailLink); | |
| } | |
| return Status; | |
| } | |
| Form = NULL; | |
| Question = NULL; | |
| // | |
| // 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, TRUE); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| // | |
| // 2. Send <ConfigResp> to Routine config Protocol. | |
| // | |
| Status = mHiiConfigRouting->RouteConfig ( | |
| mHiiConfigRouting, | |
| ConfigResp, | |
| &Progress | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| InsertTailList (&FormSet->SaveFailStorageListHead, &FormSetStorage->SaveFailLink); | |
| if (!HasInserted) { | |
| // | |
| // Call submit formset for system level, save the formset info | |
| // and process later. | |
| // | |
| FindQuestionFromProgress(FormSet, Storage, Progress, &Form, &Question); | |
| ASSERT (Form != NULL && Question != NULL); | |
| FormSet->SaveFailForm = Form; | |
| FormSet->SaveFailStatement = Question; | |
| if (SkipProcessFail) { | |
| InsertTailList (&gBrowserSaveFailFormSetList, &FormSet->SaveFailLink); | |
| } | |
| HasInserted = TRUE; | |
| } | |
| FreePool (ConfigResp); | |
| continue; | |
| } | |
| FreePool (ConfigResp); | |
| // | |
| // 3. Config success, update storage shadow Buffer | |
| // | |
| SynchronizeStorage (Storage, FormSetStorage->ConfigRequest, TRUE); | |
| } | |
| // | |
| // 4. Has save fail storage need to handle. | |
| // | |
| if (Form != NULL) { | |
| if (!SkipProcessFail) { | |
| // | |
| // If not in system level, just handl the save failed storage here. | |
| // | |
| if (ConfirmSaveFail (Form->FormTitle, FormSet->HiiHandle) == BROWSER_ACTION_DISCARD) { | |
| Link = GetFirstNode (&FormSet->SaveFailStorageListHead); | |
| while (!IsNull (&FormSet->SaveFailStorageListHead, Link)) { | |
| FormSetStorage = FORMSET_STORAGE_FROM_SAVE_FAIL_LINK (Link); | |
| Storage = FormSetStorage->BrowserStorage; | |
| Link = GetNextNode (&FormSet->SaveFailStorageListHead, Link); | |
| SynchronizeStorage(FormSetStorage->BrowserStorage, FormSetStorage->ConfigRequest, FALSE); | |
| Status = EFI_SUCCESS; | |
| } | |
| } else { | |
| UiCopyMenuList(&mPrivateData.FormBrowserEx2.FormViewHistoryHead, &Form->FormViewListHead); | |
| gCurrentSelection->Action = UI_ACTION_REFRESH_FORMSET; | |
| gCurrentSelection->Handle = FormSet->HiiHandle; | |
| CopyGuid (&gCurrentSelection->FormSetGuid, &FormSet->Guid); | |
| gCurrentSelection->FormId = Form->FormId; | |
| gCurrentSelection->QuestionId = Question->QuestionId; | |
| Status = EFI_UNSUPPORTED; | |
| } | |
| // | |
| // Free FormSet save fail list. | |
| // | |
| while (!IsListEmpty (&FormSet->SaveFailStorageListHead)) { | |
| Link = GetFirstNode (&FormSet->SaveFailStorageListHead); | |
| FormSetStorage = FORMSET_STORAGE_FROM_SAVE_FAIL_LINK (Link); | |
| RemoveEntryList (&FormSetStorage->SaveFailLink); | |
| } | |
| } else { | |
| // | |
| // If in system level, just return error and handle the failed formset later. | |
| // | |
| Status = EFI_UNSUPPORTED; | |
| } | |
| } | |
| // | |
| // 5. Update the NV flag. | |
| // | |
| ValueChangeResetFlagUpdate(TRUE, FormSet, NULL); | |
| // | |
| // 6. Call callback with Submitted type to inform the driver. | |
| // | |
| SubmitCallback (FormSet, NULL); | |
| return Status; | |
| } | |
| /** | |
| Submit data for all formsets. | |
| @retval EFI_SUCCESS The function completed successfully. | |
| @retval EFI_UNSUPPORTED Unsupport SettingScope. | |
| **/ | |
| EFI_STATUS | |
| SubmitForSystem ( | |
| VOID | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| LIST_ENTRY *Link; | |
| LIST_ENTRY *StorageLink; | |
| FORMSET_STORAGE *FormSetStorage; | |
| FORM_BROWSER_FORM *Form; | |
| FORM_BROWSER_FORMSET *LocalFormSet; | |
| UINT32 UserSelection; | |
| FORM_BROWSER_STATEMENT *Question; | |
| mSystemSubmit = TRUE; | |
| Link = GetFirstNode (&gBrowserFormSetList); | |
| while (!IsNull (&gBrowserFormSetList, Link)) { | |
| LocalFormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link); | |
| Link = GetNextNode (&gBrowserFormSetList, Link); | |
| if (!ValidateFormSet(LocalFormSet)) { | |
| continue; | |
| } | |
| Status = SubmitForFormSet (LocalFormSet, TRUE); | |
| if (EFI_ERROR (Status)) { | |
| continue; | |
| } | |
| // | |
| // Remove maintain backup list after save except for the current using FormSet. | |
| // | |
| if (!IsHiiHandleInBrowserContext (LocalFormSet->HiiHandle)) { | |
| CleanBrowserStorage(LocalFormSet); | |
| RemoveEntryList (&LocalFormSet->Link); | |
| DestroyFormSet (LocalFormSet); | |
| } | |
| } | |
| mSystemSubmit = FALSE; | |
| Status = EFI_SUCCESS; | |
| // | |
| // Process the save failed formsets. | |
| // | |
| Link = GetFirstNode (&gBrowserSaveFailFormSetList); | |
| while (!IsNull (&gBrowserSaveFailFormSetList, Link)) { | |
| LocalFormSet = FORM_BROWSER_FORMSET_FROM_SAVE_FAIL_LINK (Link); | |
| Link = GetNextNode (&gBrowserSaveFailFormSetList, Link); | |
| if (!ValidateFormSet(LocalFormSet)) { | |
| continue; | |
| } | |
| Form = LocalFormSet->SaveFailForm; | |
| Question= LocalFormSet->SaveFailStatement; | |
| // | |
| // Confirm with user, get user input. | |
| // | |
| if (IsListEmpty (&LocalFormSet->SaveFailStorageListHead)) { | |
| // | |
| // NULL for SaveFailStorageListHead means error caused by NO_SUBMIT_IF check. | |
| // | |
| UserSelection = ConfirmNoSubmitFail (Form->FormTitle, LocalFormSet->HiiHandle); | |
| } else { | |
| UserSelection = ConfirmSaveFail (Form->FormTitle, LocalFormSet->HiiHandle); | |
| } | |
| if (UserSelection == BROWSER_ACTION_DISCARD) { | |
| if (IsListEmpty (&LocalFormSet->SaveFailStorageListHead)) { | |
| StorageLink = GetFirstNode (&LocalFormSet->StorageListHead); | |
| while (!IsNull (&LocalFormSet->StorageListHead, StorageLink)) { | |
| FormSetStorage = FORMSET_STORAGE_FROM_LINK (StorageLink); | |
| StorageLink = GetNextNode (&LocalFormSet->StorageListHead, StorageLink); | |
| SynchronizeStorage(FormSetStorage->BrowserStorage, FormSetStorage->ConfigRequest, FALSE); | |
| } | |
| } else { | |
| StorageLink = GetFirstNode (&LocalFormSet->SaveFailStorageListHead); | |
| while (!IsNull (&LocalFormSet->SaveFailStorageListHead, StorageLink)) { | |
| FormSetStorage = FORMSET_STORAGE_FROM_SAVE_FAIL_LINK (StorageLink); | |
| StorageLink = GetNextNode (&LocalFormSet->SaveFailStorageListHead, StorageLink); | |
| SynchronizeStorage(FormSetStorage->BrowserStorage, FormSetStorage->ConfigRequest, FALSE); | |
| } | |
| } | |
| if (!IsHiiHandleInBrowserContext (LocalFormSet->HiiHandle)) { | |
| CleanBrowserStorage(LocalFormSet); | |
| RemoveEntryList (&LocalFormSet->Link); | |
| RemoveEntryList (&LocalFormSet->SaveFailLink); | |
| DestroyFormSet (LocalFormSet); | |
| } else { | |
| ValueChangeResetFlagUpdate(FALSE, LocalFormSet, NULL); | |
| } | |
| } else { | |
| if (IsListEmpty (&LocalFormSet->SaveFailStorageListHead)) { | |
| NoSubmitCheck (LocalFormSet, &Form, &Question); | |
| } | |
| UiCopyMenuList(&mPrivateData.FormBrowserEx2.FormViewHistoryHead, &Form->FormViewListHead); | |
| gCurrentSelection->Action = UI_ACTION_REFRESH_FORMSET; | |
| gCurrentSelection->Handle = LocalFormSet->HiiHandle; | |
| CopyGuid (&gCurrentSelection->FormSetGuid, &LocalFormSet->Guid); | |
| gCurrentSelection->FormId = Form->FormId; | |
| gCurrentSelection->QuestionId = Question->QuestionId; | |
| Status = EFI_UNSUPPORTED; | |
| break; | |
| } | |
| } | |
| // | |
| // Clean the list which will not process. | |
| // | |
| while (!IsListEmpty (&gBrowserSaveFailFormSetList)) { | |
| Link = GetFirstNode (&gBrowserSaveFailFormSetList); | |
| LocalFormSet = FORM_BROWSER_FORMSET_FROM_SAVE_FAIL_LINK (Link); | |
| RemoveEntryList (&LocalFormSet->SaveFailLink); | |
| while (!IsListEmpty (&LocalFormSet->SaveFailStorageListHead)) { | |
| StorageLink = GetFirstNode (&LocalFormSet->SaveFailStorageListHead); | |
| FormSetStorage = FORMSET_STORAGE_FROM_SAVE_FAIL_LINK (StorageLink); | |
| RemoveEntryList (&FormSetStorage->SaveFailLink); | |
| } | |
| } | |
| return Status; | |
| } | |
| /** | |
| 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; | |
| switch (SettingScope) { | |
| case FormLevel: | |
| Status = SubmitForForm(FormSet, Form); | |
| break; | |
| case FormSetLevel: | |
| Status = SubmitForFormSet (FormSet, FALSE); | |
| break; | |
| case SystemLevel: | |
| Status = SubmitForSystem (); | |
| break; | |
| default: | |
| Status = EFI_UNSUPPORTED; | |
| break; | |
| } | |
| return Status; | |
| } | |
| /** | |
| Converts the unicode character of the string from uppercase to lowercase. | |
| This is a internal function. | |
| @param ConfigString String to be converted | |
| **/ | |
| VOID | |
| EFIAPI | |
| HiiToLower ( | |
| IN EFI_STRING ConfigString | |
| ) | |
| { | |
| EFI_STRING String; | |
| BOOLEAN Lower; | |
| ASSERT (ConfigString != NULL); | |
| // | |
| // Convert all hex digits in range [A-F] in the configuration header to [a-f] | |
| // | |
| for (String = ConfigString, Lower = FALSE; *String != L'\0'; String++) { | |
| if (*String == L'=') { | |
| Lower = TRUE; | |
| } else if (*String == L'&') { | |
| Lower = FALSE; | |
| } else if (Lower && *String >= L'A' && *String <= L'F') { | |
| *String = (CHAR16) (*String - L'A' + L'a'); | |
| } | |
| } | |
| } | |
| /** | |
| Find the point in the ConfigResp string for this question. | |
| @param Question The question. | |
| @param ConfigResp Get ConfigResp string. | |
| @retval point to the offset where is for this question. | |
| **/ | |
| CHAR16 * | |
| GetOffsetFromConfigResp ( | |
| IN FORM_BROWSER_STATEMENT *Question, | |
| IN CHAR16 *ConfigResp | |
| ) | |
| { | |
| CHAR16 *RequestElement; | |
| CHAR16 *BlockData; | |
| // | |
| // Type is EFI_HII_VARSTORE_NAME_VALUE. | |
| // | |
| if (Question->Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) { | |
| RequestElement = StrStr (ConfigResp, Question->VariableName); | |
| if (RequestElement != NULL) { | |
| // | |
| // Skip the "VariableName=" field. | |
| // | |
| RequestElement += StrLen (Question->VariableName) + 1; | |
| } | |
| return RequestElement; | |
| } | |
| // | |
| // Type is EFI_HII_VARSTORE_EFI_VARIABLE or EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER | |
| // | |
| // | |
| // 1. Directly use Question->BlockName to find. | |
| // | |
| RequestElement = StrStr (ConfigResp, Question->BlockName); | |
| if (RequestElement != NULL) { | |
| // | |
| // Skip the "Question->BlockName&VALUE=" field. | |
| // | |
| RequestElement += StrLen (Question->BlockName) + StrLen (L"&VALUE="); | |
| return RequestElement; | |
| } | |
| // | |
| // 2. Change all hex digits in Question->BlockName to lower and compare again. | |
| // | |
| BlockData = AllocateCopyPool (StrSize(Question->BlockName), Question->BlockName); | |
| ASSERT (BlockData != NULL); | |
| HiiToLower (BlockData); | |
| RequestElement = StrStr (ConfigResp, BlockData); | |
| FreePool (BlockData); | |
| if (RequestElement != NULL) { | |
| // | |
| // Skip the "Question->BlockName&VALUE=" field. | |
| // | |
| RequestElement += StrLen (Question->BlockName) + StrLen (L"&VALUE="); | |
| } | |
| return RequestElement; | |
| } | |
| /** | |
| Get Question default value from AltCfg string. | |
| @param FormSet The form set. | |
| @param Form The form | |
| @param Question The question. | |
| @retval EFI_SUCCESS Question is reset to default value. | |
| **/ | |
| EFI_STATUS | |
| GetDefaultValueFromAltCfg ( | |
| IN FORM_BROWSER_FORMSET *FormSet, | |
| IN FORM_BROWSER_FORM *Form, | |
| IN OUT FORM_BROWSER_STATEMENT *Question | |
| ) | |
| { | |
| BROWSER_STORAGE *Storage; | |
| FORMSET_STORAGE *FormSetStorage; | |
| CHAR16 *ConfigResp; | |
| CHAR16 *Value; | |
| LIST_ENTRY *Link; | |
| FORM_BROWSER_CONFIG_REQUEST *ConfigInfo; | |
| Storage = Question->Storage; | |
| if ((Storage == NULL) || (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE)) { | |
| return EFI_NOT_FOUND; | |
| } | |
| // | |
| // Try to get AltCfg string from form. If not found it, then | |
| // try to get it from formset. | |
| // | |
| ConfigResp = NULL; | |
| Link = GetFirstNode (&Form->ConfigRequestHead); | |
| while (!IsNull (&Form->ConfigRequestHead, Link)) { | |
| ConfigInfo = FORM_BROWSER_CONFIG_REQUEST_FROM_LINK (Link); | |
| Link = GetNextNode (&Form->ConfigRequestHead, Link); | |
| if (Storage == ConfigInfo->Storage) { | |
| ConfigResp = ConfigInfo->ConfigAltResp; | |
| break; | |
| } | |
| } | |
| if (ConfigResp == NULL) { | |
| Link = GetFirstNode (&FormSet->StorageListHead); | |
| while (!IsNull (&FormSet->StorageListHead, Link)) { | |
| FormSetStorage = FORMSET_STORAGE_FROM_LINK (Link); | |
| Link = GetNextNode (&FormSet->StorageListHead, Link); | |
| if (Storage == FormSetStorage->BrowserStorage) { | |
| ConfigResp = FormSetStorage->ConfigAltResp; | |
| break; | |
| } | |
| } | |
| } | |
| if (ConfigResp == NULL) { | |
| return EFI_NOT_FOUND; | |
| } | |
| Value = GetOffsetFromConfigResp (Question, ConfigResp); | |
| if (Value == NULL) { | |
| return EFI_NOT_FOUND; | |
| } | |
| return BufferToValue (Question, Value); | |
| } | |
| /** | |
| 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; | |
| } | |
| } | |
| /** | |
| Return data element in an Array by its Index. | |
| @param Array The data array. | |
| @param Type Type of the data in this array. | |
| @param Index Zero based index for data in this array. | |
| @retval Value The data to be returned | |
| **/ | |
| UINT64 | |
| GetArrayData ( | |
| IN VOID *Array, | |
| IN UINT8 Type, | |
| IN UINTN Index | |
| ) | |
| { | |
| UINT64 Data; | |
| ASSERT (Array != NULL); | |
| Data = 0; | |
| switch (Type) { | |
| case EFI_IFR_TYPE_NUM_SIZE_8: | |
| Data = (UINT64) *(((UINT8 *) Array) + Index); | |
| break; | |
| case EFI_IFR_TYPE_NUM_SIZE_16: | |
| Data = (UINT64) *(((UINT16 *) Array) + Index); | |
| break; | |
| case EFI_IFR_TYPE_NUM_SIZE_32: | |
| Data = (UINT64) *(((UINT32 *) Array) + Index); | |
| break; | |
| case EFI_IFR_TYPE_NUM_SIZE_64: | |
| Data = (UINT64) *(((UINT64 *) Array) + Index); | |
| break; | |
| default: | |
| break; | |
| } | |
| return Data; | |
| } | |
| /** | |
| Set value of a data element in an Array by its Index. | |
| @param Array The data array. | |
| @param Type Type of the data in this array. | |
| @param Index Zero based index for data in this array. | |
| @param Value The value to be set. | |
| **/ | |
| VOID | |
| SetArrayData ( | |
| IN VOID *Array, | |
| IN UINT8 Type, | |
| IN UINTN Index, | |
| IN UINT64 Value | |
| ) | |
| { | |
| ASSERT (Array != NULL); | |
| switch (Type) { | |
| case EFI_IFR_TYPE_NUM_SIZE_8: | |
| *(((UINT8 *) Array) + Index) = (UINT8) Value; | |
| break; | |
| case EFI_IFR_TYPE_NUM_SIZE_16: | |
| *(((UINT16 *) Array) + Index) = (UINT16) Value; | |
| break; | |
| case EFI_IFR_TYPE_NUM_SIZE_32: | |
| *(((UINT32 *) Array) + Index) = (UINT32) Value; | |
| break; | |
| case EFI_IFR_TYPE_NUM_SIZE_64: | |
| *(((UINT64 *) Array) + Index) = (UINT64) Value; | |
| break; | |
| default: | |
| break; | |
| } | |
| } | |
| /** | |
| Search an Option of a Question by its value. | |
| @param Question The Question | |
| @param OptionValue Value for Option to be searched. | |
| @retval Pointer Pointer to the found Option. | |
| @retval NULL Option not found. | |
| **/ | |
| QUESTION_OPTION * | |
| ValueToOption ( | |
| IN FORM_BROWSER_STATEMENT *Question, | |
| IN EFI_HII_VALUE *OptionValue | |
| ) | |
| { | |
| LIST_ENTRY *Link; | |
| QUESTION_OPTION *Option; | |
| INTN Result; | |
| Link = GetFirstNode (&Question->OptionListHead); | |
| while (!IsNull (&Question->OptionListHead, Link)) { | |
| Option = QUESTION_OPTION_FROM_LINK (Link); | |
| if ((CompareHiiValue (&Option->Value, OptionValue, &Result, NULL) == EFI_SUCCESS) && (Result == 0)) { | |
| // | |
| // Check the suppressif condition, only a valid option can be return. | |
| // | |
| if ((Option->SuppressExpression == NULL) || | |
| ((EvaluateExpressionList(Option->SuppressExpression, FALSE, NULL, NULL) == ExpressFalse))) { | |
| return Option; | |
| } | |
| } | |
| Link = GetNextNode (&Question->OptionListHead, Link); | |
| } | |
| return NULL; | |
| } | |
| /** | |
| 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; | |
| CHAR16 *NewString; | |
| 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)) { | |
| if (HiiValue->Type == EFI_IFR_TYPE_STRING) { | |
| NewString = GetToken (Question->HiiValue.Value.string, FormSet->HiiHandle); | |
| ASSERT (NewString != NULL); | |
| ASSERT (StrLen (NewString) * sizeof (CHAR16) <= Question->StorageWidth); | |
| if (StrLen (NewString) * sizeof (CHAR16) <= Question->StorageWidth) { | |
| CopyMem (Question->BufferValue, NewString, StrSize (NewString)); | |
| } else { | |
| CopyMem (Question->BufferValue, NewString, Question->StorageWidth); | |
| } | |
| FreePool (NewString); | |
| } | |
| return Status; | |
| } | |
| } | |
| // | |
| // Get default value from altcfg string. | |
| // | |
| if (ConfigAccess != NULL) { | |
| Status = GetDefaultValueFromAltCfg(FormSet, Form, Question); | |
| 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 | |
| // | |
| if (Default->Value.Type == EFI_IFR_TYPE_BUFFER) { | |
| ASSERT (HiiValue->Buffer != NULL); | |
| CopyMem (HiiValue->Buffer, Default->Value.Buffer, Default->Value.BufferLen); | |
| } else { | |
| 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 ((Question->Flags & EFI_IFR_DISPLAY) == 0) { | |
| // | |
| // In EFI_IFR_DISPLAY_INT_DEC type, should check value with int* type. | |
| // | |
| switch (Question->Flags & EFI_IFR_NUMERIC_SIZE) { | |
| case EFI_IFR_NUMERIC_SIZE_1: | |
| if (((INT8) HiiValue->Value.u8 < (INT8) Question->Minimum) || ((INT8) HiiValue->Value.u8 > (INT8) Question->Maximum)) { | |
| HiiValue->Value.u8 = (UINT8) Question->Minimum; | |
| Status = EFI_SUCCESS; | |
| } | |
| break; | |
| case EFI_IFR_NUMERIC_SIZE_2: | |
| if (((INT16) HiiValue->Value.u16 < (INT16) Question->Minimum) || ((INT16) HiiValue->Value.u16 > (INT16) Question->Maximum)) { | |
| HiiValue->Value.u16 = (UINT16) Question->Minimum; | |
| Status = EFI_SUCCESS; | |
| } | |
| break; | |
| case EFI_IFR_NUMERIC_SIZE_4: | |
| if (((INT32) HiiValue->Value.u32 < (INT32) Question->Minimum) || ((INT32) HiiValue->Value.u32 > (INT32) Question->Maximum)) { | |
| HiiValue->Value.u32 = (UINT32) Question->Minimum; | |
| Status = EFI_SUCCESS; | |
| } | |
| break; | |
| case EFI_IFR_NUMERIC_SIZE_8: | |
| if (((INT64) HiiValue->Value.u64 < (INT64) Question->Minimum) || ((INT64) HiiValue->Value.u64 > (INT64) Question->Maximum)) { | |
| HiiValue->Value.u64 = Question->Minimum; | |
| Status = EFI_SUCCESS; | |
| } | |
| break; | |
| default: | |
| break; | |
| } | |
| } else { | |
| 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; | |
| } | |
| /** | |
| Get AltCfg string for current form. | |
| @param FormSet Form data structure. | |
| @param Form Form data structure. | |
| @param DefaultId The Class of the default. | |
| @param BrowserStorage The input request storage for the questions. | |
| **/ | |
| VOID | |
| ExtractAltCfgForForm ( | |
| IN FORM_BROWSER_FORMSET *FormSet, | |
| IN FORM_BROWSER_FORM *Form, | |
| IN UINT16 DefaultId, | |
| IN BROWSER_STORAGE *BrowserStorage | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| LIST_ENTRY *Link; | |
| CHAR16 *ConfigResp; | |
| CHAR16 *Progress; | |
| CHAR16 *Result; | |
| BROWSER_STORAGE *Storage; | |
| FORM_BROWSER_CONFIG_REQUEST *ConfigInfo; | |
| FORMSET_STORAGE *FormSetStorage; | |
| // | |
| // Check whether has get AltCfg string for this formset. | |
| // If yes, no need to get AltCfg for form. | |
| // | |
| Link = GetFirstNode (&FormSet->StorageListHead); | |
| while (!IsNull (&FormSet->StorageListHead, Link)) { | |
| FormSetStorage = FORMSET_STORAGE_FROM_LINK (Link); | |
| Storage = FormSetStorage->BrowserStorage; | |
| Link = GetNextNode (&FormSet->StorageListHead, Link); | |
| if (BrowserStorage != NULL && BrowserStorage != Storage) { | |
| continue; | |
| } | |
| if (Storage->Type != EFI_HII_VARSTORE_EFI_VARIABLE && | |
| FormSetStorage->ElementCount != 0 && | |
| FormSetStorage->HasCallAltCfg) { | |
| return; | |
| } | |
| } | |
| // | |
| // Get AltCfg string for each form. | |
| // | |
| 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 (BrowserStorage != NULL && BrowserStorage != Storage) { | |
| continue; | |
| } | |
| if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) { | |
| continue; | |
| } | |
| // | |
| // 1. Skip if there is no RequestElement | |
| // | |
| if (ConfigInfo->ElementCount == 0) { | |
| continue; | |
| } | |
| // | |
| // 2. Get value through hii config routine protocol. | |
| // | |
| Status = mHiiConfigRouting->ExtractConfig ( | |
| mHiiConfigRouting, | |
| ConfigInfo->ConfigRequest, | |
| &Progress, | |
| &Result | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| continue; | |
| } | |
| // | |
| // 3. 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 | |
| ); | |
| FreePool (Result); | |
| if (EFI_ERROR (Status)) { | |
| continue; | |
| } | |
| ConfigInfo->ConfigAltResp = ConfigResp; | |
| } | |
| } | |
| /** | |
| Clean AltCfg string for current form. | |
| @param Form Form data structure. | |
| **/ | |
| VOID | |
| CleanAltCfgForForm ( | |
| IN FORM_BROWSER_FORM *Form | |
| ) | |
| { | |
| LIST_ENTRY *Link; | |
| FORM_BROWSER_CONFIG_REQUEST *ConfigInfo; | |
| Link = GetFirstNode (&Form->ConfigRequestHead); | |
| while (!IsNull (&Form->ConfigRequestHead, Link)) { | |
| ConfigInfo = FORM_BROWSER_CONFIG_REQUEST_FROM_LINK (Link); | |
| Link = GetNextNode (&Form->ConfigRequestHead, Link); | |
| if (ConfigInfo->ConfigAltResp != NULL) { | |
| FreePool (ConfigInfo->ConfigAltResp); | |
| ConfigInfo->ConfigAltResp = NULL; | |
| } | |
| } | |
| } | |
| /** | |
| Get AltCfg string for current formset. | |
| @param FormSet Form data structure. | |
| @param DefaultId The Class of the default. | |
| @param BrowserStorage The input request storage for the questions. | |
| **/ | |
| VOID | |
| ExtractAltCfgForFormSet ( | |
| IN FORM_BROWSER_FORMSET *FormSet, | |
| IN UINT16 DefaultId, | |
| IN BROWSER_STORAGE *BrowserStorage | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| LIST_ENTRY *Link; | |
| CHAR16 *ConfigResp; | |
| CHAR16 *Progress; | |
| CHAR16 *Result; | |
| BROWSER_STORAGE *Storage; | |
| FORMSET_STORAGE *FormSetStorage; | |
| Link = GetFirstNode (&FormSet->StorageListHead); | |
| while (!IsNull (&FormSet->StorageListHead, Link)) { | |
| FormSetStorage = FORMSET_STORAGE_FROM_LINK (Link); | |
| Storage = FormSetStorage->BrowserStorage; | |
| Link = GetNextNode (&FormSet->StorageListHead, Link); | |
| if (BrowserStorage != NULL && BrowserStorage != Storage) { | |
| continue; | |
| } | |
| if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) { | |
| continue; | |
| } | |
| // | |
| // 1. Skip if there is no RequestElement | |
| // | |
| if (FormSetStorage->ElementCount == 0) { | |
| continue; | |
| } | |
| FormSetStorage->HasCallAltCfg = TRUE; | |
| // | |
| // 2. Get value through hii config routine protocol. | |
| // | |
| Status = mHiiConfigRouting->ExtractConfig ( | |
| mHiiConfigRouting, | |
| FormSetStorage->ConfigRequest, | |
| &Progress, | |
| &Result | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| continue; | |
| } | |
| // | |
| // 3. 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 | |
| ); | |
| FreePool (Result); | |
| if (EFI_ERROR (Status)) { | |
| continue; | |
| } | |
| FormSetStorage->ConfigAltResp = ConfigResp; | |
| } | |
| } | |
| /** | |
| Clean AltCfg string for current formset. | |
| @param FormSet Form data structure. | |
| **/ | |
| VOID | |
| CleanAltCfgForFormSet ( | |
| IN FORM_BROWSER_FORMSET *FormSet | |
| ) | |
| { | |
| LIST_ENTRY *Link; | |
| FORMSET_STORAGE *FormSetStorage; | |
| Link = GetFirstNode (&FormSet->StorageListHead); | |
| while (!IsNull (&FormSet->StorageListHead, Link)) { | |
| FormSetStorage = FORMSET_STORAGE_FROM_LINK (Link); | |
| Link = GetNextNode (&FormSet->StorageListHead, Link); | |
| if (FormSetStorage->ConfigAltResp != NULL) { | |
| FreePool (FormSetStorage->ConfigAltResp); | |
| FormSetStorage->ConfigAltResp = NULL; | |
| } | |
| FormSetStorage->HasCallAltCfg = FALSE; | |
| } | |
| } | |
| /** | |
| 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. | |
| @param SkipGetAltCfg Whether skip the get altcfg string process. | |
| @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, | |
| IN BOOLEAN SkipGetAltCfg | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| LIST_ENTRY *FormLink; | |
| LIST_ENTRY *Link; | |
| FORM_BROWSER_STATEMENT *Question; | |
| FORM_BROWSER_FORMSET *LocalFormSet; | |
| FORM_BROWSER_FORMSET *OldFormSet; | |
| 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) { | |
| // | |
| // Prepare the AltCfg String for form. | |
| // | |
| if (!SkipGetAltCfg && (GetDefaultValueScope != GetDefaultForNoStorage)) { | |
| ExtractAltCfgForForm (FormSet, Form, DefaultId, Storage); | |
| } | |
| // | |
| // 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, FormSet); | |
| } | |
| // | |
| // 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); | |
| } | |
| } | |
| // | |
| // Clean the AltCfg String. | |
| // | |
| if (!SkipGetAltCfg && (GetDefaultValueScope != GetDefaultForNoStorage)) { | |
| CleanAltCfgForForm(Form); | |
| } | |
| } else if (SettingScope == FormSetLevel) { | |
| // | |
| // Prepare the AltCfg String for formset. | |
| // | |
| if (!SkipGetAltCfg && (GetDefaultValueScope != GetDefaultForNoStorage)) { | |
| ExtractAltCfgForFormSet (FormSet, DefaultId, Storage); | |
| } | |
| FormLink = GetFirstNode (&FormSet->FormListHead); | |
| while (!IsNull (&FormSet->FormListHead, FormLink)) { | |
| Form = FORM_BROWSER_FORM_FROM_LINK (FormLink); | |
| ExtractDefault (FormSet, Form, DefaultId, FormLevel, GetDefaultValueScope, Storage, RetrieveValueFirst, SkipGetAltCfg); | |
| FormLink = GetNextNode (&FormSet->FormListHead, FormLink); | |
| } | |
| // | |
| // Clean the AltCfg String. | |
| // | |
| if (!SkipGetAltCfg && (GetDefaultValueScope != GetDefaultForNoStorage)) { | |
| CleanAltCfgForFormSet (FormSet); | |
| } | |
| } else if (SettingScope == SystemLevel) { | |
| // | |
| // Preload all Hii formset. | |
| // | |
| LoadAllHiiFormset(); | |
| OldFormSet = mSystemLevelFormSet; | |
| // | |
| // 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; | |
| } | |
| mSystemLevelFormSet = LocalFormSet; | |
| ExtractDefault (LocalFormSet, NULL, DefaultId, FormSetLevel, GetDefaultValueScope, Storage, RetrieveValueFirst, SkipGetAltCfg); | |
| } | |
| mSystemLevelFormSet = OldFormSet; | |
| } | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Validate whether this question's value has changed. | |
| @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 TRUE Question's value has changed. | |
| @retval FALSE Question's value has not changed | |
| **/ | |
| BOOLEAN | |
| IsQuestionValueChanged ( | |
| IN FORM_BROWSER_FORMSET *FormSet, | |
| IN FORM_BROWSER_FORM *Form, | |
| IN OUT FORM_BROWSER_STATEMENT *Question, | |
| IN GET_SET_QUESTION_VALUE_WITH GetValueFrom | |
| ) | |
| { | |
| EFI_HII_VALUE BackUpValue; | |
| CHAR8 *BackUpBuffer; | |
| EFI_HII_VALUE BackUpValue2; | |
| CHAR8 *BackUpBuffer2; | |
| EFI_STATUS Status; | |
| BOOLEAN ValueChanged; | |
| UINTN BufferWidth; | |
| // | |
| // For quetion without storage, always mark it as data not changed. | |
| // | |
| if (Question->Storage == NULL && Question->Operand != EFI_IFR_TIME_OP && Question->Operand != EFI_IFR_DATE_OP) { | |
| return FALSE; | |
| } | |
| BackUpBuffer = NULL; | |
| BackUpBuffer2 = NULL; | |
| ValueChanged = FALSE; | |
| switch (Question->Operand) { | |
| case EFI_IFR_ORDERED_LIST_OP: | |
| BufferWidth = Question->StorageWidth; | |
| BackUpBuffer = AllocateCopyPool (BufferWidth, Question->BufferValue); | |
| ASSERT (BackUpBuffer != NULL); | |
| break; | |
| case EFI_IFR_STRING_OP: | |
| case EFI_IFR_PASSWORD_OP: | |
| BufferWidth = (UINTN) Question->Maximum * sizeof (CHAR16); | |
| BackUpBuffer = AllocateCopyPool (BufferWidth, Question->BufferValue); | |
| ASSERT (BackUpBuffer != NULL); | |
| break; | |
| default: | |
| BufferWidth = 0; | |
| break; | |
| } | |
| CopyMem (&BackUpValue, &Question->HiiValue, sizeof (EFI_HII_VALUE)); | |
| if (GetValueFrom == GetSetValueWithBothBuffer) { | |
| Status = GetQuestionValue (FormSet, Form, Question, GetSetValueWithEditBuffer); | |
| ASSERT_EFI_ERROR(Status); | |
| switch (Question->Operand) { | |
| case EFI_IFR_ORDERED_LIST_OP: | |
| BufferWidth = Question->StorageWidth; | |
| BackUpBuffer2 = AllocateCopyPool (BufferWidth, Question->BufferValue); | |
| ASSERT (BackUpBuffer2 != NULL); | |
| break; | |
| case EFI_IFR_STRING_OP: | |
| case EFI_IFR_PASSWORD_OP: | |
| BufferWidth = (UINTN) Question->Maximum * sizeof (CHAR16); | |
| BackUpBuffer2 = AllocateCopyPool (BufferWidth, Question->BufferValue); | |
| ASSERT (BackUpBuffer2 != NULL); | |
| break; | |
| default: | |
| BufferWidth = 0; | |
| break; | |
| } | |
| CopyMem (&BackUpValue2, &Question->HiiValue, sizeof (EFI_HII_VALUE)); | |
| Status = GetQuestionValue (FormSet, Form, Question, GetSetValueWithBuffer); | |
| ASSERT_EFI_ERROR(Status); | |
| if (CompareMem (&BackUpValue2, &Question->HiiValue, sizeof (EFI_HII_VALUE)) != 0 || | |
| CompareMem (BackUpBuffer2, Question->BufferValue, BufferWidth) != 0) { | |
| ValueChanged = TRUE; | |
| } | |
| } else { | |
| Status = GetQuestionValue (FormSet, Form, Question, GetValueFrom); | |
| ASSERT_EFI_ERROR(Status); | |
| if (CompareMem (&BackUpValue, &Question->HiiValue, sizeof (EFI_HII_VALUE)) != 0 || | |
| CompareMem (BackUpBuffer, Question->BufferValue, BufferWidth) != 0) { | |
| ValueChanged = TRUE; | |
| } | |
| } | |
| CopyMem (&Question->HiiValue, &BackUpValue, sizeof (EFI_HII_VALUE)); | |
| if (BackUpBuffer != NULL) { | |
| CopyMem (Question->BufferValue, BackUpBuffer, BufferWidth); | |
| FreePool (BackUpBuffer); | |
| } | |
| if (BackUpBuffer2 != NULL) { | |
| FreePool (BackUpBuffer2); | |
| } | |
| Question->ValueChanged = ValueChanged; | |
| return ValueChanged; | |
| } | |
| /** | |
| 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; | |
| Link = GetFirstNode (&Form->StatementListHead); | |
| while (!IsNull (&Form->StatementListHead, Link)) { | |
| Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link); | |
| // | |
| // Initialize local copy of Value for each Question | |
| // | |
| if (Question->Operand == EFI_IFR_PASSWORD_OP && (Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK)== 0) { | |
| Status = GetQuestionValue (FormSet, Form, Question, GetSetValueWithHiiDriver); | |
| } else { | |
| 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); | |
| } | |
| 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); | |
| } | |
| // | |
| // Finished question initialization. | |
| // | |
| FormSet->QuestionInited = TRUE; | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Remove the Request element from the Config Request. | |
| @param Storage Pointer to the browser storage. | |
| @param RequestElement The pointer to the Request element. | |
| **/ | |
| VOID | |
| RemoveElement ( | |
| IN OUT BROWSER_STORAGE *Storage, | |
| IN CHAR16 *RequestElement | |
| ) | |
| { | |
| CHAR16 *NewStr; | |
| CHAR16 *DestStr; | |
| ASSERT (Storage->ConfigRequest != NULL && RequestElement != NULL); | |
| NewStr = StrStr (Storage->ConfigRequest, RequestElement); | |
| if (NewStr == NULL) { | |
| return; | |
| } | |
| // | |
| // Remove this element from this ConfigRequest. | |
| // | |
| DestStr = NewStr; | |
| NewStr += StrLen (RequestElement); | |
| CopyMem (DestStr, NewStr, StrSize (NewStr)); | |
| Storage->SpareStrLen += StrLen (RequestElement); | |
| } | |
| /** | |
| Adjust config request in storage, remove the request elements existed in the input ConfigRequest. | |
| @param Storage Pointer to the formset storage. | |
| @param ConfigRequest The pointer to the Request element. | |
| **/ | |
| VOID | |
| RemoveConfigRequest ( | |
| FORMSET_STORAGE *Storage, | |
| CHAR16 *ConfigRequest | |
| ) | |
| { | |
| CHAR16 *RequestElement; | |
| CHAR16 *NextRequestElement; | |
| CHAR16 *SearchKey; | |
| // | |
| // No request element in it, just return. | |
| // | |
| if (ConfigRequest == NULL) { | |
| return; | |
| } | |
| if (Storage->BrowserStorage->Type == EFI_HII_VARSTORE_NAME_VALUE) { | |
| // | |
| // "&Name1&Name2" section for EFI_HII_VARSTORE_NAME_VALUE storage | |
| // | |
| SearchKey = L"&"; | |
| } else { | |
| // | |
| // "&OFFSET=####&WIDTH=####" section for EFI_HII_VARSTORE_BUFFER storage | |
| // | |
| SearchKey = L"&OFFSET"; | |
| } | |
| // | |
| // Find SearchKey storage | |
| // | |
| if (Storage->BrowserStorage->Type == EFI_HII_VARSTORE_NAME_VALUE) { | |
| RequestElement = StrStr (ConfigRequest, L"PATH"); | |
| ASSERT (RequestElement != NULL); | |
| RequestElement = StrStr (RequestElement, SearchKey); | |
| } else { | |
| RequestElement = StrStr (ConfigRequest, SearchKey); | |
| } | |
| while (RequestElement != NULL) { | |
| // | |
| // +1 to avoid find header itself. | |
| // | |
| NextRequestElement = StrStr (RequestElement + 1, SearchKey); | |
| // | |
| // The last Request element in configRequest string. | |
| // | |
| if (NextRequestElement != NULL) { | |
| // | |
| // Replace "&" with '\0'. | |
| // | |
| *NextRequestElement = L'\0'; | |
| } | |
| RemoveElement (Storage->BrowserStorage, RequestElement); | |
| if (NextRequestElement != NULL) { | |
| // | |
| // Restore '&' with '\0' for later used. | |
| // | |
| *NextRequestElement = L'&'; | |
| } | |
| RequestElement = NextRequestElement; | |
| } | |
| // | |
| // If no request element remain, just remove the ConfigRequest string. | |
| // | |
| if (StrCmp (Storage->BrowserStorage->ConfigRequest, Storage->ConfigHdr) == 0) { | |
| FreePool (Storage->BrowserStorage->ConfigRequest); | |
| Storage->BrowserStorage->ConfigRequest = NULL; | |
| Storage->BrowserStorage->SpareStrLen = 0; | |
| } | |
| } | |
| /** | |
| Base on the current formset info, clean the ConfigRequest string in browser storage. | |
| @param FormSet Pointer of the FormSet | |
| **/ | |
| VOID | |
| CleanBrowserStorage ( | |
| IN OUT FORM_BROWSER_FORMSET *FormSet | |
| ) | |
| { | |
| LIST_ENTRY *Link; | |
| FORMSET_STORAGE *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_BUFFER) { | |
| if (Storage->ConfigRequest == NULL || Storage->BrowserStorage->ConfigRequest == NULL) { | |
| continue; | |
| } | |
| RemoveConfigRequest (Storage, Storage->ConfigRequest); | |
| } else if (Storage->BrowserStorage->Type == EFI_HII_VARSTORE_BUFFER || | |
| Storage->BrowserStorage->Type == EFI_HII_VARSTORE_NAME_VALUE) { | |
| if (Storage->BrowserStorage->ConfigRequest != NULL) { | |
| FreePool (Storage->BrowserStorage->ConfigRequest); | |
| Storage->BrowserStorage->ConfigRequest = NULL; | |
| } | |
| Storage->BrowserStorage->Initialized = FALSE; | |
| } | |
| } | |
| } | |
| /** | |
| Check whether current element in the ConfigReqeust string. | |
| @param BrowserStorage Storage which includes ConfigReqeust. | |
| @param RequestElement New element need to check. | |
| @retval TRUE The Element is in the ConfigReqeust string. | |
| @retval FALSE The Element not in the configReqeust String. | |
| **/ | |
| BOOLEAN | |
| ElementValidation ( | |
| BROWSER_STORAGE *BrowserStorage, | |
| CHAR16 *RequestElement | |
| ) | |
| { | |
| return StrStr (BrowserStorage->ConfigRequest, RequestElement) != NULL ? TRUE : FALSE; | |
| } | |
| /** | |
| Append the Request element to the Config Request. | |
| @param ConfigRequest Current ConfigRequest info. | |
| @param SpareStrLen Current remain free buffer for config reqeust. | |
| @param RequestElement New Request element. | |
| **/ | |
| VOID | |
| AppendConfigRequest ( | |
| IN OUT CHAR16 **ConfigRequest, | |
| IN OUT UINTN *SpareStrLen, | |
| IN CHAR16 *RequestElement | |
| ) | |
| { | |
| CHAR16 *NewStr; | |
| UINTN StringSize; | |
| UINTN StrLength; | |
| UINTN MaxLen; | |
| StrLength = StrLen (RequestElement); | |
| StringSize = (*ConfigRequest != NULL) ? StrSize (*ConfigRequest) : sizeof (CHAR16); | |
| MaxLen = StringSize / sizeof (CHAR16) + *SpareStrLen; | |
| // | |
| // Append <RequestElement> to <ConfigRequest> | |
| // | |
| if (StrLength > *SpareStrLen) { | |
| // | |
| // Old String buffer is not sufficient for RequestElement, allocate a new one | |
| // | |
| MaxLen = StringSize / sizeof (CHAR16) + CONFIG_REQUEST_STRING_INCREMENTAL; | |
| NewStr = AllocateZeroPool (MaxLen * sizeof (CHAR16)); | |
| ASSERT (NewStr != NULL); | |
| if (*ConfigRequest != NULL) { | |
| CopyMem (NewStr, *ConfigRequest, StringSize); | |
| FreePool (*ConfigRequest); | |
| } | |
| *ConfigRequest = NewStr; | |
| *SpareStrLen = CONFIG_REQUEST_STRING_INCREMENTAL; | |
| } | |
| StrCatS (*ConfigRequest, MaxLen, RequestElement); | |
| *SpareStrLen -= StrLength; | |
| } | |
| /** | |
| Adjust the config request info, remove the request elements which already in AllConfigRequest string. | |
| @param Storage Form set Storage. | |
| @param Request The input request string. | |
| @param RespString Whether the input is ConfigRequest or ConfigResp format. | |
| @retval TRUE Has element not covered by current used elements, need to continue to call ExtractConfig | |
| @retval FALSE All elements covered by current used elements. | |
| **/ | |
| BOOLEAN | |
| ConfigRequestAdjust ( | |
| IN BROWSER_STORAGE *Storage, | |
| IN CHAR16 *Request, | |
| IN BOOLEAN RespString | |
| ) | |
| { | |
| CHAR16 *RequestElement; | |
| CHAR16 *NextRequestElement; | |
| CHAR16 *NextElementBakup; | |
| CHAR16 *SearchKey; | |
| CHAR16 *ValueKey; | |
| BOOLEAN RetVal; | |
| CHAR16 *ConfigRequest; | |
| RetVal = FALSE; | |
| NextElementBakup = NULL; | |
| ValueKey = NULL; | |
| if (Request != NULL) { | |
| ConfigRequest = Request; | |
| } else { | |
| ConfigRequest = Storage->ConfigRequest; | |
| } | |
| if (Storage->ConfigRequest == NULL) { | |
| Storage->ConfigRequest = AllocateCopyPool (StrSize (ConfigRequest), ConfigRequest); | |
| return TRUE; | |
| } | |
| if (Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) { | |
| // | |
| // "&Name1&Name2" section for EFI_HII_VARSTORE_NAME_VALUE storage | |
| // | |
| SearchKey = L"&"; | |
| } else { | |
| // | |
| // "&OFFSET=####&WIDTH=####" section for EFI_HII_VARSTORE_BUFFER storage | |
| // | |
| SearchKey = L"&OFFSET"; | |
| ValueKey = L"&VALUE"; | |
| } | |
| // | |
| // Find SearchKey storage | |
| // | |
| if (Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) { | |
| RequestElement = StrStr (ConfigRequest, L"PATH"); | |
| ASSERT (RequestElement != NULL); | |
| RequestElement = StrStr (RequestElement, SearchKey); | |
| } else { | |
| RequestElement = StrStr (ConfigRequest, SearchKey); | |
| } | |
| while (RequestElement != NULL) { | |
| // | |
| // +1 to avoid find header itself. | |
| // | |
| NextRequestElement = StrStr (RequestElement + 1, SearchKey); | |
| // | |
| // The last Request element in configRequest string. | |
| // | |
| if (NextRequestElement != NULL) { | |
| if (RespString && (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER)) { | |
| NextElementBakup = NextRequestElement; | |
| NextRequestElement = StrStr (RequestElement, ValueKey); | |
| ASSERT (NextRequestElement != NULL); | |
| } | |
| // | |
| // Replace "&" with '\0'. | |
| // | |
| *NextRequestElement = L'\0'; | |
| } else { | |
| if (RespString && (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER)) { | |
| NextElementBakup = NextRequestElement; | |
| NextRequestElement = StrStr (RequestElement, ValueKey); | |
| ASSERT (NextRequestElement != NULL); | |
| // | |
| // Replace "&" with '\0'. | |
| // | |
| *NextRequestElement = L'\0'; | |
| } | |
| } | |
| if (!ElementValidation (Storage, RequestElement)) { | |
| // | |
| // Add this element to the Storage->BrowserStorage->AllRequestElement. | |
| // | |
| AppendConfigRequest(&Storage->ConfigRequest, &Storage->SpareStrLen, RequestElement); | |
| RetVal = TRUE; | |
| } | |
| if (NextRequestElement != NULL) { | |
| // | |
| // Restore '&' with '\0' for later used. | |
| // | |
| *NextRequestElement = L'&'; | |
| } | |
| if (RespString && (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER)) { | |
| RequestElement = NextElementBakup; | |
| } else { | |
| RequestElement = NextRequestElement; | |
| } | |
| } | |
| return RetVal; | |
| } | |
| /** | |
| Fill storage's edit copy with settings requested from Configuration Driver. | |
| @param FormSet FormSet data structure. | |
| @param Storage Buffer Storage. | |
| **/ | |
| VOID | |
| LoadStorage ( | |
| IN FORM_BROWSER_FORMSET *FormSet, | |
| IN FORMSET_STORAGE *Storage | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| EFI_STRING Progress; | |
| EFI_STRING Result; | |
| CHAR16 *StrPtr; | |
| EFI_STRING ConfigRequest; | |
| UINTN StrLen; | |
| ConfigRequest = NULL; | |
| switch (Storage->BrowserStorage->Type) { | |
| case EFI_HII_VARSTORE_EFI_VARIABLE: | |
| return; | |
| case EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER: | |
| if (Storage->BrowserStorage->ConfigRequest != NULL) { | |
| ConfigRequestAdjust(Storage->BrowserStorage, Storage->ConfigRequest, FALSE); | |
| return; | |
| } | |
| break; | |
| case EFI_HII_VARSTORE_BUFFER: | |
| case EFI_HII_VARSTORE_NAME_VALUE: | |
| // | |
| // Skip if there is no RequestElement. | |
| // | |
| if (Storage->ElementCount == 0) { | |
| return; | |
| } | |
| // | |
| // Just update the ConfigRequest, if storage already initialized. | |
| // | |
| if (Storage->BrowserStorage->Initialized) { | |
| ConfigRequestAdjust(Storage->BrowserStorage, Storage->ConfigRequest, FALSE); | |
| return; | |
| } | |
| Storage->BrowserStorage->Initialized = TRUE; | |
| break; | |
| default: | |
| return; | |
| } | |
| if (Storage->BrowserStorage->Type != EFI_HII_VARSTORE_NAME_VALUE) { | |
| // | |
| // Create the config request string to get all fields for this storage. | |
| // Allocate and fill a buffer large enough to hold the <ConfigHdr> template | |
| // followed by "&OFFSET=0&WIDTH=WWWW"followed by a Null-terminator | |
| // | |
| StrLen = StrSize (Storage->ConfigHdr) + 20 * sizeof (CHAR16); | |
| ConfigRequest = AllocateZeroPool (StrLen); | |
| ASSERT (ConfigRequest != NULL); | |
| UnicodeSPrint ( | |
| ConfigRequest, | |
| StrLen, | |
| L"%s&OFFSET=0&WIDTH=%04x", | |
| Storage->ConfigHdr, | |
| Storage->BrowserStorage->Size); | |
| } else { | |
| ConfigRequest = Storage->ConfigRequest; | |
| } | |
| // | |
| // Request current settings from Configuration Driver | |
| // | |
| Status = mHiiConfigRouting->ExtractConfig ( | |
| mHiiConfigRouting, | |
| ConfigRequest, | |
| &Progress, | |
| &Result | |
| ); | |
| // | |
| // If get value fail, extract default from IFR binary | |
| // | |
| if (EFI_ERROR (Status)) { | |
| ExtractDefault (FormSet, NULL, EFI_HII_DEFAULT_CLASS_STANDARD, FormSetLevel, GetDefaultForStorage, Storage->BrowserStorage, TRUE, TRUE); | |
| } else { | |
| // | |
| // Convert Result from <ConfigAltResp> to <ConfigResp> | |
| // | |
| StrPtr = StrStr (Result, L"&GUID="); | |
| if (StrPtr != NULL) { | |
| *StrPtr = L'\0'; | |
| } | |
| Status = ConfigRespToStorage (Storage->BrowserStorage, Result); | |
| FreePool (Result); | |
| } | |
| Storage->BrowserStorage->ConfigRequest = AllocateCopyPool (StrSize (Storage->ConfigRequest), Storage->ConfigRequest); | |
| // | |
| // Input NULL for ConfigRequest field means sync all fields from editbuffer to buffer. | |
| // | |
| SynchronizeStorage(Storage->BrowserStorage, NULL, TRUE); | |
| if (Storage->BrowserStorage->Type != EFI_HII_VARSTORE_NAME_VALUE) { | |
| if (ConfigRequest != NULL) { | |
| FreePool (ConfigRequest); | |
| } | |
| } | |
| } | |
| /** | |
| Get Value changed status from old question. | |
| @param NewFormSet FormSet data structure. | |
| @param OldQuestion Old question which has value changed. | |
| **/ | |
| VOID | |
| SyncStatusForQuestion ( | |
| IN OUT FORM_BROWSER_FORMSET *NewFormSet, | |
| IN FORM_BROWSER_STATEMENT *OldQuestion | |
| ) | |
| { | |
| LIST_ENTRY *Link; | |
| LIST_ENTRY *QuestionLink; | |
| FORM_BROWSER_FORM *Form; | |
| FORM_BROWSER_STATEMENT *Question; | |
| // | |
| // For each form in one formset. | |
| // | |
| Link = GetFirstNode (&NewFormSet->FormListHead); | |
| while (!IsNull (&NewFormSet->FormListHead, Link)) { | |
| Form = FORM_BROWSER_FORM_FROM_LINK (Link); | |
| Link = GetNextNode (&NewFormSet->FormListHead, Link); | |
| // | |
| // for each question in one form. | |
| // | |
| QuestionLink = GetFirstNode (&Form->StatementListHead); | |
| while (!IsNull (&Form->StatementListHead, QuestionLink)) { | |
| Question = FORM_BROWSER_STATEMENT_FROM_LINK (QuestionLink); | |
| QuestionLink = GetNextNode (&Form->StatementListHead, QuestionLink); | |
| if (Question->QuestionId == OldQuestion->QuestionId) { | |
| Question->ValueChanged = TRUE; | |
| return; | |
| } | |
| } | |
| } | |
| } | |
| /** | |
| Get Value changed status from old formset. | |
| @param NewFormSet FormSet data structure. | |
| @param OldFormSet FormSet data structure. | |
| **/ | |
| VOID | |
| SyncStatusForFormSet ( | |
| IN OUT FORM_BROWSER_FORMSET *NewFormSet, | |
| IN FORM_BROWSER_FORMSET *OldFormSet | |
| ) | |
| { | |
| LIST_ENTRY *Link; | |
| LIST_ENTRY *QuestionLink; | |
| FORM_BROWSER_FORM *Form; | |
| FORM_BROWSER_STATEMENT *Question; | |
| // | |
| // For each form in one formset. | |
| // | |
| Link = GetFirstNode (&OldFormSet->FormListHead); | |
| while (!IsNull (&OldFormSet->FormListHead, Link)) { | |
| Form = FORM_BROWSER_FORM_FROM_LINK (Link); | |
| Link = GetNextNode (&OldFormSet->FormListHead, Link); | |
| // | |
| // for each question in one form. | |
| // | |
| QuestionLink = GetFirstNode (&Form->StatementListHead); | |
| while (!IsNull (&Form->StatementListHead, QuestionLink)) { | |
| Question = FORM_BROWSER_STATEMENT_FROM_LINK (QuestionLink); | |
| QuestionLink = GetNextNode (&Form->StatementListHead, QuestionLink); | |
| if (!Question->ValueChanged) { | |
| continue; | |
| } | |
| // | |
| // Find the same question in new formset and update the value changed flag. | |
| // | |
| SyncStatusForQuestion (NewFormSet, Question); | |
| } | |
| } | |
| } | |
| /** | |
| Get current setting of Questions. | |
| @param FormSet FormSet data structure. | |
| **/ | |
| VOID | |
| InitializeCurrentSetting ( | |
| IN OUT FORM_BROWSER_FORMSET *FormSet | |
| ) | |
| { | |
| LIST_ENTRY *Link; | |
| FORMSET_STORAGE *Storage; | |
| FORM_BROWSER_FORMSET *OldFormSet; | |
| // | |
| // Try to find pre FormSet in the maintain backup list. | |
| // If old formset != NULL, destroy this formset. Add new formset to gBrowserFormSetList. | |
| // | |
| OldFormSet = GetFormSetFromHiiHandle (FormSet->HiiHandle); | |
| if (OldFormSet != NULL) { | |
| SyncStatusForFormSet (FormSet, OldFormSet); | |
| RemoveEntryList (&OldFormSet->Link); | |
| DestroyFormSet (OldFormSet); | |
| } | |
| InsertTailList (&gBrowserFormSetList, &FormSet->Link); | |
| // | |
| // Extract default from IFR binary for no storage questions. | |
| // | |
| ExtractDefault (FormSet, NULL, EFI_HII_DEFAULT_CLASS_STANDARD, FormSetLevel, GetDefaultForNoStorage, NULL, TRUE, FALSE); | |
| // | |
| // Request current settings from Configuration Driver | |
| // | |
| Link = GetFirstNode (&FormSet->StorageListHead); | |
| while (!IsNull (&FormSet->StorageListHead, Link)) { | |
| Storage = FORMSET_STORAGE_FROM_LINK (Link); | |
| LoadStorage (FormSet, Storage); | |
| Link = GetNextNode (&FormSet->StorageListHead, Link); | |
| } | |
| } | |
| /** | |
| 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. | |
| @retval EFI_SUCCESS The function completed successfully. | |
| @retval EFI_NOT_FOUND The specified FormSet could not be found. | |
| **/ | |
| EFI_STATUS | |
| InitializeFormSet ( | |
| IN EFI_HII_HANDLE Handle, | |
| IN OUT EFI_GUID *FormSetGuid, | |
| OUT FORM_BROWSER_FORMSET *FormSet | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| EFI_HANDLE DriverHandle; | |
| 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)); | |
| FormSet->QuestionInited = FALSE; | |
| // | |
| // 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); | |
| return Status; | |
| } | |
| /** | |
| 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; | |
| FORM_ENTRY_INFO *MenuList; | |
| FORM_BROWSER_FORMSET *FormSet; | |
| 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->Selection = gCurrentSelection; | |
| Context->ResetRequired = gResetRequired; | |
| Context->FlagReconnect = gFlagReconnect; | |
| Context->CallbackReconnect = gCallbackReconnect; | |
| Context->ExitRequired = gExitRequired; | |
| Context->HiiHandle = mCurrentHiiHandle; | |
| Context->FormId = mCurrentFormId; | |
| CopyGuid (&Context->FormSetGuid, &mCurrentFormSetGuid); | |
| Context->SystemLevelFormSet = mSystemLevelFormSet; | |
| Context->CurFakeQestId = mCurFakeQestId; | |
| Context->HiiPackageListUpdated = mHiiPackageListUpdated; | |
| Context->FinishRetrieveCall = mFinishRetrieveCall; | |
| // | |
| // Save the menu history data. | |
| // | |
| InitializeListHead(&Context->FormHistoryList); | |
| while (!IsListEmpty (&mPrivateData.FormBrowserEx2.FormViewHistoryHead)) { | |
| MenuList = FORM_ENTRY_INFO_FROM_LINK (mPrivateData.FormBrowserEx2.FormViewHistoryHead.ForwardLink); | |
| RemoveEntryList (&MenuList->Link); | |
| InsertTailList(&Context->FormHistoryList, &MenuList->Link); | |
| } | |
| // | |
| // Save formset list. | |
| // | |
| InitializeListHead(&Context->FormSetList); | |
| while (!IsListEmpty (&gBrowserFormSetList)) { | |
| FormSet = FORM_BROWSER_FORMSET_FROM_LINK (gBrowserFormSetList.ForwardLink); | |
| RemoveEntryList (&FormSet->Link); | |
| InsertTailList(&Context->FormSetList, &FormSet->Link); | |
| } | |
| // | |
| // 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; | |
| FORM_ENTRY_INFO *MenuList; | |
| FORM_BROWSER_FORMSET *FormSet; | |
| 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 | |
| // | |
| gCurrentSelection = Context->Selection; | |
| gResetRequired = Context->ResetRequired; | |
| gFlagReconnect = Context->FlagReconnect; | |
| gCallbackReconnect = Context->CallbackReconnect; | |
| gExitRequired = Context->ExitRequired; | |
| mCurrentHiiHandle = Context->HiiHandle; | |
| mCurrentFormId = Context->FormId; | |
| CopyGuid (&mCurrentFormSetGuid, &Context->FormSetGuid); | |
| mSystemLevelFormSet = Context->SystemLevelFormSet; | |
| mCurFakeQestId = Context->CurFakeQestId; | |
| mHiiPackageListUpdated = Context->HiiPackageListUpdated; | |
| mFinishRetrieveCall = Context->FinishRetrieveCall; | |
| // | |
| // Restore the menu history data. | |
| // | |
| while (!IsListEmpty (&Context->FormHistoryList)) { | |
| MenuList = FORM_ENTRY_INFO_FROM_LINK (Context->FormHistoryList.ForwardLink); | |
| RemoveEntryList (&MenuList->Link); | |
| InsertTailList(&mPrivateData.FormBrowserEx2.FormViewHistoryHead, &MenuList->Link); | |
| } | |
| // | |
| // Restore the Formset data. | |
| // | |
| while (!IsListEmpty (&Context->FormSetList)) { | |
| FormSet = FORM_BROWSER_FORMSET_FROM_LINK (Context->FormSetList.ForwardLink); | |
| RemoveEntryList (&FormSet->Link); | |
| InsertTailList(&gBrowserFormSetList, &FormSet->Link); | |
| } | |
| // | |
| // 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 (mCurrentHiiHandle == Handle) { | |
| return TRUE; | |
| } | |
| // | |
| // Check whether HiiHandle is in BrowserContext. | |
| // | |
| Link = GetFirstNode (&gBrowserContextList); | |
| while (!IsNull (&gBrowserContextList, Link)) { | |
| Context = BROWSER_CONTEXT_FROM_LINK (Link); | |
| if (Context->HiiHandle == Handle) { | |
| // | |
| // HiiHandle is in BrowserContext | |
| // | |
| return TRUE; | |
| } | |
| Link = GetNextNode (&gBrowserContextList, Link); | |
| } | |
| return FALSE; | |
| } | |
| /** | |
| Perform Password check. | |
| Passwork may be encrypted by driver that requires the specific check. | |
| @param Form Form where Password Statement is in. | |
| @param Statement Password statement | |
| @param PasswordString Password string to be checked. It may be NULL. | |
| NULL means to restore password. | |
| "" string can be used to checked whether old password does exist. | |
| @return Status Status of Password check. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| PasswordCheck ( | |
| IN FORM_DISPLAY_ENGINE_FORM *Form, | |
| IN FORM_DISPLAY_ENGINE_STATEMENT *Statement, | |
| IN EFI_STRING PasswordString OPTIONAL | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess; | |
| EFI_BROWSER_ACTION_REQUEST ActionRequest; | |
| EFI_IFR_TYPE_VALUE IfrTypeValue; | |
| FORM_BROWSER_STATEMENT *Question; | |
| ConfigAccess = gCurrentSelection->FormSet->ConfigAccess; | |
| Question = GetBrowserStatement(Statement); | |
| ASSERT (Question != NULL); | |
| if ((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) == EFI_IFR_FLAG_CALLBACK) { | |
| if (ConfigAccess == NULL) { | |
| return EFI_UNSUPPORTED; | |
| } | |
| } else { | |
| if (PasswordString == NULL) { | |
| return EFI_SUCCESS; | |
| } | |
| // | |
| // Check whether has preexisted password. | |
| // | |
| if (PasswordString[0] == 0) { | |
| if (*((CHAR16 *) Question->BufferValue) == 0) { | |
| return EFI_SUCCESS; | |
| } else { | |
| return EFI_NOT_READY; | |
| } | |
| } | |
| // | |
| // Check whether the input password is same as preexisted password. | |
| // | |
| if (StrnCmp (PasswordString, (CHAR16 *) Question->BufferValue, Question->StorageWidth/sizeof (CHAR16)) == 0) { | |
| return EFI_SUCCESS; | |
| } else { | |
| return EFI_NOT_READY; | |
| } | |
| } | |
| // | |
| // Prepare password string in HII database | |
| // | |
| if (PasswordString != NULL) { | |
| IfrTypeValue.string = NewString (PasswordString, gCurrentSelection->FormSet->HiiHandle); | |
| } else { | |
| IfrTypeValue.string = 0; | |
| } | |
| // | |
| // Send password to Configuration Driver for validation | |
| // | |
| Status = ConfigAccess->Callback ( | |
| ConfigAccess, | |
| EFI_BROWSER_ACTION_CHANGING, | |
| Question->QuestionId, | |
| Question->HiiValue.Type, | |
| &IfrTypeValue, | |
| &ActionRequest | |
| ); | |
| // | |
| // Remove password string from HII database | |
| // | |
| if (PasswordString != NULL) { | |
| DeleteString (IfrTypeValue.string, gCurrentSelection->FormSet->HiiHandle); | |
| } | |
| return Status; | |
| } | |
| /** | |
| 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. | |
| @retval EFI_ALREADY_STARTED Key already been registered for one hot key. | |
| **/ | |
| 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; | |
| } | |
| } | |
| if (HotKey != NULL) { | |
| return EFI_ALREADY_STARTED; | |
| } | |
| // | |
| // 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; | |
| } | |
| /** | |
| Check whether the browser data has been modified. | |
| @retval TRUE Browser data is modified. | |
| @retval FALSE No browser data is modified. | |
| **/ | |
| BOOLEAN | |
| EFIAPI | |
| IsBrowserDataModified ( | |
| VOID | |
| ) | |
| { | |
| LIST_ENTRY *Link; | |
| FORM_BROWSER_FORMSET *FormSet; | |
| switch (gBrowserSettingScope) { | |
| case FormLevel: | |
| if (gCurrentSelection == NULL) { | |
| return FALSE; | |
| } | |
| return IsNvUpdateRequiredForForm (gCurrentSelection->Form); | |
| case FormSetLevel: | |
| if (gCurrentSelection == NULL) { | |
| return FALSE; | |
| } | |
| return IsNvUpdateRequiredForFormSet (gCurrentSelection->FormSet); | |
| case SystemLevel: | |
| Link = GetFirstNode (&gBrowserFormSetList); | |
| while (!IsNull (&gBrowserFormSetList, Link)) { | |
| FormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link); | |
| if (!ValidateFormSet(FormSet)) { | |
| continue; | |
| } | |
| if (IsNvUpdateRequiredForFormSet (FormSet)) { | |
| return TRUE; | |
| } | |
| Link = GetNextNode (&gBrowserFormSetList, Link); | |
| } | |
| return FALSE; | |
| default: | |
| return FALSE; | |
| } | |
| } | |
| /** | |
| Execute the action requested by the Action parameter. | |
| @param[in] Action Execute the request action. | |
| @param[in] DefaultId The default Id info when need to load default value. Only used when Action is BROWSER_ACTION_DEFAULT. | |
| @retval EFI_SUCCESS Execute the request action succss. | |
| @retval EFI_INVALID_PARAMETER The input action value is invalid. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| ExecuteAction ( | |
| IN UINT32 Action, | |
| IN UINT16 DefaultId | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| FORM_BROWSER_FORMSET *FormSet; | |
| FORM_BROWSER_FORM *Form; | |
| if (gBrowserSettingScope < SystemLevel && gCurrentSelection == NULL) { | |
| return EFI_NOT_READY; | |
| } | |
| Status = EFI_SUCCESS; | |
| FormSet = NULL; | |
| Form = NULL; | |
| if (gBrowserSettingScope < SystemLevel) { | |
| FormSet = gCurrentSelection->FormSet; | |
| Form = gCurrentSelection->Form; | |
| } | |
| // | |
| // Executet the discard action. | |
| // | |
| if ((Action & BROWSER_ACTION_DISCARD) != 0) { | |
| Status = DiscardForm (FormSet, Form, gBrowserSettingScope); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| } | |
| // | |
| // Executet the difault action. | |
| // | |
| if ((Action & BROWSER_ACTION_DEFAULT) != 0) { | |
| Status = ExtractDefault (FormSet, Form, DefaultId, gBrowserSettingScope, GetDefaultForAll, NULL, FALSE, FALSE); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| UpdateStatementStatus (FormSet, Form, gBrowserSettingScope); | |
| } | |
| // | |
| // Executet the submit action. | |
| // | |
| if ((Action & BROWSER_ACTION_SUBMIT) != 0) { | |
| Status = SubmitForm (FormSet, Form, gBrowserSettingScope); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| } | |
| // | |
| // Executet the reset action. | |
| // | |
| if ((Action & BROWSER_ACTION_RESET) != 0) { | |
| gResetRequired = TRUE; | |
| } | |
| // | |
| // Executet the exit action. | |
| // | |
| if ((Action & BROWSER_ACTION_EXIT) != 0) { | |
| DiscardForm (FormSet, Form, gBrowserSettingScope); | |
| if (gBrowserSettingScope == SystemLevel) { | |
| if (ExitHandlerFunction != NULL) { | |
| ExitHandlerFunction (); | |
| } | |
| } | |
| gExitRequired = TRUE; | |
| } | |
| return Status; | |
| } | |
| /** | |
| 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. | |
| @retval BROWSER_KEEP_CURRENT Browser keep current changes. | |
| **/ | |
| UINT32 | |
| EFIAPI | |
| SaveReminder ( | |
| VOID | |
| ) | |
| { | |
| LIST_ENTRY *Link; | |
| FORM_BROWSER_FORMSET *FormSet; | |
| BOOLEAN IsDataChanged; | |
| UINT32 DataSavedAction; | |
| UINT32 ConfirmRet; | |
| 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 (IsNvUpdateRequiredForFormSet (FormSet)) { | |
| IsDataChanged = TRUE; | |
| break; | |
| } | |
| } | |
| // | |
| // No data is changed. No save is required. | |
| // | |
| if (!IsDataChanged) { | |
| return DataSavedAction; | |
| } | |
| // | |
| // If data is changed, prompt user to save or discard it. | |
| // | |
| do { | |
| ConfirmRet = (UINT32) mFormDisplay->ConfirmDataChange(); | |
| if (ConfirmRet == BROWSER_ACTION_SUBMIT) { | |
| SubmitForm (NULL, NULL, SystemLevel); | |
| DataSavedAction = BROWSER_SAVE_CHANGES; | |
| break; | |
| } else if (ConfirmRet == BROWSER_ACTION_DISCARD) { | |
| DiscardForm (NULL, NULL, SystemLevel); | |
| DataSavedAction = BROWSER_DISCARD_CHANGES; | |
| break; | |
| } else if (ConfirmRet == BROWSER_ACTION_NONE) { | |
| DataSavedAction = BROWSER_KEEP_CURRENT; | |
| break; | |
| } | |
| } while (1); | |
| return DataSavedAction; | |
| } | |
| /** | |
| Check whether the Reset Required for the browser | |
| @retval TRUE Browser required to reset after exit. | |
| @retval FALSE Browser not need to reset after exit. | |
| **/ | |
| BOOLEAN | |
| EFIAPI | |
| IsResetRequired ( | |
| VOID | |
| ) | |
| { | |
| return gResetRequired; | |
| } | |