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