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