+/**\r
+ check whether the formset need to update the NV.\r
+\r
+ @param FormSet FormSet data structure.\r
+\r
+ @retval TRUE Need to update the NV.\r
+ @retval FALSE No need to update the NV.\r
+**/\r
+BOOLEAN \r
+IsNvUpdateRequired (\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
+\r
+ if (Form->NvUpdateRequired ) {\r
+ return TRUE;\r
+ }\r
+\r
+ Link = GetNextNode (&FormSet->FormListHead, Link);\r
+ }\r
+\r
+ return FALSE;\r
+}\r
+\r
+/**\r
+ check whether the formset need to update the NV.\r
+\r
+ @param FormSet FormSet data structure.\r
+ @param SetValue Whether set new value or clear old value.\r
+\r
+**/\r
+VOID\r
+UpdateNvInfoInForm (\r
+ IN FORM_BROWSER_FORMSET *FormSet,\r
+ IN BOOLEAN SetValue\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
+\r
+ Form->NvUpdateRequired = SetValue;\r
+\r
+ Link = GetNextNode (&FormSet->FormListHead, Link);\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 Repaint Whether need to repaint the menu.\r
+ @param NewLine Whether need to show at new line.\r
+ \r
+ @retval TRUE Need return.\r
+ @retval FALSE No need to return.\r
+**/\r
+BOOLEAN\r
+FindNextMenu (\r
+ IN OUT UI_MENU_SELECTION *Selection,\r
+ IN BOOLEAN *Repaint, \r
+ IN BOOLEAN *NewLine \r
+ )\r
+{\r
+ UI_MENU_LIST *CurrentMenu;\r
+ CHAR16 YesResponse;\r
+ CHAR16 NoResponse;\r
+ EFI_INPUT_KEY Key;\r
+ EFI_STATUS Status;\r
+ \r
+ CurrentMenu = Selection->CurrentMenu;\r
+\r
+ if (CurrentMenu != NULL && CurrentMenu->Parent != NULL) {\r
+ //\r
+ // we have a parent, so go to the parent menu\r
+ //\r
+ if (CompareGuid (&CurrentMenu->FormSetGuid, &CurrentMenu->Parent->FormSetGuid)) {\r
+ //\r
+ // The parent menu and current menu are in the same formset\r
+ //\r
+ Selection->Action = UI_ACTION_REFRESH_FORM;\r
+ } else {\r
+ Selection->Action = UI_ACTION_REFRESH_FORMSET;\r
+ }\r
+ Selection->Statement = NULL;\r
+\r
+ Selection->FormId = CurrentMenu->Parent->FormId;\r
+ Selection->QuestionId = CurrentMenu->Parent->QuestionId;\r
+\r
+ //\r
+ // Clear highlight record for this menu\r
+ //\r
+ CurrentMenu->QuestionId = 0;\r
+ return FALSE;\r
+ }\r
+\r
+ if ((gClassOfVfr & FORMSET_CLASS_FRONT_PAGE) == FORMSET_CLASS_FRONT_PAGE) {\r
+ //\r
+ // We never exit FrontPage, so skip the ESC\r
+ //\r
+ Selection->Action = UI_ACTION_NONE;\r
+ return FALSE;\r
+ }\r
+\r
+ //\r
+ // We are going to leave current FormSet, so check uncommited data in this FormSet\r
+ //\r
+ if (IsNvUpdateRequired(Selection->FormSet)) {\r
+ Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);\r
+\r
+ YesResponse = gYesResponse[0];\r
+ NoResponse = gNoResponse[0];\r
+\r
+ //\r
+ // If NV flag is up, prompt user\r
+ //\r
+ do {\r
+ CreateDialog (4, TRUE, 0, NULL, &Key, gEmptyString, gSaveChanges, gAreYouSure, gEmptyString);\r
+ } while\r
+ (\r
+ (Key.ScanCode != SCAN_ESC) &&\r
+ ((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) != (NoResponse | UPPER_LOWER_CASE_OFFSET)) &&\r
+ ((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) != (YesResponse | UPPER_LOWER_CASE_OFFSET))\r
+ );\r
+\r
+ if (Key.ScanCode == SCAN_ESC) {\r
+ //\r
+ // User hits the ESC key\r
+ //\r
+ if (Repaint != NULL) {\r
+ *Repaint = TRUE;\r
+ }\r
+\r
+ if (NewLine != NULL) {\r
+ *NewLine = TRUE;\r
+ }\r
+\r
+ Selection->Action = UI_ACTION_NONE;\r
+ return FALSE;\r
+ }\r
+\r
+ //\r
+ // If the user hits the YesResponse key\r
+ //\r
+ if ((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) == (YesResponse | UPPER_LOWER_CASE_OFFSET)) {\r
+ Status = SubmitForm (Selection->FormSet, Selection->Form, FALSE);\r
+ }\r
+ }\r
+\r
+ Selection->Statement = NULL;\r
+ if (CurrentMenu != NULL) {\r
+ CurrentMenu->QuestionId = 0;\r
+ }\r
+\r
+ Selection->Action = UI_ACTION_EXIT;\r
+ return TRUE;\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 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 excutes successfully.\r
+ @return Other value if the call back function failed to excute. \r
+**/\r
+EFI_STATUS \r
+ProcessCallBackFunction (\r
+ IN OUT UI_MENU_SELECTION *Selection,\r
+ IN FORM_BROWSER_STATEMENT *Question,\r
+ IN EFI_BROWSER_ACTION Action,\r
+ IN BOOLEAN SkipSaveOrDiscard\r
+ )\r
+{\r
+ EFI_STATUS Status;\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 SingleForm;\r
+ BOOLEAN DiscardFormIsRequired;\r
+ BOOLEAN NeedExit;\r
+ LIST_ENTRY *Link;\r
+\r
+ ConfigAccess = Selection->FormSet->ConfigAccess;\r
+ SubmitFormIsRequired = FALSE;\r
+ SingleForm = FALSE;\r
+ DiscardFormIsRequired = FALSE;\r
+ NeedExit = FALSE;\r
+ Status = EFI_SUCCESS;\r
+ ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;\r
+\r
+ if (ConfigAccess == NULL) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ Link = GetFirstNode (&Selection->Form->StatementListHead);\r
+ while (!IsNull (&Selection->Form->StatementListHead, Link)) {\r
+ Statement = FORM_BROWSER_STATEMENT_FROM_LINK (Link);\r
+ Link = GetNextNode (&Selection->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->DisableExpression != NULL) {\r
+ Status = EvaluateExpression (Selection->FormSet, Selection->Form, Statement->DisableExpression);\r
+ if (!EFI_ERROR (Status) && \r
+ (Statement->DisableExpression->Result.Type == EFI_IFR_TYPE_BOOLEAN) && \r
+ (Statement->DisableExpression->Result.Value.b)) {\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
+ 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
+ switch (ActionRequest) {\r
+ case EFI_BROWSER_ACTION_REQUEST_RESET:\r
+ gResetRequired = TRUE;\r
+ break;\r
+\r
+ case EFI_BROWSER_ACTION_REQUEST_SUBMIT:\r
+ SubmitFormIsRequired = TRUE;\r
+ break;\r
+\r
+ case EFI_BROWSER_ACTION_REQUEST_EXIT:\r
+ Selection->Action = UI_ACTION_EXIT;\r
+ break;\r
+\r
+ case EFI_BROWSER_ACTION_REQUEST_FORM_SUBMIT_EXIT:\r
+ SubmitFormIsRequired = TRUE;\r
+ SingleForm = TRUE;\r
+ NeedExit = TRUE;\r
+ break;\r
+\r
+ case EFI_BROWSER_ACTION_REQUEST_FORM_DISCARD_EXIT:\r
+ DiscardFormIsRequired = TRUE;\r
+ SingleForm = TRUE; \r
+ NeedExit = TRUE;\r
+ break;\r
+\r
+ case EFI_BROWSER_ACTION_REQUEST_FORM_APPLY:\r
+ SubmitFormIsRequired = TRUE;\r
+ SingleForm = TRUE;\r
+ break;\r
+\r
+ case EFI_BROWSER_ACTION_REQUEST_FORM_DISCARD:\r
+ DiscardFormIsRequired = TRUE;\r
+ SingleForm = TRUE;\r
+ break;\r
+\r
+ default:\r
+ break;\r
+ }\r
+\r
+ //\r
+ // According the spec, return value from call back of "changing" and \r
+ // "retrieve" should update to the question's temp buffer.\r
+ //\r
+ if (Action == EFI_BROWSER_ACTION_CHANGING || Action == EFI_BROWSER_ACTION_RETRIEVE) {\r
+ SetQuestionValue(Selection->FormSet, Selection->Form, Statement, TRUE);\r
+ }\r
+ } else if (Status == EFI_UNSUPPORTED) {\r
+ //\r
+ // If return EFI_UNSUPPORTED, also consider Hii driver suceess deal with it.\r
+ //\r
+ Status = EFI_SUCCESS;\r
+ }\r
+ }\r
+\r
+ if (SubmitFormIsRequired && !SkipSaveOrDiscard) {\r
+ SubmitForm (Selection->FormSet, Selection->Form, SingleForm);\r
+ }\r
+\r
+ if (DiscardFormIsRequired && !SkipSaveOrDiscard) {\r
+ DiscardForm (Selection->FormSet, Selection->Form, SingleForm);\r
+ }\r
+\r
+ if (NeedExit) {\r
+ FindNextMenu (Selection, NULL, NULL);\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r