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