+ LIST_ENTRY *Link;\r
+\r
+ Link = GetFirstNode (&gCurrentSelection->Form->StatementListHead);\r
+ while (!IsNull (&gCurrentSelection->Form->StatementListHead, Link)) {\r
+ Statement = FORM_BROWSER_STATEMENT_FROM_LINK (Link);\r
+\r
+ if (Statement->OpCode == DisplayStatement->OpCode) {\r
+ return Statement;\r
+ }\r
+\r
+ Link = GetNextNode (&gCurrentSelection->Form->StatementListHead, Link);\r
+ }\r
+\r
+ return NULL;\r
+}\r
+\r
+/**\r
+ Update the ValueChanged status for questions in this form.\r
+\r
+ @param FormSet FormSet data structure.\r
+ @param Form Form data structure.\r
+\r
+**/\r
+VOID \r
+UpdateStatementStatusForForm (\r
+ IN FORM_BROWSER_FORMSET *FormSet,\r
+ IN FORM_BROWSER_FORM *Form\r
+ )\r
+{\r
+ LIST_ENTRY *Link;\r
+ FORM_BROWSER_STATEMENT *Question;\r
+\r
+ Link = GetFirstNode (&Form->StatementListHead);\r
+ while (!IsNull (&Form->StatementListHead, Link)) {\r
+ Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link);\r
+ Link = GetNextNode (&Form->StatementListHead, Link);\r
+\r
+ //\r
+ // For password opcode, not set the the value changed flag.\r
+ //\r
+ if (Question->Operand == EFI_IFR_PASSWORD_OP) {\r
+ continue;\r
+ }\r
+\r
+ IsQuestionValueChanged(FormSet, Form, Question, GetSetValueWithBuffer);\r
+ }\r
+}\r
+\r
+/**\r
+ Update the ValueChanged status for questions in this formset.\r
+\r
+ @param FormSet FormSet data structure.\r
+\r
+**/\r
+VOID \r
+UpdateStatementStatusForFormSet (\r
+ IN FORM_BROWSER_FORMSET *FormSet\r
+ )\r
+{\r
+ LIST_ENTRY *Link;\r
+ FORM_BROWSER_FORM *Form;\r
+\r
+ Link = GetFirstNode (&FormSet->FormListHead);\r
+ while (!IsNull (&FormSet->FormListHead, Link)) {\r
+ Form = FORM_BROWSER_FORM_FROM_LINK (Link);\r
+ Link = GetNextNode (&FormSet->FormListHead, Link);\r
+\r
+ UpdateStatementStatusForForm (FormSet, Form);\r
+ }\r
+}\r
+\r
+/**\r
+ Update the ValueChanged status for questions.\r
+\r
+ @param FormSet FormSet data structure.\r
+ @param Form Form data structure.\r
+ @param SettingScope Setting Scope for Default action.\r
+\r
+**/\r
+VOID \r
+UpdateStatementStatus (\r
+ IN FORM_BROWSER_FORMSET *FormSet,\r
+ IN FORM_BROWSER_FORM *Form, \r
+ IN BROWSER_SETTING_SCOPE SettingScope\r
+ )\r
+{\r
+ LIST_ENTRY *Link;\r
+ FORM_BROWSER_FORMSET *LocalFormSet;\r
+\r
+ switch (SettingScope) {\r
+ case SystemLevel:\r
+ Link = GetFirstNode (&gBrowserFormSetList);\r
+ while (!IsNull (&gBrowserFormSetList, Link)) {\r
+ LocalFormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link);\r
+ Link = GetNextNode (&gBrowserFormSetList, Link);\r
+ if (!ValidateFormSet(LocalFormSet)) {\r
+ continue;\r
+ }\r
+\r
+ UpdateStatementStatusForFormSet (LocalFormSet);\r
+ }\r
+ break;\r
+\r
+ case FormSetLevel:\r
+ UpdateStatementStatusForFormSet (FormSet);\r
+ break;\r
+\r
+ case FormLevel:\r
+ UpdateStatementStatusForForm (FormSet, Form);\r
+ break;\r
+\r
+ default:\r
+ break;\r
+ }\r
+}\r
+\r
+/**\r
+\r
+ Process the action request in user input.\r
+\r
+ @param Action The user input action request info.\r
+ @param DefaultId The user input default Id info.\r
+\r
+ @retval EFI_SUCESSS This function always return successfully for now.\r
+\r
+**/\r
+EFI_STATUS \r
+ProcessAction (\r
+ IN UINT32 Action,\r
+ IN UINT16 DefaultId\r
+ )\r
+{\r
+ //\r
+ // This is caused by use press ESC, and it should not combine with other action type.\r
+ //\r
+ if ((Action & BROWSER_ACTION_FORM_EXIT) == BROWSER_ACTION_FORM_EXIT) {\r
+ FindNextMenu (gCurrentSelection, FormLevel);\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ //\r
+ // Below is normal hotkey trigged action, these action maybe combine with each other.\r
+ //\r
+ if ((Action & BROWSER_ACTION_DISCARD) == BROWSER_ACTION_DISCARD) {\r
+ DiscardForm (gCurrentSelection->FormSet, gCurrentSelection->Form, gBrowserSettingScope);\r
+ }\r
+\r
+ if ((Action & BROWSER_ACTION_DEFAULT) == BROWSER_ACTION_DEFAULT) {\r
+ ExtractDefault (gCurrentSelection->FormSet, gCurrentSelection->Form, DefaultId, gBrowserSettingScope, GetDefaultForAll, NULL, FALSE, FALSE);\r
+ UpdateStatementStatus (gCurrentSelection->FormSet, gCurrentSelection->Form, gBrowserSettingScope);\r
+ }\r
+\r
+ if ((Action & BROWSER_ACTION_SUBMIT) == BROWSER_ACTION_SUBMIT) {\r
+ SubmitForm (gCurrentSelection->FormSet, gCurrentSelection->Form, gBrowserSettingScope);\r
+ }\r
+\r
+ if ((Action & BROWSER_ACTION_RESET) == BROWSER_ACTION_RESET) {\r
+ gResetRequired = TRUE;\r
+ }\r
+\r
+ if ((Action & BROWSER_ACTION_EXIT) == BROWSER_ACTION_EXIT) {\r
+ //\r
+ // Form Exit without saving, Similar to ESC Key.\r
+ // FormSet Exit without saving, Exit SendForm.\r
+ // System Exit without saving, CallExitHandler and Exit SendForm.\r
+ //\r
+ DiscardForm (gCurrentSelection->FormSet, gCurrentSelection->Form, gBrowserSettingScope);\r
+ if (gBrowserSettingScope == FormLevel || gBrowserSettingScope == FormSetLevel) {\r
+ FindNextMenu (gCurrentSelection, gBrowserSettingScope);\r
+ } else if (gBrowserSettingScope == SystemLevel) {\r
+ if (ExitHandlerFunction != NULL) {\r
+ ExitHandlerFunction ();\r
+ }\r
+ gCurrentSelection->Action = UI_ACTION_EXIT;\r
+ }\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Check whether the formset guid is in this Hii package list.\r
+\r
+ @param HiiHandle The HiiHandle for this HII package list.\r
+ @param FormSetGuid The formset guid for the request formset.\r
+\r
+ @retval TRUE Find the formset guid.\r
+ @retval FALSE Not found the formset guid.\r
+\r
+**/\r
+BOOLEAN\r
+GetFormsetGuidFromHiiHandle (\r
+ IN EFI_HII_HANDLE HiiHandle,\r
+ IN EFI_GUID *FormSetGuid\r
+ )\r
+{\r
+ EFI_HII_PACKAGE_LIST_HEADER *HiiPackageList;\r
+ UINTN BufferSize;\r
+ UINT32 Offset;\r
+ UINT32 Offset2;\r
+ UINT32 PackageListLength;\r
+ EFI_HII_PACKAGE_HEADER PackageHeader;\r
+ UINT8 *Package;\r
+ UINT8 *OpCodeData;\r
+ EFI_STATUS Status;\r
+ BOOLEAN FindGuid;\r
+\r
+ BufferSize = 0;\r
+ HiiPackageList = NULL;\r
+ FindGuid = FALSE;\r
+ \r
+ Status = mHiiDatabase->ExportPackageLists (mHiiDatabase, HiiHandle, &BufferSize, HiiPackageList);\r
+ if (Status == EFI_BUFFER_TOO_SMALL) {\r
+ HiiPackageList = AllocatePool (BufferSize);\r
+ ASSERT (HiiPackageList != NULL);\r
+\r
+ Status = mHiiDatabase->ExportPackageLists (mHiiDatabase, HiiHandle, &BufferSize, HiiPackageList);\r
+ }\r
+ if (EFI_ERROR (Status) || HiiPackageList == NULL) {\r
+ return FALSE;\r
+ }\r
+\r
+ //\r
+ // Get Form package from this HII package List\r
+ //\r
+ Offset = sizeof (EFI_HII_PACKAGE_LIST_HEADER);\r
+ Offset2 = 0;\r
+ CopyMem (&PackageListLength, &HiiPackageList->PackageLength, sizeof (UINT32)); \r
+\r
+ while (Offset < PackageListLength) {\r
+ Package = ((UINT8 *) HiiPackageList) + Offset;\r
+ CopyMem (&PackageHeader, Package, sizeof (EFI_HII_PACKAGE_HEADER));\r
+ Offset += PackageHeader.Length;\r
+\r
+ if (PackageHeader.Type == EFI_HII_PACKAGE_FORMS) {\r
+ //\r
+ // Search FormSet in this Form Package\r
+ //\r
+ Offset2 = sizeof (EFI_HII_PACKAGE_HEADER);\r
+ while (Offset2 < PackageHeader.Length) {\r
+ OpCodeData = Package + Offset2;\r
+\r
+ if (((EFI_IFR_OP_HEADER *) OpCodeData)->OpCode == EFI_IFR_FORM_SET_OP) {\r
+ if (CompareGuid (FormSetGuid, (EFI_GUID *)(OpCodeData + sizeof (EFI_IFR_OP_HEADER)))){\r
+ FindGuid = TRUE;\r
+ break;\r
+ }\r
+ }\r
+\r
+ Offset2 += ((EFI_IFR_OP_HEADER *) OpCodeData)->Length;\r
+ }\r
+ }\r
+ if (FindGuid) {\r
+ break;\r
+ }\r
+ }\r
+\r
+ FreePool (HiiPackageList);\r
+\r
+ return FindGuid;\r
+}\r
+\r
+/**\r
+ Find HII Handle in the HII database associated with given Device Path.\r
+\r
+ If DevicePath is NULL, then ASSERT.\r
+\r
+ @param DevicePath Device Path associated with the HII package list\r
+ handle.\r
+ @param FormsetGuid The formset guid for this formset.\r
+\r
+ @retval Handle HII package list Handle associated with the Device\r
+ Path.\r
+ @retval NULL Hii Package list handle is not found.\r
+\r
+**/\r
+EFI_HII_HANDLE\r
+DevicePathToHiiHandle (\r
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,\r
+ IN EFI_GUID *FormsetGuid\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_DEVICE_PATH_PROTOCOL *TmpDevicePath;\r
+ UINTN Index;\r
+ EFI_HANDLE Handle;\r
+ EFI_HANDLE DriverHandle;\r
+ EFI_HII_HANDLE *HiiHandles;\r
+ EFI_HII_HANDLE HiiHandle;\r
+\r
+ ASSERT (DevicePath != NULL);\r
+\r
+ TmpDevicePath = DevicePath;\r
+ //\r
+ // Locate Device Path Protocol handle buffer\r
+ //\r
+ Status = gBS->LocateDevicePath (\r
+ &gEfiDevicePathProtocolGuid,\r
+ &TmpDevicePath,\r
+ &DriverHandle\r
+ );\r
+ if (EFI_ERROR (Status) || !IsDevicePathEnd (TmpDevicePath)) {\r
+ return NULL;\r
+ }\r
+\r
+ //\r
+ // Retrieve all HII Handles from HII database\r
+ //\r
+ HiiHandles = HiiGetHiiHandles (NULL);\r
+ if (HiiHandles == NULL) {\r
+ return NULL;\r
+ }\r
+\r
+ //\r
+ // Search Hii Handle by Driver Handle\r
+ //\r
+ HiiHandle = NULL;\r
+ for (Index = 0; HiiHandles[Index] != NULL; Index++) {\r
+ Status = mHiiDatabase->GetPackageListHandle (\r
+ mHiiDatabase,\r
+ HiiHandles[Index],\r
+ &Handle\r
+ );\r
+ if (!EFI_ERROR (Status) && (Handle == DriverHandle)) {\r
+ if (GetFormsetGuidFromHiiHandle(HiiHandles[Index], FormsetGuid)) {\r
+ HiiHandle = HiiHandles[Index];\r
+ break;\r
+ }\r
+\r
+ if (HiiHandle != NULL) {\r
+ break;\r
+ }\r
+ }\r
+ }\r
+\r
+ FreePool (HiiHandles);\r
+ return HiiHandle;\r
+}\r
+\r
+/**\r
+ Find HII Handle in the HII database associated with given form set guid.\r
+\r
+ If FormSetGuid is NULL, then ASSERT.\r
+\r
+ @param ComparingGuid FormSet Guid associated with the HII package list\r
+ handle.\r
+\r
+ @retval Handle HII package list Handle associated with the Device\r
+ Path.\r
+ @retval NULL Hii Package list handle is not found.\r
+\r
+**/\r
+EFI_HII_HANDLE\r
+FormSetGuidToHiiHandle (\r
+ EFI_GUID *ComparingGuid\r
+ )\r
+{\r
+ EFI_HII_HANDLE *HiiHandles;\r
+ EFI_HII_HANDLE HiiHandle;\r
+ UINTN Index;\r
+\r
+ ASSERT (ComparingGuid != NULL);\r
+\r
+ HiiHandle = NULL;\r
+ //\r
+ // Get all the Hii handles\r
+ //\r
+ HiiHandles = HiiGetHiiHandles (NULL);\r
+ ASSERT (HiiHandles != NULL);\r
+\r
+ //\r
+ // Search for formset of each class type\r
+ //\r
+ for (Index = 0; HiiHandles[Index] != NULL; Index++) {\r
+ if (GetFormsetGuidFromHiiHandle(HiiHandles[Index], ComparingGuid)) {\r
+ HiiHandle = HiiHandles[Index];\r
+ break;\r
+ }\r
+\r
+ if (HiiHandle != NULL) {\r
+ break;\r
+ }\r
+ }\r
+\r
+ FreePool (HiiHandles);\r
+\r
+ return HiiHandle;\r
+}\r
+\r
+/**\r
+ check how to process the changed data in current form or form set.\r
+\r
+ @param Selection On input, Selection tell setup browser the information\r
+ about the Selection, form and formset to be displayed.\r
+ On output, Selection return the screen item that is selected\r
+ by user.\r
+\r
+ @param Scope Data save or discard scope, form or formset.\r
+\r
+ @retval TRUE Success process the changed data, will return to the parent form.\r
+ @retval FALSE Reject to process the changed data, will stay at current form.\r
+**/\r
+BOOLEAN\r
+ProcessChangedData (\r
+ IN OUT UI_MENU_SELECTION *Selection,\r
+ IN BROWSER_SETTING_SCOPE Scope\r
+ )\r
+{\r
+ BOOLEAN RetValue;\r
+ EFI_STATUS Status;\r
+\r
+ RetValue = TRUE;\r
+ switch (mFormDisplay->ConfirmDataChange()) {\r
+ case BROWSER_ACTION_DISCARD:\r
+ DiscardForm (Selection->FormSet, Selection->Form, Scope);\r
+ break;\r
+ \r
+ case BROWSER_ACTION_SUBMIT:\r
+ Status = SubmitForm (Selection->FormSet, Selection->Form, Scope);\r
+ if (EFI_ERROR (Status)) {\r
+ RetValue = FALSE;\r
+ }\r
+ break;\r
+\r
+ case BROWSER_ACTION_NONE:\r
+ RetValue = FALSE;\r
+ break;\r
+\r
+ default:\r
+ //\r
+ // if Invalid value return, process same as BROWSER_ACTION_NONE.\r
+ //\r
+ RetValue = FALSE;\r
+ break;\r
+ }\r
+\r
+ return RetValue;\r
+}\r
+\r
+/**\r
+ Find parent formset menu(the first menu which has different formset) for current menu.\r
+ If not find, just return to the first menu.\r
+\r
+ @param Selection The selection info.\r
+\r
+**/\r
+VOID\r
+FindParentFormSet (\r
+ IN OUT UI_MENU_SELECTION *Selection\r
+ )\r
+{\r
+ FORM_ENTRY_INFO *CurrentMenu;\r
+ FORM_ENTRY_INFO *ParentMenu;\r
+\r
+ CurrentMenu = Selection->CurrentMenu;\r
+ ParentMenu = UiFindParentMenu(CurrentMenu, FormSetLevel);\r
+\r
+ if (ParentMenu != NULL) {\r
+ CopyMem (&Selection->FormSetGuid, &ParentMenu->FormSetGuid, sizeof (EFI_GUID));\r
+ Selection->Handle = ParentMenu->HiiHandle;\r
+ Selection->FormId = ParentMenu->FormId;\r
+ Selection->QuestionId = ParentMenu->QuestionId;\r
+ } else {\r
+ Selection->FormId = CurrentMenu->FormId;\r
+ Selection->QuestionId = CurrentMenu->QuestionId;\r
+ }\r
+\r
+ Selection->Statement = NULL;\r
+}\r
+\r
+/**\r
+ Process the goto op code, update the info in the selection structure.\r
+\r
+ @param Statement The statement belong to goto op code.\r
+ @param Selection The selection info.\r
+\r
+ @retval EFI_SUCCESS The menu process successfully.\r
+ @return Other value if the process failed.\r
+**/\r
+EFI_STATUS\r
+ProcessGotoOpCode (\r
+ IN OUT FORM_BROWSER_STATEMENT *Statement,\r
+ IN OUT UI_MENU_SELECTION *Selection\r
+ )\r
+{\r
+ CHAR16 *StringPtr;\r
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
+ FORM_BROWSER_FORM *RefForm;\r
+ EFI_STATUS Status;\r
+ EFI_HII_HANDLE HiiHandle;\r
+ \r
+ Status = EFI_SUCCESS;\r
+ StringPtr = NULL;\r
+ HiiHandle = NULL;\r
+\r
+ //\r
+ // Prepare the device path check, get the device path info first.\r
+ //\r
+ if (Statement->HiiValue.Value.ref.DevicePath != 0) {\r
+ StringPtr = GetToken (Statement->HiiValue.Value.ref.DevicePath, Selection->FormSet->HiiHandle);\r
+ }\r
+\r
+ //\r
+ // Check whether the device path string is a valid string.\r
+ //\r
+ if (Statement->HiiValue.Value.ref.DevicePath != 0 && StringPtr != NULL && StringPtr[0] != L'\0') {\r
+ if (Selection->Form->ModalForm) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Goto another Hii Package list\r
+ //\r
+ if (mPathFromText != NULL) {\r
+ DevicePath = mPathFromText->ConvertTextToDevicePath(StringPtr);\r
+ if (DevicePath != NULL) {\r
+ HiiHandle = DevicePathToHiiHandle (DevicePath, &Statement->HiiValue.Value.ref.FormSetGuid);\r
+ FreePool (DevicePath);\r
+ }\r
+ FreePool (StringPtr);\r
+ } else {\r
+ //\r
+ // Not found the EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL protocol.\r
+ //\r
+ PopupErrorMessage(BROWSER_PROTOCOL_NOT_FOUND, NULL, NULL, NULL);\r
+ FreePool (StringPtr);\r
+ return Status;\r
+ }\r
+\r
+ if (HiiHandle != Selection->Handle) {\r
+ //\r
+ // Goto another Formset, check for uncommitted data\r
+ //\r
+ if ((gBrowserSettingScope == FormLevel || gBrowserSettingScope == FormSetLevel) &&\r
+ IsNvUpdateRequiredForFormSet(Selection->FormSet)) {\r
+ if (!ProcessChangedData(Selection, FormSetLevel)) {\r
+ return EFI_SUCCESS;\r
+ }\r
+ }\r
+ }\r
+\r
+ Selection->Action = UI_ACTION_REFRESH_FORMSET;\r
+ Selection->Handle = HiiHandle;\r
+ if (Selection->Handle == NULL) {\r
+ //\r
+ // If target Hii Handle not found, exit current formset.\r
+ //\r
+ FindParentFormSet(Selection);\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ CopyMem (&Selection->FormSetGuid,&Statement->HiiValue.Value.ref.FormSetGuid, sizeof (EFI_GUID));\r
+ Selection->FormId = Statement->HiiValue.Value.ref.FormId;\r
+ Selection->QuestionId = Statement->HiiValue.Value.ref.QuestionId;\r
+ } else if (!IsZeroGuid (&Statement->HiiValue.Value.ref.FormSetGuid)) {\r
+ if (Selection->Form->ModalForm) {\r
+ return Status;\r
+ }\r
+ if (!CompareGuid (&Statement->HiiValue.Value.ref.FormSetGuid, &Selection->FormSetGuid)) {\r
+ //\r
+ // Goto another Formset, check for uncommitted data\r
+ //\r
+ if ((gBrowserSettingScope == FormLevel || gBrowserSettingScope == FormSetLevel) &&\r
+ IsNvUpdateRequiredForFormSet(Selection->FormSet)) {\r
+ if (!ProcessChangedData(Selection, FormSetLevel)) {\r
+ return EFI_SUCCESS;\r
+ }\r
+ }\r
+ }\r
+\r
+ Selection->Action = UI_ACTION_REFRESH_FORMSET;\r
+ Selection->Handle = FormSetGuidToHiiHandle(&Statement->HiiValue.Value.ref.FormSetGuid);\r
+ if (Selection->Handle == NULL) {\r
+ //\r
+ // If target Hii Handle not found, exit current formset.\r
+ //\r
+ FindParentFormSet(Selection);\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ CopyMem (&Selection->FormSetGuid, &Statement->HiiValue.Value.ref.FormSetGuid, sizeof (EFI_GUID));\r
+ Selection->FormId = Statement->HiiValue.Value.ref.FormId;\r
+ Selection->QuestionId = Statement->HiiValue.Value.ref.QuestionId;\r
+ } else if (Statement->HiiValue.Value.ref.FormId != 0) {\r
+ //\r
+ // Goto another Form, check for uncommitted data\r
+ //\r
+ if (Statement->HiiValue.Value.ref.FormId != Selection->FormId) {\r
+ if ((gBrowserSettingScope == FormLevel && IsNvUpdateRequiredForForm(Selection->Form))) {\r
+ if (!ProcessChangedData (Selection, FormLevel)) {\r
+ return EFI_SUCCESS;\r
+ }\r
+ }\r
+ }\r
+\r
+ RefForm = IdToForm (Selection->FormSet, Statement->HiiValue.Value.ref.FormId);\r
+ if ((RefForm != NULL) && (RefForm->SuppressExpression != NULL)) {\r
+ if (EvaluateExpressionList(RefForm->SuppressExpression, TRUE, Selection->FormSet, RefForm) != ExpressFalse) {\r
+ //\r
+ // Form is suppressed. \r
+ //\r
+ PopupErrorMessage(BROWSER_FORM_SUPPRESS, NULL, NULL, NULL);\r
+ return EFI_SUCCESS;\r
+ }\r
+ }\r
+\r
+ Selection->FormId = Statement->HiiValue.Value.ref.FormId;\r
+ Selection->QuestionId = Statement->HiiValue.Value.ref.QuestionId;\r
+ } else if (Statement->HiiValue.Value.ref.QuestionId != 0) {\r
+ Selection->QuestionId = Statement->HiiValue.Value.ref.QuestionId;\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Process Question Config.\r
+\r
+ @param Selection The UI menu selection.\r
+ @param Question The Question to be peocessed.\r
+\r
+ @retval EFI_SUCCESS Question Config process success.\r
+ @retval Other Question Config process fail.\r
+\r
+**/\r
+EFI_STATUS\r
+ProcessQuestionConfig (\r
+ IN UI_MENU_SELECTION *Selection,\r
+ IN FORM_BROWSER_STATEMENT *Question\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ CHAR16 *ConfigResp;\r
+ CHAR16 *Progress;\r
+\r
+ if (Question->QuestionConfig == 0) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ //\r
+ // Get <ConfigResp>\r
+ //\r
+ ConfigResp = GetToken (Question->QuestionConfig, Selection->FormSet->HiiHandle);\r
+ if (ConfigResp == NULL) {\r
+ return EFI_NOT_FOUND;\r
+ } else if (ConfigResp[0] == L'\0') {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ //\r
+ // Send config to Configuration Driver\r
+ //\r
+ Status = mHiiConfigRouting->RouteConfig (\r
+ mHiiConfigRouting,\r
+ ConfigResp,\r
+ &Progress\r
+ );\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+\r
+ Process the user input data.\r
+\r
+ @param UserInput The user input data.\r
+\r
+ @retval EFI_SUCESSS This function always return successfully for now.\r
+\r
+**/\r
+EFI_STATUS\r
+ProcessUserInput (\r
+ IN USER_INPUT *UserInput\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ FORM_BROWSER_STATEMENT *Statement;\r
+\r
+ Status = EFI_SUCCESS;\r
+ Statement = NULL;\r
+\r
+ //\r
+ // When Exit from FormDisplay function, one of the below two cases must be true.\r
+ //\r
+ ASSERT (UserInput->Action != 0 || UserInput->SelectedStatement != NULL);\r
+\r
+ //\r
+ // Remove the last highligh question id, this id will update when show next form.\r
+ //\r
+ gCurrentSelection->QuestionId = 0;\r
+ if (UserInput->SelectedStatement != NULL){\r
+ Statement = GetBrowserStatement(UserInput->SelectedStatement);\r
+ ASSERT (Statement != NULL);\r
+\r
+ //\r
+ // This question is the current user select one,record it and later\r
+ // show it as the highlight question.\r
+ //\r
+ gCurrentSelection->CurrentMenu->QuestionId = Statement->QuestionId;\r
+ //\r
+ // For statement like text, actio, it not has question id.\r
+ // So use FakeQuestionId to save the question.\r
+ //\r
+ if (gCurrentSelection->CurrentMenu->QuestionId == 0) {\r
+ mCurFakeQestId = Statement->FakeQuestionId;\r
+ } else {\r
+ mCurFakeQestId = 0;\r
+ }\r
+ }\r
+\r
+ //\r
+ // First process the Action field in USER_INPUT.\r
+ //\r
+ if (UserInput->Action != 0) {\r
+ Status = ProcessAction (UserInput->Action, UserInput->DefaultId);\r
+ gCurrentSelection->Statement = NULL;\r
+ } else {\r
+ ASSERT (Statement != NULL);\r
+ gCurrentSelection->Statement = Statement;\r
+ switch (Statement->Operand) {\r
+ case EFI_IFR_REF_OP:\r
+ Status = ProcessGotoOpCode(Statement, gCurrentSelection);\r
+ break;\r
+ \r
+ case EFI_IFR_ACTION_OP:\r
+ //\r
+ // Process the Config string <ConfigResp>\r
+ //\r
+ Status = ProcessQuestionConfig (gCurrentSelection, Statement);\r
+ break;\r
+ \r
+ case EFI_IFR_RESET_BUTTON_OP:\r
+ //\r
+ // Reset Question to default value specified by DefaultId\r
+ //\r
+ Status = ExtractDefault (gCurrentSelection->FormSet, NULL, Statement->DefaultId, FormSetLevel, GetDefaultForAll, NULL, FALSE, FALSE);\r
+ UpdateStatementStatus (gCurrentSelection->FormSet, NULL, FormSetLevel);\r
+ break;\r
+\r
+ default:\r
+ switch (Statement->Operand) {\r
+ case EFI_IFR_STRING_OP:\r
+ DeleteString(Statement->HiiValue.Value.string, gCurrentSelection->FormSet->HiiHandle);\r
+ Statement->HiiValue.Value.string = UserInput->InputValue.Value.string;\r
+ CopyMem (Statement->BufferValue, UserInput->InputValue.Buffer, (UINTN) UserInput->InputValue.BufferLen);\r
+ FreePool (UserInput->InputValue.Buffer);\r
+ break;\r
+\r
+ case EFI_IFR_PASSWORD_OP:\r
+ if (UserInput->InputValue.Buffer == NULL) {\r
+ //\r
+ // User not input new password, just return.\r
+ //\r
+ break;\r
+ }\r
+\r
+ DeleteString(Statement->HiiValue.Value.string, gCurrentSelection->FormSet->HiiHandle);\r
+ Statement->HiiValue.Value.string = UserInput->InputValue.Value.string;\r
+ CopyMem (Statement->BufferValue, UserInput->InputValue.Buffer, (UINTN) UserInput->InputValue.BufferLen);\r
+ FreePool (UserInput->InputValue.Buffer);\r
+ //\r
+ // Two password match, send it to Configuration Driver\r
+ //\r
+ if ((Statement->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) {\r
+ PasswordCheck (NULL, UserInput->SelectedStatement, (CHAR16 *) Statement->BufferValue);\r
+ //\r
+ // Clean the value after saved it.\r
+ //\r
+ ZeroMem (Statement->BufferValue, (UINTN) UserInput->InputValue.BufferLen);\r
+ HiiSetString (gCurrentSelection->FormSet->HiiHandle, Statement->HiiValue.Value.string, (CHAR16*)Statement->BufferValue, NULL);\r
+ } else {\r
+ SetQuestionValue (gCurrentSelection->FormSet, gCurrentSelection->Form, Statement, GetSetValueWithHiiDriver);\r
+ }\r
+ break;\r
+\r
+ case EFI_IFR_ORDERED_LIST_OP:\r
+ CopyMem (Statement->BufferValue, UserInput->InputValue.Buffer, UserInput->InputValue.BufferLen);\r
+ break;\r
+\r
+ default:\r
+ CopyMem (&Statement->HiiValue, &UserInput->InputValue, sizeof (EFI_HII_VALUE));\r
+ break;\r
+ }\r
+ break;\r
+ }\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+\r
+ Display form and wait for user to select one menu option, then return it.\r
+\r
+ @retval EFI_SUCESSS This function always return successfully for now.\r
+\r
+**/\r
+EFI_STATUS\r
+DisplayForm (\r
+ VOID\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ USER_INPUT UserInput;\r
+ FORM_ENTRY_INFO *CurrentMenu;\r
+\r
+ ZeroMem (&UserInput, sizeof (USER_INPUT));\r
+\r
+ //\r
+ // Update the menu history data.\r
+ //\r
+ CurrentMenu = UiFindMenuList (gCurrentSelection->Handle, &gCurrentSelection->FormSetGuid, gCurrentSelection->FormId);\r
+ if (CurrentMenu == NULL) {\r
+ //\r
+ // Current menu not found, add it to the menu tree\r
+ //\r
+ CurrentMenu = UiAddMenuList (gCurrentSelection->Handle, &gCurrentSelection->FormSetGuid,\r
+ gCurrentSelection->FormId, gCurrentSelection->QuestionId);\r
+ ASSERT (CurrentMenu != NULL);\r
+ }\r
+\r
+ //\r
+ // Back up the form view history data for this form.\r
+ //\r
+ UiCopyMenuList(&gCurrentSelection->Form->FormViewListHead, &mPrivateData.FormBrowserEx2.FormViewHistoryHead);\r
+\r
+ gCurrentSelection->CurrentMenu = CurrentMenu;\r
+\r
+ if (gCurrentSelection->QuestionId == 0) {\r
+ //\r
+ // Highlight not specified, fetch it from cached menu\r
+ //\r
+ gCurrentSelection->QuestionId = CurrentMenu->QuestionId;\r
+ }\r
+\r
+ Status = EvaluateFormExpressions (gCurrentSelection->FormSet, gCurrentSelection->Form);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ UpdateDisplayFormData ();\r
+\r
+ ASSERT (gDisplayFormData.BrowserStatus == BROWSER_SUCCESS);\r
+ Status = mFormDisplay->FormDisplay (&gDisplayFormData, &UserInput);\r
+ if (EFI_ERROR (Status)) {\r
+ FreeDisplayFormData();\r
+ return Status;\r
+ }\r
+\r
+ Status = ProcessUserInput (&UserInput);\r
+ FreeDisplayFormData();\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Functions which are registered to receive notification of\r
+ database events have this prototype. The actual event is encoded\r
+ in NotifyType. The following table describes how PackageType,\r
+ PackageGuid, Handle, and Package are used for each of the\r
+ notification types.\r
+\r
+ @param PackageType Package type of the notification.\r
+\r
+ @param PackageGuid If PackageType is\r
+ EFI_HII_PACKAGE_TYPE_GUID, then this is\r
+ the pointer to the GUID from the Guid\r
+ field of EFI_HII_PACKAGE_GUID_HEADER.\r
+ Otherwise, it must be NULL.\r
+\r
+ @param Package Points to the package referred to by the\r
+ notification Handle The handle of the package\r
+ list which contains the specified package.\r
+\r
+ @param Handle The HII handle.\r
+\r
+ @param NotifyType The type of change concerning the\r
+ database. See\r
+ EFI_HII_DATABASE_NOTIFY_TYPE.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+FormUpdateNotify (\r
+ IN UINT8 PackageType,\r
+ IN CONST EFI_GUID *PackageGuid,\r
+ IN CONST EFI_HII_PACKAGE_HEADER *Package,\r
+ IN EFI_HII_HANDLE Handle,\r
+ IN EFI_HII_DATABASE_NOTIFY_TYPE NotifyType\r
+ )\r
+{\r
+ mHiiPackageListUpdated = TRUE;\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Update the NV flag info for this form set.\r
+\r
+ @param FormSet FormSet data structure.\r
+\r
+**/\r
+BOOLEAN\r
+IsNvUpdateRequiredForFormSet (\r
+ IN FORM_BROWSER_FORMSET *FormSet\r
+ )\r
+{\r
+ LIST_ENTRY *Link;\r
+ FORM_BROWSER_FORM *Form;\r
+ BOOLEAN RetVal;\r
+\r
+ //\r
+ // Not finished question initialization, return FALSE.\r
+ //\r
+ if (!FormSet->QuestionInited) {\r
+ return FALSE;\r
+ }\r
+\r
+ RetVal = FALSE;\r
+\r
+ Link = GetFirstNode (&FormSet->FormListHead);\r
+ while (!IsNull (&FormSet->FormListHead, Link)) {\r
+ Form = FORM_BROWSER_FORM_FROM_LINK (Link);\r
+\r
+ RetVal = IsNvUpdateRequiredForForm(Form);\r
+ if (RetVal) {\r
+ break;\r
+ }\r
+\r
+ Link = GetNextNode (&FormSet->FormListHead, Link);\r
+ }\r
+\r
+ return RetVal;\r
+}\r
+\r
+/**\r
+ Update the NvUpdateRequired flag for a form.\r
+\r
+ @param Form Form data structure.\r
+\r
+**/\r
+BOOLEAN\r
+IsNvUpdateRequiredForForm (\r
+ IN FORM_BROWSER_FORM *Form\r
+ )\r
+{\r
+ LIST_ENTRY *Link;\r
+ FORM_BROWSER_STATEMENT *Statement;\r
+\r
+ Link = GetFirstNode (&Form->StatementListHead);\r
+ while (!IsNull (&Form->StatementListHead, Link)) {\r
+ Statement = FORM_BROWSER_STATEMENT_FROM_LINK (Link);\r
+\r
+ if (Statement->ValueChanged) {\r
+ return TRUE;\r
+ }\r
+\r
+ Link = GetNextNode (&Form->StatementListHead, Link);\r
+ }\r
+\r
+ return FALSE;\r
+}\r
+\r
+/**\r
+ Find menu which will show next time.\r
+\r
+ @param Selection On input, Selection tell setup browser the information\r
+ about the Selection, form and formset to be displayed.\r
+ On output, Selection return the screen item that is selected\r
+ by user.\r
+ @param SettingLevel Input Settting level, if it is FormLevel, just exit current form. \r
+ else, we need to exit current formset.\r
+ \r
+ @retval TRUE Exit current form.\r
+ @retval FALSE User press ESC and keep in current form.\r
+**/\r
+BOOLEAN\r
+FindNextMenu (\r
+ IN OUT UI_MENU_SELECTION *Selection,\r
+ IN BROWSER_SETTING_SCOPE SettingLevel\r
+ )\r
+{\r
+ FORM_ENTRY_INFO *CurrentMenu;\r
+ FORM_ENTRY_INFO *ParentMenu;\r
+ BROWSER_SETTING_SCOPE Scope;\r
+ \r
+ CurrentMenu = Selection->CurrentMenu;\r
+ Scope = FormSetLevel;\r
+\r
+ ParentMenu = UiFindParentMenu(CurrentMenu, SettingLevel);\r
+ while (ParentMenu != NULL && !ValidateHiiHandle(ParentMenu->HiiHandle)) {\r
+ ParentMenu = UiFindParentMenu(ParentMenu, SettingLevel);\r
+ }\r
+\r
+ if (ParentMenu != NULL) {\r
+ if (CompareGuid (&CurrentMenu->FormSetGuid, &ParentMenu->FormSetGuid)) {\r
+ Scope = FormLevel;\r
+ } else {\r
+ Scope = FormSetLevel;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Form Level Check whether the data is changed.\r
+ //\r
+ if ((gBrowserSettingScope == FormLevel && IsNvUpdateRequiredForForm (Selection->Form)) ||\r
+ (gBrowserSettingScope == FormSetLevel && IsNvUpdateRequiredForFormSet(Selection->FormSet) && Scope == FormSetLevel)) {\r
+ if (!ProcessChangedData(Selection, gBrowserSettingScope)) {\r
+ return FALSE;\r
+ }\r
+ }\r
+\r
+ if (ParentMenu != NULL) {\r
+ //\r
+ // ParentMenu is found. Then, go to it.\r
+ //\r
+ if (Scope == FormLevel) {\r
+ Selection->Action = UI_ACTION_REFRESH_FORM;\r
+ } else {\r
+ Selection->Action = UI_ACTION_REFRESH_FORMSET;\r
+ CopyMem (&Selection->FormSetGuid, &ParentMenu->FormSetGuid, sizeof (EFI_GUID));\r
+ Selection->Handle = ParentMenu->HiiHandle;\r
+ }\r
+\r
+ Selection->Statement = NULL;\r
+\r
+ Selection->FormId = ParentMenu->FormId;\r
+ Selection->QuestionId = ParentMenu->QuestionId;\r
+\r
+ //\r
+ // Clear highlight record for this menu\r
+ //\r
+ CurrentMenu->QuestionId = 0;\r
+ return FALSE;\r
+ }\r
+\r
+ //\r
+ // Current in root page, exit the SendForm\r
+ //\r
+ Selection->Action = UI_ACTION_EXIT;\r
+\r
+ return TRUE;\r
+}\r
+\r
+/**\r
+ Reconnect the controller.\r
+\r
+ @param DriverHandle The controller handle which need to be reconnect.\r
+\r
+ @retval TRUE do the reconnect behavior success.\r
+ @retval FALSE do the reconnect behavior failed.\r
+ \r
+**/\r
+BOOLEAN\r
+ReconnectController (\r
+ IN EFI_HANDLE DriverHandle\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ Status = gBS->DisconnectController(DriverHandle, NULL, NULL);\r
+ if (!EFI_ERROR (Status)) {\r
+ Status = gBS->ConnectController(DriverHandle, NULL, NULL, TRUE);\r
+ }\r
+\r
+ return Status == EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Call the call back function for the question and process the return action.\r
+\r
+ @param Selection On input, Selection tell setup browser the information\r
+ about the Selection, form and formset to be displayed.\r
+ On output, Selection return the screen item that is selected\r
+ by user.\r
+ @param FormSet The formset this question belong to.\r
+ @param Form The form this question belong to.\r
+ @param Question The Question which need to call.\r
+ @param Action The action request.\r
+ @param SkipSaveOrDiscard Whether skip save or discard action.\r
+\r
+ @retval EFI_SUCCESS The call back function executes successfully.\r
+ @return Other value if the call back function failed to execute.\r
+**/\r
+EFI_STATUS \r
+ProcessCallBackFunction (\r
+ IN OUT UI_MENU_SELECTION *Selection,\r
+ IN FORM_BROWSER_FORMSET *FormSet,\r
+ IN FORM_BROWSER_FORM *Form,\r
+ IN FORM_BROWSER_STATEMENT *Question,\r
+ IN EFI_BROWSER_ACTION Action,\r
+ IN BOOLEAN SkipSaveOrDiscard\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_STATUS InternalStatus;\r
+ EFI_BROWSER_ACTION_REQUEST ActionRequest;\r
+ EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess;\r
+ EFI_HII_VALUE *HiiValue;\r
+ EFI_IFR_TYPE_VALUE *TypeValue;\r
+ FORM_BROWSER_STATEMENT *Statement;\r
+ BOOLEAN SubmitFormIsRequired;\r
+ BOOLEAN DiscardFormIsRequired;\r
+ BOOLEAN NeedExit;\r
+ LIST_ENTRY *Link;\r
+ BROWSER_SETTING_SCOPE SettingLevel;\r
+ EFI_IFR_TYPE_VALUE BackUpValue;\r
+ UINT8 *BackUpBuffer;\r
+ CHAR16 *NewString;\r
+\r
+ ConfigAccess = FormSet->ConfigAccess;\r
+ SubmitFormIsRequired = FALSE;\r
+ SettingLevel = FormSetLevel;\r
+ DiscardFormIsRequired = FALSE;\r
+ NeedExit = FALSE;\r
+ Status = EFI_SUCCESS;\r
+ ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;\r
+ BackUpBuffer = NULL;\r
+\r
+ if (ConfigAccess == NULL) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ Link = GetFirstNode (&Form->StatementListHead);\r
+ while (!IsNull (&Form->StatementListHead, Link)) {\r
+ Statement = FORM_BROWSER_STATEMENT_FROM_LINK (Link);\r
+ Link = GetNextNode (&Form->StatementListHead, Link);\r
+\r
+ //\r
+ // if Question != NULL, only process the question. Else, process all question in this form.\r
+ //\r
+ if ((Question != NULL) && (Statement != Question)) {\r
+ continue;\r
+ }\r
+ \r
+ if ((Statement->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != EFI_IFR_FLAG_CALLBACK) {\r
+ continue;\r
+ }\r
+\r
+ //\r
+ // Check whether Statement is disabled.\r
+ //\r
+ if (Statement->Expression != NULL) {\r
+ if (EvaluateExpressionList(Statement->Expression, TRUE, FormSet, Form) == ExpressDisable) {\r
+ continue;\r
+ }\r
+ }\r
+\r
+ HiiValue = &Statement->HiiValue;\r
+ TypeValue = &HiiValue->Value;\r
+ if (HiiValue->Type == EFI_IFR_TYPE_BUFFER) {\r
+ //\r
+ // For OrderedList, passing in the value buffer to Callback()\r
+ //\r
+ TypeValue = (EFI_IFR_TYPE_VALUE *) Statement->BufferValue;\r
+ }\r
+\r
+ //\r
+ // If EFI_BROWSER_ACTION_CHANGING type, back up the new question value.\r
+ //\r
+ if (Action == EFI_BROWSER_ACTION_CHANGING) {\r
+ if (HiiValue->Type == EFI_IFR_TYPE_BUFFER) {\r
+ BackUpBuffer = AllocateCopyPool(Statement->StorageWidth + sizeof(CHAR16), Statement->BufferValue);\r
+ ASSERT (BackUpBuffer != NULL);\r
+ } else {\r
+ CopyMem (&BackUpValue, &HiiValue->Value, sizeof (EFI_IFR_TYPE_VALUE));\r
+ }\r
+ }\r
+\r
+ ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;\r
+ Status = ConfigAccess->Callback (\r
+ ConfigAccess,\r
+ Action,\r
+ Statement->QuestionId,\r
+ HiiValue->Type,\r
+ TypeValue,\r
+ &ActionRequest\r
+ );\r
+ if (!EFI_ERROR (Status)) {\r
+ //\r
+ // Need to sync the value between Statement->HiiValue->Value and Statement->BufferValue\r
+ //\r
+ if (HiiValue->Type == EFI_IFR_TYPE_STRING) {\r
+ NewString = GetToken (Statement->HiiValue.Value.string, FormSet->HiiHandle);\r
+ ASSERT (NewString != NULL);\r
+\r
+ ASSERT (StrLen (NewString) * sizeof (CHAR16) <= Statement->StorageWidth);\r
+ if (StrLen (NewString) * sizeof (CHAR16) <= Statement->StorageWidth) {\r
+ ZeroMem (Statement->BufferValue, Statement->StorageWidth);\r
+ CopyMem (Statement->BufferValue, NewString, StrSize (NewString));\r
+ } else {\r
+ CopyMem (Statement->BufferValue, NewString, Statement->StorageWidth);\r
+ }\r
+ FreePool (NewString);\r
+ }\r
+\r
+ //\r
+ // Only for EFI_BROWSER_ACTION_CHANGED need to handle this ActionRequest.\r
+ //\r
+ switch (Action) {\r
+ case EFI_BROWSER_ACTION_CHANGED:\r
+ switch (ActionRequest) {\r
+ case EFI_BROWSER_ACTION_REQUEST_RESET:\r
+ DiscardFormIsRequired = TRUE;\r
+ gResetRequired = TRUE;\r
+ NeedExit = TRUE;\r
+ break;\r
+\r
+ case EFI_BROWSER_ACTION_REQUEST_SUBMIT:\r
+ SubmitFormIsRequired = TRUE;\r
+ NeedExit = TRUE;\r
+ break;\r
+\r
+ case EFI_BROWSER_ACTION_REQUEST_EXIT:\r
+ DiscardFormIsRequired = TRUE;\r
+ NeedExit = TRUE;\r
+ break;\r
+\r
+ case EFI_BROWSER_ACTION_REQUEST_FORM_SUBMIT_EXIT:\r
+ SubmitFormIsRequired = TRUE;\r
+ SettingLevel = FormLevel;\r
+ NeedExit = TRUE;\r
+ break;\r
+\r
+ case EFI_BROWSER_ACTION_REQUEST_FORM_DISCARD_EXIT:\r
+ DiscardFormIsRequired = TRUE;\r
+ SettingLevel = FormLevel;\r
+ NeedExit = TRUE;\r
+ break;\r
+\r
+ case EFI_BROWSER_ACTION_REQUEST_FORM_APPLY:\r
+ SubmitFormIsRequired = TRUE;\r
+ SettingLevel = FormLevel;\r
+ break;\r
+\r
+ case EFI_BROWSER_ACTION_REQUEST_FORM_DISCARD:\r
+ DiscardFormIsRequired = TRUE;\r
+ SettingLevel = FormLevel;\r
+ break;\r
+\r
+ case EFI_BROWSER_ACTION_REQUEST_RECONNECT:\r
+ gCallbackReconnect = TRUE;\r
+ break;\r
+\r
+ default:\r
+ break;\r
+ }\r
+ break;\r