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