Home | History | Annotate | Download | only in SetupBrowserDxe
      1 /** @file
      2 Utility functions for UI presentation.
      3 
      4 Copyright (c) 2004 - 2015, Intel Corporation. All rights reserved.<BR>
      5 (C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>
      6 This program and the accompanying materials
      7 are licensed and made available under the terms and conditions of the BSD License
      8 which accompanies this distribution.  The full text of the license may be found at
      9 http://opensource.org/licenses/bsd-license.php
     10 
     11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     13 
     14 **/
     15 
     16 #include "Setup.h"
     17 
     18 BOOLEAN            mHiiPackageListUpdated;
     19 UI_MENU_SELECTION  *gCurrentSelection;
     20 EFI_HII_HANDLE     mCurrentHiiHandle = NULL;
     21 EFI_GUID           mCurrentFormSetGuid = {0, 0, 0, {0, 0, 0, 0, 0, 0, 0, 0}};
     22 UINT16             mCurrentFormId = 0;
     23 EFI_EVENT          mValueChangedEvent = NULL;
     24 LIST_ENTRY         mRefreshEventList = INITIALIZE_LIST_HEAD_VARIABLE (mRefreshEventList);
     25 UINT16             mCurFakeQestId;
     26 FORM_DISPLAY_ENGINE_FORM gDisplayFormData;
     27 BOOLEAN            mFinishRetrieveCall = FALSE;
     28 
     29 /**
     30   Evaluate all expressions in a Form.
     31 
     32   @param  FormSet        FormSet this Form belongs to.
     33   @param  Form           The Form.
     34 
     35   @retval EFI_SUCCESS    The expression evaluated successfuly
     36 
     37 **/
     38 EFI_STATUS
     39 EvaluateFormExpressions (
     40   IN FORM_BROWSER_FORMSET  *FormSet,
     41   IN FORM_BROWSER_FORM     *Form
     42   )
     43 {
     44   EFI_STATUS       Status;
     45   LIST_ENTRY       *Link;
     46   FORM_EXPRESSION  *Expression;
     47 
     48   Link = GetFirstNode (&Form->ExpressionListHead);
     49   while (!IsNull (&Form->ExpressionListHead, Link)) {
     50     Expression = FORM_EXPRESSION_FROM_LINK (Link);
     51     Link = GetNextNode (&Form->ExpressionListHead, Link);
     52 
     53     if (Expression->Type == EFI_HII_EXPRESSION_INCONSISTENT_IF ||
     54         Expression->Type == EFI_HII_EXPRESSION_NO_SUBMIT_IF ||
     55         Expression->Type == EFI_HII_EXPRESSION_WARNING_IF ||
     56         Expression->Type == EFI_HII_EXPRESSION_WRITE ||
     57         (Expression->Type == EFI_HII_EXPRESSION_READ && Form->FormType != STANDARD_MAP_FORM_TYPE)) {
     58       //
     59       // Postpone Form validation to Question editing or Form submitting or Question Write or Question Read for nonstandard form.
     60       //
     61       continue;
     62     }
     63 
     64     Status = EvaluateExpression (FormSet, Form, Expression);
     65     if (EFI_ERROR (Status)) {
     66       return Status;
     67     }
     68   }
     69 
     70   return EFI_SUCCESS;
     71 }
     72 
     73 /**
     74   Add empty function for event process function.
     75 
     76   @param Event    The Event need to be process
     77   @param Context  The context of the event.
     78 
     79 **/
     80 VOID
     81 EFIAPI
     82 SetupBrowserEmptyFunction (
     83   IN  EFI_EVENT    Event,
     84   IN  VOID         *Context
     85   )
     86 {
     87 }
     88 
     89 /**
     90   Base on the opcode buffer info to get the display statement.
     91 
     92   @param OpCode    The input opcode buffer for this statement.
     93 
     94   @retval Statement  The statement use this opcode buffer.
     95 
     96 **/
     97 FORM_DISPLAY_ENGINE_STATEMENT *
     98 GetDisplayStatement (
     99   IN EFI_IFR_OP_HEADER     *OpCode
    100   )
    101 {
    102   FORM_DISPLAY_ENGINE_STATEMENT *DisplayStatement;
    103   LIST_ENTRY                    *Link;
    104 
    105   Link = GetFirstNode (&gDisplayFormData.StatementListHead);
    106   while (!IsNull (&gDisplayFormData.StatementListHead, Link)) {
    107     DisplayStatement = FORM_DISPLAY_ENGINE_STATEMENT_FROM_LINK (Link);
    108 
    109     if (DisplayStatement->OpCode == OpCode) {
    110       return DisplayStatement;
    111     }
    112     Link = GetNextNode (&gDisplayFormData.StatementListHead, Link);
    113   }
    114 
    115   return NULL;
    116 }
    117 
    118 /**
    119   Free the refresh event list.
    120 
    121 **/
    122 VOID
    123 FreeRefreshEvent (
    124   VOID
    125   )
    126 {
    127   LIST_ENTRY   *Link;
    128   FORM_BROWSER_REFRESH_EVENT_NODE *EventNode;
    129 
    130   while (!IsListEmpty (&mRefreshEventList)) {
    131     Link = GetFirstNode (&mRefreshEventList);
    132     EventNode = FORM_BROWSER_REFRESH_EVENT_FROM_LINK (Link);
    133     RemoveEntryList (&EventNode->Link);
    134 
    135     gBS->CloseEvent (EventNode->RefreshEvent);
    136 
    137     FreePool (EventNode);
    138   }
    139 }
    140 
    141 /**
    142   Check whether this statement value is changed. If yes, update the statement value and return TRUE;
    143   else return FALSE.
    144 
    145   @param Statement           The statement need to check.
    146 
    147 **/
    148 VOID
    149 UpdateStatement (
    150   IN OUT FORM_BROWSER_STATEMENT        *Statement
    151   )
    152 {
    153   GetQuestionValue (gCurrentSelection->FormSet, gCurrentSelection->Form, Statement, GetSetValueWithHiiDriver);
    154 
    155   //
    156   // Reset FormPackage update flag
    157   //
    158   mHiiPackageListUpdated = FALSE;
    159 
    160   //
    161   // Question value may be changed, need invoke its Callback()
    162   //
    163   ProcessCallBackFunction (gCurrentSelection, gCurrentSelection->FormSet, gCurrentSelection->Form, Statement, EFI_BROWSER_ACTION_RETRIEVE, FALSE);
    164 
    165   if (mHiiPackageListUpdated) {
    166     //
    167     // Package list is updated, force to reparse IFR binary of target Formset
    168     //
    169     mHiiPackageListUpdated = FALSE;
    170     gCurrentSelection->Action = UI_ACTION_REFRESH_FORMSET;
    171   }
    172 }
    173 
    174 /**
    175   Refresh the question which has refresh guid event attribute.
    176 
    177   @param Event    The event which has this function related.
    178   @param Context  The input context info related to this event or the status code return to the caller.
    179 **/
    180 VOID
    181 EFIAPI
    182 RefreshEventNotifyForStatement(
    183   IN      EFI_EVENT Event,
    184   IN      VOID      *Context
    185   )
    186 {
    187   FORM_BROWSER_STATEMENT        *Statement;
    188 
    189   Statement = (FORM_BROWSER_STATEMENT *)Context;
    190   UpdateStatement(Statement);
    191   gBS->SignalEvent (mValueChangedEvent);
    192 }
    193 
    194 /**
    195   Refresh the questions within this form.
    196 
    197   @param Event    The event which has this function related.
    198   @param Context  The input context info related to this event or the status code return to the caller.
    199 **/
    200 VOID
    201 EFIAPI
    202 RefreshEventNotifyForForm(
    203   IN      EFI_EVENT Event,
    204   IN      VOID      *Context
    205   )
    206 {
    207   gCurrentSelection->Action = UI_ACTION_REFRESH_FORMSET;
    208 
    209   gBS->SignalEvent (mValueChangedEvent);
    210 }
    211 
    212 /**
    213   Create refresh hook event for statement which has refresh event or interval.
    214 
    215   @param Statement           The statement need to check.
    216 
    217 **/
    218 VOID
    219 CreateRefreshEventForStatement (
    220   IN     FORM_BROWSER_STATEMENT        *Statement
    221   )
    222 {
    223   EFI_STATUS                      Status;
    224   EFI_EVENT                       RefreshEvent;
    225   FORM_BROWSER_REFRESH_EVENT_NODE *EventNode;
    226 
    227   //
    228   // If question has refresh guid, create the notify function.
    229   //
    230   Status = gBS->CreateEventEx (
    231                     EVT_NOTIFY_SIGNAL,
    232                     TPL_CALLBACK,
    233                     RefreshEventNotifyForStatement,
    234                     Statement,
    235                     &Statement->RefreshGuid,
    236                     &RefreshEvent);
    237   ASSERT_EFI_ERROR (Status);
    238 
    239   EventNode = AllocateZeroPool (sizeof (FORM_BROWSER_REFRESH_EVENT_NODE));
    240   ASSERT (EventNode != NULL);
    241   EventNode->RefreshEvent = RefreshEvent;
    242   InsertTailList(&mRefreshEventList, &EventNode->Link);
    243 }
    244 
    245 /**
    246   Create refresh hook event for form which has refresh event or interval.
    247 
    248   @param Form           The form need to check.
    249 
    250 **/
    251 VOID
    252 CreateRefreshEventForForm (
    253   IN     FORM_BROWSER_FORM        *Form
    254   )
    255 {
    256   EFI_STATUS                      Status;
    257   EFI_EVENT                       RefreshEvent;
    258   FORM_BROWSER_REFRESH_EVENT_NODE *EventNode;
    259 
    260   //
    261   // If question has refresh guid, create the notify function.
    262   //
    263   Status = gBS->CreateEventEx (
    264                     EVT_NOTIFY_SIGNAL,
    265                     TPL_CALLBACK,
    266                     RefreshEventNotifyForForm,
    267                     Form,
    268                     &Form->RefreshGuid,
    269                     &RefreshEvent);
    270   ASSERT_EFI_ERROR (Status);
    271 
    272   EventNode = AllocateZeroPool (sizeof (FORM_BROWSER_REFRESH_EVENT_NODE));
    273   ASSERT (EventNode != NULL);
    274   EventNode->RefreshEvent = RefreshEvent;
    275   InsertTailList(&mRefreshEventList, &EventNode->Link);
    276 }
    277 
    278 /**
    279 
    280   Initialize the Display statement structure data.
    281 
    282   @param DisplayStatement      Pointer to the display Statement data strucure.
    283   @param Statement             The statement need to check.
    284 **/
    285 VOID
    286 InitializeDisplayStatement (
    287   IN OUT FORM_DISPLAY_ENGINE_STATEMENT *DisplayStatement,
    288   IN     FORM_BROWSER_STATEMENT        *Statement
    289   )
    290 {
    291   LIST_ENTRY                 *Link;
    292   QUESTION_OPTION            *Option;
    293   DISPLAY_QUESTION_OPTION    *DisplayOption;
    294   FORM_DISPLAY_ENGINE_STATEMENT *ParentStatement;
    295 
    296   DisplayStatement->Signature = FORM_DISPLAY_ENGINE_STATEMENT_SIGNATURE;
    297   DisplayStatement->Version   = FORM_DISPLAY_ENGINE_STATEMENT_VERSION_1;
    298   DisplayStatement->OpCode    = Statement->OpCode;
    299   InitializeListHead (&DisplayStatement->NestStatementList);
    300   InitializeListHead (&DisplayStatement->OptionListHead);
    301 
    302   if ((EvaluateExpressionList(Statement->Expression, FALSE, NULL, NULL) == ExpressGrayOut) || Statement->Locked) {
    303     DisplayStatement->Attribute |= HII_DISPLAY_GRAYOUT;
    304   }
    305   if ((Statement->ValueExpression != NULL) || ((Statement->QuestionFlags & EFI_IFR_FLAG_READ_ONLY) != 0)) {
    306     DisplayStatement->Attribute |= HII_DISPLAY_READONLY;
    307   }
    308 
    309   //
    310   // Initilize the option list in statement.
    311   //
    312   Link = GetFirstNode (&Statement->OptionListHead);
    313   while (!IsNull (&Statement->OptionListHead, Link)) {
    314     Option = QUESTION_OPTION_FROM_LINK (Link);
    315     Link = GetNextNode (&Statement->OptionListHead, Link);
    316     if ((Option->SuppressExpression != NULL) &&
    317         ((EvaluateExpressionList(Option->SuppressExpression, FALSE, NULL, NULL) == ExpressSuppress))) {
    318       continue;
    319     }
    320 
    321     DisplayOption = AllocateZeroPool (sizeof (DISPLAY_QUESTION_OPTION));
    322     ASSERT (DisplayOption != NULL);
    323 
    324     DisplayOption->ImageId      = Option->ImageId;
    325     DisplayOption->Signature    = DISPLAY_QUESTION_OPTION_SIGNATURE;
    326     DisplayOption->OptionOpCode = Option->OpCode;
    327     InsertTailList(&DisplayStatement->OptionListHead, &DisplayOption->Link);
    328   }
    329 
    330   CopyMem (&DisplayStatement->CurrentValue, &Statement->HiiValue, sizeof (EFI_HII_VALUE));
    331 
    332   //
    333   // Some special op code need an extra buffer to save the data.
    334   // Such as string, password, orderedlist...
    335   //
    336   if (Statement->BufferValue != NULL) {
    337     //
    338     // Ordered list opcode may not initilized, get default value here.
    339     //
    340     if (Statement->OpCode->OpCode == EFI_IFR_ORDERED_LIST_OP && GetArrayData (Statement->BufferValue, Statement->ValueType, 0) == 0) {
    341       GetQuestionDefault (gCurrentSelection->FormSet, gCurrentSelection->Form, Statement, 0);
    342     }
    343 
    344     DisplayStatement->CurrentValue.Buffer    = AllocateCopyPool(Statement->StorageWidth,Statement->BufferValue);
    345     DisplayStatement->CurrentValue.BufferLen = Statement->StorageWidth;
    346   }
    347 
    348   DisplayStatement->SettingChangedFlag = Statement->ValueChanged;
    349 
    350   //
    351   // Get the highlight statement for current form.
    352   //
    353   if (((gCurrentSelection->QuestionId != 0) && (Statement->QuestionId == gCurrentSelection->QuestionId)) ||
    354       ((mCurFakeQestId != 0) && (Statement->FakeQuestionId == mCurFakeQestId))) {
    355     gDisplayFormData.HighLightedStatement = DisplayStatement;
    356   }
    357 
    358   //
    359   // Create the refresh event process function.
    360   //
    361   if (!CompareGuid (&Statement->RefreshGuid, &gZeroGuid)) {
    362     CreateRefreshEventForStatement (Statement);
    363   }
    364 
    365   //
    366   // For RTC type of date/time, set default refresh interval to be 1 second.
    367   //
    368   if ((Statement->Operand == EFI_IFR_DATE_OP || Statement->Operand == EFI_IFR_TIME_OP) && Statement->Storage == NULL) {
    369     Statement->RefreshInterval = 1;
    370   }
    371 
    372   //
    373   // Create the refresh guid hook event.
    374   // If the statement in this form has refresh event or refresh interval, browser will create this event for display engine.
    375   //
    376   if ((!CompareGuid (&Statement->RefreshGuid, &gZeroGuid)) || (Statement->RefreshInterval != 0)) {
    377     gDisplayFormData.FormRefreshEvent = mValueChangedEvent;
    378   }
    379 
    380   //
    381   // Save the password check function for later use.
    382   //
    383   if (Statement->Operand == EFI_IFR_PASSWORD_OP) {
    384     DisplayStatement->PasswordCheck = PasswordCheck;
    385   }
    386 
    387   //
    388   // If this statement is nest in the subtitle, insert to the host statement.
    389   // else insert to the form it belongs to.
    390   //
    391   if (Statement->ParentStatement != NULL) {
    392     ParentStatement = GetDisplayStatement(Statement->ParentStatement->OpCode);
    393     ASSERT (ParentStatement != NULL);
    394     InsertTailList(&ParentStatement->NestStatementList, &DisplayStatement->DisplayLink);
    395   } else {
    396     InsertTailList(&gDisplayFormData.StatementListHead, &DisplayStatement->DisplayLink);
    397   }
    398 }
    399 
    400 /**
    401   Process for the refresh interval statement.
    402 
    403   @param Event    The Event need to be process
    404   @param Context  The context of the event.
    405 
    406 **/
    407 VOID
    408 EFIAPI
    409 RefreshIntervalProcess (
    410   IN  EFI_EVENT    Event,
    411   IN  VOID         *Context
    412   )
    413 {
    414   FORM_BROWSER_STATEMENT        *Statement;
    415   LIST_ENTRY                    *Link;
    416 
    417   Link = GetFirstNode (&gCurrentSelection->Form->StatementListHead);
    418   while (!IsNull (&gCurrentSelection->Form->StatementListHead, Link)) {
    419     Statement = FORM_BROWSER_STATEMENT_FROM_LINK (Link);
    420     Link = GetNextNode (&gCurrentSelection->Form->StatementListHead, Link);
    421 
    422     if (Statement->RefreshInterval == 0) {
    423       continue;
    424     }
    425 
    426     UpdateStatement(Statement);
    427   }
    428 
    429   gBS->SignalEvent (mValueChangedEvent);
    430 }
    431 
    432 /**
    433 
    434   Make a copy of the global hotkey info.
    435 
    436 **/
    437 VOID
    438 UpdateHotkeyList (
    439   VOID
    440   )
    441 {
    442   BROWSER_HOT_KEY  *HotKey;
    443   BROWSER_HOT_KEY  *CopyKey;
    444   LIST_ENTRY       *Link;
    445 
    446   Link = GetFirstNode (&gBrowserHotKeyList);
    447   while (!IsNull (&gBrowserHotKeyList, Link)) {
    448     HotKey = BROWSER_HOT_KEY_FROM_LINK (Link);
    449 
    450     CopyKey             = AllocateCopyPool(sizeof (BROWSER_HOT_KEY), HotKey);
    451     ASSERT (CopyKey != NULL);
    452     CopyKey->KeyData    = AllocateCopyPool(sizeof (EFI_INPUT_KEY), HotKey->KeyData);
    453     ASSERT (CopyKey->KeyData != NULL);
    454     CopyKey->HelpString = AllocateCopyPool(StrSize (HotKey->HelpString), HotKey->HelpString);
    455     ASSERT (CopyKey->HelpString != NULL);
    456 
    457     InsertTailList(&gDisplayFormData.HotKeyListHead, &CopyKey->Link);
    458 
    459     Link = GetNextNode (&gBrowserHotKeyList, Link);
    460   }
    461 }
    462 
    463 /**
    464 
    465   Get the extra question attribute from override question list.
    466 
    467   @param    QuestionId    The question id for this request question.
    468 
    469   @retval   The attribute for this question or NULL if not found this
    470             question in the list.
    471 
    472 **/
    473 UINT32
    474 ProcessQuestionExtraAttr (
    475   IN   EFI_QUESTION_ID  QuestionId
    476   )
    477 {
    478   LIST_ENTRY                   *Link;
    479   QUESTION_ATTRIBUTE_OVERRIDE  *QuestionDesc;
    480 
    481   //
    482   // Return HII_DISPLAY_NONE if input a invalid question id.
    483   //
    484   if (QuestionId == 0) {
    485     return HII_DISPLAY_NONE;
    486   }
    487 
    488   Link = GetFirstNode (&mPrivateData.FormBrowserEx2.OverrideQestListHead);
    489   while (!IsNull (&mPrivateData.FormBrowserEx2.OverrideQestListHead, Link)) {
    490     QuestionDesc = FORM_QUESTION_ATTRIBUTE_OVERRIDE_FROM_LINK (Link);
    491     Link = GetNextNode (&mPrivateData.FormBrowserEx2.OverrideQestListHead, Link);
    492 
    493     if ((QuestionDesc->QuestionId == QuestionId) &&
    494         (QuestionDesc->FormId     == gCurrentSelection->FormId) &&
    495         (QuestionDesc->HiiHandle  == gCurrentSelection->Handle) &&
    496         CompareGuid (&QuestionDesc->FormSetGuid, &gCurrentSelection->FormSetGuid)) {
    497       return QuestionDesc->Attribute;
    498     }
    499   }
    500 
    501   return HII_DISPLAY_NONE;
    502 }
    503 
    504 /**
    505 
    506   Enum all statement in current form, find all the statement can be display and
    507   add to the display form.
    508 
    509 **/
    510 VOID
    511 AddStatementToDisplayForm (
    512   VOID
    513   )
    514 {
    515   EFI_STATUS                    Status;
    516   LIST_ENTRY                    *Link;
    517   FORM_BROWSER_STATEMENT        *Statement;
    518   FORM_DISPLAY_ENGINE_STATEMENT *DisplayStatement;
    519   UINT8                         MinRefreshInterval;
    520   EFI_EVENT                     RefreshIntervalEvent;
    521   FORM_BROWSER_REFRESH_EVENT_NODE *EventNode;
    522   BOOLEAN                       FormEditable;
    523   UINT32                        ExtraAttribute;
    524 
    525   MinRefreshInterval   = 0;
    526   FormEditable         = FALSE;
    527 
    528   //
    529   // Process the statement outside the form, these statements are not recognized
    530   // by browser core.
    531   //
    532   Link = GetFirstNode (&gCurrentSelection->FormSet->StatementListOSF);
    533   while (!IsNull (&gCurrentSelection->FormSet->StatementListOSF, Link)) {
    534     Statement = FORM_BROWSER_STATEMENT_FROM_LINK (Link);
    535     Link = GetNextNode (&gCurrentSelection->FormSet->StatementListOSF, Link);
    536 
    537     DisplayStatement = AllocateZeroPool (sizeof (FORM_DISPLAY_ENGINE_STATEMENT));
    538     ASSERT (DisplayStatement != NULL);
    539     DisplayStatement->Signature = FORM_DISPLAY_ENGINE_STATEMENT_SIGNATURE;
    540     DisplayStatement->Version   = FORM_DISPLAY_ENGINE_STATEMENT_VERSION_1;
    541     DisplayStatement->OpCode = Statement->OpCode;
    542 
    543     InitializeListHead (&DisplayStatement->NestStatementList);
    544     InitializeListHead (&DisplayStatement->OptionListHead);
    545 
    546     InsertTailList(&gDisplayFormData.StatementListOSF, &DisplayStatement->DisplayLink);
    547   }
    548 
    549   //
    550   // treat formset as statement outside the form,get its opcode.
    551   //
    552   DisplayStatement = AllocateZeroPool (sizeof (FORM_DISPLAY_ENGINE_STATEMENT));
    553   ASSERT (DisplayStatement != NULL);
    554 
    555   DisplayStatement->Signature = FORM_DISPLAY_ENGINE_STATEMENT_SIGNATURE;
    556   DisplayStatement->Version   = FORM_DISPLAY_ENGINE_STATEMENT_VERSION_1;
    557   DisplayStatement->OpCode = gCurrentSelection->FormSet->OpCode;
    558 
    559   InitializeListHead (&DisplayStatement->NestStatementList);
    560   InitializeListHead (&DisplayStatement->OptionListHead);
    561 
    562   InsertTailList(&gDisplayFormData.StatementListOSF, &DisplayStatement->DisplayLink);
    563 
    564   //
    565   // Process the statement in this form.
    566   //
    567   Link = GetFirstNode (&gCurrentSelection->Form->StatementListHead);
    568   while (!IsNull (&gCurrentSelection->Form->StatementListHead, Link)) {
    569     Statement = FORM_BROWSER_STATEMENT_FROM_LINK (Link);
    570     Link = GetNextNode (&gCurrentSelection->Form->StatementListHead, Link);
    571 
    572     //
    573     // This statement can't be show, skip it.
    574     //
    575     if (EvaluateExpressionList(Statement->Expression, FALSE, NULL, NULL) > ExpressGrayOut) {
    576       continue;
    577     }
    578 
    579     //
    580     // Check the extra attribute.
    581     //
    582     ExtraAttribute = ProcessQuestionExtraAttr (Statement->QuestionId);
    583     if ((ExtraAttribute & HII_DISPLAY_SUPPRESS) != 0) {
    584       continue;
    585     }
    586 
    587     DisplayStatement = AllocateZeroPool (sizeof (FORM_DISPLAY_ENGINE_STATEMENT));
    588     ASSERT (DisplayStatement != NULL);
    589 
    590     //
    591     // Initialize this statement and add it to the display form.
    592     //
    593     InitializeDisplayStatement(DisplayStatement, Statement);
    594 
    595     //
    596     // Set the extra attribute.
    597     //
    598     DisplayStatement->Attribute |= ExtraAttribute;
    599 
    600     if (Statement->Storage != NULL) {
    601       FormEditable = TRUE;
    602     }
    603 
    604     //
    605     // Get the minimal refresh interval value for later use.
    606     //
    607     if ((Statement->RefreshInterval != 0) &&
    608       (MinRefreshInterval == 0 || Statement->RefreshInterval < MinRefreshInterval)) {
    609       MinRefreshInterval = Statement->RefreshInterval;
    610     }
    611   }
    612 
    613   //
    614   // Create the periodic timer for refresh interval statement.
    615   //
    616   if (MinRefreshInterval != 0) {
    617     Status = gBS->CreateEvent (EVT_TIMER | EVT_NOTIFY_SIGNAL, TPL_CALLBACK, RefreshIntervalProcess, NULL, &RefreshIntervalEvent);
    618     ASSERT_EFI_ERROR (Status);
    619     Status = gBS->SetTimer (RefreshIntervalEvent, TimerPeriodic, MinRefreshInterval * ONE_SECOND);
    620     ASSERT_EFI_ERROR (Status);
    621 
    622     EventNode = AllocateZeroPool (sizeof (FORM_BROWSER_REFRESH_EVENT_NODE));
    623     ASSERT (EventNode != NULL);
    624     EventNode->RefreshEvent = RefreshIntervalEvent;
    625     InsertTailList(&mRefreshEventList, &EventNode->Link);
    626   }
    627 
    628   //
    629   // Create the refresh event process function for Form.
    630   //
    631   if (!CompareGuid (&gCurrentSelection->Form->RefreshGuid, &gZeroGuid)) {
    632     CreateRefreshEventForForm (gCurrentSelection->Form);
    633     if (gDisplayFormData.FormRefreshEvent == NULL) {
    634       gDisplayFormData.FormRefreshEvent = mValueChangedEvent;
    635     }
    636   }
    637 
    638   //
    639   // Update hotkey list field.
    640   //
    641   if (gBrowserSettingScope == SystemLevel || FormEditable) {
    642     UpdateHotkeyList();
    643   }
    644 }
    645 
    646 /**
    647 
    648   Initialize the SettingChangedFlag variable in the display form.
    649 
    650 **/
    651 VOID
    652 UpdateDataChangedFlag (
    653   VOID
    654   )
    655 {
    656   LIST_ENTRY           *Link;
    657   FORM_BROWSER_FORMSET *LocalFormSet;
    658 
    659   gDisplayFormData.SettingChangedFlag   = FALSE;
    660 
    661   if (IsNvUpdateRequiredForForm (gCurrentSelection->Form)) {
    662     gDisplayFormData.SettingChangedFlag = TRUE;
    663     return;
    664   }
    665 
    666   //
    667   // Base on the system level to check whether need to show the NV flag.
    668   //
    669   switch (gBrowserSettingScope) {
    670   case SystemLevel:
    671     //
    672     // Check the maintain list to see whether there is any change.
    673     //
    674     Link = GetFirstNode (&gBrowserFormSetList);
    675     while (!IsNull (&gBrowserFormSetList, Link)) {
    676       LocalFormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link);
    677       if (IsNvUpdateRequiredForFormSet(LocalFormSet)) {
    678         gDisplayFormData.SettingChangedFlag = TRUE;
    679         return;
    680       }
    681       Link = GetNextNode (&gBrowserFormSetList, Link);
    682     }
    683     break;
    684 
    685   case FormSetLevel:
    686     if (IsNvUpdateRequiredForFormSet(gCurrentSelection->FormSet)) {
    687       gDisplayFormData.SettingChangedFlag = TRUE;
    688       return;
    689     }
    690     break;
    691 
    692   default:
    693     break;
    694   }
    695 }
    696 
    697 /**
    698 
    699   Initialize the Display form structure data.
    700 
    701 **/
    702 VOID
    703 InitializeDisplayFormData (
    704   VOID
    705   )
    706 {
    707   EFI_STATUS  Status;
    708 
    709   gDisplayFormData.Signature   = FORM_DISPLAY_ENGINE_FORM_SIGNATURE;
    710   gDisplayFormData.Version     = FORM_DISPLAY_ENGINE_VERSION_1;
    711   gDisplayFormData.ImageId     = 0;
    712   gDisplayFormData.AnimationId = 0;
    713 
    714   InitializeListHead (&gDisplayFormData.StatementListHead);
    715   InitializeListHead (&gDisplayFormData.StatementListOSF);
    716   InitializeListHead (&gDisplayFormData.HotKeyListHead);
    717 
    718   Status = gBS->CreateEvent (
    719         EVT_NOTIFY_WAIT,
    720         TPL_CALLBACK,
    721         SetupBrowserEmptyFunction,
    722         NULL,
    723         &mValueChangedEvent
    724         );
    725   ASSERT_EFI_ERROR (Status);
    726 }
    727 
    728 /**
    729 
    730   Free the kotkey info saved in form data.
    731 
    732 **/
    733 VOID
    734 FreeHotkeyList (
    735   VOID
    736   )
    737 {
    738   BROWSER_HOT_KEY  *HotKey;
    739   LIST_ENTRY       *Link;
    740 
    741   while (!IsListEmpty (&gDisplayFormData.HotKeyListHead)) {
    742     Link = GetFirstNode (&gDisplayFormData.HotKeyListHead);
    743     HotKey = BROWSER_HOT_KEY_FROM_LINK (Link);
    744 
    745     RemoveEntryList (&HotKey->Link);
    746 
    747     FreePool (HotKey->KeyData);
    748     FreePool (HotKey->HelpString);
    749     FreePool (HotKey);
    750   }
    751 }
    752 
    753 /**
    754 
    755   Update the Display form structure data.
    756 
    757 **/
    758 VOID
    759 UpdateDisplayFormData (
    760   VOID
    761   )
    762 {
    763   gDisplayFormData.FormTitle        = gCurrentSelection->Form->FormTitle;
    764   gDisplayFormData.FormId           = gCurrentSelection->FormId;
    765   gDisplayFormData.HiiHandle        = gCurrentSelection->Handle;
    766   CopyGuid (&gDisplayFormData.FormSetGuid, &gCurrentSelection->FormSetGuid);
    767 
    768   gDisplayFormData.Attribute        = 0;
    769   gDisplayFormData.Attribute       |= gCurrentSelection->Form->ModalForm ? HII_DISPLAY_MODAL : 0;
    770   gDisplayFormData.Attribute       |= gCurrentSelection->Form->Locked    ? HII_DISPLAY_LOCK  : 0;
    771 
    772   gDisplayFormData.FormRefreshEvent     = NULL;
    773   gDisplayFormData.HighLightedStatement = NULL;
    774 
    775   UpdateDataChangedFlag ();
    776 
    777   AddStatementToDisplayForm ();
    778 }
    779 
    780 /**
    781 
    782   Free the Display Statement structure data.
    783 
    784   @param   StatementList         Point to the statement list which need to be free.
    785 
    786 **/
    787 VOID
    788 FreeStatementData (
    789   LIST_ENTRY           *StatementList
    790   )
    791 {
    792   LIST_ENTRY                    *Link;
    793   LIST_ENTRY                    *OptionLink;
    794   FORM_DISPLAY_ENGINE_STATEMENT *Statement;
    795   DISPLAY_QUESTION_OPTION       *Option;
    796 
    797   //
    798   // Free Statements/Questions
    799   //
    800   while (!IsListEmpty (StatementList)) {
    801     Link = GetFirstNode (StatementList);
    802     Statement = FORM_DISPLAY_ENGINE_STATEMENT_FROM_LINK (Link);
    803 
    804     //
    805     // Free Options List
    806     //
    807     while (!IsListEmpty (&Statement->OptionListHead)) {
    808       OptionLink = GetFirstNode (&Statement->OptionListHead);
    809       Option = DISPLAY_QUESTION_OPTION_FROM_LINK (OptionLink);
    810       RemoveEntryList (&Option->Link);
    811       FreePool (Option);
    812     }
    813 
    814     //
    815     // Free nest statement List
    816     //
    817     if (!IsListEmpty (&Statement->NestStatementList)) {
    818       FreeStatementData(&Statement->NestStatementList);
    819     }
    820 
    821     RemoveEntryList (&Statement->DisplayLink);
    822     FreePool (Statement);
    823   }
    824 }
    825 
    826 /**
    827 
    828   Free the Display form structure data.
    829 
    830 **/
    831 VOID
    832 FreeDisplayFormData (
    833   VOID
    834   )
    835 {
    836   FreeStatementData (&gDisplayFormData.StatementListHead);
    837   FreeStatementData (&gDisplayFormData.StatementListOSF);
    838 
    839   FreeRefreshEvent();
    840 
    841   FreeHotkeyList();
    842 }
    843 
    844 /**
    845 
    846   Get FORM_BROWSER_STATEMENT from FORM_DISPLAY_ENGINE_STATEMENT based on the OpCode info.
    847 
    848   @param DisplayStatement        The input FORM_DISPLAY_ENGINE_STATEMENT.
    849 
    850   @retval FORM_BROWSER_STATEMENT  The return FORM_BROWSER_STATEMENT info.
    851 
    852 **/
    853 FORM_BROWSER_STATEMENT *
    854 GetBrowserStatement (
    855   IN FORM_DISPLAY_ENGINE_STATEMENT *DisplayStatement
    856   )
    857 {
    858   FORM_BROWSER_STATEMENT *Statement;
    859   LIST_ENTRY             *Link;
    860 
    861   Link = GetFirstNode (&gCurrentSelection->Form->StatementListHead);
    862   while (!IsNull (&gCurrentSelection->Form->StatementListHead, Link)) {
    863     Statement = FORM_BROWSER_STATEMENT_FROM_LINK (Link);
    864 
    865     if (Statement->OpCode == DisplayStatement->OpCode) {
    866       return Statement;
    867     }
    868 
    869     Link = GetNextNode (&gCurrentSelection->Form->StatementListHead, Link);
    870   }
    871 
    872   return NULL;
    873 }
    874 
    875 /**
    876   Update the ValueChanged status for questions in this form.
    877 
    878   @param  FormSet                FormSet data structure.
    879   @param  Form                   Form data structure.
    880 
    881 **/
    882 VOID
    883 UpdateStatementStatusForForm (
    884   IN FORM_BROWSER_FORMSET             *FormSet,
    885   IN FORM_BROWSER_FORM                *Form
    886   )
    887 {
    888   LIST_ENTRY                  *Link;
    889   FORM_BROWSER_STATEMENT      *Question;
    890 
    891   Link = GetFirstNode (&Form->StatementListHead);
    892   while (!IsNull (&Form->StatementListHead, Link)) {
    893     Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link);
    894     Link = GetNextNode (&Form->StatementListHead, Link);
    895 
    896     //
    897     // For password opcode, not set the the value changed flag.
    898     //
    899     if (Question->Operand == EFI_IFR_PASSWORD_OP) {
    900       continue;
    901     }
    902 
    903     IsQuestionValueChanged(FormSet, Form, Question, GetSetValueWithBuffer);
    904   }
    905 }
    906 
    907 /**
    908   Update the ValueChanged status for questions in this formset.
    909 
    910   @param  FormSet                FormSet data structure.
    911 
    912 **/
    913 VOID
    914 UpdateStatementStatusForFormSet (
    915   IN FORM_BROWSER_FORMSET                *FormSet
    916   )
    917 {
    918   LIST_ENTRY                  *Link;
    919   FORM_BROWSER_FORM           *Form;
    920 
    921   Link = GetFirstNode (&FormSet->FormListHead);
    922   while (!IsNull (&FormSet->FormListHead, Link)) {
    923     Form = FORM_BROWSER_FORM_FROM_LINK (Link);
    924     Link = GetNextNode (&FormSet->FormListHead, Link);
    925 
    926     UpdateStatementStatusForForm (FormSet, Form);
    927   }
    928 }
    929 
    930 /**
    931   Update the ValueChanged status for questions.
    932 
    933   @param  FormSet                FormSet data structure.
    934   @param  Form                   Form data structure.
    935   @param  SettingScope           Setting Scope for Default action.
    936 
    937 **/
    938 VOID
    939 UpdateStatementStatus (
    940   IN FORM_BROWSER_FORMSET             *FormSet,
    941   IN FORM_BROWSER_FORM                *Form,
    942   IN BROWSER_SETTING_SCOPE            SettingScope
    943   )
    944 {
    945   LIST_ENTRY                  *Link;
    946   FORM_BROWSER_FORMSET        *LocalFormSet;
    947 
    948   switch (SettingScope) {
    949   case SystemLevel:
    950     Link = GetFirstNode (&gBrowserFormSetList);
    951     while (!IsNull (&gBrowserFormSetList, Link)) {
    952       LocalFormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link);
    953       Link = GetNextNode (&gBrowserFormSetList, Link);
    954       if (!ValidateFormSet(LocalFormSet)) {
    955         continue;
    956       }
    957 
    958       UpdateStatementStatusForFormSet (LocalFormSet);
    959     }
    960     break;
    961 
    962   case FormSetLevel:
    963     UpdateStatementStatusForFormSet (FormSet);
    964     break;
    965 
    966   case FormLevel:
    967     UpdateStatementStatusForForm (FormSet, Form);
    968     break;
    969 
    970   default:
    971     break;
    972   }
    973 }
    974 
    975 /**
    976 
    977   Process the action request in user input.
    978 
    979   @param Action                  The user input action request info.
    980   @param DefaultId               The user input default Id info.
    981 
    982   @retval EFI_SUCESSS            This function always return successfully for now.
    983 
    984 **/
    985 EFI_STATUS
    986 ProcessAction (
    987   IN UINT32        Action,
    988   IN UINT16        DefaultId
    989   )
    990 {
    991   //
    992   // This is caused by use press ESC, and it should not combine with other action type.
    993   //
    994   if ((Action & BROWSER_ACTION_FORM_EXIT) == BROWSER_ACTION_FORM_EXIT) {
    995     FindNextMenu (gCurrentSelection, FormLevel);
    996     return EFI_SUCCESS;
    997   }
    998 
    999   //
   1000   // Below is normal hotkey trigged action, these action maybe combine with each other.
   1001   //
   1002   if ((Action & BROWSER_ACTION_DISCARD) == BROWSER_ACTION_DISCARD) {
   1003     DiscardForm (gCurrentSelection->FormSet, gCurrentSelection->Form, gBrowserSettingScope);
   1004   }
   1005 
   1006   if ((Action & BROWSER_ACTION_DEFAULT) == BROWSER_ACTION_DEFAULT) {
   1007     ExtractDefault (gCurrentSelection->FormSet, gCurrentSelection->Form, DefaultId, gBrowserSettingScope, GetDefaultForAll, NULL, FALSE, FALSE);
   1008     UpdateStatementStatus (gCurrentSelection->FormSet, gCurrentSelection->Form, gBrowserSettingScope);
   1009   }
   1010 
   1011   if ((Action & BROWSER_ACTION_SUBMIT) == BROWSER_ACTION_SUBMIT) {
   1012     SubmitForm (gCurrentSelection->FormSet, gCurrentSelection->Form, gBrowserSettingScope);
   1013   }
   1014 
   1015   if ((Action & BROWSER_ACTION_RESET) == BROWSER_ACTION_RESET) {
   1016     gResetRequired = TRUE;
   1017   }
   1018 
   1019   if ((Action & BROWSER_ACTION_EXIT) == BROWSER_ACTION_EXIT) {
   1020     //
   1021     // Form Exit without saving, Similar to ESC Key.
   1022     // FormSet Exit without saving, Exit SendForm.
   1023     // System Exit without saving, CallExitHandler and Exit SendForm.
   1024     //
   1025     DiscardForm (gCurrentSelection->FormSet, gCurrentSelection->Form, gBrowserSettingScope);
   1026     if (gBrowserSettingScope == FormLevel || gBrowserSettingScope == FormSetLevel) {
   1027       FindNextMenu (gCurrentSelection, gBrowserSettingScope);
   1028     } else if (gBrowserSettingScope == SystemLevel) {
   1029       if (ExitHandlerFunction != NULL) {
   1030         ExitHandlerFunction ();
   1031       }
   1032       gCurrentSelection->Action = UI_ACTION_EXIT;
   1033     }
   1034   }
   1035 
   1036   return EFI_SUCCESS;
   1037 }
   1038 
   1039 /**
   1040   Check whether the formset guid is in this Hii package list.
   1041 
   1042   @param  HiiHandle              The HiiHandle for this HII package list.
   1043   @param  FormSetGuid            The formset guid for the request formset.
   1044 
   1045   @retval TRUE                   Find the formset guid.
   1046   @retval FALSE                  Not found the formset guid.
   1047 
   1048 **/
   1049 BOOLEAN
   1050 GetFormsetGuidFromHiiHandle (
   1051   IN EFI_HII_HANDLE       HiiHandle,
   1052   IN EFI_GUID             *FormSetGuid
   1053   )
   1054 {
   1055   EFI_HII_PACKAGE_LIST_HEADER  *HiiPackageList;
   1056   UINTN                        BufferSize;
   1057   UINT32                       Offset;
   1058   UINT32                       Offset2;
   1059   UINT32                       PackageListLength;
   1060   EFI_HII_PACKAGE_HEADER       PackageHeader;
   1061   UINT8                        *Package;
   1062   UINT8                        *OpCodeData;
   1063   EFI_STATUS                   Status;
   1064   BOOLEAN                      FindGuid;
   1065 
   1066   BufferSize     = 0;
   1067   HiiPackageList = NULL;
   1068   FindGuid       = FALSE;
   1069 
   1070   Status = mHiiDatabase->ExportPackageLists (mHiiDatabase, HiiHandle, &BufferSize, HiiPackageList);
   1071   if (Status == EFI_BUFFER_TOO_SMALL) {
   1072     HiiPackageList = AllocatePool (BufferSize);
   1073     ASSERT (HiiPackageList != NULL);
   1074 
   1075     Status = mHiiDatabase->ExportPackageLists (mHiiDatabase, HiiHandle, &BufferSize, HiiPackageList);
   1076   }
   1077   if (EFI_ERROR (Status) || HiiPackageList == NULL) {
   1078     return FALSE;
   1079   }
   1080 
   1081   //
   1082   // Get Form package from this HII package List
   1083   //
   1084   Offset = sizeof (EFI_HII_PACKAGE_LIST_HEADER);
   1085   Offset2 = 0;
   1086   CopyMem (&PackageListLength, &HiiPackageList->PackageLength, sizeof (UINT32));
   1087 
   1088   while (Offset < PackageListLength) {
   1089     Package = ((UINT8 *) HiiPackageList) + Offset;
   1090     CopyMem (&PackageHeader, Package, sizeof (EFI_HII_PACKAGE_HEADER));
   1091     Offset += PackageHeader.Length;
   1092 
   1093     if (PackageHeader.Type == EFI_HII_PACKAGE_FORMS) {
   1094       //
   1095       // Search FormSet in this Form Package
   1096       //
   1097       Offset2 = sizeof (EFI_HII_PACKAGE_HEADER);
   1098       while (Offset2 < PackageHeader.Length) {
   1099         OpCodeData = Package + Offset2;
   1100 
   1101         if (((EFI_IFR_OP_HEADER *) OpCodeData)->OpCode == EFI_IFR_FORM_SET_OP) {
   1102           if (CompareGuid (FormSetGuid, (EFI_GUID *)(OpCodeData + sizeof (EFI_IFR_OP_HEADER)))){
   1103             FindGuid = TRUE;
   1104             break;
   1105           }
   1106         }
   1107 
   1108         Offset2 += ((EFI_IFR_OP_HEADER *) OpCodeData)->Length;
   1109       }
   1110     }
   1111     if (FindGuid) {
   1112       break;
   1113     }
   1114   }
   1115 
   1116   FreePool (HiiPackageList);
   1117 
   1118   return FindGuid;
   1119 }
   1120 
   1121 /**
   1122   Find HII Handle in the HII database associated with given Device Path.
   1123 
   1124   If DevicePath is NULL, then ASSERT.
   1125 
   1126   @param  DevicePath             Device Path associated with the HII package list
   1127                                  handle.
   1128   @param  FormsetGuid            The formset guid for this formset.
   1129 
   1130   @retval Handle                 HII package list Handle associated with the Device
   1131                                         Path.
   1132   @retval NULL                   Hii Package list handle is not found.
   1133 
   1134 **/
   1135 EFI_HII_HANDLE
   1136 DevicePathToHiiHandle (
   1137   IN EFI_DEVICE_PATH_PROTOCOL   *DevicePath,
   1138   IN EFI_GUID                   *FormsetGuid
   1139   )
   1140 {
   1141   EFI_STATUS                  Status;
   1142   EFI_DEVICE_PATH_PROTOCOL    *TmpDevicePath;
   1143   UINTN                       Index;
   1144   EFI_HANDLE                  Handle;
   1145   EFI_HANDLE                  DriverHandle;
   1146   EFI_HII_HANDLE              *HiiHandles;
   1147   EFI_HII_HANDLE              HiiHandle;
   1148 
   1149   ASSERT (DevicePath != NULL);
   1150 
   1151   TmpDevicePath = DevicePath;
   1152   //
   1153   // Locate Device Path Protocol handle buffer
   1154   //
   1155   Status = gBS->LocateDevicePath (
   1156                   &gEfiDevicePathProtocolGuid,
   1157                   &TmpDevicePath,
   1158                   &DriverHandle
   1159                   );
   1160   if (EFI_ERROR (Status) || !IsDevicePathEnd (TmpDevicePath)) {
   1161     return NULL;
   1162   }
   1163 
   1164   //
   1165   // Retrieve all HII Handles from HII database
   1166   //
   1167   HiiHandles = HiiGetHiiHandles (NULL);
   1168   if (HiiHandles == NULL) {
   1169     return NULL;
   1170   }
   1171 
   1172   //
   1173   // Search Hii Handle by Driver Handle
   1174   //
   1175   HiiHandle = NULL;
   1176   for (Index = 0; HiiHandles[Index] != NULL; Index++) {
   1177     Status = mHiiDatabase->GetPackageListHandle (
   1178                              mHiiDatabase,
   1179                              HiiHandles[Index],
   1180                              &Handle
   1181                              );
   1182     if (!EFI_ERROR (Status) && (Handle == DriverHandle)) {
   1183       if (GetFormsetGuidFromHiiHandle(HiiHandles[Index], FormsetGuid)) {
   1184         HiiHandle = HiiHandles[Index];
   1185         break;
   1186       }
   1187 
   1188       if (HiiHandle != NULL) {
   1189         break;
   1190       }
   1191     }
   1192   }
   1193 
   1194   FreePool (HiiHandles);
   1195   return HiiHandle;
   1196 }
   1197 
   1198 /**
   1199   Find HII Handle in the HII database associated with given form set guid.
   1200 
   1201   If FormSetGuid is NULL, then ASSERT.
   1202 
   1203   @param  ComparingGuid          FormSet Guid associated with the HII package list
   1204                                  handle.
   1205 
   1206   @retval Handle                 HII package list Handle associated with the Device
   1207                                         Path.
   1208   @retval NULL                   Hii Package list handle is not found.
   1209 
   1210 **/
   1211 EFI_HII_HANDLE
   1212 FormSetGuidToHiiHandle (
   1213   EFI_GUID     *ComparingGuid
   1214   )
   1215 {
   1216   EFI_HII_HANDLE               *HiiHandles;
   1217   EFI_HII_HANDLE               HiiHandle;
   1218   UINTN                        Index;
   1219 
   1220   ASSERT (ComparingGuid != NULL);
   1221 
   1222   HiiHandle  = NULL;
   1223   //
   1224   // Get all the Hii handles
   1225   //
   1226   HiiHandles = HiiGetHiiHandles (NULL);
   1227   ASSERT (HiiHandles != NULL);
   1228 
   1229   //
   1230   // Search for formset of each class type
   1231   //
   1232   for (Index = 0; HiiHandles[Index] != NULL; Index++) {
   1233     if (GetFormsetGuidFromHiiHandle(HiiHandles[Index], ComparingGuid)) {
   1234       HiiHandle = HiiHandles[Index];
   1235       break;
   1236     }
   1237 
   1238     if (HiiHandle != NULL) {
   1239       break;
   1240     }
   1241   }
   1242 
   1243   FreePool (HiiHandles);
   1244 
   1245   return HiiHandle;
   1246 }
   1247 
   1248 /**
   1249   check how to process the changed data in current form or form set.
   1250 
   1251   @param Selection       On input, Selection tell setup browser the information
   1252                          about the Selection, form and formset to be displayed.
   1253                          On output, Selection return the screen item that is selected
   1254                          by user.
   1255 
   1256   @param Scope           Data save or discard scope, form or formset.
   1257 
   1258   @retval                TRUE   Success process the changed data, will return to the parent form.
   1259   @retval                FALSE  Reject to process the changed data, will stay at  current form.
   1260 **/
   1261 BOOLEAN
   1262 ProcessChangedData (
   1263   IN OUT UI_MENU_SELECTION       *Selection,
   1264   IN     BROWSER_SETTING_SCOPE   Scope
   1265   )
   1266 {
   1267   BOOLEAN    RetValue;
   1268   EFI_STATUS Status;
   1269 
   1270   RetValue = TRUE;
   1271   switch (mFormDisplay->ConfirmDataChange()) {
   1272     case BROWSER_ACTION_DISCARD:
   1273       DiscardForm (Selection->FormSet, Selection->Form, Scope);
   1274       break;
   1275 
   1276     case BROWSER_ACTION_SUBMIT:
   1277       Status = SubmitForm (Selection->FormSet, Selection->Form, Scope);
   1278       if (EFI_ERROR (Status)) {
   1279         RetValue = FALSE;
   1280       }
   1281       break;
   1282 
   1283     case BROWSER_ACTION_NONE:
   1284       RetValue = FALSE;
   1285       break;
   1286 
   1287     default:
   1288       //
   1289       // if Invalid value return, process same as BROWSER_ACTION_NONE.
   1290       //
   1291       RetValue = FALSE;
   1292       break;
   1293   }
   1294 
   1295   return RetValue;
   1296 }
   1297 
   1298 /**
   1299   Find parent formset menu(the first menu which has different formset) for current menu.
   1300   If not find, just return to the first menu.
   1301 
   1302   @param Selection    The selection info.
   1303 
   1304 **/
   1305 VOID
   1306 FindParentFormSet (
   1307   IN OUT   UI_MENU_SELECTION           *Selection
   1308   )
   1309 {
   1310   FORM_ENTRY_INFO            *CurrentMenu;
   1311   FORM_ENTRY_INFO            *ParentMenu;
   1312 
   1313   CurrentMenu = Selection->CurrentMenu;
   1314   ParentMenu  = UiFindParentMenu(CurrentMenu, FormSetLevel);
   1315 
   1316   if (ParentMenu != NULL) {
   1317     CopyMem (&Selection->FormSetGuid, &ParentMenu->FormSetGuid, sizeof (EFI_GUID));
   1318     Selection->Handle = ParentMenu->HiiHandle;
   1319     Selection->FormId     = ParentMenu->FormId;
   1320     Selection->QuestionId = ParentMenu->QuestionId;
   1321   } else {
   1322     Selection->FormId     = CurrentMenu->FormId;
   1323     Selection->QuestionId = CurrentMenu->QuestionId;
   1324   }
   1325 
   1326   Selection->Statement  = NULL;
   1327 }
   1328 
   1329 /**
   1330   Process the goto op code, update the info in the selection structure.
   1331 
   1332   @param Statement    The statement belong to goto op code.
   1333   @param Selection    The selection info.
   1334 
   1335   @retval EFI_SUCCESS    The menu process successfully.
   1336   @return Other value if the process failed.
   1337 **/
   1338 EFI_STATUS
   1339 ProcessGotoOpCode (
   1340   IN OUT   FORM_BROWSER_STATEMENT      *Statement,
   1341   IN OUT   UI_MENU_SELECTION           *Selection
   1342   )
   1343 {
   1344   CHAR16                          *StringPtr;
   1345   EFI_DEVICE_PATH_PROTOCOL        *DevicePath;
   1346   FORM_BROWSER_FORM               *RefForm;
   1347   EFI_STATUS                      Status;
   1348   EFI_HII_HANDLE                  HiiHandle;
   1349 
   1350   Status    = EFI_SUCCESS;
   1351   StringPtr = NULL;
   1352   HiiHandle = NULL;
   1353 
   1354   //
   1355   // Prepare the device path check, get the device path info first.
   1356   //
   1357   if (Statement->HiiValue.Value.ref.DevicePath != 0) {
   1358     StringPtr = GetToken (Statement->HiiValue.Value.ref.DevicePath, Selection->FormSet->HiiHandle);
   1359   }
   1360 
   1361   //
   1362   // Check whether the device path string is a valid string.
   1363   //
   1364   if (Statement->HiiValue.Value.ref.DevicePath != 0 && StringPtr != NULL && StringPtr[0] != L'\0') {
   1365     if (Selection->Form->ModalForm) {
   1366       return Status;
   1367     }
   1368 
   1369     //
   1370     // Goto another Hii Package list
   1371     //
   1372     if (mPathFromText != NULL) {
   1373       DevicePath = mPathFromText->ConvertTextToDevicePath(StringPtr);
   1374       if (DevicePath != NULL) {
   1375         HiiHandle = DevicePathToHiiHandle (DevicePath, &Statement->HiiValue.Value.ref.FormSetGuid);
   1376         FreePool (DevicePath);
   1377       }
   1378       FreePool (StringPtr);
   1379     } else {
   1380       //
   1381       // Not found the EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL protocol.
   1382       //
   1383       PopupErrorMessage(BROWSER_PROTOCOL_NOT_FOUND, NULL, NULL, NULL);
   1384       FreePool (StringPtr);
   1385       return Status;
   1386     }
   1387 
   1388     if (HiiHandle != Selection->Handle) {
   1389       //
   1390       // Goto another Formset, check for uncommitted data
   1391       //
   1392       if ((gBrowserSettingScope == FormLevel || gBrowserSettingScope == FormSetLevel) &&
   1393           IsNvUpdateRequiredForFormSet(Selection->FormSet)) {
   1394         if (!ProcessChangedData(Selection, FormSetLevel)) {
   1395           return EFI_SUCCESS;
   1396         }
   1397       }
   1398     }
   1399 
   1400     Selection->Action = UI_ACTION_REFRESH_FORMSET;
   1401     Selection->Handle = HiiHandle;
   1402     if (Selection->Handle == NULL) {
   1403       //
   1404       // If target Hii Handle not found, exit current formset.
   1405       //
   1406       FindParentFormSet(Selection);
   1407       return EFI_SUCCESS;
   1408     }
   1409 
   1410     CopyMem (&Selection->FormSetGuid,&Statement->HiiValue.Value.ref.FormSetGuid, sizeof (EFI_GUID));
   1411     Selection->FormId = Statement->HiiValue.Value.ref.FormId;
   1412     Selection->QuestionId = Statement->HiiValue.Value.ref.QuestionId;
   1413   } else if (!CompareGuid (&Statement->HiiValue.Value.ref.FormSetGuid, &gZeroGuid)) {
   1414     if (Selection->Form->ModalForm) {
   1415       return Status;
   1416     }
   1417     if (!CompareGuid (&Statement->HiiValue.Value.ref.FormSetGuid, &Selection->FormSetGuid)) {
   1418       //
   1419       // Goto another Formset, check for uncommitted data
   1420       //
   1421       if ((gBrowserSettingScope == FormLevel || gBrowserSettingScope == FormSetLevel) &&
   1422          IsNvUpdateRequiredForFormSet(Selection->FormSet)) {
   1423         if (!ProcessChangedData(Selection, FormSetLevel)) {
   1424           return EFI_SUCCESS;
   1425         }
   1426       }
   1427     }
   1428 
   1429     Selection->Action = UI_ACTION_REFRESH_FORMSET;
   1430     Selection->Handle = FormSetGuidToHiiHandle(&Statement->HiiValue.Value.ref.FormSetGuid);
   1431     if (Selection->Handle == NULL) {
   1432       //
   1433       // If target Hii Handle not found, exit current formset.
   1434       //
   1435       FindParentFormSet(Selection);
   1436       return EFI_SUCCESS;
   1437     }
   1438 
   1439     CopyMem (&Selection->FormSetGuid, &Statement->HiiValue.Value.ref.FormSetGuid, sizeof (EFI_GUID));
   1440     Selection->FormId = Statement->HiiValue.Value.ref.FormId;
   1441     Selection->QuestionId = Statement->HiiValue.Value.ref.QuestionId;
   1442   } else if (Statement->HiiValue.Value.ref.FormId != 0) {
   1443     //
   1444     // Goto another Form, check for uncommitted data
   1445     //
   1446     if (Statement->HiiValue.Value.ref.FormId != Selection->FormId) {
   1447       if ((gBrowserSettingScope == FormLevel && IsNvUpdateRequiredForForm(Selection->Form))) {
   1448         if (!ProcessChangedData (Selection, FormLevel)) {
   1449           return EFI_SUCCESS;
   1450         }
   1451       }
   1452     }
   1453 
   1454     RefForm = IdToForm (Selection->FormSet, Statement->HiiValue.Value.ref.FormId);
   1455     if ((RefForm != NULL) && (RefForm->SuppressExpression != NULL)) {
   1456       if (EvaluateExpressionList(RefForm->SuppressExpression, TRUE, Selection->FormSet, RefForm) != ExpressFalse) {
   1457         //
   1458         // Form is suppressed.
   1459         //
   1460         PopupErrorMessage(BROWSER_FORM_SUPPRESS, NULL, NULL, NULL);
   1461         return EFI_SUCCESS;
   1462       }
   1463     }
   1464 
   1465     Selection->FormId = Statement->HiiValue.Value.ref.FormId;
   1466     Selection->QuestionId = Statement->HiiValue.Value.ref.QuestionId;
   1467   } else if (Statement->HiiValue.Value.ref.QuestionId != 0) {
   1468     Selection->QuestionId = Statement->HiiValue.Value.ref.QuestionId;
   1469   }
   1470 
   1471   return Status;
   1472 }
   1473 
   1474 
   1475 /**
   1476   Process Question Config.
   1477 
   1478   @param  Selection              The UI menu selection.
   1479   @param  Question               The Question to be peocessed.
   1480 
   1481   @retval EFI_SUCCESS            Question Config process success.
   1482   @retval Other                  Question Config process fail.
   1483 
   1484 **/
   1485 EFI_STATUS
   1486 ProcessQuestionConfig (
   1487   IN  UI_MENU_SELECTION       *Selection,
   1488   IN  FORM_BROWSER_STATEMENT  *Question
   1489   )
   1490 {
   1491   EFI_STATUS                      Status;
   1492   CHAR16                          *ConfigResp;
   1493   CHAR16                          *Progress;
   1494 
   1495   if (Question->QuestionConfig == 0) {
   1496     return EFI_SUCCESS;
   1497   }
   1498 
   1499   //
   1500   // Get <ConfigResp>
   1501   //
   1502   ConfigResp = GetToken (Question->QuestionConfig, Selection->FormSet->HiiHandle);
   1503   if (ConfigResp == NULL) {
   1504     return EFI_NOT_FOUND;
   1505   } else if (ConfigResp[0] == L'\0') {
   1506     return EFI_SUCCESS;
   1507   }
   1508 
   1509   //
   1510   // Send config to Configuration Driver
   1511   //
   1512   Status = mHiiConfigRouting->RouteConfig (
   1513                            mHiiConfigRouting,
   1514                            ConfigResp,
   1515                            &Progress
   1516                            );
   1517 
   1518   return Status;
   1519 }
   1520 
   1521 /**
   1522 
   1523   Process the user input data.
   1524 
   1525   @param UserInput               The user input data.
   1526 
   1527   @retval EFI_SUCESSS            This function always return successfully for now.
   1528 
   1529 **/
   1530 EFI_STATUS
   1531 ProcessUserInput (
   1532   IN USER_INPUT               *UserInput
   1533   )
   1534 {
   1535   EFI_STATUS                    Status;
   1536   FORM_BROWSER_STATEMENT        *Statement;
   1537 
   1538   Status    = EFI_SUCCESS;
   1539   Statement = NULL;
   1540 
   1541   //
   1542   // When Exit from FormDisplay function, one of the below two cases must be true.
   1543   //
   1544   ASSERT (UserInput->Action != 0 || UserInput->SelectedStatement != NULL);
   1545 
   1546   //
   1547   // Remove the last highligh question id, this id will update when show next form.
   1548   //
   1549   gCurrentSelection->QuestionId = 0;
   1550   if (UserInput->SelectedStatement != NULL){
   1551     Statement = GetBrowserStatement(UserInput->SelectedStatement);
   1552     ASSERT (Statement != NULL);
   1553 
   1554     //
   1555     // This question is the current user select one,record it and later
   1556     // show it as the highlight question.
   1557     //
   1558     gCurrentSelection->CurrentMenu->QuestionId = Statement->QuestionId;
   1559     //
   1560     // For statement like text, actio, it not has question id.
   1561     // So use FakeQuestionId to save the question.
   1562     //
   1563     if (gCurrentSelection->CurrentMenu->QuestionId == 0) {
   1564       mCurFakeQestId = Statement->FakeQuestionId;
   1565     } else {
   1566       mCurFakeQestId = 0;
   1567     }
   1568   }
   1569 
   1570   //
   1571   // First process the Action field in USER_INPUT.
   1572   //
   1573   if (UserInput->Action != 0) {
   1574     Status = ProcessAction (UserInput->Action, UserInput->DefaultId);
   1575     gCurrentSelection->Statement = NULL;
   1576   } else {
   1577     ASSERT (Statement != NULL);
   1578     gCurrentSelection->Statement = Statement;
   1579     switch (Statement->Operand) {
   1580     case EFI_IFR_REF_OP:
   1581       Status = ProcessGotoOpCode(Statement, gCurrentSelection);
   1582       break;
   1583 
   1584     case EFI_IFR_ACTION_OP:
   1585       //
   1586       // Process the Config string <ConfigResp>
   1587       //
   1588       Status = ProcessQuestionConfig (gCurrentSelection, Statement);
   1589       break;
   1590 
   1591     case EFI_IFR_RESET_BUTTON_OP:
   1592       //
   1593       // Reset Question to default value specified by DefaultId
   1594       //
   1595       Status = ExtractDefault (gCurrentSelection->FormSet, NULL, Statement->DefaultId, FormSetLevel, GetDefaultForAll, NULL, FALSE, FALSE);
   1596       UpdateStatementStatus (gCurrentSelection->FormSet, NULL, FormSetLevel);
   1597       break;
   1598 
   1599     default:
   1600       switch (Statement->Operand) {
   1601       case EFI_IFR_STRING_OP:
   1602         DeleteString(Statement->HiiValue.Value.string, gCurrentSelection->FormSet->HiiHandle);
   1603         Statement->HiiValue.Value.string = UserInput->InputValue.Value.string;
   1604         CopyMem (Statement->BufferValue, UserInput->InputValue.Buffer, (UINTN) UserInput->InputValue.BufferLen);
   1605         FreePool (UserInput->InputValue.Buffer);
   1606         break;
   1607 
   1608       case EFI_IFR_PASSWORD_OP:
   1609         if (UserInput->InputValue.Buffer == NULL) {
   1610           //
   1611           // User not input new password, just return.
   1612           //
   1613           break;
   1614         }
   1615 
   1616         DeleteString(Statement->HiiValue.Value.string, gCurrentSelection->FormSet->HiiHandle);
   1617         Statement->HiiValue.Value.string = UserInput->InputValue.Value.string;
   1618         CopyMem (Statement->BufferValue, UserInput->InputValue.Buffer, (UINTN) UserInput->InputValue.BufferLen);
   1619         FreePool (UserInput->InputValue.Buffer);
   1620         //
   1621         // Two password match, send it to Configuration Driver
   1622         //
   1623         if ((Statement->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) {
   1624           PasswordCheck (NULL, UserInput->SelectedStatement, (CHAR16 *) Statement->BufferValue);
   1625           //
   1626           // Clean the value after saved it.
   1627           //
   1628           ZeroMem (Statement->BufferValue, (UINTN) UserInput->InputValue.BufferLen);
   1629           HiiSetString (gCurrentSelection->FormSet->HiiHandle, Statement->HiiValue.Value.string, (CHAR16*)Statement->BufferValue, NULL);
   1630         } else {
   1631           SetQuestionValue (gCurrentSelection->FormSet, gCurrentSelection->Form, Statement, GetSetValueWithHiiDriver);
   1632         }
   1633         break;
   1634 
   1635       case EFI_IFR_ORDERED_LIST_OP:
   1636         CopyMem (Statement->BufferValue, UserInput->InputValue.Buffer, UserInput->InputValue.BufferLen);
   1637         break;
   1638 
   1639       default:
   1640         CopyMem (&Statement->HiiValue, &UserInput->InputValue, sizeof (EFI_HII_VALUE));
   1641         break;
   1642       }
   1643       break;
   1644     }
   1645   }
   1646 
   1647   return Status;
   1648 }
   1649 
   1650 /**
   1651 
   1652   Display form and wait for user to select one menu option, then return it.
   1653 
   1654   @retval EFI_SUCESSS            This function always return successfully for now.
   1655 
   1656 **/
   1657 EFI_STATUS
   1658 DisplayForm (
   1659   VOID
   1660   )
   1661 {
   1662   EFI_STATUS               Status;
   1663   USER_INPUT               UserInput;
   1664   FORM_ENTRY_INFO          *CurrentMenu;
   1665 
   1666   ZeroMem (&UserInput, sizeof (USER_INPUT));
   1667 
   1668   //
   1669   // Update the menu history data.
   1670   //
   1671   CurrentMenu = UiFindMenuList (gCurrentSelection->Handle, &gCurrentSelection->FormSetGuid, gCurrentSelection->FormId);
   1672   if (CurrentMenu == NULL) {
   1673     //
   1674     // Current menu not found, add it to the menu tree
   1675     //
   1676     CurrentMenu = UiAddMenuList (gCurrentSelection->Handle, &gCurrentSelection->FormSetGuid,
   1677                                  gCurrentSelection->FormId, gCurrentSelection->QuestionId);
   1678     ASSERT (CurrentMenu != NULL);
   1679   }
   1680 
   1681   //
   1682   // Back up the form view history data for this form.
   1683   //
   1684   UiCopyMenuList(&gCurrentSelection->Form->FormViewListHead, &mPrivateData.FormBrowserEx2.FormViewHistoryHead);
   1685 
   1686   gCurrentSelection->CurrentMenu = CurrentMenu;
   1687 
   1688   if (gCurrentSelection->QuestionId == 0) {
   1689     //
   1690     // Highlight not specified, fetch it from cached menu
   1691     //
   1692     gCurrentSelection->QuestionId = CurrentMenu->QuestionId;
   1693   }
   1694 
   1695   Status = EvaluateFormExpressions (gCurrentSelection->FormSet, gCurrentSelection->Form);
   1696   if (EFI_ERROR (Status)) {
   1697     return Status;
   1698   }
   1699 
   1700   UpdateDisplayFormData ();
   1701 
   1702   ASSERT (gDisplayFormData.BrowserStatus == BROWSER_SUCCESS);
   1703   Status = mFormDisplay->FormDisplay (&gDisplayFormData, &UserInput);
   1704   if (EFI_ERROR (Status)) {
   1705     FreeDisplayFormData();
   1706     return Status;
   1707   }
   1708 
   1709   Status = ProcessUserInput (&UserInput);
   1710   FreeDisplayFormData();
   1711   return Status;
   1712 }
   1713 
   1714 /**
   1715   Functions which are registered to receive notification of
   1716   database events have this prototype. The actual event is encoded
   1717   in NotifyType. The following table describes how PackageType,
   1718   PackageGuid, Handle, and Package are used for each of the
   1719   notification types.
   1720 
   1721   @param PackageType  Package type of the notification.
   1722 
   1723   @param PackageGuid  If PackageType is
   1724                       EFI_HII_PACKAGE_TYPE_GUID, then this is
   1725                       the pointer to the GUID from the Guid
   1726                       field of EFI_HII_PACKAGE_GUID_HEADER.
   1727                       Otherwise, it must be NULL.
   1728 
   1729   @param Package  Points to the package referred to by the
   1730                   notification Handle The handle of the package
   1731                   list which contains the specified package.
   1732 
   1733   @param Handle       The HII handle.
   1734 
   1735   @param NotifyType   The type of change concerning the
   1736                       database. See
   1737                       EFI_HII_DATABASE_NOTIFY_TYPE.
   1738 
   1739 **/
   1740 EFI_STATUS
   1741 EFIAPI
   1742 FormUpdateNotify (
   1743   IN UINT8                              PackageType,
   1744   IN CONST EFI_GUID                     *PackageGuid,
   1745   IN CONST EFI_HII_PACKAGE_HEADER       *Package,
   1746   IN EFI_HII_HANDLE                     Handle,
   1747   IN EFI_HII_DATABASE_NOTIFY_TYPE       NotifyType
   1748   )
   1749 {
   1750   mHiiPackageListUpdated = TRUE;
   1751 
   1752   return EFI_SUCCESS;
   1753 }
   1754 
   1755 /**
   1756   Update the NV flag info for this form set.
   1757 
   1758   @param  FormSet                FormSet data structure.
   1759 
   1760 **/
   1761 BOOLEAN
   1762 IsNvUpdateRequiredForFormSet (
   1763   IN FORM_BROWSER_FORMSET  *FormSet
   1764   )
   1765 {
   1766   LIST_ENTRY              *Link;
   1767   FORM_BROWSER_FORM       *Form;
   1768   BOOLEAN                 RetVal;
   1769 
   1770   //
   1771   // Not finished question initialization, return FALSE.
   1772   //
   1773   if (!FormSet->QuestionInited) {
   1774     return FALSE;
   1775   }
   1776 
   1777   RetVal = FALSE;
   1778 
   1779   Link = GetFirstNode (&FormSet->FormListHead);
   1780   while (!IsNull (&FormSet->FormListHead, Link)) {
   1781     Form = FORM_BROWSER_FORM_FROM_LINK (Link);
   1782 
   1783     RetVal = IsNvUpdateRequiredForForm(Form);
   1784     if (RetVal) {
   1785       break;
   1786     }
   1787 
   1788     Link = GetNextNode (&FormSet->FormListHead, Link);
   1789   }
   1790 
   1791   return RetVal;
   1792 }
   1793 
   1794 /**
   1795   Update the NvUpdateRequired flag for a form.
   1796 
   1797   @param  Form                Form data structure.
   1798 
   1799 **/
   1800 BOOLEAN
   1801 IsNvUpdateRequiredForForm (
   1802   IN FORM_BROWSER_FORM    *Form
   1803   )
   1804 {
   1805   LIST_ENTRY              *Link;
   1806   FORM_BROWSER_STATEMENT  *Statement;
   1807 
   1808   Link = GetFirstNode (&Form->StatementListHead);
   1809   while (!IsNull (&Form->StatementListHead, Link)) {
   1810     Statement = FORM_BROWSER_STATEMENT_FROM_LINK (Link);
   1811 
   1812     if (Statement->ValueChanged) {
   1813       return TRUE;
   1814     }
   1815 
   1816     Link = GetNextNode (&Form->StatementListHead, Link);
   1817   }
   1818 
   1819   return FALSE;
   1820 }
   1821 
   1822 /**
   1823   Find menu which will show next time.
   1824 
   1825   @param Selection       On input, Selection tell setup browser the information
   1826                          about the Selection, form and formset to be displayed.
   1827                          On output, Selection return the screen item that is selected
   1828                          by user.
   1829   @param SettingLevel    Input Settting level, if it is FormLevel, just exit current form.
   1830                          else, we need to exit current formset.
   1831 
   1832   @retval TRUE           Exit current form.
   1833   @retval FALSE          User press ESC and keep in current form.
   1834 **/
   1835 BOOLEAN
   1836 FindNextMenu (
   1837   IN OUT UI_MENU_SELECTION        *Selection,
   1838   IN     BROWSER_SETTING_SCOPE     SettingLevel
   1839   )
   1840 {
   1841   FORM_ENTRY_INFO            *CurrentMenu;
   1842   FORM_ENTRY_INFO            *ParentMenu;
   1843   BROWSER_SETTING_SCOPE      Scope;
   1844 
   1845   CurrentMenu = Selection->CurrentMenu;
   1846   Scope       = FormSetLevel;
   1847 
   1848   ParentMenu = UiFindParentMenu(CurrentMenu, SettingLevel);
   1849   while (ParentMenu != NULL && !ValidateHiiHandle(ParentMenu->HiiHandle)) {
   1850     ParentMenu = UiFindParentMenu(ParentMenu, SettingLevel);
   1851   }
   1852 
   1853   if (ParentMenu != NULL) {
   1854     if (CompareGuid (&CurrentMenu->FormSetGuid, &ParentMenu->FormSetGuid)) {
   1855       Scope = FormLevel;
   1856     } else {
   1857       Scope = FormSetLevel;
   1858     }
   1859   }
   1860 
   1861   //
   1862   // Form Level Check whether the data is changed.
   1863   //
   1864   if ((gBrowserSettingScope == FormLevel && IsNvUpdateRequiredForForm (Selection->Form)) ||
   1865       (gBrowserSettingScope == FormSetLevel && IsNvUpdateRequiredForFormSet(Selection->FormSet) && Scope == FormSetLevel)) {
   1866     if (!ProcessChangedData(Selection, gBrowserSettingScope)) {
   1867       return FALSE;
   1868     }
   1869   }
   1870 
   1871   if (ParentMenu != NULL) {
   1872     //
   1873     // ParentMenu is found. Then, go to it.
   1874     //
   1875     if (Scope == FormLevel) {
   1876       Selection->Action = UI_ACTION_REFRESH_FORM;
   1877     } else {
   1878       Selection->Action = UI_ACTION_REFRESH_FORMSET;
   1879       CopyMem (&Selection->FormSetGuid, &ParentMenu->FormSetGuid, sizeof (EFI_GUID));
   1880       Selection->Handle = ParentMenu->HiiHandle;
   1881     }
   1882 
   1883     Selection->Statement = NULL;
   1884 
   1885     Selection->FormId = ParentMenu->FormId;
   1886     Selection->QuestionId = ParentMenu->QuestionId;
   1887 
   1888     //
   1889     // Clear highlight record for this menu
   1890     //
   1891     CurrentMenu->QuestionId = 0;
   1892     return FALSE;
   1893   }
   1894 
   1895   //
   1896   // Current in root page, exit the SendForm
   1897   //
   1898   Selection->Action = UI_ACTION_EXIT;
   1899 
   1900   return TRUE;
   1901 }
   1902 
   1903 /**
   1904   Reconnect the controller.
   1905 
   1906   @param DriverHandle          The controller handle which need to be reconnect.
   1907 
   1908   @retval   TRUE     do the reconnect behavior success.
   1909   @retval   FALSE    do the reconnect behavior failed.
   1910 
   1911 **/
   1912 BOOLEAN
   1913 ReconnectController (
   1914   IN EFI_HANDLE   DriverHandle
   1915   )
   1916 {
   1917   EFI_STATUS                      Status;
   1918 
   1919   Status = gBS->DisconnectController(DriverHandle, NULL, NULL);
   1920   if (!EFI_ERROR (Status)) {
   1921     Status = gBS->ConnectController(DriverHandle, NULL, NULL, TRUE);
   1922   }
   1923 
   1924   return Status == EFI_SUCCESS;
   1925 }
   1926 
   1927 /**
   1928   Call the call back function for the question and process the return action.
   1929 
   1930   @param Selection             On input, Selection tell setup browser the information
   1931                                about the Selection, form and formset to be displayed.
   1932                                On output, Selection return the screen item that is selected
   1933                                by user.
   1934   @param FormSet               The formset this question belong to.
   1935   @param Form                  The form this question belong to.
   1936   @param Question              The Question which need to call.
   1937   @param Action                The action request.
   1938   @param SkipSaveOrDiscard     Whether skip save or discard action.
   1939 
   1940   @retval EFI_SUCCESS          The call back function excutes successfully.
   1941   @return Other value if the call back function failed to excute.
   1942 **/
   1943 EFI_STATUS
   1944 ProcessCallBackFunction (
   1945   IN OUT UI_MENU_SELECTION               *Selection,
   1946   IN     FORM_BROWSER_FORMSET            *FormSet,
   1947   IN     FORM_BROWSER_FORM               *Form,
   1948   IN     FORM_BROWSER_STATEMENT          *Question,
   1949   IN     EFI_BROWSER_ACTION              Action,
   1950   IN     BOOLEAN                         SkipSaveOrDiscard
   1951   )
   1952 {
   1953   EFI_STATUS                      Status;
   1954   EFI_STATUS                      InternalStatus;
   1955   EFI_BROWSER_ACTION_REQUEST      ActionRequest;
   1956   EFI_HII_CONFIG_ACCESS_PROTOCOL  *ConfigAccess;
   1957   EFI_HII_VALUE                   *HiiValue;
   1958   EFI_IFR_TYPE_VALUE              *TypeValue;
   1959   FORM_BROWSER_STATEMENT          *Statement;
   1960   BOOLEAN                         SubmitFormIsRequired;
   1961   BOOLEAN                         DiscardFormIsRequired;
   1962   BOOLEAN                         NeedExit;
   1963   LIST_ENTRY                      *Link;
   1964   BROWSER_SETTING_SCOPE           SettingLevel;
   1965   EFI_IFR_TYPE_VALUE              BackUpValue;
   1966   UINT8                           *BackUpBuffer;
   1967   CHAR16                          *NewString;
   1968 
   1969   ConfigAccess = FormSet->ConfigAccess;
   1970   SubmitFormIsRequired  = FALSE;
   1971   SettingLevel          = FormSetLevel;
   1972   DiscardFormIsRequired = FALSE;
   1973   NeedExit              = FALSE;
   1974   Status                = EFI_SUCCESS;
   1975   ActionRequest         = EFI_BROWSER_ACTION_REQUEST_NONE;
   1976   BackUpBuffer          = NULL;
   1977 
   1978   if (ConfigAccess == NULL) {
   1979     return EFI_SUCCESS;
   1980   }
   1981 
   1982   Link = GetFirstNode (&Form->StatementListHead);
   1983   while (!IsNull (&Form->StatementListHead, Link)) {
   1984     Statement = FORM_BROWSER_STATEMENT_FROM_LINK (Link);
   1985     Link = GetNextNode (&Form->StatementListHead, Link);
   1986 
   1987     //
   1988     // if Question != NULL, only process the question. Else, process all question in this form.
   1989     //
   1990     if ((Question != NULL) && (Statement != Question)) {
   1991       continue;
   1992     }
   1993 
   1994     if ((Statement->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != EFI_IFR_FLAG_CALLBACK) {
   1995       continue;
   1996     }
   1997 
   1998     //
   1999     // Check whether Statement is disabled.
   2000     //
   2001     if (Statement->Expression != NULL) {
   2002       if (EvaluateExpressionList(Statement->Expression, TRUE, FormSet, Form) == ExpressDisable) {
   2003         continue;
   2004       }
   2005     }
   2006 
   2007     HiiValue = &Statement->HiiValue;
   2008     TypeValue = &HiiValue->Value;
   2009     if (HiiValue->Type == EFI_IFR_TYPE_BUFFER) {
   2010       //
   2011       // For OrderedList, passing in the value buffer to Callback()
   2012       //
   2013       TypeValue = (EFI_IFR_TYPE_VALUE *) Statement->BufferValue;
   2014     }
   2015 
   2016     //
   2017     // If EFI_BROWSER_ACTION_CHANGING type, back up the new question value.
   2018     //
   2019     if (Action == EFI_BROWSER_ACTION_CHANGING) {
   2020       if (HiiValue->Type == EFI_IFR_TYPE_BUFFER) {
   2021         BackUpBuffer = AllocateCopyPool(Statement->StorageWidth + sizeof(CHAR16), Statement->BufferValue);
   2022         ASSERT (BackUpBuffer != NULL);
   2023       } else {
   2024         CopyMem (&BackUpValue, &HiiValue->Value, sizeof (EFI_IFR_TYPE_VALUE));
   2025       }
   2026     }
   2027 
   2028     ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;
   2029     Status = ConfigAccess->Callback (
   2030                              ConfigAccess,
   2031                              Action,
   2032                              Statement->QuestionId,
   2033                              HiiValue->Type,
   2034                              TypeValue,
   2035                              &ActionRequest
   2036                              );
   2037     if (!EFI_ERROR (Status)) {
   2038       //
   2039       // Need to sync the value between Statement->HiiValue->Value and Statement->BufferValue
   2040       //
   2041       if (HiiValue->Type == EFI_IFR_TYPE_STRING) {
   2042         NewString = GetToken (Statement->HiiValue.Value.string, FormSet->HiiHandle);
   2043         ASSERT (NewString != NULL);
   2044 
   2045         ASSERT (StrLen (NewString) * sizeof (CHAR16) <= Statement->StorageWidth);
   2046         if (StrLen (NewString) * sizeof (CHAR16) <= Statement->StorageWidth) {
   2047           CopyMem (Statement->BufferValue, NewString, StrSize (NewString));
   2048         } else {
   2049           CopyMem (Statement->BufferValue, NewString, Statement->StorageWidth);
   2050         }
   2051         FreePool (NewString);
   2052       }
   2053 
   2054       //
   2055       // Only for EFI_BROWSER_ACTION_CHANGED need to handle this ActionRequest.
   2056       //
   2057       switch (Action) {
   2058       case EFI_BROWSER_ACTION_CHANGED:
   2059         switch (ActionRequest) {
   2060         case EFI_BROWSER_ACTION_REQUEST_RESET:
   2061           DiscardFormIsRequired = TRUE;
   2062           gResetRequired = TRUE;
   2063           NeedExit              = TRUE;
   2064           break;
   2065 
   2066         case EFI_BROWSER_ACTION_REQUEST_SUBMIT:
   2067           SubmitFormIsRequired = TRUE;
   2068           NeedExit              = TRUE;
   2069           break;
   2070 
   2071         case EFI_BROWSER_ACTION_REQUEST_EXIT:
   2072           DiscardFormIsRequired = TRUE;
   2073           NeedExit              = TRUE;
   2074           break;
   2075 
   2076         case EFI_BROWSER_ACTION_REQUEST_FORM_SUBMIT_EXIT:
   2077           SubmitFormIsRequired  = TRUE;
   2078           SettingLevel          = FormLevel;
   2079           NeedExit              = TRUE;
   2080           break;
   2081 
   2082         case EFI_BROWSER_ACTION_REQUEST_FORM_DISCARD_EXIT:
   2083           DiscardFormIsRequired = TRUE;
   2084           SettingLevel          = FormLevel;
   2085           NeedExit              = TRUE;
   2086           break;
   2087 
   2088         case EFI_BROWSER_ACTION_REQUEST_FORM_APPLY:
   2089           SubmitFormIsRequired  = TRUE;
   2090           SettingLevel          = FormLevel;
   2091           break;
   2092 
   2093         case EFI_BROWSER_ACTION_REQUEST_FORM_DISCARD:
   2094           DiscardFormIsRequired = TRUE;
   2095           SettingLevel          = FormLevel;
   2096           break;
   2097 
   2098         case EFI_BROWSER_ACTION_REQUEST_RECONNECT:
   2099           gCallbackReconnect    = TRUE;
   2100           break;
   2101 
   2102         default:
   2103           break;
   2104         }
   2105         break;
   2106 
   2107       case EFI_BROWSER_ACTION_CHANGING:
   2108         //
   2109         // Do the question validation.
   2110         //
   2111         Status = ValueChangedValidation (gCurrentSelection->FormSet, gCurrentSelection->Form, Statement);
   2112         if (!EFI_ERROR (Status)) {
   2113           //
   2114           //check whether the question value  changed compared with edit buffer before updating edit buffer
   2115           // if changed, set the ValueChanged flag to TRUE,in order to trig the CHANGED callback function
   2116           //
   2117           IsQuestionValueChanged(gCurrentSelection->FormSet, gCurrentSelection->Form, Statement, GetSetValueWithEditBuffer);
   2118           //
   2119           // According the spec, return value from call back of "changing" and
   2120           // "retrieve" should update to the question's temp buffer.
   2121           //
   2122           SetQuestionValue(FormSet, Form, Statement, GetSetValueWithEditBuffer);
   2123         }
   2124         break;
   2125 
   2126       case EFI_BROWSER_ACTION_RETRIEVE:
   2127         //
   2128         // According the spec, return value from call back of "changing" and
   2129         // "retrieve" should update to the question's temp buffer.
   2130         //
   2131         SetQuestionValue(FormSet, Form, Statement, GetSetValueWithEditBuffer);
   2132         break;
   2133 
   2134       default:
   2135         break;
   2136       }
   2137     } else {
   2138       //
   2139       // If the callback returns EFI_UNSUPPORTED for EFI_BROWSER_ACTION_CHANGING,
   2140       // then the browser will use the value passed to Callback() and ignore the
   2141       // value returned by Callback().
   2142       //
   2143       if (Action  == EFI_BROWSER_ACTION_CHANGING && Status == EFI_UNSUPPORTED) {
   2144         if (HiiValue->Type == EFI_IFR_TYPE_BUFFER) {
   2145           CopyMem (Statement->BufferValue, BackUpBuffer, Statement->StorageWidth + sizeof(CHAR16));
   2146         } else {
   2147           CopyMem (&HiiValue->Value, &BackUpValue, sizeof (EFI_IFR_TYPE_VALUE));
   2148         }
   2149 
   2150         //
   2151         // Do the question validation.
   2152         //
   2153         InternalStatus = ValueChangedValidation (gCurrentSelection->FormSet, gCurrentSelection->Form, Statement);
   2154         if (!EFI_ERROR (InternalStatus)) {
   2155           //
   2156           //check whether the question value  changed compared with edit buffer before updating edit buffer
   2157           // if changed, set the ValueChanged flag to TRUE,in order to trig the CHANGED callback function
   2158           //
   2159           IsQuestionValueChanged(gCurrentSelection->FormSet, gCurrentSelection->Form, Statement, GetSetValueWithEditBuffer);
   2160           SetQuestionValue(FormSet, Form, Statement, GetSetValueWithEditBuffer);
   2161         }
   2162       }
   2163 
   2164       //
   2165       // According the spec, return fail from call back of "changing" and
   2166       // "retrieve", should restore the question's value.
   2167       //
   2168       if (Action == EFI_BROWSER_ACTION_CHANGING && Status != EFI_UNSUPPORTED) {
   2169         if (Statement->Storage != NULL) {
   2170           GetQuestionValue(FormSet, Form, Statement, GetSetValueWithEditBuffer);
   2171         } else if ((Statement->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) {
   2172           ProcessCallBackFunction (Selection, FormSet, Form, Question, EFI_BROWSER_ACTION_RETRIEVE, FALSE);
   2173         }
   2174       }
   2175 
   2176       if (Action == EFI_BROWSER_ACTION_RETRIEVE) {
   2177         GetQuestionValue(FormSet, Form, Statement, GetSetValueWithEditBuffer);
   2178       }
   2179 
   2180       if (Status == EFI_UNSUPPORTED) {
   2181         //
   2182         // If return EFI_UNSUPPORTED, also consider Hii driver suceess deal with it.
   2183         //
   2184         Status = EFI_SUCCESS;
   2185       }
   2186     }
   2187 
   2188     if (BackUpBuffer != NULL) {
   2189       FreePool (BackUpBuffer);
   2190     }
   2191 
   2192     //
   2193     // If Question != NULL, means just process one question
   2194     // and if code reach here means this question has finished
   2195     // processing, so just break.
   2196     //
   2197     if (Question != NULL) {
   2198       break;
   2199     }
   2200   }
   2201 
   2202   if (gCallbackReconnect && (EFI_BROWSER_ACTION_CHANGED == Action)) {
   2203     //
   2204     // Confirm changes with user first.
   2205     //
   2206     if (IsNvUpdateRequiredForFormSet(FormSet)) {
   2207       if (BROWSER_ACTION_DISCARD == PopupErrorMessage(BROWSER_RECONNECT_SAVE_CHANGES, NULL, NULL, NULL)) {
   2208         gCallbackReconnect = FALSE;
   2209         DiscardFormIsRequired = TRUE;
   2210       } else {
   2211         SubmitFormIsRequired = TRUE;
   2212       }
   2213     } else {
   2214       PopupErrorMessage(BROWSER_RECONNECT_REQUIRED, NULL, NULL, NULL);
   2215     }
   2216 
   2217     //
   2218     // Exit current formset before do the reconnect.
   2219     //
   2220     NeedExit = TRUE;
   2221     SettingLevel = FormSetLevel;
   2222   }
   2223 
   2224   if (SubmitFormIsRequired && !SkipSaveOrDiscard) {
   2225     SubmitForm (FormSet, Form, SettingLevel);
   2226   }
   2227 
   2228   if (DiscardFormIsRequired && !SkipSaveOrDiscard) {
   2229     DiscardForm (FormSet, Form, SettingLevel);
   2230   }
   2231 
   2232   if (NeedExit) {
   2233     FindNextMenu (Selection, SettingLevel);
   2234   }
   2235 
   2236   return Status;
   2237 }
   2238 
   2239 /**
   2240   Call the retrieve type call back function for one question to get the initialize data.
   2241 
   2242   This function only used when in the initialize stage, because in this stage, the
   2243   Selection->Form is not ready. For other case, use the ProcessCallBackFunction instead.
   2244 
   2245   @param ConfigAccess          The config access protocol produced by the hii driver.
   2246   @param Statement             The Question which need to call.
   2247   @param FormSet               The formset this question belong to.
   2248 
   2249   @retval EFI_SUCCESS          The call back function excutes successfully.
   2250   @return Other value if the call back function failed to excute.
   2251 **/
   2252 EFI_STATUS
   2253 ProcessRetrieveForQuestion (
   2254   IN     EFI_HII_CONFIG_ACCESS_PROTOCOL  *ConfigAccess,
   2255   IN     FORM_BROWSER_STATEMENT          *Statement,
   2256   IN     FORM_BROWSER_FORMSET            *FormSet
   2257   )
   2258 {
   2259   EFI_STATUS                      Status;
   2260   EFI_BROWSER_ACTION_REQUEST      ActionRequest;
   2261   EFI_HII_VALUE                   *HiiValue;
   2262   EFI_IFR_TYPE_VALUE              *TypeValue;
   2263   CHAR16                          *NewString;
   2264 
   2265   Status                = EFI_SUCCESS;
   2266   ActionRequest         = EFI_BROWSER_ACTION_REQUEST_NONE;
   2267 
   2268   if (((Statement->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != EFI_IFR_FLAG_CALLBACK) || ConfigAccess == NULL) {
   2269     return EFI_UNSUPPORTED;
   2270   }
   2271 
   2272   HiiValue  = &Statement->HiiValue;
   2273   TypeValue = &HiiValue->Value;
   2274   if (HiiValue->Type == EFI_IFR_TYPE_BUFFER) {
   2275     //
   2276     // For OrderedList, passing in the value buffer to Callback()
   2277     //
   2278     TypeValue = (EFI_IFR_TYPE_VALUE *) Statement->BufferValue;
   2279   }
   2280 
   2281   ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;
   2282   Status = ConfigAccess->Callback (
   2283                            ConfigAccess,
   2284                            EFI_BROWSER_ACTION_RETRIEVE,
   2285                            Statement->QuestionId,
   2286                            HiiValue->Type,
   2287                            TypeValue,
   2288                            &ActionRequest
   2289                            );
   2290   if (!EFI_ERROR (Status) && HiiValue->Type == EFI_IFR_TYPE_STRING) {
   2291     NewString = GetToken (Statement->HiiValue.Value.string, FormSet->HiiHandle);
   2292     ASSERT (NewString != NULL);
   2293 
   2294     ASSERT (StrLen (NewString) * sizeof (CHAR16) <= Statement->StorageWidth);
   2295     if (StrLen (NewString) * sizeof (CHAR16) <= Statement->StorageWidth) {
   2296       CopyMem (Statement->BufferValue, NewString, StrSize (NewString));
   2297     } else {
   2298       CopyMem (Statement->BufferValue, NewString, Statement->StorageWidth);
   2299     }
   2300     FreePool (NewString);
   2301   }
   2302 
   2303   return Status;
   2304 }
   2305 
   2306 /**
   2307   The worker function that send the displays to the screen. On output,
   2308   the selection made by user is returned.
   2309 
   2310   @param Selection       On input, Selection tell setup browser the information
   2311                          about the Selection, form and formset to be displayed.
   2312                          On output, Selection return the screen item that is selected
   2313                          by user.
   2314 
   2315   @retval EFI_SUCCESS    The page is displayed successfully.
   2316   @return Other value if the page failed to be diplayed.
   2317 
   2318 **/
   2319 EFI_STATUS
   2320 SetupBrowser (
   2321   IN OUT UI_MENU_SELECTION    *Selection
   2322   )
   2323 {
   2324   EFI_STATUS                      Status;
   2325   LIST_ENTRY                      *Link;
   2326   EFI_HANDLE                      NotifyHandle;
   2327   FORM_BROWSER_STATEMENT          *Statement;
   2328   EFI_HII_CONFIG_ACCESS_PROTOCOL  *ConfigAccess;
   2329 
   2330   ConfigAccess = Selection->FormSet->ConfigAccess;
   2331 
   2332   //
   2333   // Register notify for Form package update
   2334   //
   2335   Status = mHiiDatabase->RegisterPackageNotify (
   2336                            mHiiDatabase,
   2337                            EFI_HII_PACKAGE_FORMS,
   2338                            NULL,
   2339                            FormUpdateNotify,
   2340                            EFI_HII_DATABASE_NOTIFY_REMOVE_PACK,
   2341                            &NotifyHandle
   2342                            );
   2343   if (EFI_ERROR (Status)) {
   2344     return Status;
   2345   }
   2346 
   2347   //
   2348   // Initialize current settings of Questions in this FormSet
   2349   //
   2350   InitializeCurrentSetting (Selection->FormSet);
   2351 
   2352   //
   2353   // Initilize Action field.
   2354   //
   2355   Selection->Action = UI_ACTION_REFRESH_FORM;
   2356 
   2357   //
   2358   // Clean the mCurFakeQestId value is formset refreshed.
   2359   //
   2360   mCurFakeQestId = 0;
   2361 
   2362   do {
   2363 
   2364     //
   2365     // Reset Status to prevent the next break from returning incorrect error status.
   2366     //
   2367     Status = EFI_SUCCESS;
   2368 
   2369     //
   2370     // IFR is updated, force to reparse the IFR binary
   2371     // This check is shared by EFI_BROWSER_ACTION_FORM_CLOSE and
   2372     // EFI_BROWSER_ACTION_RETRIEVE, so code place here.
   2373     //
   2374     if (mHiiPackageListUpdated) {
   2375       Selection->Action = UI_ACTION_REFRESH_FORMSET;
   2376       mHiiPackageListUpdated = FALSE;
   2377       break;
   2378     }
   2379 
   2380     //
   2381     // Initialize Selection->Form
   2382     //
   2383     if (Selection->FormId == 0) {
   2384       //
   2385       // Zero FormId indicates display the first Form in a FormSet
   2386       //
   2387       Link = GetFirstNode (&Selection->FormSet->FormListHead);
   2388 
   2389       Selection->Form = FORM_BROWSER_FORM_FROM_LINK (Link);
   2390       Selection->FormId = Selection->Form->FormId;
   2391     } else {
   2392       Selection->Form = IdToForm (Selection->FormSet, Selection->FormId);
   2393     }
   2394 
   2395     if (Selection->Form == NULL) {
   2396       //
   2397       // No Form to display
   2398       //
   2399       Status = EFI_NOT_FOUND;
   2400       goto Done;
   2401     }
   2402 
   2403     //
   2404     // Check Form is suppressed.
   2405     //
   2406     if (Selection->Form->SuppressExpression != NULL) {
   2407       if (EvaluateExpressionList(Selection->Form->SuppressExpression, TRUE, Selection->FormSet, Selection->Form) == ExpressSuppress) {
   2408         //
   2409         // Form is suppressed.
   2410         //
   2411         PopupErrorMessage(BROWSER_FORM_SUPPRESS, NULL, NULL, NULL);
   2412         Status = EFI_NOT_FOUND;
   2413         goto Done;
   2414       }
   2415     }
   2416 
   2417     //
   2418     // Before display new form, invoke ConfigAccess.Callback() with EFI_BROWSER_ACTION_FORM_OPEN
   2419     // for each question with callback flag.
   2420     // New form may be the first form, or the different form after another form close.
   2421     //
   2422     if (((Selection->Handle != mCurrentHiiHandle) ||
   2423         (!CompareGuid (&Selection->FormSetGuid, &mCurrentFormSetGuid)) ||
   2424         (Selection->FormId != mCurrentFormId))) {
   2425       //
   2426       // Update Retrieve flag.
   2427       //
   2428       mFinishRetrieveCall = FALSE;
   2429 
   2430       //
   2431       // Keep current form information
   2432       //
   2433       mCurrentHiiHandle   = Selection->Handle;
   2434       CopyGuid (&mCurrentFormSetGuid, &Selection->FormSetGuid);
   2435       mCurrentFormId      = Selection->FormId;
   2436 
   2437       if (ConfigAccess != NULL) {
   2438         Status = ProcessCallBackFunction (Selection, Selection->FormSet, Selection->Form, NULL, EFI_BROWSER_ACTION_FORM_OPEN, FALSE);
   2439         if (EFI_ERROR (Status)) {
   2440           goto Done;
   2441         }
   2442 
   2443         //
   2444         // IFR is updated during callback of EFI_BROWSER_ACTION_FORM_OPEN, force to reparse the IFR binary
   2445         //
   2446         if (mHiiPackageListUpdated) {
   2447           Selection->Action = UI_ACTION_REFRESH_FORMSET;
   2448           mHiiPackageListUpdated = FALSE;
   2449           break;
   2450         }
   2451       }
   2452     }
   2453 
   2454     //
   2455     // Load Questions' Value for display
   2456     //
   2457     Status = LoadFormSetConfig (Selection, Selection->FormSet);
   2458     if (EFI_ERROR (Status)) {
   2459       goto Done;
   2460     }
   2461 
   2462     if (!mFinishRetrieveCall) {
   2463       //
   2464       // Finish call RETRIEVE callback for this form.
   2465       //
   2466       mFinishRetrieveCall = TRUE;
   2467 
   2468       if (ConfigAccess != NULL) {
   2469         Status = ProcessCallBackFunction (Selection, Selection->FormSet, Selection->Form, NULL, EFI_BROWSER_ACTION_RETRIEVE, FALSE);
   2470         if (EFI_ERROR (Status)) {
   2471           goto Done;
   2472         }
   2473 
   2474         //
   2475         // IFR is updated during callback of open form, force to reparse the IFR binary
   2476         //
   2477         if (mHiiPackageListUpdated) {
   2478           Selection->Action = UI_ACTION_REFRESH_FORMSET;
   2479           mHiiPackageListUpdated = FALSE;
   2480           break;
   2481         }
   2482       }
   2483     }
   2484 
   2485     //
   2486     // Display form
   2487     //
   2488     Status = DisplayForm ();
   2489     if (EFI_ERROR (Status)) {
   2490       goto Done;
   2491     }
   2492 
   2493     //
   2494     // Check Selected Statement (if press ESC, Selection->Statement will be NULL)
   2495     //
   2496     Statement = Selection->Statement;
   2497     if (Statement != NULL) {
   2498       if ((ConfigAccess != NULL) &&
   2499           ((Statement->QuestionFlags & EFI_IFR_FLAG_CALLBACK) == EFI_IFR_FLAG_CALLBACK) &&
   2500           (Statement->Operand != EFI_IFR_PASSWORD_OP)) {
   2501         Status = ProcessCallBackFunction(Selection, Selection->FormSet, Selection->Form, Statement, EFI_BROWSER_ACTION_CHANGING, FALSE);
   2502         if (Statement->Operand == EFI_IFR_REF_OP) {
   2503           //
   2504           // Process dynamic update ref opcode.
   2505           //
   2506           if (!EFI_ERROR (Status)) {
   2507             Status = ProcessGotoOpCode(Statement, Selection);
   2508           }
   2509 
   2510           //
   2511           // Callback return error status or status return from process goto opcode.
   2512           //
   2513           if (EFI_ERROR (Status)) {
   2514             //
   2515             // Cross reference will not be taken, restore all essential field
   2516             //
   2517             Selection->Handle = mCurrentHiiHandle;
   2518             CopyMem (&Selection->FormSetGuid, &mCurrentFormSetGuid, sizeof (EFI_GUID));
   2519             Selection->FormId = mCurrentFormId;
   2520             Selection->QuestionId = 0;
   2521             Selection->Action = UI_ACTION_REFRESH_FORM;
   2522           }
   2523         }
   2524 
   2525 
   2526         if (!EFI_ERROR (Status) &&
   2527             (Statement->Operand != EFI_IFR_REF_OP) &&
   2528             ((Statement->Storage == NULL) || (Statement->Storage != NULL && Statement->ValueChanged))) {
   2529           //
   2530           // Only question value has been changed, browser will trig CHANGED callback.
   2531           //
   2532           ProcessCallBackFunction(Selection, Selection->FormSet, Selection->Form, Statement, EFI_BROWSER_ACTION_CHANGED, FALSE);
   2533           //
   2534           //check whether the question value changed compared with buffer value
   2535           //if doesn't change ,set the ValueChanged flag to FALSE ,in order not to display the "configuration changed "information on the screen
   2536           //
   2537           IsQuestionValueChanged(gCurrentSelection->FormSet, gCurrentSelection->Form, Statement, GetSetValueWithBuffer);
   2538         }
   2539       } else {
   2540         //
   2541         // Do the question validation.
   2542         //
   2543         Status = ValueChangedValidation (gCurrentSelection->FormSet, gCurrentSelection->Form, Statement);
   2544         if (!EFI_ERROR (Status) && (Statement->Operand != EFI_IFR_PASSWORD_OP)) {
   2545           SetQuestionValue (gCurrentSelection->FormSet, gCurrentSelection->Form, Statement, GetSetValueWithEditBuffer);
   2546           //
   2547           // Verify whether question value has checked, update the ValueChanged flag in Question.
   2548           //
   2549           IsQuestionValueChanged(gCurrentSelection->FormSet, gCurrentSelection->Form, Statement, GetSetValueWithBuffer);
   2550         }
   2551       }
   2552 
   2553       //
   2554       // If question has EFI_IFR_FLAG_RESET_REQUIRED/EFI_IFR_FLAG_RECONNECT_REQUIRED flag and without storage
   2555       // and process question success till here, trig the gResetFlag/gFlagReconnect.
   2556       //
   2557       if ((Status == EFI_SUCCESS) &&
   2558           (Statement->Storage == NULL)) {
   2559         if ((Statement->QuestionFlags & EFI_IFR_FLAG_RESET_REQUIRED) != 0) {
   2560           gResetRequired = TRUE;
   2561         }
   2562 
   2563         if ((Statement->QuestionFlags & EFI_IFR_FLAG_RECONNECT_REQUIRED) != 0) {
   2564           gFlagReconnect = TRUE;
   2565         }
   2566       }
   2567     }
   2568 
   2569     //
   2570     // Check whether Exit flag is TRUE.
   2571     //
   2572     if (gExitRequired) {
   2573       switch (gBrowserSettingScope) {
   2574       case SystemLevel:
   2575         Selection->Action = UI_ACTION_EXIT;
   2576         break;
   2577 
   2578       case FormSetLevel:
   2579       case FormLevel:
   2580         FindNextMenu (Selection, gBrowserSettingScope);
   2581         break;
   2582 
   2583       default:
   2584         break;
   2585       }
   2586 
   2587       gExitRequired = FALSE;
   2588     }
   2589 
   2590     //
   2591     // Before exit the form, invoke ConfigAccess.Callback() with EFI_BROWSER_ACTION_FORM_CLOSE
   2592     // for each question with callback flag.
   2593     //
   2594     if ((ConfigAccess != NULL) &&
   2595         ((Selection->Action == UI_ACTION_EXIT) ||
   2596          (Selection->Handle != mCurrentHiiHandle) ||
   2597          (!CompareGuid (&Selection->FormSetGuid, &mCurrentFormSetGuid)) ||
   2598          (Selection->FormId != mCurrentFormId))) {
   2599 
   2600       Status = ProcessCallBackFunction (Selection, Selection->FormSet, Selection->Form, NULL, EFI_BROWSER_ACTION_FORM_CLOSE, FALSE);
   2601       if (EFI_ERROR (Status)) {
   2602         goto Done;
   2603       }
   2604     }
   2605   } while (Selection->Action == UI_ACTION_REFRESH_FORM);
   2606 
   2607 Done:
   2608   //
   2609   // Reset current form information to the initial setting when error happens or form exit.
   2610   //
   2611   if (EFI_ERROR (Status) || Selection->Action == UI_ACTION_EXIT) {
   2612     mCurrentHiiHandle = NULL;
   2613     CopyGuid (&mCurrentFormSetGuid, &gZeroGuid);
   2614     mCurrentFormId = 0;
   2615   }
   2616 
   2617   //
   2618   // Unregister notify for Form package update
   2619   //
   2620   mHiiDatabase->UnregisterPackageNotify (
   2621                    mHiiDatabase,
   2622                    NotifyHandle
   2623                    );
   2624   return Status;
   2625 }
   2626