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 --- .../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 +- 7 files changed, 917 insertions(+), 198 deletions(-) (limited to 'MdeModulePkg/Universal') 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