From 4d4deaaccb9b39106775d260ea0397c1991b0f04 Mon Sep 17 00:00:00 2001 From: Eric Dong Date: Tue, 8 Jul 2014 06:04:53 +0000 Subject: Refine the save action for the browser. Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Eric Dong Reviewed-by: Liming Gao git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@15639 6f19259b-4bc3-4df7-8a09-765794883524 --- MdeModulePkg/Include/Protocol/DisplayProtocol.h | 21 +- MdeModulePkg/Include/Protocol/FormBrowserEx.h | 3 +- .../Universal/DisplayEngineDxe/FormDisplay.c | 131 ++- .../Universal/DisplayEngineDxe/FormDisplay.h | 2 + .../Universal/DisplayEngineDxe/FormDisplayStr.uni | Bin 8660 -> 10844 bytes MdeModulePkg/Universal/SetupBrowserDxe/IfrParse.c | 6 + .../Universal/SetupBrowserDxe/Presentation.c | 30 +- MdeModulePkg/Universal/SetupBrowserDxe/Setup.c | 912 +++++++++++++++++---- MdeModulePkg/Universal/SetupBrowserDxe/Setup.h | 34 +- 9 files changed, 930 insertions(+), 209 deletions(-) (limited to 'MdeModulePkg') diff --git a/MdeModulePkg/Include/Protocol/DisplayProtocol.h b/MdeModulePkg/Include/Protocol/DisplayProtocol.h index 664c227..d49c625 100644 --- a/MdeModulePkg/Include/Protocol/DisplayProtocol.h +++ b/MdeModulePkg/Include/Protocol/DisplayProtocol.h @@ -1,7 +1,7 @@ /** @file FormDiplay protocol to show Form -Copyright (c) 2013, Intel Corporation. All rights reserved.
+Copyright (c) 2013 - 2014, Intel Corporation. All rights reserved.
This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License that accompanies this distribution. The full text of the license may be found at @@ -29,15 +29,16 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. // #define BROWSER_ACTION_FORM_EXIT BIT17 -#define BROWSER_SUCCESS 0x0 -#define BROWSER_ERROR BIT31 -#define BROWSER_SUBMIT_FAIL BROWSER_ERROR | 0x01 -#define BROWSER_NO_SUBMIT_IF BROWSER_ERROR | 0x02 -#define BROWSER_FORM_NOT_FOUND BROWSER_ERROR | 0x03 -#define BROWSER_FORM_SUPPRESS BROWSER_ERROR | 0x04 -#define BROWSER_PROTOCOL_NOT_FOUND BROWSER_ERROR | 0x05 -#define BROWSER_INCONSISTENT_IF BROWSER_ERROR | 0x06 -#define BROWSER_WARNING_IF BROWSER_ERROR | 0x07 +#define BROWSER_SUCCESS 0x0 +#define BROWSER_ERROR BIT31 +#define BROWSER_SUBMIT_FAIL BROWSER_ERROR | 0x01 +#define BROWSER_NO_SUBMIT_IF BROWSER_ERROR | 0x02 +#define BROWSER_FORM_NOT_FOUND BROWSER_ERROR | 0x03 +#define BROWSER_FORM_SUPPRESS BROWSER_ERROR | 0x04 +#define BROWSER_PROTOCOL_NOT_FOUND BROWSER_ERROR | 0x05 +#define BROWSER_INCONSISTENT_IF BROWSER_ERROR | 0x06 +#define BROWSER_WARNING_IF BROWSER_ERROR | 0x07 +#define BROWSER_SUBMIT_FAIL_NO_SUBMIT_IF BROWSER_ERROR | 0x08 #define FORM_DISPLAY_ENGINE_STATEMENT_VERSION_1 0x10000 #define FORM_DISPLAY_ENGINE_VERSION_1 0x10000 diff --git a/MdeModulePkg/Include/Protocol/FormBrowserEx.h b/MdeModulePkg/Include/Protocol/FormBrowserEx.h index 3bb64c6..ef3e8cb 100644 --- a/MdeModulePkg/Include/Protocol/FormBrowserEx.h +++ b/MdeModulePkg/Include/Protocol/FormBrowserEx.h @@ -2,7 +2,7 @@ Extension Form Browser Protocol provides the services that can be used to register the different hot keys for the standard Browser actions described in UEFI specification. -Copyright (c) 2011, Intel Corporation. All rights reserved.
+Copyright (c) 2011 - 2014, Intel Corporation. All rights reserved.
This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License that accompanies this distribution. The full text of the license may be found at @@ -39,6 +39,7 @@ typedef struct _EFI_FORM_BROWSER_EXTENSION_PROTOCOL EFI_FORM_BROWSER_EXTENSION #define BROWSER_ACTION_SUBMIT BIT2 #define BROWSER_ACTION_RESET BIT3 #define BROWSER_ACTION_EXIT BIT4 +#define BROWSER_ACTION_GOTO BIT5 // // Scope for Browser action. It may be Form, FormSet or System level. diff --git a/MdeModulePkg/Universal/DisplayEngineDxe/FormDisplay.c b/MdeModulePkg/Universal/DisplayEngineDxe/FormDisplay.c index df0fbfe..6d0dd25 100644 --- a/MdeModulePkg/Universal/DisplayEngineDxe/FormDisplay.c +++ b/MdeModulePkg/Universal/DisplayEngineDxe/FormDisplay.c @@ -117,6 +117,12 @@ CHAR16 *gFormNotFound; CHAR16 *gNoSubmitIf; CHAR16 *gBrwoserError; CHAR16 *gSaveFailed; +CHAR16 *gNoSubmitIfFailed; +CHAR16 *gSaveProcess; +CHAR16 *gSaveNoSubmitProcess; +CHAR16 *gDiscardChange; +CHAR16 *gJumpToFormSet; +CHAR16 *gCheckError; CHAR16 *gPromptForData; CHAR16 *gPromptForPassword; CHAR16 *gPromptForNewPassword; @@ -186,6 +192,12 @@ InitializeDisplayStrings ( { mUnknownString = GetToken (STRING_TOKEN (UNKNOWN_STRING), gHiiHandle); gSaveFailed = GetToken (STRING_TOKEN (SAVE_FAILED), gHiiHandle); + gNoSubmitIfFailed = GetToken (STRING_TOKEN (NO_SUBMIT_IF_CHECK_FAILED), gHiiHandle); + gSaveProcess = GetToken (STRING_TOKEN (DISCARD_OR_JUMP), gHiiHandle); + gSaveNoSubmitProcess = GetToken (STRING_TOKEN (DISCARD_OR_CHECK), gHiiHandle); + gDiscardChange = GetToken (STRING_TOKEN (DISCARD_OR_JUMP_DISCARD), gHiiHandle); + gJumpToFormSet = GetToken (STRING_TOKEN (DISCARD_OR_JUMP_JUMP), gHiiHandle); + gCheckError = GetToken (STRING_TOKEN (DISCARD_OR_CHECK_CHECK), gHiiHandle); gPromptForData = GetToken (STRING_TOKEN (PROMPT_FOR_DATA), gHiiHandle); gPromptForPassword = GetToken (STRING_TOKEN (PROMPT_FOR_PASSWORD), gHiiHandle); gPromptForNewPassword = GetToken (STRING_TOKEN (PROMPT_FOR_NEW_PASSWORD), gHiiHandle); @@ -216,6 +228,12 @@ FreeDisplayStrings ( FreePool (mUnknownString); FreePool (gEmptyString); FreePool (gSaveFailed); + FreePool (gNoSubmitIfFailed); + FreePool (gSaveProcess); + FreePool (gSaveNoSubmitProcess); + FreePool (gDiscardChange); + FreePool (gJumpToFormSet); + FreePool (gCheckError); FreePool (gPromptForData); FreePool (gPromptForPassword); FreePool (gPromptForNewPassword); @@ -3208,6 +3226,9 @@ BrowserStatusProcess ( WARNING_IF_CONTEXT EventContext; EFI_IFR_OP_HEADER *OpCodeBuf; EFI_STRING_ID StringToken; + CHAR16 DiscardChange; + CHAR16 JumpToFormSet; + CHAR16 *PrintString; if (gFormData->BrowserStatus == BROWSER_SUCCESS) { return; @@ -3263,63 +3284,95 @@ BrowserStatusProcess ( ErrorInfo = gProtocolNotFound; break; + case BROWSER_SUBMIT_FAIL_NO_SUBMIT_IF: + ErrorInfo = gNoSubmitIfFailed; + break; + default: ErrorInfo = gBrwoserError; break; } } - if (TimeOut == 0) { + switch (gFormData->BrowserStatus) { + case BROWSER_SUBMIT_FAIL: + case BROWSER_SUBMIT_FAIL_NO_SUBMIT_IF: + ASSERT (gUserInput != NULL); + if (gFormData->BrowserStatus == (BROWSER_SUBMIT_FAIL)) { + PrintString = gSaveProcess; + JumpToFormSet = gJumpToFormSet[0]; + } else { + PrintString = gSaveNoSubmitProcess; + JumpToFormSet = gCheckError[0]; + } + DiscardChange = gDiscardChange[0]; + do { - CreateDialog (&Key, gEmptyString, ErrorInfo, gPressEnter, gEmptyString, NULL); - } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN); - } else { - Status = gBS->CreateEvent (EVT_NOTIFY_WAIT, TPL_CALLBACK, EmptyEventProcess, NULL, &TimeOutEvent); - ASSERT_EFI_ERROR (Status); + CreateDialog (&Key, gEmptyString, ErrorInfo, PrintString, gEmptyString, NULL); + } while (((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) != (DiscardChange | UPPER_LOWER_CASE_OFFSET)) && + ((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) != (JumpToFormSet | UPPER_LOWER_CASE_OFFSET))); - EventContext.SyncEvent = TimeOutEvent; - EventContext.TimeOut = &TimeOut; - EventContext.ErrorInfo = ErrorInfo; + if ((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) == (DiscardChange | UPPER_LOWER_CASE_OFFSET)) { + gUserInput->Action = BROWSER_ACTION_DISCARD; + } else { + gUserInput->Action = BROWSER_ACTION_GOTO; + } + break; - Status = gBS->CreateEvent (EVT_TIMER | EVT_NOTIFY_SIGNAL, TPL_CALLBACK, RefreshTimeOutProcess, &EventContext, &RefreshIntervalEvent); - ASSERT_EFI_ERROR (Status); + default: + if (TimeOut == 0) { + do { + CreateDialog (&Key, gEmptyString, ErrorInfo, gPressEnter, gEmptyString, NULL); + } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN); + } else { + Status = gBS->CreateEvent (EVT_NOTIFY_WAIT, TPL_CALLBACK, EmptyEventProcess, NULL, &TimeOutEvent); + ASSERT_EFI_ERROR (Status); - // - // Show the dialog first to avoid long time not reaction. - // - gBS->SignalEvent (RefreshIntervalEvent); + EventContext.SyncEvent = TimeOutEvent; + EventContext.TimeOut = &TimeOut; + EventContext.ErrorInfo = ErrorInfo; - Status = gBS->SetTimer (RefreshIntervalEvent, TimerPeriodic, ONE_SECOND); - ASSERT_EFI_ERROR (Status); + Status = gBS->CreateEvent (EVT_TIMER | EVT_NOTIFY_SIGNAL, TPL_CALLBACK, RefreshTimeOutProcess, &EventContext, &RefreshIntervalEvent); + ASSERT_EFI_ERROR (Status); - while (TRUE) { - Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key); - if (!EFI_ERROR (Status) && Key.UnicodeChar == CHAR_CARRIAGE_RETURN) { - break; - } + // + // Show the dialog first to avoid long time not reaction. + // + gBS->SignalEvent (RefreshIntervalEvent); + + Status = gBS->SetTimer (RefreshIntervalEvent, TimerPeriodic, ONE_SECOND); + ASSERT_EFI_ERROR (Status); - if (Status != EFI_NOT_READY) { - continue; - } + while (TRUE) { + Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key); + if (!EFI_ERROR (Status) && Key.UnicodeChar == CHAR_CARRIAGE_RETURN) { + break; + } - WaitList[0] = TimeOutEvent; - WaitList[1] = gST->ConIn->WaitForKey; + if (Status != EFI_NOT_READY) { + continue; + } - Status = gBS->WaitForEvent (2, WaitList, &Index); - ASSERT_EFI_ERROR (Status); + WaitList[0] = TimeOutEvent; + WaitList[1] = gST->ConIn->WaitForKey; - if (Index == 0) { - // - // Timeout occur, close the hoot time out event. - // - break; + Status = gBS->WaitForEvent (2, WaitList, &Index); + ASSERT_EFI_ERROR (Status); + + if (Index == 0) { + // + // Timeout occur, close the hoot time out event. + // + break; + } } + + gBS->CloseEvent (TimeOutEvent); + gBS->CloseEvent (RefreshIntervalEvent); } + break; } - gBS->CloseEvent (TimeOutEvent); - gBS->CloseEvent (RefreshIntervalEvent); - if (StringToken != 0) { FreePool (ErrorInfo); } @@ -3357,9 +3410,9 @@ FormDisplay ( // Process the status info first. // BrowserStatusProcess(); - if (UserInputData == NULL) { + if (gFormData->BrowserStatus != BROWSER_SUCCESS) { // - // UserInputData == NULL, means only need to print the error info, return here. + // gFormData->BrowserStatus != BROWSER_SUCCESS, means only need to print the error info, return here. // return EFI_SUCCESS; } diff --git a/MdeModulePkg/Universal/DisplayEngineDxe/FormDisplay.h b/MdeModulePkg/Universal/DisplayEngineDxe/FormDisplay.h index 3f045cc..438e220 100644 --- a/MdeModulePkg/Universal/DisplayEngineDxe/FormDisplay.h +++ b/MdeModulePkg/Universal/DisplayEngineDxe/FormDisplay.h @@ -73,6 +73,8 @@ extern CHAR16 *mUnknownString; #define POPUP_PAD_SPACE_COUNT 5 #define POPUP_FRAME_WIDTH 2 +#define UPPER_LOWER_CASE_OFFSET 0x20 + // // Display definitions // diff --git a/MdeModulePkg/Universal/DisplayEngineDxe/FormDisplayStr.uni b/MdeModulePkg/Universal/DisplayEngineDxe/FormDisplayStr.uni index 0ee7f46..654dbe3 100644 Binary files a/MdeModulePkg/Universal/DisplayEngineDxe/FormDisplayStr.uni and b/MdeModulePkg/Universal/DisplayEngineDxe/FormDisplayStr.uni differ diff --git a/MdeModulePkg/Universal/SetupBrowserDxe/IfrParse.c b/MdeModulePkg/Universal/SetupBrowserDxe/IfrParse.c index 22f257d..946fbb2 100644 --- a/MdeModulePkg/Universal/SetupBrowserDxe/IfrParse.c +++ b/MdeModulePkg/Universal/SetupBrowserDxe/IfrParse.c @@ -913,6 +913,8 @@ DestroyForm ( FreePool (Form->SuppressExpression); } + UiFreeMenuList (&Form->FormViewListHead); + // // Free this Form // @@ -1227,6 +1229,7 @@ ParseOpCodes ( InitializeListHead (&FormSet->StatementListOSF); InitializeListHead (&FormSet->StorageListHead); + InitializeListHead (&FormSet->SaveFailStorageListHead); InitializeListHead (&FormSet->DefaultStoreListHead); InitializeListHead (&FormSet->FormListHead); InitializeListHead (&FormSet->ExpressionListHead); @@ -1604,6 +1607,7 @@ ParseOpCodes ( InitializeListHead (&CurrentForm->ExpressionListHead); InitializeListHead (&CurrentForm->StatementListHead); InitializeListHead (&CurrentForm->ConfigRequestHead); + InitializeListHead (&CurrentForm->FormViewListHead); CurrentForm->FormType = STANDARD_MAP_FORM_TYPE; CopyMem (&CurrentForm->FormId, &((EFI_IFR_FORM *) OpCodeData)->FormId, sizeof (UINT16)); @@ -1645,6 +1649,8 @@ ParseOpCodes ( InitializeListHead (&CurrentForm->ExpressionListHead); InitializeListHead (&CurrentForm->StatementListHead); InitializeListHead (&CurrentForm->ConfigRequestHead); + InitializeListHead (&CurrentForm->FormViewListHead); + CopyMem (&CurrentForm->FormId, &((EFI_IFR_FORM *) OpCodeData)->FormId, sizeof (UINT16)); MapMethod = (EFI_IFR_FORM_MAP_METHOD *) (OpCodeData + sizeof (EFI_IFR_FORM_MAP)); diff --git a/MdeModulePkg/Universal/SetupBrowserDxe/Presentation.c b/MdeModulePkg/Universal/SetupBrowserDxe/Presentation.c index f06b8a2..99a30bc 100644 --- a/MdeModulePkg/Universal/SetupBrowserDxe/Presentation.c +++ b/MdeModulePkg/Universal/SetupBrowserDxe/Presentation.c @@ -905,8 +905,6 @@ ProcessAction ( IN UINT16 DefaultId ) { - EFI_STATUS Status; - // // This is caused by use press ESC, and it should not combine with other action type. // @@ -928,10 +926,7 @@ ProcessAction ( } if ((Action & BROWSER_ACTION_SUBMIT) == BROWSER_ACTION_SUBMIT) { - Status = SubmitForm (gCurrentSelection->FormSet, gCurrentSelection->Form, gBrowserSettingScope); - if (EFI_ERROR (Status)) { - PopupErrorMessage(BROWSER_SUBMIT_FAIL, NULL, NULL); - } + SubmitForm (gCurrentSelection->FormSet, gCurrentSelection->Form, gBrowserSettingScope); } if ((Action & BROWSER_ACTION_RESET) == BROWSER_ACTION_RESET) { @@ -1186,7 +1181,8 @@ ProcessChangedData ( IN BROWSER_SETTING_SCOPE Scope ) { - BOOLEAN RetValue; + BOOLEAN RetValue; + EFI_STATUS Status; RetValue = TRUE; switch (mFormDisplay->ConfirmDataChange()) { @@ -1195,7 +1191,10 @@ ProcessChangedData ( break; case BROWSER_ACTION_SUBMIT: - SubmitForm (Selection->FormSet, Selection->Form, Scope); + Status = SubmitForm (Selection->FormSet, Selection->Form, Scope); + if (EFI_ERROR (Status)) { + RetValue = FALSE; + } break; case BROWSER_ACTION_NONE: @@ -1306,7 +1305,7 @@ ProcessGotoOpCode ( // // Not found the EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL protocol. // - PopupErrorMessage(BROWSER_PROTOCOL_NOT_FOUND, NULL, NULL); + PopupErrorMessage(BROWSER_PROTOCOL_NOT_FOUND, NULL, NULL, NULL); FreePool (StringPtr); return Status; } @@ -1383,7 +1382,7 @@ ProcessGotoOpCode ( // // Form is suppressed. // - PopupErrorMessage(BROWSER_FORM_SUPPRESS, NULL, NULL); + PopupErrorMessage(BROWSER_FORM_SUPPRESS, NULL, NULL, NULL); return EFI_SUCCESS; } } @@ -1630,6 +1629,12 @@ DisplayForm ( gCurrentSelection->FormId, gCurrentSelection->QuestionId); ASSERT (CurrentMenu != NULL); } + + // + // Back up the form view history data for this form. + // + UiCopyMenuList(&gCurrentSelection->Form->FormViewListHead, &mPrivateData.FormBrowserEx2.FormViewHistoryHead); + gCurrentSelection->CurrentMenu = CurrentMenu; // @@ -1660,6 +1665,7 @@ DisplayForm ( // and an valid value has return. // EFI_SUCCESS: Success shows form and get user input in UserInput paramenter. // + ASSERT (gDisplayFormData.BrowserStatus == BROWSER_SUCCESS); Status = mFormDisplay->FormDisplay (&gDisplayFormData, &UserInput); if (EFI_ERROR (Status) && Status != EFI_NOT_FOUND) { FreeDisplayFormData(); @@ -1849,7 +1855,7 @@ FindNextMenu ( // if ((gBrowserSettingScope == FormLevel && IsNvUpdateRequiredForForm (Selection->Form)) || (gBrowserSettingScope == FormSetLevel && IsNvUpdateRequiredForFormSet(Selection->FormSet) && Scope == FormSetLevel)) { - if (!ProcessChangedData(Selection, Scope)) { + if (!ProcessChangedData(Selection, gBrowserSettingScope)) { return FALSE; } } @@ -2309,7 +2315,7 @@ SetupBrowser ( // // Form is suppressed. // - PopupErrorMessage(BROWSER_FORM_SUPPRESS, NULL, NULL); + PopupErrorMessage(BROWSER_FORM_SUPPRESS, NULL, NULL, NULL); Status = EFI_NOT_FOUND; goto Done; } diff --git a/MdeModulePkg/Universal/SetupBrowserDxe/Setup.c b/MdeModulePkg/Universal/SetupBrowserDxe/Setup.c index 68bb0bb..c11b325 100644 --- a/MdeModulePkg/Universal/SetupBrowserDxe/Setup.c +++ b/MdeModulePkg/Universal/SetupBrowserDxe/Setup.c @@ -50,7 +50,9 @@ LIST_ENTRY gBrowserContextList = INITIALIZE_LIST_HEAD_VARIABLE (gBrowserCon 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; BROWSER_SETTING_SCOPE gBrowserSettingScope = FormSetLevel; @@ -244,6 +246,45 @@ UiFreeMenuList ( } /** + 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. **/ @@ -315,18 +356,21 @@ LoadAllHiiFormset ( 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. **/ -VOID +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; @@ -343,8 +387,12 @@ PopupErrorMessage ( // gDisplayFormData.ErrorString = ErrorString; gDisplayFormData.BrowserStatus = BrowserStatus; - - mFormDisplay->FormDisplay (&gDisplayFormData, NULL); + + if (HiiHandle != NULL) { + gDisplayFormData.HiiHandle = HiiHandle; + } + + mFormDisplay->FormDisplay (&gDisplayFormData, &UserInputData); gDisplayFormData.BrowserStatus = BROWSER_SUCCESS; gDisplayFormData.ErrorString = NULL; @@ -352,6 +400,8 @@ PopupErrorMessage ( if (OpCode != NULL) { FreePool (Statement); } + + return UserInputData.Action; } /** @@ -2014,7 +2064,13 @@ ValidateQuestion ( break; } - PopupErrorMessage(BrowserStatus, Expression->OpCode, ErrorStr); + 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); @@ -2083,6 +2139,7 @@ ValueChangedValidation ( @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. @@ -2090,8 +2147,9 @@ ValueChangedValidation ( **/ EFI_STATUS NoSubmitCheck ( - IN FORM_BROWSER_FORMSET *FormSet, - IN FORM_BROWSER_FORM *CurrentForm + IN FORM_BROWSER_FORMSET *FormSet, + IN OUT FORM_BROWSER_FORM **CurrentForm, + OUT FORM_BROWSER_STATEMENT **Statement ) { EFI_STATUS Status; @@ -2105,16 +2163,21 @@ NoSubmitCheck ( Form = FORM_BROWSER_FORM_FROM_LINK (LinkForm); LinkForm = GetNextNode (&FormSet->FormListHead, LinkForm); - if (CurrentForm != NULL && CurrentForm != Form) { + 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; } @@ -2128,7 +2191,6 @@ NoSubmitCheck ( /** Fill storage's edit copy with settings requested from Configuration Driver. - @param FormSet FormSet data structure. @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 @@ -2141,7 +2203,6 @@ NoSubmitCheck ( **/ EFI_STATUS SynchronizeStorage ( - IN FORM_BROWSER_FORMSET *FormSet, OUT BROWSER_STORAGE *Storage, IN CHAR16 *ConfigRequest, IN BOOLEAN SyncOrRestore @@ -2336,33 +2397,43 @@ ValidateFormSet ( 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 FindOne; + BOOLEAN OldValue; - FindOne = FALSE; Link = GetFirstNode (&Form->StatementListHead); while (!IsNull (&Form->StatementListHead, Link)) { Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link); - - if (SetFlag && Question->ValueChanged && ((Question->QuestionFlags & EFI_IFR_FLAG_RESET_REQUIRED) != 0)) { - gResetRequired = TRUE; - } + Link = GetNextNode (&Form->StatementListHead, Link); - if (Question->ValueChanged) { - Question->ValueChanged = FALSE; + if (!Question->ValueChanged) { + continue; } - - Link = GetNextNode (&Form->StatementListHead, Link); + + 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 && ((Question->QuestionFlags & EFI_IFR_FLAG_RESET_REQUIRED) != 0)) { + gResetRequired = TRUE; + } } } @@ -2387,11 +2458,8 @@ ValueChangeResetFlagUpdate ( FORM_BROWSER_FORM *CurrentForm; LIST_ENTRY *Link; - // - // Form != NULL means only check form level. - // if (Form != NULL) { - UpdateFlagForForm(SetFlag, Form); + UpdateFlagForForm(SetFlag, FormSet, Form); return; } @@ -2400,8 +2468,233 @@ ValueChangeResetFlagUpdate ( CurrentForm = FORM_BROWSER_FORM_FROM_LINK (Link); Link = GetNextNode (&FormSet->FormListHead, Link); - UpdateFlagForForm(SetFlag, CurrentForm); + 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="); + while (*EndStr != '&') { + EndStr++; + } + + *EndStr = '\0'; + } else { + // + // For Buffer type, Skip the ConfigHdr part. + // + EndStr = StrStr (Progress, L"&OFFSET="); + *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"="); + *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="); + *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 (*RetForm != NULL) { + break; + } } + + // + // restore the OffsetWidth string to the original format. + // + if (Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) { + *EndStr = '='; + } else { + *EndStr = '&'; + } + + return *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; } /** @@ -2456,7 +2749,7 @@ DiscardForm ( // // Prepare // - SynchronizeStorage(FormSet, ConfigInfo->Storage, ConfigInfo->ConfigRequest, FALSE); + SynchronizeStorage(ConfigInfo->Storage, ConfigInfo->ConfigRequest, FALSE); // // Call callback with Changed type to inform the driver. @@ -2464,7 +2757,7 @@ DiscardForm ( SendDiscardInfoToDriver (FormSet, Form); } - ValueChangeResetFlagUpdate (FALSE, NULL, Form); + ValueChangeResetFlagUpdate (FALSE, FormSet, Form); } else if (SettingScope == FormSetLevel && IsNvUpdateRequiredForFormSet (FormSet)) { // @@ -2486,7 +2779,7 @@ DiscardForm ( continue; } - SynchronizeStorage(FormSet, Storage->BrowserStorage, Storage->ConfigRequest, FALSE); + SynchronizeStorage(Storage->BrowserStorage, Storage->ConfigRequest, FALSE); } Link = GetFirstNode (&FormSet->FormListHead); @@ -2538,21 +2831,19 @@ DiscardForm ( } /** - Submit data based on the input Setting level (Form, FormSet or System). + Submit data for a form. @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 ( +SubmitForForm ( IN FORM_BROWSER_FORMSET *FormSet, - IN FORM_BROWSER_FORM *Form, - IN BROWSER_SETTING_SCOPE SettingScope + IN FORM_BROWSER_FORM *Form ) { EFI_STATUS Status; @@ -2560,162 +2851,453 @@ SubmitForm ( EFI_STRING ConfigResp; EFI_STRING Progress; BROWSER_STORAGE *Storage; - FORMSET_STORAGE *FormSetStorage; - FORM_BROWSER_FORMSET *LocalFormSet; 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 + // + 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); + } + // - // Check the supported setting level. + // 4. Process the save failed storage. // - if (SettingScope >= MaxLevel) { - return EFI_UNSUPPORTED; + 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); + } } // - // Validate the Form by NoSubmit check + // 5. Update the NV flag. // - Status = EFI_SUCCESS; - if (SettingScope == FormLevel) { - Status = NoSubmitCheck (FormSet, Form); - } else if (SettingScope == FormSetLevel) { - Status = NoSubmitCheck (FormSet, NULL); + ValueChangeResetFlagUpdate(TRUE, 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; } - 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); + 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); - Storage = ConfigInfo->Storage; - if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) { - continue; - } + if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) { + continue; + } - // - // Skip if there is no RequestElement - // - if (ConfigInfo->ElementCount == 0) { - continue; - } + // + // Skip if there is no RequestElement + // + if (FormSetStorage->ElementCount == 0) { + continue; + } - // - // 1. Prepare - // - Status = StorageToConfigResp (ConfigInfo->Storage, &ConfigResp, ConfigInfo->ConfigRequest, TRUE); - if (EFI_ERROR (Status)) { - return Status; - } + // + // 1. Prepare + // + Status = StorageToConfigResp (Storage, &ConfigResp, FormSetStorage->ConfigRequest, TRUE); + if (EFI_ERROR (Status)) { + return Status; + } - // - // 2. Set value to hii config routine protocol. - // - Status = mHiiConfigRouting->RouteConfig ( - mHiiConfigRouting, - ConfigResp, - &Progress - ); - if (EFI_ERROR (Status)) { - FreePool (ConfigResp); - return Status; + // + // 2. Send 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); - // - // 3. Config success, update storage shadow Buffer, only update the data belong to this form. - // - SynchronizeStorage (FormSet, ConfigInfo->Storage, ConfigInfo->ConfigRequest, TRUE); + continue; } + FreePool (ConfigResp); // - // 4. Update the NV flag. - // - ValueChangeResetFlagUpdate(TRUE, NULL, Form); - } else if (SettingScope == FormSetLevel && IsNvUpdateRequiredForFormSet (FormSet)) { - // - // Submit Buffer storage or Name/Value storage + // 3. Config success, update storage shadow Buffer // - 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; - } + SynchronizeStorage (Storage, FormSetStorage->ConfigRequest, TRUE); + } + // + // 4. Has save fail storage need to handle. + // + if (Form != NULL) { + if (!SkipProcessFail) { // - // Skip if there is no RequestElement + // If not in system level, just handl the save failed storage here. // - if (FormSetStorage->ElementCount == 0) { - continue; - } + 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); - // - // 1. Prepare - // - Status = StorageToConfigResp (Storage, &ConfigResp, FormSetStorage->ConfigRequest, TRUE); - if (EFI_ERROR (Status)) { - return Status; + 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; } // - // 2. Send to Routine config Protocol. + // Free FormSet save fail list. // - Status = mHiiConfigRouting->RouteConfig ( - mHiiConfigRouting, - ConfigResp, - &Progress - ); - if (EFI_ERROR (Status)) { - FreePool (ConfigResp); - return Status; + while (!IsListEmpty (&FormSet->SaveFailStorageListHead)) { + Link = GetFirstNode (&FormSet->SaveFailStorageListHead); + FormSetStorage = FORMSET_STORAGE_FROM_SAVE_FAIL_LINK (Link); + RemoveEntryList (&FormSetStorage->SaveFailLink); } - - FreePool (ConfigResp); + } else { // - // 3. Config success, update storage shadow Buffer + // If in system level, just return error and handle the failed formset later. // - SynchronizeStorage (FormSet, Storage, FormSetStorage->ConfigRequest, TRUE); + Status = EFI_UNSUPPORTED; + } + } + + // + // 5. Update the NV flag. + // + ValueChangeResetFlagUpdate(TRUE, 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; + BROWSER_STORAGE *Storage; + 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; } // - // 4. Update the NV flag. - // - ValueChangeResetFlagUpdate(TRUE, FormSet, NULL); - } else if (SettingScope == SystemLevel) { - // - // System Level Save. - // + // 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; // - // Save changed value for each FormSet in the maintain list. + // Confirm with user, get user input. // - Link = GetFirstNode (&gBrowserFormSetList); - while (!IsNull (&gBrowserFormSetList, Link)) { - LocalFormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link); - Link = GetNextNode (&gBrowserFormSetList, Link); - if (!ValidateFormSet(LocalFormSet)) { - continue; + 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); + Storage = FormSetStorage->BrowserStorage; + 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); + Storage = FormSetStorage->BrowserStorage; + StorageLink = GetNextNode (&LocalFormSet->SaveFailStorageListHead, StorageLink); + + SynchronizeStorage(FormSetStorage->BrowserStorage, FormSetStorage->ConfigRequest, FALSE); + } } - SubmitForm (LocalFormSet, NULL, FormSetLevel); + if (!IsHiiHandleInBrowserContext (LocalFormSet->HiiHandle)) { - // - // Remove maintain backup list after save except for the current using FormSet. - // 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; } } - return EFI_SUCCESS; + // + // 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; } /** @@ -3520,6 +4102,8 @@ IsQuestionValueChanged ( { EFI_HII_VALUE BackUpValue; CHAR8 *BackUpBuffer; + EFI_HII_VALUE BackUpValue2; + CHAR8 *BackUpBuffer2; EFI_STATUS Status; BOOLEAN ValueChanged; UINTN BufferWidth; @@ -3532,6 +4116,7 @@ IsQuestionValueChanged ( } BackUpBuffer = NULL; + BackUpBuffer2 = NULL; ValueChanged = FALSE; switch (Question->Operand) { @@ -3554,12 +4139,45 @@ IsQuestionValueChanged ( } CopyMem (&BackUpValue, &Question->HiiValue, sizeof (EFI_HII_VALUE)); - Status = GetQuestionValue (FormSet, Form, Question, GetValueFrom); - ASSERT_EFI_ERROR(Status); + if (GetValueFrom == GetSetValueWithBothBuffer) { + Status = GetQuestionValue (FormSet, Form, Question, GetSetValueWithEditBuffer); + ASSERT_EFI_ERROR(Status); - if (CompareMem (&BackUpValue, &Question->HiiValue, sizeof (EFI_HII_VALUE)) != 0 || - CompareMem (BackUpBuffer, Question->BufferValue, BufferWidth) != 0) { - ValueChanged = TRUE; + 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)); @@ -3569,6 +4187,10 @@ IsQuestionValueChanged ( FreePool (BackUpBuffer); } + if (BackUpBuffer2 != NULL) { + FreePool (BackUpBuffer2); + } + Question->ValueChanged = ValueChanged; return ValueChanged; @@ -4272,7 +4894,7 @@ LoadStorage ( // // Input NULL for ConfigRequest field means sync all fields from editbuffer to buffer. // - SynchronizeStorage(FormSet, Storage->BrowserStorage, NULL, TRUE); + SynchronizeStorage(Storage->BrowserStorage, NULL, TRUE); if (Storage->BrowserStorage->Type != EFI_HII_VARSTORE_NAME_VALUE) { if (ConfigRequest != NULL) { diff --git a/MdeModulePkg/Universal/SetupBrowserDxe/Setup.h b/MdeModulePkg/Universal/SetupBrowserDxe/Setup.h index d21a6cd..34b6d94 100644 --- a/MdeModulePkg/Universal/SetupBrowserDxe/Setup.h +++ b/MdeModulePkg/Universal/SetupBrowserDxe/Setup.h @@ -164,6 +164,8 @@ typedef struct { UINTN Signature; LIST_ENTRY Link; + LIST_ENTRY SaveFailLink; + UINT16 VarStoreId; BROWSER_STORAGE *BrowserStorage; @@ -174,6 +176,7 @@ typedef struct { } FORMSET_STORAGE; #define FORMSET_STORAGE_FROM_LINK(a) CR (a, FORMSET_STORAGE, Link, FORMSET_STORAGE_SIGNATURE) +#define FORMSET_STORAGE_FROM_SAVE_FAIL_LINK(a) CR (a, FORMSET_STORAGE, SaveFailLink, FORMSET_STORAGE_SIGNATURE) typedef union { EFI_STRING_ID VarName; @@ -373,6 +376,8 @@ typedef struct { UINTN Signature; LIST_ENTRY Link; + LIST_ENTRY SaveFailLink; + CHAR16 *ConfigRequest; // = + UINTN ElementCount; // Number of in the UINTN SpareStrLen; @@ -380,6 +385,7 @@ typedef struct { BROWSER_STORAGE *Storage; } FORM_BROWSER_CONFIG_REQUEST; #define FORM_BROWSER_CONFIG_REQUEST_FROM_LINK(a) CR (a, FORM_BROWSER_CONFIG_REQUEST, Link, FORM_BROWSER_CONFIG_REQUEST_SIGNATURE) +#define FORM_BROWSER_CONFIG_REQUEST_FROM_SAVE_FAIL_LINK(a) CR (a, FORM_BROWSER_CONFIG_REQUEST, SaveFailLink, FORM_BROWSER_CONFIG_REQUEST_SIGNATURE) #define FORM_BROWSER_FORM_SIGNATURE SIGNATURE_32 ('F', 'F', 'R', 'M') #define STANDARD_MAP_FORM_TYPE 0x01 @@ -397,6 +403,7 @@ typedef struct { BOOLEAN ModalForm; // Whether this is a modal form. BOOLEAN Locked; // Whether this form is locked. + LIST_ENTRY FormViewListHead; // List of type FORMID_INFO is Browser View Form History List. LIST_ENTRY ExpressionListHead; // List of Expressions (FORM_EXPRESSION) LIST_ENTRY StatementListHead; // List of Statements and Questions (FORM_BROWSER_STATEMENT) LIST_ENTRY ConfigRequestHead; // List of configreques for all storage. @@ -422,6 +429,8 @@ typedef struct { typedef struct { UINTN Signature; LIST_ENTRY Link; + LIST_ENTRY SaveFailLink; + EFI_HII_HANDLE HiiHandle; // unique id for formset. EFI_HANDLE DriverHandle; EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess; @@ -442,15 +451,20 @@ typedef struct { FORM_BROWSER_STATEMENT *StatementBuffer; // Buffer for all Statements and Questions EXPRESSION_OPCODE *ExpressionBuffer; // Buffer for all Expression OpCode + FORM_BROWSER_FORM *SaveFailForm; // The form which failed to save. + FORM_BROWSER_STATEMENT *SaveFailStatement; // The Statement which failed to save. LIST_ENTRY StatementListOSF; // Statement list out side of the form. LIST_ENTRY StorageListHead; // Storage list (FORMSET_STORAGE) + LIST_ENTRY SaveFailStorageListHead; // Storage list for the save fail storage. LIST_ENTRY DefaultStoreListHead; // DefaultStore list (FORMSET_DEFAULTSTORE) LIST_ENTRY FormListHead; // Form list (FORM_BROWSER_FORM) LIST_ENTRY ExpressionListHead; // List of Expressions (FORM_EXPRESSION) } FORM_BROWSER_FORMSET; #define FORM_BROWSER_FORMSET_FROM_LINK(a) CR (a, FORM_BROWSER_FORMSET, Link, FORM_BROWSER_FORMSET_SIGNATURE) +#define FORM_BROWSER_FORMSET_FROM_SAVE_FAIL_LINK(a) CR (a, FORM_BROWSER_FORMSET, SaveFailLink, FORM_BROWSER_FORMSET_SIGNATURE) + typedef struct { LIST_ENTRY Link; EFI_EVENT RefreshEvent; @@ -534,9 +548,10 @@ typedef enum { // Get/set question value from/to. // typedef enum { - GetSetValueWithEditBuffer, // Get/Set question value from/to editbuffer in the storage. + GetSetValueWithEditBuffer = 0, // Get/Set question value from/to editbuffer in the storage. GetSetValueWithBuffer, // Get/Set question value from/to buffer in the storage. GetSetValueWithHiiDriver, // Get/Set question value from/to hii driver. + GetSetValueWithBothBuffer, // Compare the editbuffer with buffer for this question, not use the question value. GetSetValueWithMax // Invalid value. } GET_SET_QUESTION_VALUE_WITH; @@ -1524,6 +1539,19 @@ UiFindParentMenu ( ); /** + 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 + ); + +/** Search an Option of a Question by its value. @param Question The Question @@ -1713,13 +1741,15 @@ ValueChangedValidation ( Pop up the error info. @param BrowserStatus The input browser status. + @param HiiHandle The HiiHandle for this error opcode. @param OpCode The opcode use to get the erro info and timeout value. @param ErrorString Error string used by BROWSER_NO_SUBMIT_IF. **/ -VOID +UINT32 PopupErrorMessage ( IN UINT32 BrowserStatus, + IN EFI_HII_HANDLE HiiHandle, IN EFI_IFR_OP_HEADER *OpCode, OPTIONAL IN CHAR16 *ErrorString ); -- cgit v1.1