]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/SetupBrowserDxe/Presentation.c
Refine the save action for the browser.
[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 IsQuestionValueChanged(FormSet, Form, Question, GetSetValueWithBuffer);
821 }
822 }
823
824 /**
825 Update the ValueChanged status for questions in this formset.
826
827 @param FormSet FormSet data structure.
828
829 **/
830 VOID
831 UpdateStatementStatusForFormSet (
832 IN FORM_BROWSER_FORMSET *FormSet
833 )
834 {
835 LIST_ENTRY *Link;
836 FORM_BROWSER_FORM *Form;
837
838 Link = GetFirstNode (&FormSet->FormListHead);
839 while (!IsNull (&FormSet->FormListHead, Link)) {
840 Form = FORM_BROWSER_FORM_FROM_LINK (Link);
841 Link = GetNextNode (&FormSet->FormListHead, Link);
842
843 UpdateStatementStatusForForm (FormSet, Form);
844 }
845 }
846
847 /**
848 Update the ValueChanged status for questions.
849
850 @param FormSet FormSet data structure.
851 @param Form Form data structure.
852 @param SettingScope Setting Scope for Default action.
853
854 **/
855 VOID
856 UpdateStatementStatus (
857 IN FORM_BROWSER_FORMSET *FormSet,
858 IN FORM_BROWSER_FORM *Form,
859 IN BROWSER_SETTING_SCOPE SettingScope
860 )
861 {
862 LIST_ENTRY *Link;
863 FORM_BROWSER_FORMSET *LocalFormSet;
864
865 switch (SettingScope) {
866 case SystemLevel:
867 Link = GetFirstNode (&gBrowserFormSetList);
868 while (!IsNull (&gBrowserFormSetList, Link)) {
869 LocalFormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link);
870 Link = GetNextNode (&gBrowserFormSetList, Link);
871 if (!ValidateFormSet(LocalFormSet)) {
872 continue;
873 }
874
875 UpdateStatementStatusForFormSet (LocalFormSet);
876 }
877 break;
878
879 case FormSetLevel:
880 UpdateStatementStatusForFormSet (FormSet);
881 break;
882
883 case FormLevel:
884 UpdateStatementStatusForForm (FormSet, Form);
885 break;
886
887 default:
888 break;
889 }
890 }
891
892 /**
893
894 Process the action request in user input.
895
896 @param Action The user input action request info.
897 @param DefaultId The user input default Id info.
898
899 @retval EFI_SUCESSS This function always return successfully for now.
900
901 **/
902 EFI_STATUS
903 ProcessAction (
904 IN UINT32 Action,
905 IN UINT16 DefaultId
906 )
907 {
908 //
909 // This is caused by use press ESC, and it should not combine with other action type.
910 //
911 if ((Action & BROWSER_ACTION_FORM_EXIT) == BROWSER_ACTION_FORM_EXIT) {
912 FindNextMenu (gCurrentSelection, FormLevel);
913 return EFI_SUCCESS;
914 }
915
916 //
917 // Below is normal hotkey trigged action, these action maybe combine with each other.
918 //
919 if ((Action & BROWSER_ACTION_DISCARD) == BROWSER_ACTION_DISCARD) {
920 DiscardForm (gCurrentSelection->FormSet, gCurrentSelection->Form, gBrowserSettingScope);
921 }
922
923 if ((Action & BROWSER_ACTION_DEFAULT) == BROWSER_ACTION_DEFAULT) {
924 ExtractDefault (gCurrentSelection->FormSet, gCurrentSelection->Form, DefaultId, gBrowserSettingScope, GetDefaultForAll, NULL, FALSE);
925 UpdateStatementStatus (gCurrentSelection->FormSet, gCurrentSelection->Form, gBrowserSettingScope);
926 }
927
928 if ((Action & BROWSER_ACTION_SUBMIT) == BROWSER_ACTION_SUBMIT) {
929 SubmitForm (gCurrentSelection->FormSet, gCurrentSelection->Form, gBrowserSettingScope);
930 }
931
932 if ((Action & BROWSER_ACTION_RESET) == BROWSER_ACTION_RESET) {
933 gResetRequired = TRUE;
934 }
935
936 if ((Action & BROWSER_ACTION_EXIT) == BROWSER_ACTION_EXIT) {
937 //
938 // Form Exit without saving, Similar to ESC Key.
939 // FormSet Exit without saving, Exit SendForm.
940 // System Exit without saving, CallExitHandler and Exit SendForm.
941 //
942 DiscardForm (gCurrentSelection->FormSet, gCurrentSelection->Form, gBrowserSettingScope);
943 if (gBrowserSettingScope == FormLevel || gBrowserSettingScope == FormSetLevel) {
944 FindNextMenu (gCurrentSelection, gBrowserSettingScope);
945 } else if (gBrowserSettingScope == SystemLevel) {
946 if (ExitHandlerFunction != NULL) {
947 ExitHandlerFunction ();
948 }
949 gCurrentSelection->Action = UI_ACTION_EXIT;
950 }
951 }
952
953 return EFI_SUCCESS;
954 }
955
956 /**
957 Check whether the formset guid is in this Hii package list.
958
959 @param HiiHandle The HiiHandle for this HII package list.
960 @param FormSetGuid The formset guid for the request formset.
961
962 @retval TRUE Find the formset guid.
963 @retval FALSE Not found the formset guid.
964
965 **/
966 BOOLEAN
967 GetFormsetGuidFromHiiHandle (
968 IN EFI_HII_HANDLE HiiHandle,
969 IN EFI_GUID *FormSetGuid
970 )
971 {
972 EFI_HII_PACKAGE_LIST_HEADER *HiiPackageList;
973 UINTN BufferSize;
974 UINT32 Offset;
975 UINT32 Offset2;
976 UINT32 PackageListLength;
977 EFI_HII_PACKAGE_HEADER PackageHeader;
978 UINT8 *Package;
979 UINT8 *OpCodeData;
980 EFI_STATUS Status;
981 BOOLEAN FindGuid;
982
983 BufferSize = 0;
984 HiiPackageList = NULL;
985 FindGuid = FALSE;
986
987 Status = mHiiDatabase->ExportPackageLists (mHiiDatabase, HiiHandle, &BufferSize, HiiPackageList);
988 if (Status == EFI_BUFFER_TOO_SMALL) {
989 HiiPackageList = AllocatePool (BufferSize);
990 ASSERT (HiiPackageList != NULL);
991
992 Status = mHiiDatabase->ExportPackageLists (mHiiDatabase, HiiHandle, &BufferSize, HiiPackageList);
993 }
994 if (EFI_ERROR (Status) || HiiPackageList == NULL) {
995 return FALSE;
996 }
997
998 //
999 // Get Form package from this HII package List
1000 //
1001 Offset = sizeof (EFI_HII_PACKAGE_LIST_HEADER);
1002 Offset2 = 0;
1003 CopyMem (&PackageListLength, &HiiPackageList->PackageLength, sizeof (UINT32));
1004
1005 while (Offset < PackageListLength) {
1006 Package = ((UINT8 *) HiiPackageList) + Offset;
1007 CopyMem (&PackageHeader, Package, sizeof (EFI_HII_PACKAGE_HEADER));
1008 Offset += PackageHeader.Length;
1009
1010 if (PackageHeader.Type == EFI_HII_PACKAGE_FORMS) {
1011 //
1012 // Search FormSet in this Form Package
1013 //
1014 Offset2 = sizeof (EFI_HII_PACKAGE_HEADER);
1015 while (Offset2 < PackageHeader.Length) {
1016 OpCodeData = Package + Offset2;
1017
1018 if (((EFI_IFR_OP_HEADER *) OpCodeData)->OpCode == EFI_IFR_FORM_SET_OP) {
1019 if (CompareGuid (FormSetGuid, (EFI_GUID *)(OpCodeData + sizeof (EFI_IFR_OP_HEADER)))){
1020 FindGuid = TRUE;
1021 break;
1022 }
1023 }
1024
1025 Offset2 += ((EFI_IFR_OP_HEADER *) OpCodeData)->Length;
1026 }
1027 }
1028 if (FindGuid) {
1029 break;
1030 }
1031 }
1032
1033 FreePool (HiiPackageList);
1034
1035 return FindGuid;
1036 }
1037
1038 /**
1039 Find HII Handle in the HII database associated with given Device Path.
1040
1041 If DevicePath is NULL, then ASSERT.
1042
1043 @param DevicePath Device Path associated with the HII package list
1044 handle.
1045 @param FormsetGuid The formset guid for this formset.
1046
1047 @retval Handle HII package list Handle associated with the Device
1048 Path.
1049 @retval NULL Hii Package list handle is not found.
1050
1051 **/
1052 EFI_HII_HANDLE
1053 DevicePathToHiiHandle (
1054 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
1055 IN EFI_GUID *FormsetGuid
1056 )
1057 {
1058 EFI_STATUS Status;
1059 EFI_DEVICE_PATH_PROTOCOL *TmpDevicePath;
1060 UINTN Index;
1061 EFI_HANDLE Handle;
1062 EFI_HANDLE DriverHandle;
1063 EFI_HII_HANDLE *HiiHandles;
1064 EFI_HII_HANDLE HiiHandle;
1065
1066 ASSERT (DevicePath != NULL);
1067
1068 TmpDevicePath = DevicePath;
1069 //
1070 // Locate Device Path Protocol handle buffer
1071 //
1072 Status = gBS->LocateDevicePath (
1073 &gEfiDevicePathProtocolGuid,
1074 &TmpDevicePath,
1075 &DriverHandle
1076 );
1077 if (EFI_ERROR (Status) || !IsDevicePathEnd (TmpDevicePath)) {
1078 return NULL;
1079 }
1080
1081 //
1082 // Retrieve all HII Handles from HII database
1083 //
1084 HiiHandles = HiiGetHiiHandles (NULL);
1085 if (HiiHandles == NULL) {
1086 return NULL;
1087 }
1088
1089 //
1090 // Search Hii Handle by Driver Handle
1091 //
1092 HiiHandle = NULL;
1093 for (Index = 0; HiiHandles[Index] != NULL; Index++) {
1094 Status = mHiiDatabase->GetPackageListHandle (
1095 mHiiDatabase,
1096 HiiHandles[Index],
1097 &Handle
1098 );
1099 if (!EFI_ERROR (Status) && (Handle == DriverHandle)) {
1100 if (GetFormsetGuidFromHiiHandle(HiiHandles[Index], FormsetGuid)) {
1101 HiiHandle = HiiHandles[Index];
1102 break;
1103 }
1104
1105 if (HiiHandle != NULL) {
1106 break;
1107 }
1108 }
1109 }
1110
1111 FreePool (HiiHandles);
1112 return HiiHandle;
1113 }
1114
1115 /**
1116 Find HII Handle in the HII database associated with given form set guid.
1117
1118 If FormSetGuid is NULL, then ASSERT.
1119
1120 @param ComparingGuid FormSet Guid associated with the HII package list
1121 handle.
1122
1123 @retval Handle HII package list Handle associated with the Device
1124 Path.
1125 @retval NULL Hii Package list handle is not found.
1126
1127 **/
1128 EFI_HII_HANDLE
1129 FormSetGuidToHiiHandle (
1130 EFI_GUID *ComparingGuid
1131 )
1132 {
1133 EFI_HII_HANDLE *HiiHandles;
1134 EFI_HII_HANDLE HiiHandle;
1135 UINTN Index;
1136
1137 ASSERT (ComparingGuid != NULL);
1138
1139 HiiHandle = NULL;
1140 //
1141 // Get all the Hii handles
1142 //
1143 HiiHandles = HiiGetHiiHandles (NULL);
1144 ASSERT (HiiHandles != NULL);
1145
1146 //
1147 // Search for formset of each class type
1148 //
1149 for (Index = 0; HiiHandles[Index] != NULL; Index++) {
1150 if (GetFormsetGuidFromHiiHandle(HiiHandles[Index], ComparingGuid)) {
1151 HiiHandle = HiiHandles[Index];
1152 break;
1153 }
1154
1155 if (HiiHandle != NULL) {
1156 break;
1157 }
1158 }
1159
1160 FreePool (HiiHandles);
1161
1162 return HiiHandle;
1163 }
1164
1165 /**
1166 check how to process the changed data in current form or form set.
1167
1168 @param Selection On input, Selection tell setup browser the information
1169 about the Selection, form and formset to be displayed.
1170 On output, Selection return the screen item that is selected
1171 by user.
1172
1173 @param Scope Data save or discard scope, form or formset.
1174
1175 @retval TRUE Success process the changed data, will return to the parent form.
1176 @retval FALSE Reject to process the changed data, will stay at current form.
1177 **/
1178 BOOLEAN
1179 ProcessChangedData (
1180 IN OUT UI_MENU_SELECTION *Selection,
1181 IN BROWSER_SETTING_SCOPE Scope
1182 )
1183 {
1184 BOOLEAN RetValue;
1185 EFI_STATUS Status;
1186
1187 RetValue = TRUE;
1188 switch (mFormDisplay->ConfirmDataChange()) {
1189 case BROWSER_ACTION_DISCARD:
1190 DiscardForm (Selection->FormSet, Selection->Form, Scope);
1191 break;
1192
1193 case BROWSER_ACTION_SUBMIT:
1194 Status = SubmitForm (Selection->FormSet, Selection->Form, Scope);
1195 if (EFI_ERROR (Status)) {
1196 RetValue = FALSE;
1197 }
1198 break;
1199
1200 case BROWSER_ACTION_NONE:
1201 RetValue = FALSE;
1202 break;
1203
1204 default:
1205 //
1206 // if Invalid value return, process same as BROWSER_ACTION_NONE.
1207 //
1208 RetValue = FALSE;
1209 break;
1210 }
1211
1212 return RetValue;
1213 }
1214
1215 /**
1216 Find parent formset menu(the first menu which has different formset) for current menu.
1217 If not find, just return to the first menu.
1218
1219 @param Selection The selection info.
1220
1221 **/
1222 VOID
1223 FindParentFormSet (
1224 IN OUT UI_MENU_SELECTION *Selection
1225 )
1226 {
1227 FORM_ENTRY_INFO *CurrentMenu;
1228 FORM_ENTRY_INFO *ParentMenu;
1229
1230 CurrentMenu = Selection->CurrentMenu;
1231 ParentMenu = UiFindParentMenu(CurrentMenu);
1232
1233 //
1234 // Find a menu which has different formset guid with current.
1235 //
1236 while (ParentMenu != NULL && CompareGuid (&CurrentMenu->FormSetGuid, &ParentMenu->FormSetGuid)) {
1237 CurrentMenu = ParentMenu;
1238 ParentMenu = UiFindParentMenu(CurrentMenu);
1239 }
1240
1241 if (ParentMenu != NULL) {
1242 CopyMem (&Selection->FormSetGuid, &ParentMenu->FormSetGuid, sizeof (EFI_GUID));
1243 Selection->Handle = ParentMenu->HiiHandle;
1244 Selection->FormId = ParentMenu->FormId;
1245 Selection->QuestionId = ParentMenu->QuestionId;
1246 } else {
1247 Selection->FormId = CurrentMenu->FormId;
1248 Selection->QuestionId = CurrentMenu->QuestionId;
1249 }
1250
1251 Selection->Statement = NULL;
1252 }
1253
1254 /**
1255 Process the goto op code, update the info in the selection structure.
1256
1257 @param Statement The statement belong to goto op code.
1258 @param Selection The selection info.
1259
1260 @retval EFI_SUCCESS The menu process successfully.
1261 @return Other value if the process failed.
1262 **/
1263 EFI_STATUS
1264 ProcessGotoOpCode (
1265 IN OUT FORM_BROWSER_STATEMENT *Statement,
1266 IN OUT UI_MENU_SELECTION *Selection
1267 )
1268 {
1269 CHAR16 *StringPtr;
1270 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
1271 FORM_BROWSER_FORM *RefForm;
1272 EFI_STATUS Status;
1273 EFI_HII_HANDLE HiiHandle;
1274
1275 Status = EFI_SUCCESS;
1276 StringPtr = NULL;
1277 HiiHandle = NULL;
1278
1279 //
1280 // Prepare the device path check, get the device path info first.
1281 //
1282 if (Statement->HiiValue.Value.ref.DevicePath != 0) {
1283 StringPtr = GetToken (Statement->HiiValue.Value.ref.DevicePath, Selection->FormSet->HiiHandle);
1284 }
1285
1286 //
1287 // Check whether the device path string is a valid string.
1288 //
1289 if (Statement->HiiValue.Value.ref.DevicePath != 0 && StringPtr != NULL && StringPtr[0] != L'\0') {
1290 if (Selection->Form->ModalForm) {
1291 return Status;
1292 }
1293
1294 //
1295 // Goto another Hii Package list
1296 //
1297 if (mPathFromText != NULL) {
1298 DevicePath = mPathFromText->ConvertTextToDevicePath(StringPtr);
1299 if (DevicePath != NULL) {
1300 HiiHandle = DevicePathToHiiHandle (DevicePath, &Statement->HiiValue.Value.ref.FormSetGuid);
1301 FreePool (DevicePath);
1302 }
1303 FreePool (StringPtr);
1304 } else {
1305 //
1306 // Not found the EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL protocol.
1307 //
1308 PopupErrorMessage(BROWSER_PROTOCOL_NOT_FOUND, NULL, NULL, NULL);
1309 FreePool (StringPtr);
1310 return Status;
1311 }
1312
1313 if (HiiHandle != Selection->Handle) {
1314 //
1315 // Goto another Formset, check for uncommitted data
1316 //
1317 if ((gBrowserSettingScope == FormLevel || gBrowserSettingScope == FormSetLevel) &&
1318 IsNvUpdateRequiredForFormSet(Selection->FormSet)) {
1319 if (!ProcessChangedData(Selection, FormSetLevel)) {
1320 return EFI_SUCCESS;
1321 }
1322 }
1323 }
1324
1325 Selection->Action = UI_ACTION_REFRESH_FORMSET;
1326 Selection->Handle = HiiHandle;
1327 if (Selection->Handle == NULL) {
1328 //
1329 // If target Hii Handle not found, exit current formset.
1330 //
1331 FindParentFormSet(Selection);
1332 return EFI_SUCCESS;
1333 }
1334
1335 CopyMem (&Selection->FormSetGuid,&Statement->HiiValue.Value.ref.FormSetGuid, sizeof (EFI_GUID));
1336 Selection->FormId = Statement->HiiValue.Value.ref.FormId;
1337 Selection->QuestionId = Statement->HiiValue.Value.ref.QuestionId;
1338 } else if (!CompareGuid (&Statement->HiiValue.Value.ref.FormSetGuid, &gZeroGuid)) {
1339 if (Selection->Form->ModalForm) {
1340 return Status;
1341 }
1342 if (!CompareGuid (&Statement->HiiValue.Value.ref.FormSetGuid, &Selection->FormSetGuid)) {
1343 //
1344 // Goto another Formset, check for uncommitted data
1345 //
1346 if ((gBrowserSettingScope == FormLevel || gBrowserSettingScope == FormSetLevel) &&
1347 IsNvUpdateRequiredForFormSet(Selection->FormSet)) {
1348 if (!ProcessChangedData(Selection, FormSetLevel)) {
1349 return EFI_SUCCESS;
1350 }
1351 }
1352 }
1353
1354 Selection->Action = UI_ACTION_REFRESH_FORMSET;
1355 Selection->Handle = FormSetGuidToHiiHandle(&Statement->HiiValue.Value.ref.FormSetGuid);
1356 if (Selection->Handle == NULL) {
1357 //
1358 // If target Hii Handle not found, exit current formset.
1359 //
1360 FindParentFormSet(Selection);
1361 return EFI_SUCCESS;
1362 }
1363
1364 CopyMem (&Selection->FormSetGuid, &Statement->HiiValue.Value.ref.FormSetGuid, sizeof (EFI_GUID));
1365 Selection->FormId = Statement->HiiValue.Value.ref.FormId;
1366 Selection->QuestionId = Statement->HiiValue.Value.ref.QuestionId;
1367 } else if (Statement->HiiValue.Value.ref.FormId != 0) {
1368 //
1369 // Goto another Form, check for uncommitted data
1370 //
1371 if (Statement->HiiValue.Value.ref.FormId != Selection->FormId) {
1372 if ((gBrowserSettingScope == FormLevel && IsNvUpdateRequiredForForm(Selection->Form))) {
1373 if (!ProcessChangedData (Selection, FormLevel)) {
1374 return EFI_SUCCESS;
1375 }
1376 }
1377 }
1378
1379 RefForm = IdToForm (Selection->FormSet, Statement->HiiValue.Value.ref.FormId);
1380 if ((RefForm != NULL) && (RefForm->SuppressExpression != NULL)) {
1381 if (EvaluateExpressionList(RefForm->SuppressExpression, TRUE, Selection->FormSet, RefForm) != ExpressFalse) {
1382 //
1383 // Form is suppressed.
1384 //
1385 PopupErrorMessage(BROWSER_FORM_SUPPRESS, NULL, NULL, NULL);
1386 return EFI_SUCCESS;
1387 }
1388 }
1389
1390 Selection->FormId = Statement->HiiValue.Value.ref.FormId;
1391 Selection->QuestionId = Statement->HiiValue.Value.ref.QuestionId;
1392 } else if (Statement->HiiValue.Value.ref.QuestionId != 0) {
1393 Selection->QuestionId = Statement->HiiValue.Value.ref.QuestionId;
1394 }
1395
1396 return Status;
1397 }
1398
1399
1400 /**
1401 Process Question Config.
1402
1403 @param Selection The UI menu selection.
1404 @param Question The Question to be peocessed.
1405
1406 @retval EFI_SUCCESS Question Config process success.
1407 @retval Other Question Config process fail.
1408
1409 **/
1410 EFI_STATUS
1411 ProcessQuestionConfig (
1412 IN UI_MENU_SELECTION *Selection,
1413 IN FORM_BROWSER_STATEMENT *Question
1414 )
1415 {
1416 EFI_STATUS Status;
1417 CHAR16 *ConfigResp;
1418 CHAR16 *Progress;
1419
1420 if (Question->QuestionConfig == 0) {
1421 return EFI_SUCCESS;
1422 }
1423
1424 //
1425 // Get <ConfigResp>
1426 //
1427 ConfigResp = GetToken (Question->QuestionConfig, Selection->FormSet->HiiHandle);
1428 if (ConfigResp == NULL) {
1429 return EFI_NOT_FOUND;
1430 }
1431
1432 //
1433 // Send config to Configuration Driver
1434 //
1435 Status = mHiiConfigRouting->RouteConfig (
1436 mHiiConfigRouting,
1437 ConfigResp,
1438 &Progress
1439 );
1440
1441 return Status;
1442 }
1443
1444 /**
1445
1446 Process the user input data.
1447
1448 @param UserInput The user input data.
1449 @param ChangeHighlight Whether need to change the highlight statement.
1450
1451 @retval EFI_SUCESSS This function always return successfully for now.
1452
1453 **/
1454 EFI_STATUS
1455 ProcessUserInput (
1456 IN USER_INPUT *UserInput,
1457 IN BOOLEAN ChangeHighlight
1458 )
1459 {
1460 EFI_STATUS Status;
1461 FORM_BROWSER_STATEMENT *Statement;
1462
1463 Status = EFI_SUCCESS;
1464
1465 //
1466 // When Exit from FormDisplay function, one of the below two cases must be true.
1467 //
1468 ASSERT (UserInput->Action != 0 || UserInput->SelectedStatement != NULL);
1469
1470 //
1471 // Remove the last highligh question id, this id will update when show next form.
1472 //
1473 gCurrentSelection->QuestionId = 0;
1474
1475 //
1476 // First process the Action field in USER_INPUT.
1477 //
1478 if (UserInput->Action != 0) {
1479 Status = ProcessAction (UserInput->Action, UserInput->DefaultId);
1480 if (EFI_ERROR (Status)) {
1481 return Status;
1482 }
1483
1484 //
1485 // Clear the highlight info.
1486 //
1487 gCurrentSelection->Statement = NULL;
1488
1489 if (UserInput->SelectedStatement != NULL) {
1490 Statement = GetBrowserStatement(UserInput->SelectedStatement);
1491 ASSERT (Statement != NULL);
1492 //
1493 // Save the current highlight menu in the menu history data.
1494 // which will be used when later browse back to this form.
1495 //
1496 gCurrentSelection->CurrentMenu->QuestionId = Statement->QuestionId;
1497 //
1498 // For statement like text, actio, it not has question id.
1499 // So use FakeQuestionId to save the question.
1500 //
1501 if (gCurrentSelection->CurrentMenu->QuestionId == 0) {
1502 mCurFakeQestId = Statement->FakeQuestionId;
1503 } else {
1504 mCurFakeQestId = 0;
1505 }
1506 }
1507 } else {
1508 Statement = GetBrowserStatement(UserInput->SelectedStatement);
1509 ASSERT (Statement != NULL);
1510
1511 gCurrentSelection->Statement = Statement;
1512
1513 if (ChangeHighlight) {
1514 //
1515 // This question is the current user select one,record it and later
1516 // show it as the highlight question.
1517 //
1518 gCurrentSelection->CurrentMenu->QuestionId = Statement->QuestionId;
1519 //
1520 // For statement like text, actio, it not has question id.
1521 // So use FakeQuestionId to save the question.
1522 //
1523 if (gCurrentSelection->CurrentMenu->QuestionId == 0) {
1524 mCurFakeQestId = Statement->FakeQuestionId;
1525 } else {
1526 mCurFakeQestId = 0;
1527 }
1528 }
1529
1530 switch (Statement->Operand) {
1531 case EFI_IFR_REF_OP:
1532 Status = ProcessGotoOpCode(Statement, gCurrentSelection);
1533 break;
1534
1535 case EFI_IFR_ACTION_OP:
1536 //
1537 // Process the Config string <ConfigResp>
1538 //
1539 Status = ProcessQuestionConfig (gCurrentSelection, Statement);
1540 break;
1541
1542 case EFI_IFR_RESET_BUTTON_OP:
1543 //
1544 // Reset Question to default value specified by DefaultId
1545 //
1546 Status = ExtractDefault (gCurrentSelection->FormSet, NULL, Statement->DefaultId, FormSetLevel, GetDefaultForAll, NULL, FALSE);
1547 UpdateStatementStatus (gCurrentSelection->FormSet, NULL, FormSetLevel);
1548 break;
1549
1550 default:
1551 switch (Statement->Operand) {
1552 case EFI_IFR_STRING_OP:
1553 DeleteString(Statement->HiiValue.Value.string, gCurrentSelection->FormSet->HiiHandle);
1554 Statement->HiiValue.Value.string = UserInput->InputValue.Value.string;
1555 CopyMem (Statement->BufferValue, UserInput->InputValue.Buffer, (UINTN) UserInput->InputValue.BufferLen);
1556 FreePool (UserInput->InputValue.Buffer);
1557 break;
1558
1559 case EFI_IFR_PASSWORD_OP:
1560 if (UserInput->InputValue.Buffer == NULL) {
1561 //
1562 // User not input new password, just return.
1563 //
1564 break;
1565 }
1566
1567 DeleteString(Statement->HiiValue.Value.string, gCurrentSelection->FormSet->HiiHandle);
1568 Statement->HiiValue.Value.string = UserInput->InputValue.Value.string;
1569 CopyMem (Statement->BufferValue, UserInput->InputValue.Buffer, (UINTN) UserInput->InputValue.BufferLen);
1570 FreePool (UserInput->InputValue.Buffer);
1571 //
1572 // Two password match, send it to Configuration Driver
1573 //
1574 if ((Statement->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) {
1575 PasswordCheck (NULL, UserInput->SelectedStatement, (CHAR16 *) Statement->BufferValue);
1576 //
1577 // Clean the value after saved it.
1578 //
1579 ZeroMem (Statement->BufferValue, (UINTN) UserInput->InputValue.BufferLen);
1580 HiiSetString (gCurrentSelection->FormSet->HiiHandle, Statement->HiiValue.Value.string, (CHAR16*)Statement->BufferValue, NULL);
1581 } else {
1582 SetQuestionValue (gCurrentSelection->FormSet, gCurrentSelection->Form, Statement, GetSetValueWithHiiDriver);
1583 }
1584 break;
1585
1586 case EFI_IFR_ORDERED_LIST_OP:
1587 CopyMem (Statement->BufferValue, UserInput->InputValue.Buffer, UserInput->InputValue.BufferLen);
1588 break;
1589
1590 default:
1591 CopyMem (&Statement->HiiValue, &UserInput->InputValue, sizeof (EFI_HII_VALUE));
1592 break;
1593 }
1594 break;
1595 }
1596 }
1597
1598 return Status;
1599 }
1600
1601 /**
1602
1603 Display form and wait for user to select one menu option, then return it.
1604
1605 @retval EFI_SUCESSS This function always return successfully for now.
1606
1607 **/
1608 EFI_STATUS
1609 DisplayForm (
1610 VOID
1611 )
1612 {
1613 EFI_STATUS Status;
1614 USER_INPUT UserInput;
1615 FORM_ENTRY_INFO *CurrentMenu;
1616 BOOLEAN ChangeHighlight;
1617
1618 ZeroMem (&UserInput, sizeof (USER_INPUT));
1619
1620 //
1621 // Update the menu history data.
1622 //
1623 CurrentMenu = UiFindMenuList (gCurrentSelection->Handle, &gCurrentSelection->FormSetGuid, gCurrentSelection->FormId);
1624 if (CurrentMenu == NULL) {
1625 //
1626 // Current menu not found, add it to the menu tree
1627 //
1628 CurrentMenu = UiAddMenuList (gCurrentSelection->Handle, &gCurrentSelection->FormSetGuid,
1629 gCurrentSelection->FormId, gCurrentSelection->QuestionId);
1630 ASSERT (CurrentMenu != NULL);
1631 }
1632
1633 //
1634 // Back up the form view history data for this form.
1635 //
1636 UiCopyMenuList(&gCurrentSelection->Form->FormViewListHead, &mPrivateData.FormBrowserEx2.FormViewHistoryHead);
1637
1638 gCurrentSelection->CurrentMenu = CurrentMenu;
1639
1640 //
1641 // Find currrent highlight statement.
1642 //
1643 if (gCurrentSelection->QuestionId == 0) {
1644 //
1645 // Highlight not specified, fetch it from cached menu
1646 //
1647 gCurrentSelection->QuestionId = CurrentMenu->QuestionId;
1648 }
1649
1650 //
1651 // Evaluate all the Expressions in this Form
1652 //
1653 Status = EvaluateFormExpressions (gCurrentSelection->FormSet, gCurrentSelection->Form);
1654 if (EFI_ERROR (Status)) {
1655 return Status;
1656 }
1657
1658 UpdateDisplayFormData ();
1659
1660 //
1661 // Three possible status maybe return.
1662 //
1663 // EFI_INVALID_PARAMETER: The input dimension info is not valid.
1664 // EFI_NOT_FOUND: The input value for oneof/orderedlist opcode is not valid
1665 // and an valid value has return.
1666 // EFI_SUCCESS: Success shows form and get user input in UserInput paramenter.
1667 //
1668 ASSERT (gDisplayFormData.BrowserStatus == BROWSER_SUCCESS);
1669 Status = mFormDisplay->FormDisplay (&gDisplayFormData, &UserInput);
1670 if (EFI_ERROR (Status) && Status != EFI_NOT_FOUND) {
1671 FreeDisplayFormData();
1672 return Status;
1673 }
1674
1675 //
1676 // If status is EFI_SUCCESS, means user has change the highlight menu and new user input return.
1677 // in this case, browser need to change the highlight menu.
1678 // If status is EFI_NOT_FOUND, means the input DisplayFormData has error for oneof/orderedlist
1679 // opcode and new valid value has return, browser core need to adjust
1680 // value for this opcode and shows this form again.
1681 //
1682 ChangeHighlight = (Status == EFI_SUCCESS ? TRUE :FALSE);
1683
1684 Status = ProcessUserInput (&UserInput, ChangeHighlight);
1685
1686 FreeDisplayFormData();
1687
1688 return Status;
1689 }
1690
1691 /**
1692 Functions which are registered to receive notification of
1693 database events have this prototype. The actual event is encoded
1694 in NotifyType. The following table describes how PackageType,
1695 PackageGuid, Handle, and Package are used for each of the
1696 notification types.
1697
1698 @param PackageType Package type of the notification.
1699
1700 @param PackageGuid If PackageType is
1701 EFI_HII_PACKAGE_TYPE_GUID, then this is
1702 the pointer to the GUID from the Guid
1703 field of EFI_HII_PACKAGE_GUID_HEADER.
1704 Otherwise, it must be NULL.
1705
1706 @param Package Points to the package referred to by the
1707 notification Handle The handle of the package
1708 list which contains the specified package.
1709
1710 @param Handle The HII handle.
1711
1712 @param NotifyType The type of change concerning the
1713 database. See
1714 EFI_HII_DATABASE_NOTIFY_TYPE.
1715
1716 **/
1717 EFI_STATUS
1718 EFIAPI
1719 FormUpdateNotify (
1720 IN UINT8 PackageType,
1721 IN CONST EFI_GUID *PackageGuid,
1722 IN CONST EFI_HII_PACKAGE_HEADER *Package,
1723 IN EFI_HII_HANDLE Handle,
1724 IN EFI_HII_DATABASE_NOTIFY_TYPE NotifyType
1725 )
1726 {
1727 mHiiPackageListUpdated = TRUE;
1728
1729 return EFI_SUCCESS;
1730 }
1731
1732 /**
1733 Update the NV flag info for this form set.
1734
1735 @param FormSet FormSet data structure.
1736
1737 **/
1738 BOOLEAN
1739 IsNvUpdateRequiredForFormSet (
1740 IN FORM_BROWSER_FORMSET *FormSet
1741 )
1742 {
1743 LIST_ENTRY *Link;
1744 FORM_BROWSER_FORM *Form;
1745 BOOLEAN RetVal;
1746
1747 //
1748 // Not finished question initialization, return FALSE.
1749 //
1750 if (!FormSet->QuestionInited) {
1751 return FALSE;
1752 }
1753
1754 RetVal = FALSE;
1755
1756 Link = GetFirstNode (&FormSet->FormListHead);
1757 while (!IsNull (&FormSet->FormListHead, Link)) {
1758 Form = FORM_BROWSER_FORM_FROM_LINK (Link);
1759
1760 RetVal = IsNvUpdateRequiredForForm(Form);
1761 if (RetVal) {
1762 break;
1763 }
1764
1765 Link = GetNextNode (&FormSet->FormListHead, Link);
1766 }
1767
1768 return RetVal;
1769 }
1770
1771 /**
1772 Update the NvUpdateRequired flag for a form.
1773
1774 @param Form Form data structure.
1775
1776 **/
1777 BOOLEAN
1778 IsNvUpdateRequiredForForm (
1779 IN FORM_BROWSER_FORM *Form
1780 )
1781 {
1782 LIST_ENTRY *Link;
1783 FORM_BROWSER_STATEMENT *Statement;
1784
1785 Link = GetFirstNode (&Form->StatementListHead);
1786 while (!IsNull (&Form->StatementListHead, Link)) {
1787 Statement = FORM_BROWSER_STATEMENT_FROM_LINK (Link);
1788
1789 if (Statement->ValueChanged) {
1790 return TRUE;
1791 }
1792
1793 Link = GetNextNode (&Form->StatementListHead, Link);
1794 }
1795
1796 return FALSE;
1797 }
1798
1799 /**
1800 Find menu which will show next time.
1801
1802 @param Selection On input, Selection tell setup browser the information
1803 about the Selection, form and formset to be displayed.
1804 On output, Selection return the screen item that is selected
1805 by user.
1806 @param SettingLevel Input Settting level, if it is FormLevel, just exit current form.
1807 else, we need to exit current formset.
1808
1809 @retval TRUE Exit current form.
1810 @retval FALSE User press ESC and keep in current form.
1811 **/
1812 BOOLEAN
1813 FindNextMenu (
1814 IN OUT UI_MENU_SELECTION *Selection,
1815 IN BROWSER_SETTING_SCOPE SettingLevel
1816 )
1817 {
1818 FORM_ENTRY_INFO *CurrentMenu;
1819 FORM_ENTRY_INFO *ParentMenu;
1820 BROWSER_SETTING_SCOPE Scope;
1821
1822 CurrentMenu = Selection->CurrentMenu;
1823 ParentMenu = NULL;
1824 Scope = FormSetLevel;
1825
1826 if (CurrentMenu != NULL && (ParentMenu = UiFindParentMenu(CurrentMenu)) != NULL) {
1827 //
1828 // we have a parent, so go to the parent menu
1829 //
1830 if (CompareGuid (&CurrentMenu->FormSetGuid, &ParentMenu->FormSetGuid)) {
1831 if (SettingLevel == FormSetLevel) {
1832 //
1833 // Find a menu which has different formset guid with current.
1834 //
1835 while (CompareGuid (&CurrentMenu->FormSetGuid, &ParentMenu->FormSetGuid)) {
1836 CurrentMenu = ParentMenu;
1837 if ((ParentMenu = UiFindParentMenu(CurrentMenu)) == NULL) {
1838 break;
1839 }
1840 }
1841
1842 if (ParentMenu != NULL) {
1843 Scope = FormSetLevel;
1844 }
1845 } else {
1846 Scope = FormLevel;
1847 }
1848 } else {
1849 Scope = FormSetLevel;
1850 }
1851 }
1852
1853 //
1854 // Form Level Check whether the data is changed.
1855 //
1856 if ((gBrowserSettingScope == FormLevel && IsNvUpdateRequiredForForm (Selection->Form)) ||
1857 (gBrowserSettingScope == FormSetLevel && IsNvUpdateRequiredForFormSet(Selection->FormSet) && Scope == FormSetLevel)) {
1858 if (!ProcessChangedData(Selection, gBrowserSettingScope)) {
1859 return FALSE;
1860 }
1861 }
1862
1863 if (ParentMenu != NULL) {
1864 //
1865 // ParentMenu is found. Then, go to it.
1866 //
1867 if (Scope == FormLevel) {
1868 Selection->Action = UI_ACTION_REFRESH_FORM;
1869 } else {
1870 Selection->Action = UI_ACTION_REFRESH_FORMSET;
1871 CopyMem (&Selection->FormSetGuid, &ParentMenu->FormSetGuid, sizeof (EFI_GUID));
1872 Selection->Handle = ParentMenu->HiiHandle;
1873 }
1874
1875 Selection->Statement = NULL;
1876
1877 Selection->FormId = ParentMenu->FormId;
1878 Selection->QuestionId = ParentMenu->QuestionId;
1879
1880 //
1881 // Clear highlight record for this menu
1882 //
1883 CurrentMenu->QuestionId = 0;
1884 return FALSE;
1885 }
1886
1887 //
1888 // Current in root page, exit the SendForm
1889 //
1890 Selection->Action = UI_ACTION_EXIT;
1891
1892 return TRUE;
1893 }
1894
1895 /**
1896 Call the call back function for the question and process the return action.
1897
1898 @param Selection On input, Selection tell setup browser the information
1899 about the Selection, form and formset to be displayed.
1900 On output, Selection return the screen item that is selected
1901 by user.
1902 @param FormSet The formset this question belong to.
1903 @param Form The form this question belong to.
1904 @param Question The Question which need to call.
1905 @param Action The action request.
1906 @param SkipSaveOrDiscard Whether skip save or discard action.
1907
1908 @retval EFI_SUCCESS The call back function excutes successfully.
1909 @return Other value if the call back function failed to excute.
1910 **/
1911 EFI_STATUS
1912 ProcessCallBackFunction (
1913 IN OUT UI_MENU_SELECTION *Selection,
1914 IN FORM_BROWSER_FORMSET *FormSet,
1915 IN FORM_BROWSER_FORM *Form,
1916 IN FORM_BROWSER_STATEMENT *Question,
1917 IN EFI_BROWSER_ACTION Action,
1918 IN BOOLEAN SkipSaveOrDiscard
1919 )
1920 {
1921 EFI_STATUS Status;
1922 EFI_BROWSER_ACTION_REQUEST ActionRequest;
1923 EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess;
1924 EFI_HII_VALUE *HiiValue;
1925 EFI_IFR_TYPE_VALUE *TypeValue;
1926 FORM_BROWSER_STATEMENT *Statement;
1927 BOOLEAN SubmitFormIsRequired;
1928 BOOLEAN DiscardFormIsRequired;
1929 BOOLEAN NeedExit;
1930 LIST_ENTRY *Link;
1931 BROWSER_SETTING_SCOPE SettingLevel;
1932 EFI_IFR_TYPE_VALUE BackUpValue;
1933 UINT8 *BackUpBuffer;
1934 CHAR16 *NewString;
1935
1936 ConfigAccess = FormSet->ConfigAccess;
1937 SubmitFormIsRequired = FALSE;
1938 SettingLevel = FormSetLevel;
1939 DiscardFormIsRequired = FALSE;
1940 NeedExit = FALSE;
1941 Status = EFI_SUCCESS;
1942 ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;
1943 BackUpBuffer = NULL;
1944
1945 if (ConfigAccess == NULL) {
1946 return EFI_SUCCESS;
1947 }
1948
1949 Link = GetFirstNode (&Form->StatementListHead);
1950 while (!IsNull (&Form->StatementListHead, Link)) {
1951 Statement = FORM_BROWSER_STATEMENT_FROM_LINK (Link);
1952 Link = GetNextNode (&Form->StatementListHead, Link);
1953
1954 //
1955 // if Question != NULL, only process the question. Else, process all question in this form.
1956 //
1957 if ((Question != NULL) && (Statement != Question)) {
1958 continue;
1959 }
1960
1961 if ((Statement->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != EFI_IFR_FLAG_CALLBACK) {
1962 continue;
1963 }
1964
1965 //
1966 // Check whether Statement is disabled.
1967 //
1968 if (Statement->Expression != NULL) {
1969 if (EvaluateExpressionList(Statement->Expression, TRUE, FormSet, Form) == ExpressDisable) {
1970 continue;
1971 }
1972 }
1973
1974 HiiValue = &Statement->HiiValue;
1975 TypeValue = &HiiValue->Value;
1976 if (HiiValue->Type == EFI_IFR_TYPE_BUFFER) {
1977 //
1978 // For OrderedList, passing in the value buffer to Callback()
1979 //
1980 TypeValue = (EFI_IFR_TYPE_VALUE *) Statement->BufferValue;
1981 }
1982
1983 //
1984 // If EFI_BROWSER_ACTION_CHANGING type, back up the new question value.
1985 //
1986 if (Action == EFI_BROWSER_ACTION_CHANGING) {
1987 if (HiiValue->Type == EFI_IFR_TYPE_BUFFER) {
1988 BackUpBuffer = AllocateCopyPool(Statement->StorageWidth + sizeof(CHAR16), Statement->BufferValue);
1989 ASSERT (BackUpBuffer != NULL);
1990 } else {
1991 CopyMem (&BackUpValue, &HiiValue->Value, sizeof (EFI_IFR_TYPE_VALUE));
1992 }
1993 }
1994
1995 ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;
1996 Status = ConfigAccess->Callback (
1997 ConfigAccess,
1998 Action,
1999 Statement->QuestionId,
2000 HiiValue->Type,
2001 TypeValue,
2002 &ActionRequest
2003 );
2004 if (!EFI_ERROR (Status)) {
2005 //
2006 // Need to sync the value between Statement->HiiValue->Value and Statement->BufferValue
2007 //
2008 if (HiiValue->Type == EFI_IFR_TYPE_STRING) {
2009 NewString = GetToken (Statement->HiiValue.Value.string, FormSet->HiiHandle);
2010 ASSERT (NewString != NULL);
2011
2012 ASSERT (StrLen (NewString) * sizeof (CHAR16) <= Statement->StorageWidth);
2013 if (StrLen (NewString) * sizeof (CHAR16) <= Statement->StorageWidth) {
2014 CopyMem (Statement->BufferValue, NewString, StrSize (NewString));
2015 } else {
2016 CopyMem (Statement->BufferValue, NewString, Statement->StorageWidth);
2017 }
2018 FreePool (NewString);
2019 }
2020
2021 //
2022 // Only for EFI_BROWSER_ACTION_CHANGED need to handle this ActionRequest.
2023 //
2024 switch (Action) {
2025 case EFI_BROWSER_ACTION_CHANGED:
2026 switch (ActionRequest) {
2027 case EFI_BROWSER_ACTION_REQUEST_RESET:
2028 DiscardFormIsRequired = TRUE;
2029 gResetRequired = TRUE;
2030 NeedExit = TRUE;
2031 break;
2032
2033 case EFI_BROWSER_ACTION_REQUEST_SUBMIT:
2034 SubmitFormIsRequired = TRUE;
2035 NeedExit = TRUE;
2036 break;
2037
2038 case EFI_BROWSER_ACTION_REQUEST_EXIT:
2039 DiscardFormIsRequired = TRUE;
2040 NeedExit = TRUE;
2041 break;
2042
2043 case EFI_BROWSER_ACTION_REQUEST_FORM_SUBMIT_EXIT:
2044 SubmitFormIsRequired = TRUE;
2045 SettingLevel = FormLevel;
2046 NeedExit = TRUE;
2047 break;
2048
2049 case EFI_BROWSER_ACTION_REQUEST_FORM_DISCARD_EXIT:
2050 DiscardFormIsRequired = TRUE;
2051 SettingLevel = FormLevel;
2052 NeedExit = TRUE;
2053 break;
2054
2055 case EFI_BROWSER_ACTION_REQUEST_FORM_APPLY:
2056 SubmitFormIsRequired = TRUE;
2057 SettingLevel = FormLevel;
2058 break;
2059
2060 case EFI_BROWSER_ACTION_REQUEST_FORM_DISCARD:
2061 DiscardFormIsRequired = TRUE;
2062 SettingLevel = FormLevel;
2063 break;
2064
2065 default:
2066 break;
2067 }
2068 break;
2069
2070 case EFI_BROWSER_ACTION_CHANGING:
2071 //
2072 // Do the question validation.
2073 //
2074 Status = ValueChangedValidation (gCurrentSelection->FormSet, gCurrentSelection->Form, Statement);
2075 if (!EFI_ERROR (Status)) {
2076 //
2077 // According the spec, return value from call back of "changing" and
2078 // "retrieve" should update to the question's temp buffer.
2079 //
2080 SetQuestionValue(FormSet, Form, Statement, GetSetValueWithEditBuffer);
2081 }
2082 break;
2083
2084 case EFI_BROWSER_ACTION_RETRIEVE:
2085 //
2086 // According the spec, return value from call back of "changing" and
2087 // "retrieve" should update to the question's temp buffer.
2088 //
2089 SetQuestionValue(FormSet, Form, Statement, GetSetValueWithEditBuffer);
2090 break;
2091
2092 default:
2093 break;
2094 }
2095 } else {
2096 //
2097 // If the callback returns EFI_UNSUPPORTED for EFI_BROWSER_ACTION_CHANGING,
2098 // then the browser will use the value passed to Callback() and ignore the
2099 // value returned by Callback().
2100 //
2101 if (Action == EFI_BROWSER_ACTION_CHANGING && Status == EFI_UNSUPPORTED) {
2102 if (HiiValue->Type == EFI_IFR_TYPE_BUFFER) {
2103 CopyMem (Statement->BufferValue, BackUpBuffer, Statement->StorageWidth + sizeof(CHAR16));
2104 } else {
2105 CopyMem (&HiiValue->Value, &BackUpValue, sizeof (EFI_IFR_TYPE_VALUE));
2106 }
2107
2108 //
2109 // Do the question validation.
2110 //
2111 Status = ValueChangedValidation (gCurrentSelection->FormSet, gCurrentSelection->Form, Statement);
2112 if (!EFI_ERROR (Status)) {
2113 SetQuestionValue(FormSet, Form, Statement, GetSetValueWithEditBuffer);
2114 }
2115 }
2116
2117 //
2118 // According the spec, return fail from call back of "changing" and
2119 // "retrieve", should restore the question's value.
2120 //
2121 if ((Action == EFI_BROWSER_ACTION_CHANGING && Status != EFI_UNSUPPORTED) ||
2122 Action == EFI_BROWSER_ACTION_RETRIEVE) {
2123 GetQuestionValue(FormSet, Form, Statement, GetSetValueWithEditBuffer);
2124 }
2125
2126 if (Status == EFI_UNSUPPORTED) {
2127 //
2128 // If return EFI_UNSUPPORTED, also consider Hii driver suceess deal with it.
2129 //
2130 Status = EFI_SUCCESS;
2131 }
2132 }
2133
2134 if (BackUpBuffer != NULL) {
2135 FreePool (BackUpBuffer);
2136 }
2137 }
2138
2139 if (SubmitFormIsRequired && !SkipSaveOrDiscard) {
2140 SubmitForm (FormSet, Form, SettingLevel);
2141 }
2142
2143 if (DiscardFormIsRequired && !SkipSaveOrDiscard) {
2144 DiscardForm (FormSet, Form, SettingLevel);
2145 }
2146
2147 if (NeedExit) {
2148 FindNextMenu (Selection, SettingLevel);
2149 }
2150
2151 return Status;
2152 }
2153
2154 /**
2155 Call the retrieve type call back function for one question to get the initialize data.
2156
2157 This function only used when in the initialize stage, because in this stage, the
2158 Selection->Form is not ready. For other case, use the ProcessCallBackFunction instead.
2159
2160 @param ConfigAccess The config access protocol produced by the hii driver.
2161 @param Statement The Question which need to call.
2162 @param FormSet The formset this question belong to.
2163
2164 @retval EFI_SUCCESS The call back function excutes successfully.
2165 @return Other value if the call back function failed to excute.
2166 **/
2167 EFI_STATUS
2168 ProcessRetrieveForQuestion (
2169 IN EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess,
2170 IN FORM_BROWSER_STATEMENT *Statement,
2171 IN FORM_BROWSER_FORMSET *FormSet
2172 )
2173 {
2174 EFI_STATUS Status;
2175 EFI_BROWSER_ACTION_REQUEST ActionRequest;
2176 EFI_HII_VALUE *HiiValue;
2177 EFI_IFR_TYPE_VALUE *TypeValue;
2178 CHAR16 *NewString;
2179
2180 Status = EFI_SUCCESS;
2181 ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;
2182
2183 if (((Statement->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != EFI_IFR_FLAG_CALLBACK) || ConfigAccess == NULL) {
2184 return EFI_UNSUPPORTED;
2185 }
2186
2187 HiiValue = &Statement->HiiValue;
2188 TypeValue = &HiiValue->Value;
2189 if (HiiValue->Type == EFI_IFR_TYPE_BUFFER) {
2190 //
2191 // For OrderedList, passing in the value buffer to Callback()
2192 //
2193 TypeValue = (EFI_IFR_TYPE_VALUE *) Statement->BufferValue;
2194 }
2195
2196 ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;
2197 Status = ConfigAccess->Callback (
2198 ConfigAccess,
2199 EFI_BROWSER_ACTION_RETRIEVE,
2200 Statement->QuestionId,
2201 HiiValue->Type,
2202 TypeValue,
2203 &ActionRequest
2204 );
2205 if (!EFI_ERROR (Status) && HiiValue->Type == EFI_IFR_TYPE_STRING) {
2206 NewString = GetToken (Statement->HiiValue.Value.string, FormSet->HiiHandle);
2207 ASSERT (NewString != NULL);
2208
2209 ASSERT (StrLen (NewString) * sizeof (CHAR16) <= Statement->StorageWidth);
2210 if (StrLen (NewString) * sizeof (CHAR16) <= Statement->StorageWidth) {
2211 CopyMem (Statement->BufferValue, NewString, StrSize (NewString));
2212 } else {
2213 CopyMem (Statement->BufferValue, NewString, Statement->StorageWidth);
2214 }
2215 FreePool (NewString);
2216 }
2217
2218 return Status;
2219 }
2220
2221 /**
2222 The worker function that send the displays to the screen. On output,
2223 the selection made by user is returned.
2224
2225 @param Selection On input, Selection tell setup browser the information
2226 about the Selection, form and formset to be displayed.
2227 On output, Selection return the screen item that is selected
2228 by user.
2229
2230 @retval EFI_SUCCESS The page is displayed successfully.
2231 @return Other value if the page failed to be diplayed.
2232
2233 **/
2234 EFI_STATUS
2235 SetupBrowser (
2236 IN OUT UI_MENU_SELECTION *Selection
2237 )
2238 {
2239 EFI_STATUS Status;
2240 LIST_ENTRY *Link;
2241 EFI_HANDLE NotifyHandle;
2242 FORM_BROWSER_STATEMENT *Statement;
2243 EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess;
2244
2245 ConfigAccess = Selection->FormSet->ConfigAccess;
2246
2247 //
2248 // Register notify for Form package update
2249 //
2250 Status = mHiiDatabase->RegisterPackageNotify (
2251 mHiiDatabase,
2252 EFI_HII_PACKAGE_FORMS,
2253 NULL,
2254 FormUpdateNotify,
2255 EFI_HII_DATABASE_NOTIFY_REMOVE_PACK,
2256 &NotifyHandle
2257 );
2258 if (EFI_ERROR (Status)) {
2259 return Status;
2260 }
2261
2262 //
2263 // Initialize current settings of Questions in this FormSet
2264 //
2265 InitializeCurrentSetting (Selection->FormSet);
2266
2267 //
2268 // Initilize Action field.
2269 //
2270 Selection->Action = UI_ACTION_REFRESH_FORM;
2271
2272 //
2273 // Clean the mCurFakeQestId value is formset refreshed.
2274 //
2275 mCurFakeQestId = 0;
2276
2277 do {
2278 //
2279 // IFR is updated, force to reparse the IFR binary
2280 //
2281 if (mHiiPackageListUpdated) {
2282 Selection->Action = UI_ACTION_REFRESH_FORMSET;
2283 mHiiPackageListUpdated = FALSE;
2284 break;
2285 }
2286
2287 //
2288 // Initialize Selection->Form
2289 //
2290 if (Selection->FormId == 0) {
2291 //
2292 // Zero FormId indicates display the first Form in a FormSet
2293 //
2294 Link = GetFirstNode (&Selection->FormSet->FormListHead);
2295
2296 Selection->Form = FORM_BROWSER_FORM_FROM_LINK (Link);
2297 Selection->FormId = Selection->Form->FormId;
2298 } else {
2299 Selection->Form = IdToForm (Selection->FormSet, Selection->FormId);
2300 }
2301
2302 if (Selection->Form == NULL) {
2303 //
2304 // No Form to display
2305 //
2306 Status = EFI_NOT_FOUND;
2307 goto Done;
2308 }
2309
2310 //
2311 // Check Form is suppressed.
2312 //
2313 if (Selection->Form->SuppressExpression != NULL) {
2314 if (EvaluateExpressionList(Selection->Form->SuppressExpression, TRUE, Selection->FormSet, Selection->Form) == ExpressSuppress) {
2315 //
2316 // Form is suppressed.
2317 //
2318 PopupErrorMessage(BROWSER_FORM_SUPPRESS, NULL, NULL, NULL);
2319 Status = EFI_NOT_FOUND;
2320 goto Done;
2321 }
2322 }
2323
2324 //
2325 // Before display new form, invoke ConfigAccess.Callback() with EFI_BROWSER_ACTION_FORM_OPEN
2326 // for each question with callback flag.
2327 // New form may be the first form, or the different form after another form close.
2328 //
2329 if (((Selection->Handle != mCurrentHiiHandle) ||
2330 (!CompareGuid (&Selection->FormSetGuid, &mCurrentFormSetGuid)) ||
2331 (Selection->FormId != mCurrentFormId))) {
2332 //
2333 // Update Retrieve flag.
2334 //
2335 mFinishRetrieveCall = FALSE;
2336
2337 //
2338 // Keep current form information
2339 //
2340 mCurrentHiiHandle = Selection->Handle;
2341 CopyGuid (&mCurrentFormSetGuid, &Selection->FormSetGuid);
2342 mCurrentFormId = Selection->FormId;
2343
2344 if (ConfigAccess != NULL) {
2345 Status = ProcessCallBackFunction (Selection, Selection->FormSet, Selection->Form, NULL, EFI_BROWSER_ACTION_FORM_OPEN, FALSE);
2346 if (EFI_ERROR (Status)) {
2347 goto Done;
2348 }
2349
2350 //
2351 // IFR is updated during callback of open form, force to reparse the IFR binary
2352 //
2353 if (mHiiPackageListUpdated) {
2354 Selection->Action = UI_ACTION_REFRESH_FORMSET;
2355 mHiiPackageListUpdated = FALSE;
2356 break;
2357 }
2358 }
2359 }
2360
2361 //
2362 // Load Questions' Value for display
2363 //
2364 Status = LoadFormSetConfig (Selection, Selection->FormSet);
2365 if (EFI_ERROR (Status)) {
2366 goto Done;
2367 }
2368
2369 if (!mFinishRetrieveCall) {
2370 //
2371 // Finish call RETRIEVE callback for this form.
2372 //
2373 mFinishRetrieveCall = TRUE;
2374
2375 if (ConfigAccess != NULL) {
2376 Status = ProcessCallBackFunction (Selection, Selection->FormSet, Selection->Form, NULL, EFI_BROWSER_ACTION_RETRIEVE, FALSE);
2377 if (EFI_ERROR (Status)) {
2378 goto Done;
2379 }
2380
2381 //
2382 // IFR is updated during callback of open form, force to reparse the IFR binary
2383 //
2384 if (mHiiPackageListUpdated) {
2385 Selection->Action = UI_ACTION_REFRESH_FORMSET;
2386 mHiiPackageListUpdated = FALSE;
2387 break;
2388 }
2389 }
2390 }
2391
2392 //
2393 // Display form
2394 //
2395 Status = DisplayForm ();
2396 if (EFI_ERROR (Status)) {
2397 goto Done;
2398 }
2399
2400 //
2401 // Check Selected Statement (if press ESC, Selection->Statement will be NULL)
2402 //
2403 Statement = Selection->Statement;
2404 if (Statement != NULL) {
2405 if ((ConfigAccess != NULL) &&
2406 ((Statement->QuestionFlags & EFI_IFR_FLAG_CALLBACK) == EFI_IFR_FLAG_CALLBACK) &&
2407 (Statement->Operand != EFI_IFR_PASSWORD_OP)) {
2408 Status = ProcessCallBackFunction(Selection, Selection->FormSet, Selection->Form, Statement, EFI_BROWSER_ACTION_CHANGING, FALSE);
2409 if (Statement->Operand == EFI_IFR_REF_OP) {
2410 //
2411 // Process dynamic update ref opcode.
2412 //
2413 if (!EFI_ERROR (Status)) {
2414 Status = ProcessGotoOpCode(Statement, Selection);
2415 }
2416
2417 //
2418 // Callback return error status or status return from process goto opcode.
2419 //
2420 if (EFI_ERROR (Status)) {
2421 //
2422 // Cross reference will not be taken
2423 //
2424 Selection->FormId = Selection->Form->FormId;
2425 Selection->QuestionId = 0;
2426 }
2427 }
2428
2429 //
2430 // Verify whether question value has checked, update the ValueChanged flag in Question.
2431 //
2432 IsQuestionValueChanged(gCurrentSelection->FormSet, gCurrentSelection->Form, Statement, GetSetValueWithBuffer);
2433
2434 if (!EFI_ERROR (Status) && Statement->Operand != EFI_IFR_REF_OP) {
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 }