| /** @file | |
| Utility functions for UI presentation. | |
| Copyright (c) 2004 - 2015, Intel Corporation. All rights reserved.<BR> | |
| (C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR> | |
| This program and the accompanying materials | |
| are licensed and made available under the terms and conditions of the BSD License | |
| which accompanies this distribution. The full text of the license may be found at | |
| http://opensource.org/licenses/bsd-license.php | |
| THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, | |
| WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. | |
| **/ | |
| #include "Setup.h" | |
| BOOLEAN mHiiPackageListUpdated; | |
| UI_MENU_SELECTION *gCurrentSelection; | |
| EFI_HII_HANDLE mCurrentHiiHandle = NULL; | |
| EFI_GUID mCurrentFormSetGuid = {0, 0, 0, {0, 0, 0, 0, 0, 0, 0, 0}}; | |
| UINT16 mCurrentFormId = 0; | |
| EFI_EVENT mValueChangedEvent = NULL; | |
| LIST_ENTRY mRefreshEventList = INITIALIZE_LIST_HEAD_VARIABLE (mRefreshEventList); | |
| UINT16 mCurFakeQestId; | |
| FORM_DISPLAY_ENGINE_FORM gDisplayFormData; | |
| BOOLEAN mFinishRetrieveCall = FALSE; | |
| /** | |
| Evaluate all expressions in a Form. | |
| @param FormSet FormSet this Form belongs to. | |
| @param Form The Form. | |
| @retval EFI_SUCCESS The expression evaluated successfuly | |
| **/ | |
| EFI_STATUS | |
| EvaluateFormExpressions ( | |
| IN FORM_BROWSER_FORMSET *FormSet, | |
| IN FORM_BROWSER_FORM *Form | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| LIST_ENTRY *Link; | |
| FORM_EXPRESSION *Expression; | |
| Link = GetFirstNode (&Form->ExpressionListHead); | |
| while (!IsNull (&Form->ExpressionListHead, Link)) { | |
| Expression = FORM_EXPRESSION_FROM_LINK (Link); | |
| Link = GetNextNode (&Form->ExpressionListHead, Link); | |
| if (Expression->Type == EFI_HII_EXPRESSION_INCONSISTENT_IF || | |
| Expression->Type == EFI_HII_EXPRESSION_NO_SUBMIT_IF || | |
| Expression->Type == EFI_HII_EXPRESSION_WARNING_IF || | |
| Expression->Type == EFI_HII_EXPRESSION_WRITE || | |
| (Expression->Type == EFI_HII_EXPRESSION_READ && Form->FormType != STANDARD_MAP_FORM_TYPE)) { | |
| // | |
| // Postpone Form validation to Question editing or Form submitting or Question Write or Question Read for nonstandard form. | |
| // | |
| continue; | |
| } | |
| Status = EvaluateExpression (FormSet, Form, Expression); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| } | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Add empty function for event process function. | |
| @param Event The Event need to be process | |
| @param Context The context of the event. | |
| **/ | |
| VOID | |
| EFIAPI | |
| SetupBrowserEmptyFunction ( | |
| IN EFI_EVENT Event, | |
| IN VOID *Context | |
| ) | |
| { | |
| } | |
| /** | |
| Base on the opcode buffer info to get the display statement. | |
| @param OpCode The input opcode buffer for this statement. | |
| @retval Statement The statement use this opcode buffer. | |
| **/ | |
| FORM_DISPLAY_ENGINE_STATEMENT * | |
| GetDisplayStatement ( | |
| IN EFI_IFR_OP_HEADER *OpCode | |
| ) | |
| { | |
| FORM_DISPLAY_ENGINE_STATEMENT *DisplayStatement; | |
| LIST_ENTRY *Link; | |
| Link = GetFirstNode (&gDisplayFormData.StatementListHead); | |
| while (!IsNull (&gDisplayFormData.StatementListHead, Link)) { | |
| DisplayStatement = FORM_DISPLAY_ENGINE_STATEMENT_FROM_LINK (Link); | |
| if (DisplayStatement->OpCode == OpCode) { | |
| return DisplayStatement; | |
| } | |
| Link = GetNextNode (&gDisplayFormData.StatementListHead, Link); | |
| } | |
| return NULL; | |
| } | |
| /** | |
| Free the refresh event list. | |
| **/ | |
| VOID | |
| FreeRefreshEvent ( | |
| VOID | |
| ) | |
| { | |
| LIST_ENTRY *Link; | |
| FORM_BROWSER_REFRESH_EVENT_NODE *EventNode; | |
| while (!IsListEmpty (&mRefreshEventList)) { | |
| Link = GetFirstNode (&mRefreshEventList); | |
| EventNode = FORM_BROWSER_REFRESH_EVENT_FROM_LINK (Link); | |
| RemoveEntryList (&EventNode->Link); | |
| gBS->CloseEvent (EventNode->RefreshEvent); | |
| FreePool (EventNode); | |
| } | |
| } | |
| /** | |
| Check whether this statement value is changed. If yes, update the statement value and return TRUE; | |
| else return FALSE. | |
| @param Statement The statement need to check. | |
| **/ | |
| VOID | |
| UpdateStatement ( | |
| IN OUT FORM_BROWSER_STATEMENT *Statement | |
| ) | |
| { | |
| GetQuestionValue (gCurrentSelection->FormSet, gCurrentSelection->Form, Statement, GetSetValueWithHiiDriver); | |
| // | |
| // Reset FormPackage update flag | |
| // | |
| mHiiPackageListUpdated = FALSE; | |
| // | |
| // Question value may be changed, need invoke its Callback() | |
| // | |
| ProcessCallBackFunction (gCurrentSelection, gCurrentSelection->FormSet, gCurrentSelection->Form, Statement, EFI_BROWSER_ACTION_RETRIEVE, FALSE); | |
| if (mHiiPackageListUpdated) { | |
| // | |
| // Package list is updated, force to reparse IFR binary of target Formset | |
| // | |
| mHiiPackageListUpdated = FALSE; | |
| gCurrentSelection->Action = UI_ACTION_REFRESH_FORMSET; | |
| } | |
| } | |
| /** | |
| Refresh the question which has refresh guid event attribute. | |
| @param Event The event which has this function related. | |
| @param Context The input context info related to this event or the status code return to the caller. | |
| **/ | |
| VOID | |
| EFIAPI | |
| RefreshEventNotifyForStatement( | |
| IN EFI_EVENT Event, | |
| IN VOID *Context | |
| ) | |
| { | |
| FORM_BROWSER_STATEMENT *Statement; | |
| Statement = (FORM_BROWSER_STATEMENT *)Context; | |
| UpdateStatement(Statement); | |
| gBS->SignalEvent (mValueChangedEvent); | |
| } | |
| /** | |
| Refresh the questions within this form. | |
| @param Event The event which has this function related. | |
| @param Context The input context info related to this event or the status code return to the caller. | |
| **/ | |
| VOID | |
| EFIAPI | |
| RefreshEventNotifyForForm( | |
| IN EFI_EVENT Event, | |
| IN VOID *Context | |
| ) | |
| { | |
| gCurrentSelection->Action = UI_ACTION_REFRESH_FORMSET; | |
| gBS->SignalEvent (mValueChangedEvent); | |
| } | |
| /** | |
| Create refresh hook event for statement which has refresh event or interval. | |
| @param Statement The statement need to check. | |
| **/ | |
| VOID | |
| CreateRefreshEventForStatement ( | |
| IN FORM_BROWSER_STATEMENT *Statement | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| EFI_EVENT RefreshEvent; | |
| FORM_BROWSER_REFRESH_EVENT_NODE *EventNode; | |
| // | |
| // If question has refresh guid, create the notify function. | |
| // | |
| Status = gBS->CreateEventEx ( | |
| EVT_NOTIFY_SIGNAL, | |
| TPL_CALLBACK, | |
| RefreshEventNotifyForStatement, | |
| Statement, | |
| &Statement->RefreshGuid, | |
| &RefreshEvent); | |
| ASSERT_EFI_ERROR (Status); | |
| EventNode = AllocateZeroPool (sizeof (FORM_BROWSER_REFRESH_EVENT_NODE)); | |
| ASSERT (EventNode != NULL); | |
| EventNode->RefreshEvent = RefreshEvent; | |
| InsertTailList(&mRefreshEventList, &EventNode->Link); | |
| } | |
| /** | |
| Create refresh hook event for form which has refresh event or interval. | |
| @param Form The form need to check. | |
| **/ | |
| VOID | |
| CreateRefreshEventForForm ( | |
| IN FORM_BROWSER_FORM *Form | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| EFI_EVENT RefreshEvent; | |
| FORM_BROWSER_REFRESH_EVENT_NODE *EventNode; | |
| // | |
| // If question has refresh guid, create the notify function. | |
| // | |
| Status = gBS->CreateEventEx ( | |
| EVT_NOTIFY_SIGNAL, | |
| TPL_CALLBACK, | |
| RefreshEventNotifyForForm, | |
| Form, | |
| &Form->RefreshGuid, | |
| &RefreshEvent); | |
| ASSERT_EFI_ERROR (Status); | |
| EventNode = AllocateZeroPool (sizeof (FORM_BROWSER_REFRESH_EVENT_NODE)); | |
| ASSERT (EventNode != NULL); | |
| EventNode->RefreshEvent = RefreshEvent; | |
| InsertTailList(&mRefreshEventList, &EventNode->Link); | |
| } | |
| /** | |
| Initialize the Display statement structure data. | |
| @param DisplayStatement Pointer to the display Statement data strucure. | |
| @param Statement The statement need to check. | |
| **/ | |
| VOID | |
| InitializeDisplayStatement ( | |
| IN OUT FORM_DISPLAY_ENGINE_STATEMENT *DisplayStatement, | |
| IN FORM_BROWSER_STATEMENT *Statement | |
| ) | |
| { | |
| LIST_ENTRY *Link; | |
| QUESTION_OPTION *Option; | |
| DISPLAY_QUESTION_OPTION *DisplayOption; | |
| FORM_DISPLAY_ENGINE_STATEMENT *ParentStatement; | |
| DisplayStatement->Signature = FORM_DISPLAY_ENGINE_STATEMENT_SIGNATURE; | |
| DisplayStatement->Version = FORM_DISPLAY_ENGINE_STATEMENT_VERSION_1; | |
| DisplayStatement->OpCode = Statement->OpCode; | |
| InitializeListHead (&DisplayStatement->NestStatementList); | |
| InitializeListHead (&DisplayStatement->OptionListHead); | |
| if ((EvaluateExpressionList(Statement->Expression, FALSE, NULL, NULL) == ExpressGrayOut) || Statement->Locked) { | |
| DisplayStatement->Attribute |= HII_DISPLAY_GRAYOUT; | |
| } | |
| if ((Statement->ValueExpression != NULL) || ((Statement->QuestionFlags & EFI_IFR_FLAG_READ_ONLY) != 0)) { | |
| DisplayStatement->Attribute |= HII_DISPLAY_READONLY; | |
| } | |
| // | |
| // Initilize the option list in statement. | |
| // | |
| Link = GetFirstNode (&Statement->OptionListHead); | |
| while (!IsNull (&Statement->OptionListHead, Link)) { | |
| Option = QUESTION_OPTION_FROM_LINK (Link); | |
| Link = GetNextNode (&Statement->OptionListHead, Link); | |
| if ((Option->SuppressExpression != NULL) && | |
| ((EvaluateExpressionList(Option->SuppressExpression, FALSE, NULL, NULL) == ExpressSuppress))) { | |
| continue; | |
| } | |
| DisplayOption = AllocateZeroPool (sizeof (DISPLAY_QUESTION_OPTION)); | |
| ASSERT (DisplayOption != NULL); | |
| DisplayOption->ImageId = Option->ImageId; | |
| DisplayOption->Signature = DISPLAY_QUESTION_OPTION_SIGNATURE; | |
| DisplayOption->OptionOpCode = Option->OpCode; | |
| InsertTailList(&DisplayStatement->OptionListHead, &DisplayOption->Link); | |
| } | |
| CopyMem (&DisplayStatement->CurrentValue, &Statement->HiiValue, sizeof (EFI_HII_VALUE)); | |
| // | |
| // Some special op code need an extra buffer to save the data. | |
| // Such as string, password, orderedlist... | |
| // | |
| if (Statement->BufferValue != NULL) { | |
| // | |
| // Ordered list opcode may not initilized, get default value here. | |
| // | |
| if (Statement->OpCode->OpCode == EFI_IFR_ORDERED_LIST_OP && GetArrayData (Statement->BufferValue, Statement->ValueType, 0) == 0) { | |
| GetQuestionDefault (gCurrentSelection->FormSet, gCurrentSelection->Form, Statement, 0); | |
| } | |
| DisplayStatement->CurrentValue.Buffer = AllocateCopyPool(Statement->StorageWidth,Statement->BufferValue); | |
| DisplayStatement->CurrentValue.BufferLen = Statement->StorageWidth; | |
| } | |
| DisplayStatement->SettingChangedFlag = Statement->ValueChanged; | |
| // | |
| // Get the highlight statement for current form. | |
| // | |
| if (((gCurrentSelection->QuestionId != 0) && (Statement->QuestionId == gCurrentSelection->QuestionId)) || | |
| ((mCurFakeQestId != 0) && (Statement->FakeQuestionId == mCurFakeQestId))) { | |
| gDisplayFormData.HighLightedStatement = DisplayStatement; | |
| } | |
| // | |
| // Create the refresh event process function. | |
| // | |
| if (!CompareGuid (&Statement->RefreshGuid, &gZeroGuid)) { | |
| CreateRefreshEventForStatement (Statement); | |
| } | |
| // | |
| // For RTC type of date/time, set default refresh interval to be 1 second. | |
| // | |
| if ((Statement->Operand == EFI_IFR_DATE_OP || Statement->Operand == EFI_IFR_TIME_OP) && Statement->Storage == NULL) { | |
| Statement->RefreshInterval = 1; | |
| } | |
| // | |
| // Create the refresh guid hook event. | |
| // If the statement in this form has refresh event or refresh interval, browser will create this event for display engine. | |
| // | |
| if ((!CompareGuid (&Statement->RefreshGuid, &gZeroGuid)) || (Statement->RefreshInterval != 0)) { | |
| gDisplayFormData.FormRefreshEvent = mValueChangedEvent; | |
| } | |
| // | |
| // Save the password check function for later use. | |
| // | |
| if (Statement->Operand == EFI_IFR_PASSWORD_OP) { | |
| DisplayStatement->PasswordCheck = PasswordCheck; | |
| } | |
| // | |
| // If this statement is nest in the subtitle, insert to the host statement. | |
| // else insert to the form it belongs to. | |
| // | |
| if (Statement->ParentStatement != NULL) { | |
| ParentStatement = GetDisplayStatement(Statement->ParentStatement->OpCode); | |
| ASSERT (ParentStatement != NULL); | |
| InsertTailList(&ParentStatement->NestStatementList, &DisplayStatement->DisplayLink); | |
| } else { | |
| InsertTailList(&gDisplayFormData.StatementListHead, &DisplayStatement->DisplayLink); | |
| } | |
| } | |
| /** | |
| Process for the refresh interval statement. | |
| @param Event The Event need to be process | |
| @param Context The context of the event. | |
| **/ | |
| VOID | |
| EFIAPI | |
| RefreshIntervalProcess ( | |
| IN EFI_EVENT Event, | |
| IN VOID *Context | |
| ) | |
| { | |
| FORM_BROWSER_STATEMENT *Statement; | |
| LIST_ENTRY *Link; | |
| Link = GetFirstNode (&gCurrentSelection->Form->StatementListHead); | |
| while (!IsNull (&gCurrentSelection->Form->StatementListHead, Link)) { | |
| Statement = FORM_BROWSER_STATEMENT_FROM_LINK (Link); | |
| Link = GetNextNode (&gCurrentSelection->Form->StatementListHead, Link); | |
| if (Statement->RefreshInterval == 0) { | |
| continue; | |
| } | |
| UpdateStatement(Statement); | |
| } | |
| gBS->SignalEvent (mValueChangedEvent); | |
| } | |
| /** | |
| Make a copy of the global hotkey info. | |
| **/ | |
| VOID | |
| UpdateHotkeyList ( | |
| VOID | |
| ) | |
| { | |
| BROWSER_HOT_KEY *HotKey; | |
| BROWSER_HOT_KEY *CopyKey; | |
| LIST_ENTRY *Link; | |
| Link = GetFirstNode (&gBrowserHotKeyList); | |
| while (!IsNull (&gBrowserHotKeyList, Link)) { | |
| HotKey = BROWSER_HOT_KEY_FROM_LINK (Link); | |
| CopyKey = AllocateCopyPool(sizeof (BROWSER_HOT_KEY), HotKey); | |
| ASSERT (CopyKey != NULL); | |
| CopyKey->KeyData = AllocateCopyPool(sizeof (EFI_INPUT_KEY), HotKey->KeyData); | |
| ASSERT (CopyKey->KeyData != NULL); | |
| CopyKey->HelpString = AllocateCopyPool(StrSize (HotKey->HelpString), HotKey->HelpString); | |
| ASSERT (CopyKey->HelpString != NULL); | |
| InsertTailList(&gDisplayFormData.HotKeyListHead, &CopyKey->Link); | |
| Link = GetNextNode (&gBrowserHotKeyList, Link); | |
| } | |
| } | |
| /** | |
| Get the extra question attribute from override question list. | |
| @param QuestionId The question id for this request question. | |
| @retval The attribute for this question or NULL if not found this | |
| question in the list. | |
| **/ | |
| UINT32 | |
| ProcessQuestionExtraAttr ( | |
| IN EFI_QUESTION_ID QuestionId | |
| ) | |
| { | |
| LIST_ENTRY *Link; | |
| QUESTION_ATTRIBUTE_OVERRIDE *QuestionDesc; | |
| // | |
| // Return HII_DISPLAY_NONE if input a invalid question id. | |
| // | |
| if (QuestionId == 0) { | |
| return HII_DISPLAY_NONE; | |
| } | |
| Link = GetFirstNode (&mPrivateData.FormBrowserEx2.OverrideQestListHead); | |
| while (!IsNull (&mPrivateData.FormBrowserEx2.OverrideQestListHead, Link)) { | |
| QuestionDesc = FORM_QUESTION_ATTRIBUTE_OVERRIDE_FROM_LINK (Link); | |
| Link = GetNextNode (&mPrivateData.FormBrowserEx2.OverrideQestListHead, Link); | |
| if ((QuestionDesc->QuestionId == QuestionId) && | |
| (QuestionDesc->FormId == gCurrentSelection->FormId) && | |
| (QuestionDesc->HiiHandle == gCurrentSelection->Handle) && | |
| CompareGuid (&QuestionDesc->FormSetGuid, &gCurrentSelection->FormSetGuid)) { | |
| return QuestionDesc->Attribute; | |
| } | |
| } | |
| return HII_DISPLAY_NONE; | |
| } | |
| /** | |
| Enum all statement in current form, find all the statement can be display and | |
| add to the display form. | |
| **/ | |
| VOID | |
| AddStatementToDisplayForm ( | |
| VOID | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| LIST_ENTRY *Link; | |
| FORM_BROWSER_STATEMENT *Statement; | |
| FORM_DISPLAY_ENGINE_STATEMENT *DisplayStatement; | |
| UINT8 MinRefreshInterval; | |
| EFI_EVENT RefreshIntervalEvent; | |
| FORM_BROWSER_REFRESH_EVENT_NODE *EventNode; | |
| BOOLEAN FormEditable; | |
| UINT32 ExtraAttribute; | |
| MinRefreshInterval = 0; | |
| FormEditable = FALSE; | |
| // | |
| // Process the statement outside the form, these statements are not recognized | |
| // by browser core. | |
| // | |
| Link = GetFirstNode (&gCurrentSelection->FormSet->StatementListOSF); | |
| while (!IsNull (&gCurrentSelection->FormSet->StatementListOSF, Link)) { | |
| Statement = FORM_BROWSER_STATEMENT_FROM_LINK (Link); | |
| Link = GetNextNode (&gCurrentSelection->FormSet->StatementListOSF, Link); | |
| DisplayStatement = AllocateZeroPool (sizeof (FORM_DISPLAY_ENGINE_STATEMENT)); | |
| ASSERT (DisplayStatement != NULL); | |
| DisplayStatement->Signature = FORM_DISPLAY_ENGINE_STATEMENT_SIGNATURE; | |
| DisplayStatement->Version = FORM_DISPLAY_ENGINE_STATEMENT_VERSION_1; | |
| DisplayStatement->OpCode = Statement->OpCode; | |
| InitializeListHead (&DisplayStatement->NestStatementList); | |
| InitializeListHead (&DisplayStatement->OptionListHead); | |
| InsertTailList(&gDisplayFormData.StatementListOSF, &DisplayStatement->DisplayLink); | |
| } | |
| // | |
| // treat formset as statement outside the form,get its opcode. | |
| // | |
| DisplayStatement = AllocateZeroPool (sizeof (FORM_DISPLAY_ENGINE_STATEMENT)); | |
| ASSERT (DisplayStatement != NULL); | |
| DisplayStatement->Signature = FORM_DISPLAY_ENGINE_STATEMENT_SIGNATURE; | |
| DisplayStatement->Version = FORM_DISPLAY_ENGINE_STATEMENT_VERSION_1; | |
| DisplayStatement->OpCode = gCurrentSelection->FormSet->OpCode; | |
| InitializeListHead (&DisplayStatement->NestStatementList); | |
| InitializeListHead (&DisplayStatement->OptionListHead); | |
| InsertTailList(&gDisplayFormData.StatementListOSF, &DisplayStatement->DisplayLink); | |
| // | |
| // Process the statement in this form. | |
| // | |
| Link = GetFirstNode (&gCurrentSelection->Form->StatementListHead); | |
| while (!IsNull (&gCurrentSelection->Form->StatementListHead, Link)) { | |
| Statement = FORM_BROWSER_STATEMENT_FROM_LINK (Link); | |
| Link = GetNextNode (&gCurrentSelection->Form->StatementListHead, Link); | |
| // | |
| // This statement can't be show, skip it. | |
| // | |
| if (EvaluateExpressionList(Statement->Expression, FALSE, NULL, NULL) > ExpressGrayOut) { | |
| continue; | |
| } | |
| // | |
| // Check the extra attribute. | |
| // | |
| ExtraAttribute = ProcessQuestionExtraAttr (Statement->QuestionId); | |
| if ((ExtraAttribute & HII_DISPLAY_SUPPRESS) != 0) { | |
| continue; | |
| } | |
| DisplayStatement = AllocateZeroPool (sizeof (FORM_DISPLAY_ENGINE_STATEMENT)); | |
| ASSERT (DisplayStatement != NULL); | |
| // | |
| // Initialize this statement and add it to the display form. | |
| // | |
| InitializeDisplayStatement(DisplayStatement, Statement); | |
| // | |
| // Set the extra attribute. | |
| // | |
| DisplayStatement->Attribute |= ExtraAttribute; | |
| if (Statement->Storage != NULL) { | |
| FormEditable = TRUE; | |
| } | |
| // | |
| // Get the minimal refresh interval value for later use. | |
| // | |
| if ((Statement->RefreshInterval != 0) && | |
| (MinRefreshInterval == 0 || Statement->RefreshInterval < MinRefreshInterval)) { | |
| MinRefreshInterval = Statement->RefreshInterval; | |
| } | |
| } | |
| // | |
| // Create the periodic timer for refresh interval statement. | |
| // | |
| if (MinRefreshInterval != 0) { | |
| Status = gBS->CreateEvent (EVT_TIMER | EVT_NOTIFY_SIGNAL, TPL_CALLBACK, RefreshIntervalProcess, NULL, &RefreshIntervalEvent); | |
| ASSERT_EFI_ERROR (Status); | |
| Status = gBS->SetTimer (RefreshIntervalEvent, TimerPeriodic, MinRefreshInterval * ONE_SECOND); | |
| ASSERT_EFI_ERROR (Status); | |
| EventNode = AllocateZeroPool (sizeof (FORM_BROWSER_REFRESH_EVENT_NODE)); | |
| ASSERT (EventNode != NULL); | |
| EventNode->RefreshEvent = RefreshIntervalEvent; | |
| InsertTailList(&mRefreshEventList, &EventNode->Link); | |
| } | |
| // | |
| // Create the refresh event process function for Form. | |
| // | |
| if (!CompareGuid (&gCurrentSelection->Form->RefreshGuid, &gZeroGuid)) { | |
| CreateRefreshEventForForm (gCurrentSelection->Form); | |
| if (gDisplayFormData.FormRefreshEvent == NULL) { | |
| gDisplayFormData.FormRefreshEvent = mValueChangedEvent; | |
| } | |
| } | |
| // | |
| // Update hotkey list field. | |
| // | |
| if (gBrowserSettingScope == SystemLevel || FormEditable) { | |
| UpdateHotkeyList(); | |
| } | |
| } | |
| /** | |
| Initialize the SettingChangedFlag variable in the display form. | |
| **/ | |
| VOID | |
| UpdateDataChangedFlag ( | |
| VOID | |
| ) | |
| { | |
| LIST_ENTRY *Link; | |
| FORM_BROWSER_FORMSET *LocalFormSet; | |
| gDisplayFormData.SettingChangedFlag = FALSE; | |
| if (IsNvUpdateRequiredForForm (gCurrentSelection->Form)) { | |
| gDisplayFormData.SettingChangedFlag = TRUE; | |
| return; | |
| } | |
| // | |
| // Base on the system level to check whether need to show the NV flag. | |
| // | |
| switch (gBrowserSettingScope) { | |
| case SystemLevel: | |
| // | |
| // Check the maintain list to see whether there is any change. | |
| // | |
| Link = GetFirstNode (&gBrowserFormSetList); | |
| while (!IsNull (&gBrowserFormSetList, Link)) { | |
| LocalFormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link); | |
| if (IsNvUpdateRequiredForFormSet(LocalFormSet)) { | |
| gDisplayFormData.SettingChangedFlag = TRUE; | |
| return; | |
| } | |
| Link = GetNextNode (&gBrowserFormSetList, Link); | |
| } | |
| break; | |
| case FormSetLevel: | |
| if (IsNvUpdateRequiredForFormSet(gCurrentSelection->FormSet)) { | |
| gDisplayFormData.SettingChangedFlag = TRUE; | |
| return; | |
| } | |
| break; | |
| default: | |
| break; | |
| } | |
| } | |
| /** | |
| Initialize the Display form structure data. | |
| **/ | |
| VOID | |
| InitializeDisplayFormData ( | |
| VOID | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| gDisplayFormData.Signature = FORM_DISPLAY_ENGINE_FORM_SIGNATURE; | |
| gDisplayFormData.Version = FORM_DISPLAY_ENGINE_VERSION_1; | |
| gDisplayFormData.ImageId = 0; | |
| gDisplayFormData.AnimationId = 0; | |
| InitializeListHead (&gDisplayFormData.StatementListHead); | |
| InitializeListHead (&gDisplayFormData.StatementListOSF); | |
| InitializeListHead (&gDisplayFormData.HotKeyListHead); | |
| Status = gBS->CreateEvent ( | |
| EVT_NOTIFY_WAIT, | |
| TPL_CALLBACK, | |
| SetupBrowserEmptyFunction, | |
| NULL, | |
| &mValueChangedEvent | |
| ); | |
| ASSERT_EFI_ERROR (Status); | |
| } | |
| /** | |
| Free the kotkey info saved in form data. | |
| **/ | |
| VOID | |
| FreeHotkeyList ( | |
| VOID | |
| ) | |
| { | |
| BROWSER_HOT_KEY *HotKey; | |
| LIST_ENTRY *Link; | |
| while (!IsListEmpty (&gDisplayFormData.HotKeyListHead)) { | |
| Link = GetFirstNode (&gDisplayFormData.HotKeyListHead); | |
| HotKey = BROWSER_HOT_KEY_FROM_LINK (Link); | |
| RemoveEntryList (&HotKey->Link); | |
| FreePool (HotKey->KeyData); | |
| FreePool (HotKey->HelpString); | |
| FreePool (HotKey); | |
| } | |
| } | |
| /** | |
| Update the Display form structure data. | |
| **/ | |
| VOID | |
| UpdateDisplayFormData ( | |
| VOID | |
| ) | |
| { | |
| gDisplayFormData.FormTitle = gCurrentSelection->Form->FormTitle; | |
| gDisplayFormData.FormId = gCurrentSelection->FormId; | |
| gDisplayFormData.HiiHandle = gCurrentSelection->Handle; | |
| CopyGuid (&gDisplayFormData.FormSetGuid, &gCurrentSelection->FormSetGuid); | |
| gDisplayFormData.Attribute = 0; | |
| gDisplayFormData.Attribute |= gCurrentSelection->Form->ModalForm ? HII_DISPLAY_MODAL : 0; | |
| gDisplayFormData.Attribute |= gCurrentSelection->Form->Locked ? HII_DISPLAY_LOCK : 0; | |
| gDisplayFormData.FormRefreshEvent = NULL; | |
| gDisplayFormData.HighLightedStatement = NULL; | |
| UpdateDataChangedFlag (); | |
| AddStatementToDisplayForm (); | |
| } | |
| /** | |
| Free the Display Statement structure data. | |
| @param StatementList Point to the statement list which need to be free. | |
| **/ | |
| VOID | |
| FreeStatementData ( | |
| LIST_ENTRY *StatementList | |
| ) | |
| { | |
| LIST_ENTRY *Link; | |
| LIST_ENTRY *OptionLink; | |
| FORM_DISPLAY_ENGINE_STATEMENT *Statement; | |
| DISPLAY_QUESTION_OPTION *Option; | |
| // | |
| // Free Statements/Questions | |
| // | |
| while (!IsListEmpty (StatementList)) { | |
| Link = GetFirstNode (StatementList); | |
| Statement = FORM_DISPLAY_ENGINE_STATEMENT_FROM_LINK (Link); | |
| // | |
| // Free Options List | |
| // | |
| while (!IsListEmpty (&Statement->OptionListHead)) { | |
| OptionLink = GetFirstNode (&Statement->OptionListHead); | |
| Option = DISPLAY_QUESTION_OPTION_FROM_LINK (OptionLink); | |
| RemoveEntryList (&Option->Link); | |
| FreePool (Option); | |
| } | |
| // | |
| // Free nest statement List | |
| // | |
| if (!IsListEmpty (&Statement->NestStatementList)) { | |
| FreeStatementData(&Statement->NestStatementList); | |
| } | |
| RemoveEntryList (&Statement->DisplayLink); | |
| FreePool (Statement); | |
| } | |
| } | |
| /** | |
| Free the Display form structure data. | |
| **/ | |
| VOID | |
| FreeDisplayFormData ( | |
| VOID | |
| ) | |
| { | |
| FreeStatementData (&gDisplayFormData.StatementListHead); | |
| FreeStatementData (&gDisplayFormData.StatementListOSF); | |
| FreeRefreshEvent(); | |
| FreeHotkeyList(); | |
| } | |
| /** | |
| Get FORM_BROWSER_STATEMENT from FORM_DISPLAY_ENGINE_STATEMENT based on the OpCode info. | |
| @param DisplayStatement The input FORM_DISPLAY_ENGINE_STATEMENT. | |
| @retval FORM_BROWSER_STATEMENT The return FORM_BROWSER_STATEMENT info. | |
| **/ | |
| FORM_BROWSER_STATEMENT * | |
| GetBrowserStatement ( | |
| IN FORM_DISPLAY_ENGINE_STATEMENT *DisplayStatement | |
| ) | |
| { | |
| FORM_BROWSER_STATEMENT *Statement; | |
| LIST_ENTRY *Link; | |
| Link = GetFirstNode (&gCurrentSelection->Form->StatementListHead); | |
| while (!IsNull (&gCurrentSelection->Form->StatementListHead, Link)) { | |
| Statement = FORM_BROWSER_STATEMENT_FROM_LINK (Link); | |
| if (Statement->OpCode == DisplayStatement->OpCode) { | |
| return Statement; | |
| } | |
| Link = GetNextNode (&gCurrentSelection->Form->StatementListHead, Link); | |
| } | |
| return NULL; | |
| } | |
| /** | |
| Update the ValueChanged status for questions in this form. | |
| @param FormSet FormSet data structure. | |
| @param Form Form data structure. | |
| **/ | |
| VOID | |
| UpdateStatementStatusForForm ( | |
| IN FORM_BROWSER_FORMSET *FormSet, | |
| IN FORM_BROWSER_FORM *Form | |
| ) | |
| { | |
| LIST_ENTRY *Link; | |
| FORM_BROWSER_STATEMENT *Question; | |
| Link = GetFirstNode (&Form->StatementListHead); | |
| while (!IsNull (&Form->StatementListHead, Link)) { | |
| Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link); | |
| Link = GetNextNode (&Form->StatementListHead, Link); | |
| // | |
| // For password opcode, not set the the value changed flag. | |
| // | |
| if (Question->Operand == EFI_IFR_PASSWORD_OP) { | |
| continue; | |
| } | |
| IsQuestionValueChanged(FormSet, Form, Question, GetSetValueWithBuffer); | |
| } | |
| } | |
| /** | |
| Update the ValueChanged status for questions in this formset. | |
| @param FormSet FormSet data structure. | |
| **/ | |
| VOID | |
| UpdateStatementStatusForFormSet ( | |
| IN FORM_BROWSER_FORMSET *FormSet | |
| ) | |
| { | |
| LIST_ENTRY *Link; | |
| FORM_BROWSER_FORM *Form; | |
| Link = GetFirstNode (&FormSet->FormListHead); | |
| while (!IsNull (&FormSet->FormListHead, Link)) { | |
| Form = FORM_BROWSER_FORM_FROM_LINK (Link); | |
| Link = GetNextNode (&FormSet->FormListHead, Link); | |
| UpdateStatementStatusForForm (FormSet, Form); | |
| } | |
| } | |
| /** | |
| Update the ValueChanged status for questions. | |
| @param FormSet FormSet data structure. | |
| @param Form Form data structure. | |
| @param SettingScope Setting Scope for Default action. | |
| **/ | |
| VOID | |
| UpdateStatementStatus ( | |
| IN FORM_BROWSER_FORMSET *FormSet, | |
| IN FORM_BROWSER_FORM *Form, | |
| IN BROWSER_SETTING_SCOPE SettingScope | |
| ) | |
| { | |
| LIST_ENTRY *Link; | |
| FORM_BROWSER_FORMSET *LocalFormSet; | |
| switch (SettingScope) { | |
| case SystemLevel: | |
| Link = GetFirstNode (&gBrowserFormSetList); | |
| while (!IsNull (&gBrowserFormSetList, Link)) { | |
| LocalFormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link); | |
| Link = GetNextNode (&gBrowserFormSetList, Link); | |
| if (!ValidateFormSet(LocalFormSet)) { | |
| continue; | |
| } | |
| UpdateStatementStatusForFormSet (LocalFormSet); | |
| } | |
| break; | |
| case FormSetLevel: | |
| UpdateStatementStatusForFormSet (FormSet); | |
| break; | |
| case FormLevel: | |
| UpdateStatementStatusForForm (FormSet, Form); | |
| break; | |
| default: | |
| break; | |
| } | |
| } | |
| /** | |
| Process the action request in user input. | |
| @param Action The user input action request info. | |
| @param DefaultId The user input default Id info. | |
| @retval EFI_SUCESSS This function always return successfully for now. | |
| **/ | |
| EFI_STATUS | |
| ProcessAction ( | |
| IN UINT32 Action, | |
| IN UINT16 DefaultId | |
| ) | |
| { | |
| // | |
| // This is caused by use press ESC, and it should not combine with other action type. | |
| // | |
| if ((Action & BROWSER_ACTION_FORM_EXIT) == BROWSER_ACTION_FORM_EXIT) { | |
| FindNextMenu (gCurrentSelection, FormLevel); | |
| return EFI_SUCCESS; | |
| } | |
| // | |
| // Below is normal hotkey trigged action, these action maybe combine with each other. | |
| // | |
| if ((Action & BROWSER_ACTION_DISCARD) == BROWSER_ACTION_DISCARD) { | |
| DiscardForm (gCurrentSelection->FormSet, gCurrentSelection->Form, gBrowserSettingScope); | |
| } | |
| if ((Action & BROWSER_ACTION_DEFAULT) == BROWSER_ACTION_DEFAULT) { | |
| ExtractDefault (gCurrentSelection->FormSet, gCurrentSelection->Form, DefaultId, gBrowserSettingScope, GetDefaultForAll, NULL, FALSE, FALSE); | |
| UpdateStatementStatus (gCurrentSelection->FormSet, gCurrentSelection->Form, gBrowserSettingScope); | |
| } | |
| if ((Action & BROWSER_ACTION_SUBMIT) == BROWSER_ACTION_SUBMIT) { | |
| SubmitForm (gCurrentSelection->FormSet, gCurrentSelection->Form, gBrowserSettingScope); | |
| } | |
| if ((Action & BROWSER_ACTION_RESET) == BROWSER_ACTION_RESET) { | |
| gResetRequired = TRUE; | |
| } | |
| if ((Action & BROWSER_ACTION_EXIT) == BROWSER_ACTION_EXIT) { | |
| // | |
| // Form Exit without saving, Similar to ESC Key. | |
| // FormSet Exit without saving, Exit SendForm. | |
| // System Exit without saving, CallExitHandler and Exit SendForm. | |
| // | |
| DiscardForm (gCurrentSelection->FormSet, gCurrentSelection->Form, gBrowserSettingScope); | |
| if (gBrowserSettingScope == FormLevel || gBrowserSettingScope == FormSetLevel) { | |
| FindNextMenu (gCurrentSelection, gBrowserSettingScope); | |
| } else if (gBrowserSettingScope == SystemLevel) { | |
| if (ExitHandlerFunction != NULL) { | |
| ExitHandlerFunction (); | |
| } | |
| gCurrentSelection->Action = UI_ACTION_EXIT; | |
| } | |
| } | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Check whether the formset guid is in this Hii package list. | |
| @param HiiHandle The HiiHandle for this HII package list. | |
| @param FormSetGuid The formset guid for the request formset. | |
| @retval TRUE Find the formset guid. | |
| @retval FALSE Not found the formset guid. | |
| **/ | |
| BOOLEAN | |
| GetFormsetGuidFromHiiHandle ( | |
| IN EFI_HII_HANDLE HiiHandle, | |
| IN EFI_GUID *FormSetGuid | |
| ) | |
| { | |
| EFI_HII_PACKAGE_LIST_HEADER *HiiPackageList; | |
| UINTN BufferSize; | |
| UINT32 Offset; | |
| UINT32 Offset2; | |
| UINT32 PackageListLength; | |
| EFI_HII_PACKAGE_HEADER PackageHeader; | |
| UINT8 *Package; | |
| UINT8 *OpCodeData; | |
| EFI_STATUS Status; | |
| BOOLEAN FindGuid; | |
| BufferSize = 0; | |
| HiiPackageList = NULL; | |
| FindGuid = FALSE; | |
| Status = mHiiDatabase->ExportPackageLists (mHiiDatabase, HiiHandle, &BufferSize, HiiPackageList); | |
| if (Status == EFI_BUFFER_TOO_SMALL) { | |
| HiiPackageList = AllocatePool (BufferSize); | |
| ASSERT (HiiPackageList != NULL); | |
| Status = mHiiDatabase->ExportPackageLists (mHiiDatabase, HiiHandle, &BufferSize, HiiPackageList); | |
| } | |
| if (EFI_ERROR (Status) || HiiPackageList == NULL) { | |
| return FALSE; | |
| } | |
| // | |
| // Get Form package from this HII package List | |
| // | |
| Offset = sizeof (EFI_HII_PACKAGE_LIST_HEADER); | |
| Offset2 = 0; | |
| CopyMem (&PackageListLength, &HiiPackageList->PackageLength, sizeof (UINT32)); | |
| while (Offset < PackageListLength) { | |
| Package = ((UINT8 *) HiiPackageList) + Offset; | |
| CopyMem (&PackageHeader, Package, sizeof (EFI_HII_PACKAGE_HEADER)); | |
| Offset += PackageHeader.Length; | |
| if (PackageHeader.Type == EFI_HII_PACKAGE_FORMS) { | |
| // | |
| // Search FormSet in this Form Package | |
| // | |
| Offset2 = sizeof (EFI_HII_PACKAGE_HEADER); | |
| while (Offset2 < PackageHeader.Length) { | |
| OpCodeData = Package + Offset2; | |
| if (((EFI_IFR_OP_HEADER *) OpCodeData)->OpCode == EFI_IFR_FORM_SET_OP) { | |
| if (CompareGuid (FormSetGuid, (EFI_GUID *)(OpCodeData + sizeof (EFI_IFR_OP_HEADER)))){ | |
| FindGuid = TRUE; | |
| break; | |
| } | |
| } | |
| Offset2 += ((EFI_IFR_OP_HEADER *) OpCodeData)->Length; | |
| } | |
| } | |
| if (FindGuid) { | |
| break; | |
| } | |
| } | |
| FreePool (HiiPackageList); | |
| return FindGuid; | |
| } | |
| /** | |
| Find HII Handle in the HII database associated with given Device Path. | |
| If DevicePath is NULL, then ASSERT. | |
| @param DevicePath Device Path associated with the HII package list | |
| handle. | |
| @param FormsetGuid The formset guid for this formset. | |
| @retval Handle HII package list Handle associated with the Device | |
| Path. | |
| @retval NULL Hii Package list handle is not found. | |
| **/ | |
| EFI_HII_HANDLE | |
| DevicePathToHiiHandle ( | |
| IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, | |
| IN EFI_GUID *FormsetGuid | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| EFI_DEVICE_PATH_PROTOCOL *TmpDevicePath; | |
| UINTN Index; | |
| EFI_HANDLE Handle; | |
| EFI_HANDLE DriverHandle; | |
| EFI_HII_HANDLE *HiiHandles; | |
| EFI_HII_HANDLE HiiHandle; | |
| ASSERT (DevicePath != NULL); | |
| TmpDevicePath = DevicePath; | |
| // | |
| // Locate Device Path Protocol handle buffer | |
| // | |
| Status = gBS->LocateDevicePath ( | |
| &gEfiDevicePathProtocolGuid, | |
| &TmpDevicePath, | |
| &DriverHandle | |
| ); | |
| if (EFI_ERROR (Status) || !IsDevicePathEnd (TmpDevicePath)) { | |
| return NULL; | |
| } | |
| // | |
| // Retrieve all HII Handles from HII database | |
| // | |
| HiiHandles = HiiGetHiiHandles (NULL); | |
| if (HiiHandles == NULL) { | |
| return NULL; | |
| } | |
| // | |
| // Search Hii Handle by Driver Handle | |
| // | |
| HiiHandle = NULL; | |
| for (Index = 0; HiiHandles[Index] != NULL; Index++) { | |
| Status = mHiiDatabase->GetPackageListHandle ( | |
| mHiiDatabase, | |
| HiiHandles[Index], | |
| &Handle | |
| ); | |
| if (!EFI_ERROR (Status) && (Handle == DriverHandle)) { | |
| if (GetFormsetGuidFromHiiHandle(HiiHandles[Index], FormsetGuid)) { | |
| HiiHandle = HiiHandles[Index]; | |
| break; | |
| } | |
| if (HiiHandle != NULL) { | |
| break; | |
| } | |
| } | |
| } | |
| FreePool (HiiHandles); | |
| return HiiHandle; | |
| } | |
| /** | |
| Find HII Handle in the HII database associated with given form set guid. | |
| If FormSetGuid is NULL, then ASSERT. | |
| @param ComparingGuid FormSet Guid associated with the HII package list | |
| handle. | |
| @retval Handle HII package list Handle associated with the Device | |
| Path. | |
| @retval NULL Hii Package list handle is not found. | |
| **/ | |
| EFI_HII_HANDLE | |
| FormSetGuidToHiiHandle ( | |
| EFI_GUID *ComparingGuid | |
| ) | |
| { | |
| EFI_HII_HANDLE *HiiHandles; | |
| EFI_HII_HANDLE HiiHandle; | |
| UINTN Index; | |
| ASSERT (ComparingGuid != NULL); | |
| HiiHandle = NULL; | |
| // | |
| // Get all the Hii handles | |
| // | |
| HiiHandles = HiiGetHiiHandles (NULL); | |
| ASSERT (HiiHandles != NULL); | |
| // | |
| // Search for formset of each class type | |
| // | |
| for (Index = 0; HiiHandles[Index] != NULL; Index++) { | |
| if (GetFormsetGuidFromHiiHandle(HiiHandles[Index], ComparingGuid)) { | |
| HiiHandle = HiiHandles[Index]; | |
| break; | |
| } | |
| if (HiiHandle != NULL) { | |
| break; | |
| } | |
| } | |
| FreePool (HiiHandles); | |
| return HiiHandle; | |
| } | |
| /** | |
| check how to process the changed data in current form or form set. | |
| @param Selection On input, Selection tell setup browser the information | |
| about the Selection, form and formset to be displayed. | |
| On output, Selection return the screen item that is selected | |
| by user. | |
| @param Scope Data save or discard scope, form or formset. | |
| @retval TRUE Success process the changed data, will return to the parent form. | |
| @retval FALSE Reject to process the changed data, will stay at current form. | |
| **/ | |
| BOOLEAN | |
| ProcessChangedData ( | |
| IN OUT UI_MENU_SELECTION *Selection, | |
| IN BROWSER_SETTING_SCOPE Scope | |
| ) | |
| { | |
| BOOLEAN RetValue; | |
| EFI_STATUS Status; | |
| RetValue = TRUE; | |
| switch (mFormDisplay->ConfirmDataChange()) { | |
| case BROWSER_ACTION_DISCARD: | |
| DiscardForm (Selection->FormSet, Selection->Form, Scope); | |
| break; | |
| case BROWSER_ACTION_SUBMIT: | |
| Status = SubmitForm (Selection->FormSet, Selection->Form, Scope); | |
| if (EFI_ERROR (Status)) { | |
| RetValue = FALSE; | |
| } | |
| break; | |
| case BROWSER_ACTION_NONE: | |
| RetValue = FALSE; | |
| break; | |
| default: | |
| // | |
| // if Invalid value return, process same as BROWSER_ACTION_NONE. | |
| // | |
| RetValue = FALSE; | |
| break; | |
| } | |
| return RetValue; | |
| } | |
| /** | |
| Find parent formset menu(the first menu which has different formset) for current menu. | |
| If not find, just return to the first menu. | |
| @param Selection The selection info. | |
| **/ | |
| VOID | |
| FindParentFormSet ( | |
| IN OUT UI_MENU_SELECTION *Selection | |
| ) | |
| { | |
| FORM_ENTRY_INFO *CurrentMenu; | |
| FORM_ENTRY_INFO *ParentMenu; | |
| CurrentMenu = Selection->CurrentMenu; | |
| ParentMenu = UiFindParentMenu(CurrentMenu, FormSetLevel); | |
| if (ParentMenu != NULL) { | |
| CopyMem (&Selection->FormSetGuid, &ParentMenu->FormSetGuid, sizeof (EFI_GUID)); | |
| Selection->Handle = ParentMenu->HiiHandle; | |
| Selection->FormId = ParentMenu->FormId; | |
| Selection->QuestionId = ParentMenu->QuestionId; | |
| } else { | |
| Selection->FormId = CurrentMenu->FormId; | |
| Selection->QuestionId = CurrentMenu->QuestionId; | |
| } | |
| Selection->Statement = NULL; | |
| } | |
| /** | |
| Process the goto op code, update the info in the selection structure. | |
| @param Statement The statement belong to goto op code. | |
| @param Selection The selection info. | |
| @retval EFI_SUCCESS The menu process successfully. | |
| @return Other value if the process failed. | |
| **/ | |
| EFI_STATUS | |
| ProcessGotoOpCode ( | |
| IN OUT FORM_BROWSER_STATEMENT *Statement, | |
| IN OUT UI_MENU_SELECTION *Selection | |
| ) | |
| { | |
| CHAR16 *StringPtr; | |
| EFI_DEVICE_PATH_PROTOCOL *DevicePath; | |
| FORM_BROWSER_FORM *RefForm; | |
| EFI_STATUS Status; | |
| EFI_HII_HANDLE HiiHandle; | |
| Status = EFI_SUCCESS; | |
| StringPtr = NULL; | |
| HiiHandle = NULL; | |
| // | |
| // Prepare the device path check, get the device path info first. | |
| // | |
| if (Statement->HiiValue.Value.ref.DevicePath != 0) { | |
| StringPtr = GetToken (Statement->HiiValue.Value.ref.DevicePath, Selection->FormSet->HiiHandle); | |
| } | |
| // | |
| // Check whether the device path string is a valid string. | |
| // | |
| if (Statement->HiiValue.Value.ref.DevicePath != 0 && StringPtr != NULL && StringPtr[0] != L'\0') { | |
| if (Selection->Form->ModalForm) { | |
| return Status; | |
| } | |
| // | |
| // Goto another Hii Package list | |
| // | |
| if (mPathFromText != NULL) { | |
| DevicePath = mPathFromText->ConvertTextToDevicePath(StringPtr); | |
| if (DevicePath != NULL) { | |
| HiiHandle = DevicePathToHiiHandle (DevicePath, &Statement->HiiValue.Value.ref.FormSetGuid); | |
| FreePool (DevicePath); | |
| } | |
| FreePool (StringPtr); | |
| } else { | |
| // | |
| // Not found the EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL protocol. | |
| // | |
| PopupErrorMessage(BROWSER_PROTOCOL_NOT_FOUND, NULL, NULL, NULL); | |
| FreePool (StringPtr); | |
| return Status; | |
| } | |
| if (HiiHandle != Selection->Handle) { | |
| // | |
| // Goto another Formset, check for uncommitted data | |
| // | |
| if ((gBrowserSettingScope == FormLevel || gBrowserSettingScope == FormSetLevel) && | |
| IsNvUpdateRequiredForFormSet(Selection->FormSet)) { | |
| if (!ProcessChangedData(Selection, FormSetLevel)) { | |
| return EFI_SUCCESS; | |
| } | |
| } | |
| } | |
| Selection->Action = UI_ACTION_REFRESH_FORMSET; | |
| Selection->Handle = HiiHandle; | |
| if (Selection->Handle == NULL) { | |
| // | |
| // If target Hii Handle not found, exit current formset. | |
| // | |
| FindParentFormSet(Selection); | |
| return EFI_SUCCESS; | |
| } | |
| CopyMem (&Selection->FormSetGuid,&Statement->HiiValue.Value.ref.FormSetGuid, sizeof (EFI_GUID)); | |
| Selection->FormId = Statement->HiiValue.Value.ref.FormId; | |
| Selection->QuestionId = Statement->HiiValue.Value.ref.QuestionId; | |
| } else if (!CompareGuid (&Statement->HiiValue.Value.ref.FormSetGuid, &gZeroGuid)) { | |
| if (Selection->Form->ModalForm) { | |
| return Status; | |
| } | |
| if (!CompareGuid (&Statement->HiiValue.Value.ref.FormSetGuid, &Selection->FormSetGuid)) { | |
| // | |
| // Goto another Formset, check for uncommitted data | |
| // | |
| if ((gBrowserSettingScope == FormLevel || gBrowserSettingScope == FormSetLevel) && | |
| IsNvUpdateRequiredForFormSet(Selection->FormSet)) { | |
| if (!ProcessChangedData(Selection, FormSetLevel)) { | |
| return EFI_SUCCESS; | |
| } | |
| } | |
| } | |
| Selection->Action = UI_ACTION_REFRESH_FORMSET; | |
| Selection->Handle = FormSetGuidToHiiHandle(&Statement->HiiValue.Value.ref.FormSetGuid); | |
| if (Selection->Handle == NULL) { | |
| // | |
| // If target Hii Handle not found, exit current formset. | |
| // | |
| FindParentFormSet(Selection); | |
| return EFI_SUCCESS; | |
| } | |
| CopyMem (&Selection->FormSetGuid, &Statement->HiiValue.Value.ref.FormSetGuid, sizeof (EFI_GUID)); | |
| Selection->FormId = Statement->HiiValue.Value.ref.FormId; | |
| Selection->QuestionId = Statement->HiiValue.Value.ref.QuestionId; | |
| } else if (Statement->HiiValue.Value.ref.FormId != 0) { | |
| // | |
| // Goto another Form, check for uncommitted data | |
| // | |
| if (Statement->HiiValue.Value.ref.FormId != Selection->FormId) { | |
| if ((gBrowserSettingScope == FormLevel && IsNvUpdateRequiredForForm(Selection->Form))) { | |
| if (!ProcessChangedData (Selection, FormLevel)) { | |
| return EFI_SUCCESS; | |
| } | |
| } | |
| } | |
| RefForm = IdToForm (Selection->FormSet, Statement->HiiValue.Value.ref.FormId); | |
| if ((RefForm != NULL) && (RefForm->SuppressExpression != NULL)) { | |
| if (EvaluateExpressionList(RefForm->SuppressExpression, TRUE, Selection->FormSet, RefForm) != ExpressFalse) { | |
| // | |
| // Form is suppressed. | |
| // | |
| PopupErrorMessage(BROWSER_FORM_SUPPRESS, NULL, NULL, NULL); | |
| return EFI_SUCCESS; | |
| } | |
| } | |
| Selection->FormId = Statement->HiiValue.Value.ref.FormId; | |
| Selection->QuestionId = Statement->HiiValue.Value.ref.QuestionId; | |
| } else if (Statement->HiiValue.Value.ref.QuestionId != 0) { | |
| Selection->QuestionId = Statement->HiiValue.Value.ref.QuestionId; | |
| } | |
| return Status; | |
| } | |
| /** | |
| Process Question Config. | |
| @param Selection The UI menu selection. | |
| @param Question The Question to be peocessed. | |
| @retval EFI_SUCCESS Question Config process success. | |
| @retval Other Question Config process fail. | |
| **/ | |
| EFI_STATUS | |
| ProcessQuestionConfig ( | |
| IN UI_MENU_SELECTION *Selection, | |
| IN FORM_BROWSER_STATEMENT *Question | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| CHAR16 *ConfigResp; | |
| CHAR16 *Progress; | |
| if (Question->QuestionConfig == 0) { | |
| return EFI_SUCCESS; | |
| } | |
| // | |
| // Get <ConfigResp> | |
| // | |
| ConfigResp = GetToken (Question->QuestionConfig, Selection->FormSet->HiiHandle); | |
| if (ConfigResp == NULL) { | |
| return EFI_NOT_FOUND; | |
| } else if (ConfigResp[0] == L'\0') { | |
| return EFI_SUCCESS; | |
| } | |
| // | |
| // Send config to Configuration Driver | |
| // | |
| Status = mHiiConfigRouting->RouteConfig ( | |
| mHiiConfigRouting, | |
| ConfigResp, | |
| &Progress | |
| ); | |
| return Status; | |
| } | |
| /** | |
| Process the user input data. | |
| @param UserInput The user input data. | |
| @retval EFI_SUCESSS This function always return successfully for now. | |
| **/ | |
| EFI_STATUS | |
| ProcessUserInput ( | |
| IN USER_INPUT *UserInput | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| FORM_BROWSER_STATEMENT *Statement; | |
| Status = EFI_SUCCESS; | |
| Statement = NULL; | |
| // | |
| // When Exit from FormDisplay function, one of the below two cases must be true. | |
| // | |
| ASSERT (UserInput->Action != 0 || UserInput->SelectedStatement != NULL); | |
| // | |
| // Remove the last highligh question id, this id will update when show next form. | |
| // | |
| gCurrentSelection->QuestionId = 0; | |
| if (UserInput->SelectedStatement != NULL){ | |
| Statement = GetBrowserStatement(UserInput->SelectedStatement); | |
| ASSERT (Statement != NULL); | |
| // | |
| // This question is the current user select one,record it and later | |
| // show it as the highlight question. | |
| // | |
| gCurrentSelection->CurrentMenu->QuestionId = Statement->QuestionId; | |
| // | |
| // For statement like text, actio, it not has question id. | |
| // So use FakeQuestionId to save the question. | |
| // | |
| if (gCurrentSelection->CurrentMenu->QuestionId == 0) { | |
| mCurFakeQestId = Statement->FakeQuestionId; | |
| } else { | |
| mCurFakeQestId = 0; | |
| } | |
| } | |
| // | |
| // First process the Action field in USER_INPUT. | |
| // | |
| if (UserInput->Action != 0) { | |
| Status = ProcessAction (UserInput->Action, UserInput->DefaultId); | |
| gCurrentSelection->Statement = NULL; | |
| } else { | |
| ASSERT (Statement != NULL); | |
| gCurrentSelection->Statement = Statement; | |
| switch (Statement->Operand) { | |
| case EFI_IFR_REF_OP: | |
| Status = ProcessGotoOpCode(Statement, gCurrentSelection); | |
| break; | |
| case EFI_IFR_ACTION_OP: | |
| // | |
| // Process the Config string <ConfigResp> | |
| // | |
| Status = ProcessQuestionConfig (gCurrentSelection, Statement); | |
| break; | |
| case EFI_IFR_RESET_BUTTON_OP: | |
| // | |
| // Reset Question to default value specified by DefaultId | |
| // | |
| Status = ExtractDefault (gCurrentSelection->FormSet, NULL, Statement->DefaultId, FormSetLevel, GetDefaultForAll, NULL, FALSE, FALSE); | |
| UpdateStatementStatus (gCurrentSelection->FormSet, NULL, FormSetLevel); | |
| break; | |
| default: | |
| switch (Statement->Operand) { | |
| case EFI_IFR_STRING_OP: | |
| DeleteString(Statement->HiiValue.Value.string, gCurrentSelection->FormSet->HiiHandle); | |
| Statement->HiiValue.Value.string = UserInput->InputValue.Value.string; | |
| CopyMem (Statement->BufferValue, UserInput->InputValue.Buffer, (UINTN) UserInput->InputValue.BufferLen); | |
| FreePool (UserInput->InputValue.Buffer); | |
| break; | |
| case EFI_IFR_PASSWORD_OP: | |
| if (UserInput->InputValue.Buffer == NULL) { | |
| // | |
| // User not input new password, just return. | |
| // | |
| break; | |
| } | |
| DeleteString(Statement->HiiValue.Value.string, gCurrentSelection->FormSet->HiiHandle); | |
| Statement->HiiValue.Value.string = UserInput->InputValue.Value.string; | |
| CopyMem (Statement->BufferValue, UserInput->InputValue.Buffer, (UINTN) UserInput->InputValue.BufferLen); | |
| FreePool (UserInput->InputValue.Buffer); | |
| // | |
| // Two password match, send it to Configuration Driver | |
| // | |
| if ((Statement->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) { | |
| PasswordCheck (NULL, UserInput->SelectedStatement, (CHAR16 *) Statement->BufferValue); | |
| // | |
| // Clean the value after saved it. | |
| // | |
| ZeroMem (Statement->BufferValue, (UINTN) UserInput->InputValue.BufferLen); | |
| HiiSetString (gCurrentSelection->FormSet->HiiHandle, Statement->HiiValue.Value.string, (CHAR16*)Statement->BufferValue, NULL); | |
| } else { | |
| SetQuestionValue (gCurrentSelection->FormSet, gCurrentSelection->Form, Statement, GetSetValueWithHiiDriver); | |
| } | |
| break; | |
| case EFI_IFR_ORDERED_LIST_OP: | |
| CopyMem (Statement->BufferValue, UserInput->InputValue.Buffer, UserInput->InputValue.BufferLen); | |
| break; | |
| default: | |
| CopyMem (&Statement->HiiValue, &UserInput->InputValue, sizeof (EFI_HII_VALUE)); | |
| break; | |
| } | |
| break; | |
| } | |
| } | |
| return Status; | |
| } | |
| /** | |
| Display form and wait for user to select one menu option, then return it. | |
| @retval EFI_SUCESSS This function always return successfully for now. | |
| **/ | |
| EFI_STATUS | |
| DisplayForm ( | |
| VOID | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| USER_INPUT UserInput; | |
| FORM_ENTRY_INFO *CurrentMenu; | |
| ZeroMem (&UserInput, sizeof (USER_INPUT)); | |
| // | |
| // Update the menu history data. | |
| // | |
| CurrentMenu = UiFindMenuList (gCurrentSelection->Handle, &gCurrentSelection->FormSetGuid, gCurrentSelection->FormId); | |
| if (CurrentMenu == NULL) { | |
| // | |
| // Current menu not found, add it to the menu tree | |
| // | |
| CurrentMenu = UiAddMenuList (gCurrentSelection->Handle, &gCurrentSelection->FormSetGuid, | |
| 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; | |
| if (gCurrentSelection->QuestionId == 0) { | |
| // | |
| // Highlight not specified, fetch it from cached menu | |
| // | |
| gCurrentSelection->QuestionId = CurrentMenu->QuestionId; | |
| } | |
| Status = EvaluateFormExpressions (gCurrentSelection->FormSet, gCurrentSelection->Form); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| UpdateDisplayFormData (); | |
| ASSERT (gDisplayFormData.BrowserStatus == BROWSER_SUCCESS); | |
| Status = mFormDisplay->FormDisplay (&gDisplayFormData, &UserInput); | |
| if (EFI_ERROR (Status)) { | |
| FreeDisplayFormData(); | |
| return Status; | |
| } | |
| Status = ProcessUserInput (&UserInput); | |
| FreeDisplayFormData(); | |
| return Status; | |
| } | |
| /** | |
| Functions which are registered to receive notification of | |
| database events have this prototype. The actual event is encoded | |
| in NotifyType. The following table describes how PackageType, | |
| PackageGuid, Handle, and Package are used for each of the | |
| notification types. | |
| @param PackageType Package type of the notification. | |
| @param PackageGuid If PackageType is | |
| EFI_HII_PACKAGE_TYPE_GUID, then this is | |
| the pointer to the GUID from the Guid | |
| field of EFI_HII_PACKAGE_GUID_HEADER. | |
| Otherwise, it must be NULL. | |
| @param Package Points to the package referred to by the | |
| notification Handle The handle of the package | |
| list which contains the specified package. | |
| @param Handle The HII handle. | |
| @param NotifyType The type of change concerning the | |
| database. See | |
| EFI_HII_DATABASE_NOTIFY_TYPE. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| FormUpdateNotify ( | |
| IN UINT8 PackageType, | |
| IN CONST EFI_GUID *PackageGuid, | |
| IN CONST EFI_HII_PACKAGE_HEADER *Package, | |
| IN EFI_HII_HANDLE Handle, | |
| IN EFI_HII_DATABASE_NOTIFY_TYPE NotifyType | |
| ) | |
| { | |
| mHiiPackageListUpdated = TRUE; | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Update the NV flag info for this form set. | |
| @param FormSet FormSet data structure. | |
| **/ | |
| BOOLEAN | |
| IsNvUpdateRequiredForFormSet ( | |
| IN FORM_BROWSER_FORMSET *FormSet | |
| ) | |
| { | |
| LIST_ENTRY *Link; | |
| FORM_BROWSER_FORM *Form; | |
| BOOLEAN RetVal; | |
| // | |
| // Not finished question initialization, return FALSE. | |
| // | |
| if (!FormSet->QuestionInited) { | |
| return FALSE; | |
| } | |
| RetVal = FALSE; | |
| Link = GetFirstNode (&FormSet->FormListHead); | |
| while (!IsNull (&FormSet->FormListHead, Link)) { | |
| Form = FORM_BROWSER_FORM_FROM_LINK (Link); | |
| RetVal = IsNvUpdateRequiredForForm(Form); | |
| if (RetVal) { | |
| break; | |
| } | |
| Link = GetNextNode (&FormSet->FormListHead, Link); | |
| } | |
| return RetVal; | |
| } | |
| /** | |
| Update the NvUpdateRequired flag for a form. | |
| @param Form Form data structure. | |
| **/ | |
| BOOLEAN | |
| IsNvUpdateRequiredForForm ( | |
| IN FORM_BROWSER_FORM *Form | |
| ) | |
| { | |
| LIST_ENTRY *Link; | |
| FORM_BROWSER_STATEMENT *Statement; | |
| Link = GetFirstNode (&Form->StatementListHead); | |
| while (!IsNull (&Form->StatementListHead, Link)) { | |
| Statement = FORM_BROWSER_STATEMENT_FROM_LINK (Link); | |
| if (Statement->ValueChanged) { | |
| return TRUE; | |
| } | |
| Link = GetNextNode (&Form->StatementListHead, Link); | |
| } | |
| return FALSE; | |
| } | |
| /** | |
| Find menu which will show next time. | |
| @param Selection On input, Selection tell setup browser the information | |
| about the Selection, form and formset to be displayed. | |
| On output, Selection return the screen item that is selected | |
| by user. | |
| @param SettingLevel Input Settting level, if it is FormLevel, just exit current form. | |
| else, we need to exit current formset. | |
| @retval TRUE Exit current form. | |
| @retval FALSE User press ESC and keep in current form. | |
| **/ | |
| BOOLEAN | |
| FindNextMenu ( | |
| IN OUT UI_MENU_SELECTION *Selection, | |
| IN BROWSER_SETTING_SCOPE SettingLevel | |
| ) | |
| { | |
| FORM_ENTRY_INFO *CurrentMenu; | |
| FORM_ENTRY_INFO *ParentMenu; | |
| BROWSER_SETTING_SCOPE Scope; | |
| CurrentMenu = Selection->CurrentMenu; | |
| Scope = FormSetLevel; | |
| ParentMenu = UiFindParentMenu(CurrentMenu, SettingLevel); | |
| while (ParentMenu != NULL && !ValidateHiiHandle(ParentMenu->HiiHandle)) { | |
| ParentMenu = UiFindParentMenu(ParentMenu, SettingLevel); | |
| } | |
| if (ParentMenu != NULL) { | |
| if (CompareGuid (&CurrentMenu->FormSetGuid, &ParentMenu->FormSetGuid)) { | |
| Scope = FormLevel; | |
| } else { | |
| Scope = FormSetLevel; | |
| } | |
| } | |
| // | |
| // Form Level Check whether the data is changed. | |
| // | |
| if ((gBrowserSettingScope == FormLevel && IsNvUpdateRequiredForForm (Selection->Form)) || | |
| (gBrowserSettingScope == FormSetLevel && IsNvUpdateRequiredForFormSet(Selection->FormSet) && Scope == FormSetLevel)) { | |
| if (!ProcessChangedData(Selection, gBrowserSettingScope)) { | |
| return FALSE; | |
| } | |
| } | |
| if (ParentMenu != NULL) { | |
| // | |
| // ParentMenu is found. Then, go to it. | |
| // | |
| if (Scope == FormLevel) { | |
| Selection->Action = UI_ACTION_REFRESH_FORM; | |
| } else { | |
| Selection->Action = UI_ACTION_REFRESH_FORMSET; | |
| CopyMem (&Selection->FormSetGuid, &ParentMenu->FormSetGuid, sizeof (EFI_GUID)); | |
| Selection->Handle = ParentMenu->HiiHandle; | |
| } | |
| Selection->Statement = NULL; | |
| Selection->FormId = ParentMenu->FormId; | |
| Selection->QuestionId = ParentMenu->QuestionId; | |
| // | |
| // Clear highlight record for this menu | |
| // | |
| CurrentMenu->QuestionId = 0; | |
| return FALSE; | |
| } | |
| // | |
| // Current in root page, exit the SendForm | |
| // | |
| Selection->Action = UI_ACTION_EXIT; | |
| return TRUE; | |
| } | |
| /** | |
| Reconnect the controller. | |
| @param DriverHandle The controller handle which need to be reconnect. | |
| @retval TRUE do the reconnect behavior success. | |
| @retval FALSE do the reconnect behavior failed. | |
| **/ | |
| BOOLEAN | |
| ReconnectController ( | |
| IN EFI_HANDLE DriverHandle | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| Status = gBS->DisconnectController(DriverHandle, NULL, NULL); | |
| if (!EFI_ERROR (Status)) { | |
| Status = gBS->ConnectController(DriverHandle, NULL, NULL, TRUE); | |
| } | |
| return Status == EFI_SUCCESS; | |
| } | |
| /** | |
| Call the call back function for the question and process the return action. | |
| @param Selection On input, Selection tell setup browser the information | |
| about the Selection, form and formset to be displayed. | |
| On output, Selection return the screen item that is selected | |
| by user. | |
| @param FormSet The formset this question belong to. | |
| @param Form The form this question belong to. | |
| @param Question The Question which need to call. | |
| @param Action The action request. | |
| @param SkipSaveOrDiscard Whether skip save or discard action. | |
| @retval EFI_SUCCESS The call back function excutes successfully. | |
| @return Other value if the call back function failed to excute. | |
| **/ | |
| EFI_STATUS | |
| ProcessCallBackFunction ( | |
| IN OUT UI_MENU_SELECTION *Selection, | |
| IN FORM_BROWSER_FORMSET *FormSet, | |
| IN FORM_BROWSER_FORM *Form, | |
| IN FORM_BROWSER_STATEMENT *Question, | |
| IN EFI_BROWSER_ACTION Action, | |
| IN BOOLEAN SkipSaveOrDiscard | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| EFI_STATUS InternalStatus; | |
| EFI_BROWSER_ACTION_REQUEST ActionRequest; | |
| EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess; | |
| EFI_HII_VALUE *HiiValue; | |
| EFI_IFR_TYPE_VALUE *TypeValue; | |
| FORM_BROWSER_STATEMENT *Statement; | |
| BOOLEAN SubmitFormIsRequired; | |
| BOOLEAN DiscardFormIsRequired; | |
| BOOLEAN NeedExit; | |
| LIST_ENTRY *Link; | |
| BROWSER_SETTING_SCOPE SettingLevel; | |
| EFI_IFR_TYPE_VALUE BackUpValue; | |
| UINT8 *BackUpBuffer; | |
| CHAR16 *NewString; | |
| ConfigAccess = FormSet->ConfigAccess; | |
| SubmitFormIsRequired = FALSE; | |
| SettingLevel = FormSetLevel; | |
| DiscardFormIsRequired = FALSE; | |
| NeedExit = FALSE; | |
| Status = EFI_SUCCESS; | |
| ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE; | |
| BackUpBuffer = NULL; | |
| if (ConfigAccess == NULL) { | |
| return EFI_SUCCESS; | |
| } | |
| Link = GetFirstNode (&Form->StatementListHead); | |
| while (!IsNull (&Form->StatementListHead, Link)) { | |
| Statement = FORM_BROWSER_STATEMENT_FROM_LINK (Link); | |
| Link = GetNextNode (&Form->StatementListHead, Link); | |
| // | |
| // if Question != NULL, only process the question. Else, process all question in this form. | |
| // | |
| if ((Question != NULL) && (Statement != Question)) { | |
| continue; | |
| } | |
| if ((Statement->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != EFI_IFR_FLAG_CALLBACK) { | |
| continue; | |
| } | |
| // | |
| // Check whether Statement is disabled. | |
| // | |
| if (Statement->Expression != NULL) { | |
| if (EvaluateExpressionList(Statement->Expression, TRUE, FormSet, Form) == ExpressDisable) { | |
| continue; | |
| } | |
| } | |
| HiiValue = &Statement->HiiValue; | |
| TypeValue = &HiiValue->Value; | |
| if (HiiValue->Type == EFI_IFR_TYPE_BUFFER) { | |
| // | |
| // For OrderedList, passing in the value buffer to Callback() | |
| // | |
| TypeValue = (EFI_IFR_TYPE_VALUE *) Statement->BufferValue; | |
| } | |
| // | |
| // If EFI_BROWSER_ACTION_CHANGING type, back up the new question value. | |
| // | |
| if (Action == EFI_BROWSER_ACTION_CHANGING) { | |
| if (HiiValue->Type == EFI_IFR_TYPE_BUFFER) { | |
| BackUpBuffer = AllocateCopyPool(Statement->StorageWidth + sizeof(CHAR16), Statement->BufferValue); | |
| ASSERT (BackUpBuffer != NULL); | |
| } else { | |
| CopyMem (&BackUpValue, &HiiValue->Value, sizeof (EFI_IFR_TYPE_VALUE)); | |
| } | |
| } | |
| ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE; | |
| Status = ConfigAccess->Callback ( | |
| ConfigAccess, | |
| Action, | |
| Statement->QuestionId, | |
| HiiValue->Type, | |
| TypeValue, | |
| &ActionRequest | |
| ); | |
| if (!EFI_ERROR (Status)) { | |
| // | |
| // Need to sync the value between Statement->HiiValue->Value and Statement->BufferValue | |
| // | |
| if (HiiValue->Type == EFI_IFR_TYPE_STRING) { | |
| NewString = GetToken (Statement->HiiValue.Value.string, FormSet->HiiHandle); | |
| ASSERT (NewString != NULL); | |
| ASSERT (StrLen (NewString) * sizeof (CHAR16) <= Statement->StorageWidth); | |
| if (StrLen (NewString) * sizeof (CHAR16) <= Statement->StorageWidth) { | |
| CopyMem (Statement->BufferValue, NewString, StrSize (NewString)); | |
| } else { | |
| CopyMem (Statement->BufferValue, NewString, Statement->StorageWidth); | |
| } | |
| FreePool (NewString); | |
| } | |
| // | |
| // Only for EFI_BROWSER_ACTION_CHANGED need to handle this ActionRequest. | |
| // | |
| switch (Action) { | |
| case EFI_BROWSER_ACTION_CHANGED: | |
| switch (ActionRequest) { | |
| case EFI_BROWSER_ACTION_REQUEST_RESET: | |
| DiscardFormIsRequired = TRUE; | |
| gResetRequired = TRUE; | |
| NeedExit = TRUE; | |
| break; | |
| case EFI_BROWSER_ACTION_REQUEST_SUBMIT: | |
| SubmitFormIsRequired = TRUE; | |
| NeedExit = TRUE; | |
| break; | |
| case EFI_BROWSER_ACTION_REQUEST_EXIT: | |
| DiscardFormIsRequired = TRUE; | |
| NeedExit = TRUE; | |
| break; | |
| case EFI_BROWSER_ACTION_REQUEST_FORM_SUBMIT_EXIT: | |
| SubmitFormIsRequired = TRUE; | |
| SettingLevel = FormLevel; | |
| NeedExit = TRUE; | |
| break; | |
| case EFI_BROWSER_ACTION_REQUEST_FORM_DISCARD_EXIT: | |
| DiscardFormIsRequired = TRUE; | |
| SettingLevel = FormLevel; | |
| NeedExit = TRUE; | |
| break; | |
| case EFI_BROWSER_ACTION_REQUEST_FORM_APPLY: | |
| SubmitFormIsRequired = TRUE; | |
| SettingLevel = FormLevel; | |
| break; | |
| case EFI_BROWSER_ACTION_REQUEST_FORM_DISCARD: | |
| DiscardFormIsRequired = TRUE; | |
| SettingLevel = FormLevel; | |
| break; | |
| case EFI_BROWSER_ACTION_REQUEST_RECONNECT: | |
| gCallbackReconnect = TRUE; | |
| break; | |
| default: | |
| break; | |
| } | |
| break; | |
| case EFI_BROWSER_ACTION_CHANGING: | |
| // | |
| // Do the question validation. | |
| // | |
| Status = ValueChangedValidation (gCurrentSelection->FormSet, gCurrentSelection->Form, Statement); | |
| if (!EFI_ERROR (Status)) { | |
| // | |
| //check whether the question value changed compared with edit buffer before updating edit buffer | |
| // if changed, set the ValueChanged flag to TRUE,in order to trig the CHANGED callback function | |
| // | |
| IsQuestionValueChanged(gCurrentSelection->FormSet, gCurrentSelection->Form, Statement, GetSetValueWithEditBuffer); | |
| // | |
| // According the spec, return value from call back of "changing" and | |
| // "retrieve" should update to the question's temp buffer. | |
| // | |
| SetQuestionValue(FormSet, Form, Statement, GetSetValueWithEditBuffer); | |
| } | |
| break; | |
| case EFI_BROWSER_ACTION_RETRIEVE: | |
| // | |
| // According the spec, return value from call back of "changing" and | |
| // "retrieve" should update to the question's temp buffer. | |
| // | |
| SetQuestionValue(FormSet, Form, Statement, GetSetValueWithEditBuffer); | |
| break; | |
| default: | |
| break; | |
| } | |
| } else { | |
| // | |
| // If the callback returns EFI_UNSUPPORTED for EFI_BROWSER_ACTION_CHANGING, | |
| // then the browser will use the value passed to Callback() and ignore the | |
| // value returned by Callback(). | |
| // | |
| if (Action == EFI_BROWSER_ACTION_CHANGING && Status == EFI_UNSUPPORTED) { | |
| if (HiiValue->Type == EFI_IFR_TYPE_BUFFER) { | |
| CopyMem (Statement->BufferValue, BackUpBuffer, Statement->StorageWidth + sizeof(CHAR16)); | |
| } else { | |
| CopyMem (&HiiValue->Value, &BackUpValue, sizeof (EFI_IFR_TYPE_VALUE)); | |
| } | |
| // | |
| // Do the question validation. | |
| // | |
| InternalStatus = ValueChangedValidation (gCurrentSelection->FormSet, gCurrentSelection->Form, Statement); | |
| if (!EFI_ERROR (InternalStatus)) { | |
| // | |
| //check whether the question value changed compared with edit buffer before updating edit buffer | |
| // if changed, set the ValueChanged flag to TRUE,in order to trig the CHANGED callback function | |
| // | |
| IsQuestionValueChanged(gCurrentSelection->FormSet, gCurrentSelection->Form, Statement, GetSetValueWithEditBuffer); | |
| SetQuestionValue(FormSet, Form, Statement, GetSetValueWithEditBuffer); | |
| } | |
| } | |
| // | |
| // According the spec, return fail from call back of "changing" and | |
| // "retrieve", should restore the question's value. | |
| // | |
| if (Action == EFI_BROWSER_ACTION_CHANGING && Status != EFI_UNSUPPORTED) { | |
| if (Statement->Storage != NULL) { | |
| GetQuestionValue(FormSet, Form, Statement, GetSetValueWithEditBuffer); | |
| } else if ((Statement->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) { | |
| ProcessCallBackFunction (Selection, FormSet, Form, Question, EFI_BROWSER_ACTION_RETRIEVE, FALSE); | |
| } | |
| } | |
| if (Action == EFI_BROWSER_ACTION_RETRIEVE) { | |
| GetQuestionValue(FormSet, Form, Statement, GetSetValueWithEditBuffer); | |
| } | |
| if (Status == EFI_UNSUPPORTED) { | |
| // | |
| // If return EFI_UNSUPPORTED, also consider Hii driver suceess deal with it. | |
| // | |
| Status = EFI_SUCCESS; | |
| } | |
| } | |
| if (BackUpBuffer != NULL) { | |
| FreePool (BackUpBuffer); | |
| } | |
| // | |
| // If Question != NULL, means just process one question | |
| // and if code reach here means this question has finished | |
| // processing, so just break. | |
| // | |
| if (Question != NULL) { | |
| break; | |
| } | |
| } | |
| if (gCallbackReconnect && (EFI_BROWSER_ACTION_CHANGED == Action)) { | |
| // | |
| // Confirm changes with user first. | |
| // | |
| if (IsNvUpdateRequiredForFormSet(FormSet)) { | |
| if (BROWSER_ACTION_DISCARD == PopupErrorMessage(BROWSER_RECONNECT_SAVE_CHANGES, NULL, NULL, NULL)) { | |
| gCallbackReconnect = FALSE; | |
| DiscardFormIsRequired = TRUE; | |
| } else { | |
| SubmitFormIsRequired = TRUE; | |
| } | |
| } else { | |
| PopupErrorMessage(BROWSER_RECONNECT_REQUIRED, NULL, NULL, NULL); | |
| } | |
| // | |
| // Exit current formset before do the reconnect. | |
| // | |
| NeedExit = TRUE; | |
| SettingLevel = FormSetLevel; | |
| } | |
| if (SubmitFormIsRequired && !SkipSaveOrDiscard) { | |
| SubmitForm (FormSet, Form, SettingLevel); | |
| } | |
| if (DiscardFormIsRequired && !SkipSaveOrDiscard) { | |
| DiscardForm (FormSet, Form, SettingLevel); | |
| } | |
| if (NeedExit) { | |
| FindNextMenu (Selection, SettingLevel); | |
| } | |
| return Status; | |
| } | |
| /** | |
| Call the retrieve type call back function for one question to get the initialize data. | |
| This function only used when in the initialize stage, because in this stage, the | |
| Selection->Form is not ready. For other case, use the ProcessCallBackFunction instead. | |
| @param ConfigAccess The config access protocol produced by the hii driver. | |
| @param Statement The Question which need to call. | |
| @param FormSet The formset this question belong to. | |
| @retval EFI_SUCCESS The call back function excutes successfully. | |
| @return Other value if the call back function failed to excute. | |
| **/ | |
| EFI_STATUS | |
| ProcessRetrieveForQuestion ( | |
| IN EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess, | |
| IN FORM_BROWSER_STATEMENT *Statement, | |
| IN FORM_BROWSER_FORMSET *FormSet | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| EFI_BROWSER_ACTION_REQUEST ActionRequest; | |
| EFI_HII_VALUE *HiiValue; | |
| EFI_IFR_TYPE_VALUE *TypeValue; | |
| CHAR16 *NewString; | |
| Status = EFI_SUCCESS; | |
| ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE; | |
| if (((Statement->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != EFI_IFR_FLAG_CALLBACK) || ConfigAccess == NULL) { | |
| return EFI_UNSUPPORTED; | |
| } | |
| HiiValue = &Statement->HiiValue; | |
| TypeValue = &HiiValue->Value; | |
| if (HiiValue->Type == EFI_IFR_TYPE_BUFFER) { | |
| // | |
| // For OrderedList, passing in the value buffer to Callback() | |
| // | |
| TypeValue = (EFI_IFR_TYPE_VALUE *) Statement->BufferValue; | |
| } | |
| ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE; | |
| Status = ConfigAccess->Callback ( | |
| ConfigAccess, | |
| EFI_BROWSER_ACTION_RETRIEVE, | |
| Statement->QuestionId, | |
| HiiValue->Type, | |
| TypeValue, | |
| &ActionRequest | |
| ); | |
| if (!EFI_ERROR (Status) && HiiValue->Type == EFI_IFR_TYPE_STRING) { | |
| NewString = GetToken (Statement->HiiValue.Value.string, FormSet->HiiHandle); | |
| ASSERT (NewString != NULL); | |
| ASSERT (StrLen (NewString) * sizeof (CHAR16) <= Statement->StorageWidth); | |
| if (StrLen (NewString) * sizeof (CHAR16) <= Statement->StorageWidth) { | |
| CopyMem (Statement->BufferValue, NewString, StrSize (NewString)); | |
| } else { | |
| CopyMem (Statement->BufferValue, NewString, Statement->StorageWidth); | |
| } | |
| FreePool (NewString); | |
| } | |
| return Status; | |
| } | |
| /** | |
| The worker function that send the displays to the screen. On output, | |
| the selection made by user is returned. | |
| @param Selection On input, Selection tell setup browser the information | |
| about the Selection, form and formset to be displayed. | |
| On output, Selection return the screen item that is selected | |
| by user. | |
| @retval EFI_SUCCESS The page is displayed successfully. | |
| @return Other value if the page failed to be diplayed. | |
| **/ | |
| EFI_STATUS | |
| SetupBrowser ( | |
| IN OUT UI_MENU_SELECTION *Selection | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| LIST_ENTRY *Link; | |
| EFI_HANDLE NotifyHandle; | |
| FORM_BROWSER_STATEMENT *Statement; | |
| EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess; | |
| ConfigAccess = Selection->FormSet->ConfigAccess; | |
| // | |
| // Register notify for Form package update | |
| // | |
| Status = mHiiDatabase->RegisterPackageNotify ( | |
| mHiiDatabase, | |
| EFI_HII_PACKAGE_FORMS, | |
| NULL, | |
| FormUpdateNotify, | |
| EFI_HII_DATABASE_NOTIFY_REMOVE_PACK, | |
| &NotifyHandle | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| // | |
| // Initialize current settings of Questions in this FormSet | |
| // | |
| InitializeCurrentSetting (Selection->FormSet); | |
| // | |
| // Initilize Action field. | |
| // | |
| Selection->Action = UI_ACTION_REFRESH_FORM; | |
| // | |
| // Clean the mCurFakeQestId value is formset refreshed. | |
| // | |
| mCurFakeQestId = 0; | |
| do { | |
| // | |
| // Reset Status to prevent the next break from returning incorrect error status. | |
| // | |
| Status = EFI_SUCCESS; | |
| // | |
| // IFR is updated, force to reparse the IFR binary | |
| // This check is shared by EFI_BROWSER_ACTION_FORM_CLOSE and | |
| // EFI_BROWSER_ACTION_RETRIEVE, so code place here. | |
| // | |
| if (mHiiPackageListUpdated) { | |
| Selection->Action = UI_ACTION_REFRESH_FORMSET; | |
| mHiiPackageListUpdated = FALSE; | |
| break; | |
| } | |
| // | |
| // Initialize Selection->Form | |
| // | |
| if (Selection->FormId == 0) { | |
| // | |
| // Zero FormId indicates display the first Form in a FormSet | |
| // | |
| Link = GetFirstNode (&Selection->FormSet->FormListHead); | |
| Selection->Form = FORM_BROWSER_FORM_FROM_LINK (Link); | |
| Selection->FormId = Selection->Form->FormId; | |
| } else { | |
| Selection->Form = IdToForm (Selection->FormSet, Selection->FormId); | |
| } | |
| if (Selection->Form == NULL) { | |
| // | |
| // No Form to display | |
| // | |
| Status = EFI_NOT_FOUND; | |
| goto Done; | |
| } | |
| // | |
| // Check Form is suppressed. | |
| // | |
| if (Selection->Form->SuppressExpression != NULL) { | |
| if (EvaluateExpressionList(Selection->Form->SuppressExpression, TRUE, Selection->FormSet, Selection->Form) == ExpressSuppress) { | |
| // | |
| // Form is suppressed. | |
| // | |
| PopupErrorMessage(BROWSER_FORM_SUPPRESS, NULL, NULL, NULL); | |
| Status = EFI_NOT_FOUND; | |
| goto Done; | |
| } | |
| } | |
| // | |
| // Before display new form, invoke ConfigAccess.Callback() with EFI_BROWSER_ACTION_FORM_OPEN | |
| // for each question with callback flag. | |
| // New form may be the first form, or the different form after another form close. | |
| // | |
| if (((Selection->Handle != mCurrentHiiHandle) || | |
| (!CompareGuid (&Selection->FormSetGuid, &mCurrentFormSetGuid)) || | |
| (Selection->FormId != mCurrentFormId))) { | |
| // | |
| // Update Retrieve flag. | |
| // | |
| mFinishRetrieveCall = FALSE; | |
| // | |
| // Keep current form information | |
| // | |
| mCurrentHiiHandle = Selection->Handle; | |
| CopyGuid (&mCurrentFormSetGuid, &Selection->FormSetGuid); | |
| mCurrentFormId = Selection->FormId; | |
| if (ConfigAccess != NULL) { | |
| Status = ProcessCallBackFunction (Selection, Selection->FormSet, Selection->Form, NULL, EFI_BROWSER_ACTION_FORM_OPEN, FALSE); | |
| if (EFI_ERROR (Status)) { | |
| goto Done; | |
| } | |
| // | |
| // IFR is updated during callback of EFI_BROWSER_ACTION_FORM_OPEN, force to reparse the IFR binary | |
| // | |
| if (mHiiPackageListUpdated) { | |
| Selection->Action = UI_ACTION_REFRESH_FORMSET; | |
| mHiiPackageListUpdated = FALSE; | |
| break; | |
| } | |
| } | |
| } | |
| // | |
| // Load Questions' Value for display | |
| // | |
| Status = LoadFormSetConfig (Selection, Selection->FormSet); | |
| if (EFI_ERROR (Status)) { | |
| goto Done; | |
| } | |
| if (!mFinishRetrieveCall) { | |
| // | |
| // Finish call RETRIEVE callback for this form. | |
| // | |
| mFinishRetrieveCall = TRUE; | |
| if (ConfigAccess != NULL) { | |
| Status = ProcessCallBackFunction (Selection, Selection->FormSet, Selection->Form, NULL, EFI_BROWSER_ACTION_RETRIEVE, FALSE); | |
| if (EFI_ERROR (Status)) { | |
| goto Done; | |
| } | |
| // | |
| // IFR is updated during callback of open form, force to reparse the IFR binary | |
| // | |
| if (mHiiPackageListUpdated) { | |
| Selection->Action = UI_ACTION_REFRESH_FORMSET; | |
| mHiiPackageListUpdated = FALSE; | |
| break; | |
| } | |
| } | |
| } | |
| // | |
| // Display form | |
| // | |
| Status = DisplayForm (); | |
| if (EFI_ERROR (Status)) { | |
| goto Done; | |
| } | |
| // | |
| // Check Selected Statement (if press ESC, Selection->Statement will be NULL) | |
| // | |
| Statement = Selection->Statement; | |
| if (Statement != NULL) { | |
| if ((ConfigAccess != NULL) && | |
| ((Statement->QuestionFlags & EFI_IFR_FLAG_CALLBACK) == EFI_IFR_FLAG_CALLBACK) && | |
| (Statement->Operand != EFI_IFR_PASSWORD_OP)) { | |
| Status = ProcessCallBackFunction(Selection, Selection->FormSet, Selection->Form, Statement, EFI_BROWSER_ACTION_CHANGING, FALSE); | |
| if (Statement->Operand == EFI_IFR_REF_OP) { | |
| // | |
| // Process dynamic update ref opcode. | |
| // | |
| if (!EFI_ERROR (Status)) { | |
| Status = ProcessGotoOpCode(Statement, Selection); | |
| } | |
| // | |
| // Callback return error status or status return from process goto opcode. | |
| // | |
| if (EFI_ERROR (Status)) { | |
| // | |
| // Cross reference will not be taken, restore all essential field | |
| // | |
| Selection->Handle = mCurrentHiiHandle; | |
| CopyMem (&Selection->FormSetGuid, &mCurrentFormSetGuid, sizeof (EFI_GUID)); | |
| Selection->FormId = mCurrentFormId; | |
| Selection->QuestionId = 0; | |
| Selection->Action = UI_ACTION_REFRESH_FORM; | |
| } | |
| } | |
| if (!EFI_ERROR (Status) && | |
| (Statement->Operand != EFI_IFR_REF_OP) && | |
| ((Statement->Storage == NULL) || (Statement->Storage != NULL && Statement->ValueChanged))) { | |
| // | |
| // Only question value has been changed, browser will trig CHANGED callback. | |
| // | |
| ProcessCallBackFunction(Selection, Selection->FormSet, Selection->Form, Statement, EFI_BROWSER_ACTION_CHANGED, FALSE); | |
| // | |
| //check whether the question value changed compared with buffer value | |
| //if doesn't change ,set the ValueChanged flag to FALSE ,in order not to display the "configuration changed "information on the screen | |
| // | |
| IsQuestionValueChanged(gCurrentSelection->FormSet, gCurrentSelection->Form, Statement, GetSetValueWithBuffer); | |
| } | |
| } else { | |
| // | |
| // Do the question validation. | |
| // | |
| Status = ValueChangedValidation (gCurrentSelection->FormSet, gCurrentSelection->Form, Statement); | |
| if (!EFI_ERROR (Status) && (Statement->Operand != EFI_IFR_PASSWORD_OP)) { | |
| SetQuestionValue (gCurrentSelection->FormSet, gCurrentSelection->Form, Statement, GetSetValueWithEditBuffer); | |
| // | |
| // Verify whether question value has checked, update the ValueChanged flag in Question. | |
| // | |
| IsQuestionValueChanged(gCurrentSelection->FormSet, gCurrentSelection->Form, Statement, GetSetValueWithBuffer); | |
| } | |
| } | |
| // | |
| // If question has EFI_IFR_FLAG_RESET_REQUIRED/EFI_IFR_FLAG_RECONNECT_REQUIRED flag and without storage | |
| // and process question success till here, trig the gResetFlag/gFlagReconnect. | |
| // | |
| if ((Status == EFI_SUCCESS) && | |
| (Statement->Storage == NULL)) { | |
| if ((Statement->QuestionFlags & EFI_IFR_FLAG_RESET_REQUIRED) != 0) { | |
| gResetRequired = TRUE; | |
| } | |
| if ((Statement->QuestionFlags & EFI_IFR_FLAG_RECONNECT_REQUIRED) != 0) { | |
| gFlagReconnect = TRUE; | |
| } | |
| } | |
| } | |
| // | |
| // Check whether Exit flag is TRUE. | |
| // | |
| if (gExitRequired) { | |
| switch (gBrowserSettingScope) { | |
| case SystemLevel: | |
| Selection->Action = UI_ACTION_EXIT; | |
| break; | |
| case FormSetLevel: | |
| case FormLevel: | |
| FindNextMenu (Selection, gBrowserSettingScope); | |
| break; | |
| default: | |
| break; | |
| } | |
| gExitRequired = FALSE; | |
| } | |
| // | |
| // Before exit the form, invoke ConfigAccess.Callback() with EFI_BROWSER_ACTION_FORM_CLOSE | |
| // for each question with callback flag. | |
| // | |
| if ((ConfigAccess != NULL) && | |
| ((Selection->Action == UI_ACTION_EXIT) || | |
| (Selection->Handle != mCurrentHiiHandle) || | |
| (!CompareGuid (&Selection->FormSetGuid, &mCurrentFormSetGuid)) || | |
| (Selection->FormId != mCurrentFormId))) { | |
| Status = ProcessCallBackFunction (Selection, Selection->FormSet, Selection->Form, NULL, EFI_BROWSER_ACTION_FORM_CLOSE, FALSE); | |
| if (EFI_ERROR (Status)) { | |
| goto Done; | |
| } | |
| } | |
| } while (Selection->Action == UI_ACTION_REFRESH_FORM); | |
| Done: | |
| // | |
| // Reset current form information to the initial setting when error happens or form exit. | |
| // | |
| if (EFI_ERROR (Status) || Selection->Action == UI_ACTION_EXIT) { | |
| mCurrentHiiHandle = NULL; | |
| CopyGuid (&mCurrentFormSetGuid, &gZeroGuid); | |
| mCurrentFormId = 0; | |
| } | |
| // | |
| // Unregister notify for Form package update | |
| // | |
| mHiiDatabase->UnregisterPackageNotify ( | |
| mHiiDatabase, | |
| NotifyHandle | |
| ); | |
| return Status; | |
| } |