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