]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/SetupBrowserDxe/Presentation.c
002a86a9b5ddc10d1be95329b22f3a3cf30ffcb8
[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 Reconnect the controller.
1889
1890 @param DriverHandle The controller handle which need to be reconnect.
1891
1892 @retval TRUE do the reconnect behavior success.
1893 @retval FALSE do the reconnect behavior failed.
1894
1895 **/
1896 BOOLEAN
1897 ReconnectController (
1898 IN EFI_HANDLE DriverHandle
1899 )
1900 {
1901 EFI_STATUS Status;
1902
1903 Status = gBS->DisconnectController(DriverHandle, NULL, NULL);
1904 if (!EFI_ERROR (Status)) {
1905 Status = gBS->ConnectController(DriverHandle, NULL, NULL, TRUE);
1906 }
1907
1908 return Status == EFI_SUCCESS;
1909 }
1910
1911 /**
1912 Call the call back function for the question and process the return action.
1913
1914 @param Selection On input, Selection tell setup browser the information
1915 about the Selection, form and formset to be displayed.
1916 On output, Selection return the screen item that is selected
1917 by user.
1918 @param FormSet The formset this question belong to.
1919 @param Form The form this question belong to.
1920 @param Question The Question which need to call.
1921 @param Action The action request.
1922 @param SkipSaveOrDiscard Whether skip save or discard action.
1923
1924 @retval EFI_SUCCESS The call back function excutes successfully.
1925 @return Other value if the call back function failed to excute.
1926 **/
1927 EFI_STATUS
1928 ProcessCallBackFunction (
1929 IN OUT UI_MENU_SELECTION *Selection,
1930 IN FORM_BROWSER_FORMSET *FormSet,
1931 IN FORM_BROWSER_FORM *Form,
1932 IN FORM_BROWSER_STATEMENT *Question,
1933 IN EFI_BROWSER_ACTION Action,
1934 IN BOOLEAN SkipSaveOrDiscard
1935 )
1936 {
1937 EFI_STATUS Status;
1938 EFI_STATUS InternalStatus;
1939 EFI_BROWSER_ACTION_REQUEST ActionRequest;
1940 EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess;
1941 EFI_HII_VALUE *HiiValue;
1942 EFI_IFR_TYPE_VALUE *TypeValue;
1943 FORM_BROWSER_STATEMENT *Statement;
1944 BOOLEAN SubmitFormIsRequired;
1945 BOOLEAN DiscardFormIsRequired;
1946 BOOLEAN NeedExit;
1947 LIST_ENTRY *Link;
1948 BROWSER_SETTING_SCOPE SettingLevel;
1949 EFI_IFR_TYPE_VALUE BackUpValue;
1950 UINT8 *BackUpBuffer;
1951 CHAR16 *NewString;
1952
1953 ConfigAccess = FormSet->ConfigAccess;
1954 SubmitFormIsRequired = FALSE;
1955 SettingLevel = FormSetLevel;
1956 DiscardFormIsRequired = FALSE;
1957 NeedExit = FALSE;
1958 Status = EFI_SUCCESS;
1959 ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;
1960 BackUpBuffer = NULL;
1961
1962 if (ConfigAccess == NULL) {
1963 return EFI_SUCCESS;
1964 }
1965
1966 Link = GetFirstNode (&Form->StatementListHead);
1967 while (!IsNull (&Form->StatementListHead, Link)) {
1968 Statement = FORM_BROWSER_STATEMENT_FROM_LINK (Link);
1969 Link = GetNextNode (&Form->StatementListHead, Link);
1970
1971 //
1972 // if Question != NULL, only process the question. Else, process all question in this form.
1973 //
1974 if ((Question != NULL) && (Statement != Question)) {
1975 continue;
1976 }
1977
1978 if ((Statement->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != EFI_IFR_FLAG_CALLBACK) {
1979 continue;
1980 }
1981
1982 //
1983 // Check whether Statement is disabled.
1984 //
1985 if (Statement->Expression != NULL) {
1986 if (EvaluateExpressionList(Statement->Expression, TRUE, FormSet, Form) == ExpressDisable) {
1987 continue;
1988 }
1989 }
1990
1991 HiiValue = &Statement->HiiValue;
1992 TypeValue = &HiiValue->Value;
1993 if (HiiValue->Type == EFI_IFR_TYPE_BUFFER) {
1994 //
1995 // For OrderedList, passing in the value buffer to Callback()
1996 //
1997 TypeValue = (EFI_IFR_TYPE_VALUE *) Statement->BufferValue;
1998 }
1999
2000 //
2001 // If EFI_BROWSER_ACTION_CHANGING type, back up the new question value.
2002 //
2003 if (Action == EFI_BROWSER_ACTION_CHANGING) {
2004 if (HiiValue->Type == EFI_IFR_TYPE_BUFFER) {
2005 BackUpBuffer = AllocateCopyPool(Statement->StorageWidth + sizeof(CHAR16), Statement->BufferValue);
2006 ASSERT (BackUpBuffer != NULL);
2007 } else {
2008 CopyMem (&BackUpValue, &HiiValue->Value, sizeof (EFI_IFR_TYPE_VALUE));
2009 }
2010 }
2011
2012 ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;
2013 Status = ConfigAccess->Callback (
2014 ConfigAccess,
2015 Action,
2016 Statement->QuestionId,
2017 HiiValue->Type,
2018 TypeValue,
2019 &ActionRequest
2020 );
2021 if (!EFI_ERROR (Status)) {
2022 //
2023 // Need to sync the value between Statement->HiiValue->Value and Statement->BufferValue
2024 //
2025 if (HiiValue->Type == EFI_IFR_TYPE_STRING) {
2026 NewString = GetToken (Statement->HiiValue.Value.string, FormSet->HiiHandle);
2027 ASSERT (NewString != NULL);
2028
2029 ASSERT (StrLen (NewString) * sizeof (CHAR16) <= Statement->StorageWidth);
2030 if (StrLen (NewString) * sizeof (CHAR16) <= Statement->StorageWidth) {
2031 CopyMem (Statement->BufferValue, NewString, StrSize (NewString));
2032 } else {
2033 CopyMem (Statement->BufferValue, NewString, Statement->StorageWidth);
2034 }
2035 FreePool (NewString);
2036 }
2037
2038 //
2039 // Only for EFI_BROWSER_ACTION_CHANGED need to handle this ActionRequest.
2040 //
2041 switch (Action) {
2042 case EFI_BROWSER_ACTION_CHANGED:
2043 switch (ActionRequest) {
2044 case EFI_BROWSER_ACTION_REQUEST_RESET:
2045 DiscardFormIsRequired = TRUE;
2046 gResetRequired = TRUE;
2047 NeedExit = TRUE;
2048 break;
2049
2050 case EFI_BROWSER_ACTION_REQUEST_SUBMIT:
2051 SubmitFormIsRequired = TRUE;
2052 NeedExit = TRUE;
2053 break;
2054
2055 case EFI_BROWSER_ACTION_REQUEST_EXIT:
2056 DiscardFormIsRequired = TRUE;
2057 NeedExit = TRUE;
2058 break;
2059
2060 case EFI_BROWSER_ACTION_REQUEST_FORM_SUBMIT_EXIT:
2061 SubmitFormIsRequired = TRUE;
2062 SettingLevel = FormLevel;
2063 NeedExit = TRUE;
2064 break;
2065
2066 case EFI_BROWSER_ACTION_REQUEST_FORM_DISCARD_EXIT:
2067 DiscardFormIsRequired = TRUE;
2068 SettingLevel = FormLevel;
2069 NeedExit = TRUE;
2070 break;
2071
2072 case EFI_BROWSER_ACTION_REQUEST_FORM_APPLY:
2073 SubmitFormIsRequired = TRUE;
2074 SettingLevel = FormLevel;
2075 break;
2076
2077 case EFI_BROWSER_ACTION_REQUEST_FORM_DISCARD:
2078 DiscardFormIsRequired = TRUE;
2079 SettingLevel = FormLevel;
2080 break;
2081
2082 case EFI_BROWSER_ACTION_REQUEST_RECONNECT:
2083 gCallbackReconnect = TRUE;
2084 break;
2085
2086 default:
2087 break;
2088 }
2089 break;
2090
2091 case EFI_BROWSER_ACTION_CHANGING:
2092 //
2093 // Do the question validation.
2094 //
2095 Status = ValueChangedValidation (gCurrentSelection->FormSet, gCurrentSelection->Form, Statement);
2096 if (!EFI_ERROR (Status)) {
2097 //
2098 //check whether the question value changed compared with edit buffer before updating edit buffer
2099 // if changed, set the ValueChanged flag to TRUE,in order to trig the CHANGED callback function
2100 //
2101 IsQuestionValueChanged(gCurrentSelection->FormSet, gCurrentSelection->Form, Statement, GetSetValueWithEditBuffer);
2102 //
2103 // According the spec, return value from call back of "changing" and
2104 // "retrieve" should update to the question's temp buffer.
2105 //
2106 SetQuestionValue(FormSet, Form, Statement, GetSetValueWithEditBuffer);
2107 }
2108 break;
2109
2110 case EFI_BROWSER_ACTION_RETRIEVE:
2111 //
2112 // According the spec, return value from call back of "changing" and
2113 // "retrieve" should update to the question's temp buffer.
2114 //
2115 SetQuestionValue(FormSet, Form, Statement, GetSetValueWithEditBuffer);
2116 break;
2117
2118 default:
2119 break;
2120 }
2121 } else {
2122 //
2123 // If the callback returns EFI_UNSUPPORTED for EFI_BROWSER_ACTION_CHANGING,
2124 // then the browser will use the value passed to Callback() and ignore the
2125 // value returned by Callback().
2126 //
2127 if (Action == EFI_BROWSER_ACTION_CHANGING && Status == EFI_UNSUPPORTED) {
2128 if (HiiValue->Type == EFI_IFR_TYPE_BUFFER) {
2129 CopyMem (Statement->BufferValue, BackUpBuffer, Statement->StorageWidth + sizeof(CHAR16));
2130 } else {
2131 CopyMem (&HiiValue->Value, &BackUpValue, sizeof (EFI_IFR_TYPE_VALUE));
2132 }
2133
2134 //
2135 // Do the question validation.
2136 //
2137 InternalStatus = ValueChangedValidation (gCurrentSelection->FormSet, gCurrentSelection->Form, Statement);
2138 if (!EFI_ERROR (InternalStatus)) {
2139 //
2140 //check whether the question value changed compared with edit buffer before updating edit buffer
2141 // if changed, set the ValueChanged flag to TRUE,in order to trig the CHANGED callback function
2142 //
2143 IsQuestionValueChanged(gCurrentSelection->FormSet, gCurrentSelection->Form, Statement, GetSetValueWithEditBuffer);
2144 SetQuestionValue(FormSet, Form, Statement, GetSetValueWithEditBuffer);
2145 }
2146 }
2147
2148 //
2149 // According the spec, return fail from call back of "changing" and
2150 // "retrieve", should restore the question's value.
2151 //
2152 if (Action == EFI_BROWSER_ACTION_CHANGING && Status != EFI_UNSUPPORTED) {
2153 if (Statement->Storage != NULL) {
2154 GetQuestionValue(FormSet, Form, Statement, GetSetValueWithEditBuffer);
2155 } else if ((Statement->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) {
2156 ProcessCallBackFunction (Selection, FormSet, Form, Question, EFI_BROWSER_ACTION_RETRIEVE, FALSE);
2157 }
2158 }
2159
2160 if (Action == EFI_BROWSER_ACTION_RETRIEVE) {
2161 GetQuestionValue(FormSet, Form, Statement, GetSetValueWithEditBuffer);
2162 }
2163
2164 if (Status == EFI_UNSUPPORTED) {
2165 //
2166 // If return EFI_UNSUPPORTED, also consider Hii driver suceess deal with it.
2167 //
2168 Status = EFI_SUCCESS;
2169 }
2170 }
2171
2172 if (BackUpBuffer != NULL) {
2173 FreePool (BackUpBuffer);
2174 }
2175
2176 //
2177 // If Question != NULL, means just process one question
2178 // and if code reach here means this question has finished
2179 // processing, so just break.
2180 //
2181 if (Question != NULL) {
2182 break;
2183 }
2184 }
2185
2186 if (gCallbackReconnect && (EFI_BROWSER_ACTION_CHANGED == Action)) {
2187 //
2188 // Confirm changes with user first.
2189 //
2190 if (IsNvUpdateRequiredForFormSet(FormSet)) {
2191 if (BROWSER_ACTION_DISCARD == PopupErrorMessage(BROWSER_RECONNECT_SAVE_CHANGES, NULL, NULL, NULL)) {
2192 gCallbackReconnect = FALSE;
2193 DiscardFormIsRequired = TRUE;
2194 } else {
2195 SubmitFormIsRequired = TRUE;
2196 }
2197 } else {
2198 PopupErrorMessage(BROWSER_RECONNECT_REQUIRED, NULL, NULL, NULL);
2199 }
2200
2201 //
2202 // Exit current formset before do the reconnect.
2203 //
2204 NeedExit = TRUE;
2205 SettingLevel = FormSetLevel;
2206 }
2207
2208 if (SubmitFormIsRequired && !SkipSaveOrDiscard) {
2209 SubmitForm (FormSet, Form, SettingLevel);
2210 }
2211
2212 if (DiscardFormIsRequired && !SkipSaveOrDiscard) {
2213 DiscardForm (FormSet, Form, SettingLevel);
2214 }
2215
2216 if (NeedExit) {
2217 FindNextMenu (Selection, SettingLevel);
2218 }
2219
2220 return Status;
2221 }
2222
2223 /**
2224 Call the retrieve type call back function for one question to get the initialize data.
2225
2226 This function only used when in the initialize stage, because in this stage, the
2227 Selection->Form is not ready. For other case, use the ProcessCallBackFunction instead.
2228
2229 @param ConfigAccess The config access protocol produced by the hii driver.
2230 @param Statement The Question which need to call.
2231 @param FormSet The formset this question belong to.
2232
2233 @retval EFI_SUCCESS The call back function excutes successfully.
2234 @return Other value if the call back function failed to excute.
2235 **/
2236 EFI_STATUS
2237 ProcessRetrieveForQuestion (
2238 IN EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess,
2239 IN FORM_BROWSER_STATEMENT *Statement,
2240 IN FORM_BROWSER_FORMSET *FormSet
2241 )
2242 {
2243 EFI_STATUS Status;
2244 EFI_BROWSER_ACTION_REQUEST ActionRequest;
2245 EFI_HII_VALUE *HiiValue;
2246 EFI_IFR_TYPE_VALUE *TypeValue;
2247 CHAR16 *NewString;
2248
2249 Status = EFI_SUCCESS;
2250 ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;
2251
2252 if (((Statement->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != EFI_IFR_FLAG_CALLBACK) || ConfigAccess == NULL) {
2253 return EFI_UNSUPPORTED;
2254 }
2255
2256 HiiValue = &Statement->HiiValue;
2257 TypeValue = &HiiValue->Value;
2258 if (HiiValue->Type == EFI_IFR_TYPE_BUFFER) {
2259 //
2260 // For OrderedList, passing in the value buffer to Callback()
2261 //
2262 TypeValue = (EFI_IFR_TYPE_VALUE *) Statement->BufferValue;
2263 }
2264
2265 ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;
2266 Status = ConfigAccess->Callback (
2267 ConfigAccess,
2268 EFI_BROWSER_ACTION_RETRIEVE,
2269 Statement->QuestionId,
2270 HiiValue->Type,
2271 TypeValue,
2272 &ActionRequest
2273 );
2274 if (!EFI_ERROR (Status) && HiiValue->Type == EFI_IFR_TYPE_STRING) {
2275 NewString = GetToken (Statement->HiiValue.Value.string, FormSet->HiiHandle);
2276 ASSERT (NewString != NULL);
2277
2278 ASSERT (StrLen (NewString) * sizeof (CHAR16) <= Statement->StorageWidth);
2279 if (StrLen (NewString) * sizeof (CHAR16) <= Statement->StorageWidth) {
2280 CopyMem (Statement->BufferValue, NewString, StrSize (NewString));
2281 } else {
2282 CopyMem (Statement->BufferValue, NewString, Statement->StorageWidth);
2283 }
2284 FreePool (NewString);
2285 }
2286
2287 return Status;
2288 }
2289
2290 /**
2291 The worker function that send the displays to the screen. On output,
2292 the selection made by user is returned.
2293
2294 @param Selection On input, Selection tell setup browser the information
2295 about the Selection, form and formset to be displayed.
2296 On output, Selection return the screen item that is selected
2297 by user.
2298
2299 @retval EFI_SUCCESS The page is displayed successfully.
2300 @return Other value if the page failed to be diplayed.
2301
2302 **/
2303 EFI_STATUS
2304 SetupBrowser (
2305 IN OUT UI_MENU_SELECTION *Selection
2306 )
2307 {
2308 EFI_STATUS Status;
2309 LIST_ENTRY *Link;
2310 EFI_HANDLE NotifyHandle;
2311 FORM_BROWSER_STATEMENT *Statement;
2312 EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess;
2313
2314 ConfigAccess = Selection->FormSet->ConfigAccess;
2315
2316 //
2317 // Register notify for Form package update
2318 //
2319 Status = mHiiDatabase->RegisterPackageNotify (
2320 mHiiDatabase,
2321 EFI_HII_PACKAGE_FORMS,
2322 NULL,
2323 FormUpdateNotify,
2324 EFI_HII_DATABASE_NOTIFY_REMOVE_PACK,
2325 &NotifyHandle
2326 );
2327 if (EFI_ERROR (Status)) {
2328 return Status;
2329 }
2330
2331 //
2332 // Initialize current settings of Questions in this FormSet
2333 //
2334 InitializeCurrentSetting (Selection->FormSet);
2335
2336 //
2337 // Initilize Action field.
2338 //
2339 Selection->Action = UI_ACTION_REFRESH_FORM;
2340
2341 //
2342 // Clean the mCurFakeQestId value is formset refreshed.
2343 //
2344 mCurFakeQestId = 0;
2345
2346 do {
2347 //
2348 // IFR is updated, force to reparse the IFR binary
2349 // This check is shared by EFI_BROWSER_ACTION_FORM_CLOSE and
2350 // EFI_BROWSER_ACTION_RETRIEVE, so code place here.
2351 //
2352 if (mHiiPackageListUpdated) {
2353 Selection->Action = UI_ACTION_REFRESH_FORMSET;
2354 mHiiPackageListUpdated = FALSE;
2355 break;
2356 }
2357
2358 //
2359 // Initialize Selection->Form
2360 //
2361 if (Selection->FormId == 0) {
2362 //
2363 // Zero FormId indicates display the first Form in a FormSet
2364 //
2365 Link = GetFirstNode (&Selection->FormSet->FormListHead);
2366
2367 Selection->Form = FORM_BROWSER_FORM_FROM_LINK (Link);
2368 Selection->FormId = Selection->Form->FormId;
2369 } else {
2370 Selection->Form = IdToForm (Selection->FormSet, Selection->FormId);
2371 }
2372
2373 if (Selection->Form == NULL) {
2374 //
2375 // No Form to display
2376 //
2377 Status = EFI_NOT_FOUND;
2378 goto Done;
2379 }
2380
2381 //
2382 // Check Form is suppressed.
2383 //
2384 if (Selection->Form->SuppressExpression != NULL) {
2385 if (EvaluateExpressionList(Selection->Form->SuppressExpression, TRUE, Selection->FormSet, Selection->Form) == ExpressSuppress) {
2386 //
2387 // Form is suppressed.
2388 //
2389 PopupErrorMessage(BROWSER_FORM_SUPPRESS, NULL, NULL, NULL);
2390 Status = EFI_NOT_FOUND;
2391 goto Done;
2392 }
2393 }
2394
2395 //
2396 // Before display new form, invoke ConfigAccess.Callback() with EFI_BROWSER_ACTION_FORM_OPEN
2397 // for each question with callback flag.
2398 // New form may be the first form, or the different form after another form close.
2399 //
2400 if (((Selection->Handle != mCurrentHiiHandle) ||
2401 (!CompareGuid (&Selection->FormSetGuid, &mCurrentFormSetGuid)) ||
2402 (Selection->FormId != mCurrentFormId))) {
2403 //
2404 // Update Retrieve flag.
2405 //
2406 mFinishRetrieveCall = FALSE;
2407
2408 //
2409 // Keep current form information
2410 //
2411 mCurrentHiiHandle = Selection->Handle;
2412 CopyGuid (&mCurrentFormSetGuid, &Selection->FormSetGuid);
2413 mCurrentFormId = Selection->FormId;
2414
2415 if (ConfigAccess != NULL) {
2416 Status = ProcessCallBackFunction (Selection, Selection->FormSet, Selection->Form, NULL, EFI_BROWSER_ACTION_FORM_OPEN, FALSE);
2417 if (EFI_ERROR (Status)) {
2418 goto Done;
2419 }
2420
2421 //
2422 // IFR is updated during callback of EFI_BROWSER_ACTION_FORM_OPEN, force to reparse the IFR binary
2423 //
2424 if (mHiiPackageListUpdated) {
2425 Selection->Action = UI_ACTION_REFRESH_FORMSET;
2426 mHiiPackageListUpdated = FALSE;
2427 break;
2428 }
2429 }
2430 }
2431
2432 //
2433 // Load Questions' Value for display
2434 //
2435 Status = LoadFormSetConfig (Selection, Selection->FormSet);
2436 if (EFI_ERROR (Status)) {
2437 goto Done;
2438 }
2439
2440 if (!mFinishRetrieveCall) {
2441 //
2442 // Finish call RETRIEVE callback for this form.
2443 //
2444 mFinishRetrieveCall = TRUE;
2445
2446 if (ConfigAccess != NULL) {
2447 Status = ProcessCallBackFunction (Selection, Selection->FormSet, Selection->Form, NULL, EFI_BROWSER_ACTION_RETRIEVE, FALSE);
2448 if (EFI_ERROR (Status)) {
2449 goto Done;
2450 }
2451
2452 //
2453 // IFR is updated during callback of open form, force to reparse the IFR binary
2454 //
2455 if (mHiiPackageListUpdated) {
2456 Selection->Action = UI_ACTION_REFRESH_FORMSET;
2457 mHiiPackageListUpdated = FALSE;
2458 break;
2459 }
2460 }
2461 }
2462
2463 //
2464 // Display form
2465 //
2466 Status = DisplayForm ();
2467 if (EFI_ERROR (Status)) {
2468 goto Done;
2469 }
2470
2471 //
2472 // Check Selected Statement (if press ESC, Selection->Statement will be NULL)
2473 //
2474 Statement = Selection->Statement;
2475 if (Statement != NULL) {
2476 if ((ConfigAccess != NULL) &&
2477 ((Statement->QuestionFlags & EFI_IFR_FLAG_CALLBACK) == EFI_IFR_FLAG_CALLBACK) &&
2478 (Statement->Operand != EFI_IFR_PASSWORD_OP)) {
2479 Status = ProcessCallBackFunction(Selection, Selection->FormSet, Selection->Form, Statement, EFI_BROWSER_ACTION_CHANGING, FALSE);
2480 if (Statement->Operand == EFI_IFR_REF_OP) {
2481 //
2482 // Process dynamic update ref opcode.
2483 //
2484 if (!EFI_ERROR (Status)) {
2485 Status = ProcessGotoOpCode(Statement, Selection);
2486 }
2487
2488 //
2489 // Callback return error status or status return from process goto opcode.
2490 //
2491 if (EFI_ERROR (Status)) {
2492 //
2493 // Cross reference will not be taken
2494 //
2495 Selection->FormId = Selection->Form->FormId;
2496 Selection->QuestionId = 0;
2497 }
2498 }
2499
2500
2501 if (!EFI_ERROR (Status) &&
2502 (Statement->Operand != EFI_IFR_REF_OP) &&
2503 ((Statement->Storage == NULL) || (Statement->Storage != NULL && Statement->ValueChanged))) {
2504 //
2505 // Only question value has been changed, browser will trig CHANGED callback.
2506 //
2507 ProcessCallBackFunction(Selection, Selection->FormSet, Selection->Form, Statement, EFI_BROWSER_ACTION_CHANGED, FALSE);
2508 //
2509 //check whether the question value changed compared with buffer value
2510 //if doesn't change ,set the ValueChanged flag to FALSE ,in order not to display the "configuration changed "information on the screen
2511 //
2512 IsQuestionValueChanged(gCurrentSelection->FormSet, gCurrentSelection->Form, Statement, GetSetValueWithBuffer);
2513 }
2514 } else {
2515 //
2516 // Do the question validation.
2517 //
2518 Status = ValueChangedValidation (gCurrentSelection->FormSet, gCurrentSelection->Form, Statement);
2519 if (!EFI_ERROR (Status) && (Statement->Operand != EFI_IFR_PASSWORD_OP)) {
2520 SetQuestionValue (gCurrentSelection->FormSet, gCurrentSelection->Form, Statement, GetSetValueWithEditBuffer);
2521 //
2522 // Verify whether question value has checked, update the ValueChanged flag in Question.
2523 //
2524 IsQuestionValueChanged(gCurrentSelection->FormSet, gCurrentSelection->Form, Statement, GetSetValueWithBuffer);
2525 }
2526 }
2527
2528 //
2529 // If question has EFI_IFR_FLAG_RESET_REQUIRED/EFI_IFR_FLAG_RECONNECT_REQUIRED flag and without storage
2530 // and process question success till here, trig the gResetFlag/gFlagReconnect.
2531 //
2532 if ((Status == EFI_SUCCESS) &&
2533 (Statement->Storage == NULL)) {
2534 if ((Statement->QuestionFlags & EFI_IFR_FLAG_RESET_REQUIRED) != 0) {
2535 gResetRequired = TRUE;
2536 }
2537
2538 if ((Statement->QuestionFlags & EFI_IFR_FLAG_RECONNECT_REQUIRED) != 0) {
2539 gFlagReconnect = TRUE;
2540 }
2541 }
2542 }
2543
2544 //
2545 // Check whether Exit flag is TRUE.
2546 //
2547 if (gExitRequired) {
2548 switch (gBrowserSettingScope) {
2549 case SystemLevel:
2550 Selection->Action = UI_ACTION_EXIT;
2551 break;
2552
2553 case FormSetLevel:
2554 case FormLevel:
2555 FindNextMenu (Selection, gBrowserSettingScope);
2556 break;
2557
2558 default:
2559 break;
2560 }
2561
2562 gExitRequired = FALSE;
2563 }
2564
2565 //
2566 // Before exit the form, invoke ConfigAccess.Callback() with EFI_BROWSER_ACTION_FORM_CLOSE
2567 // for each question with callback flag.
2568 //
2569 if ((ConfigAccess != NULL) &&
2570 ((Selection->Action == UI_ACTION_EXIT) ||
2571 (Selection->Handle != mCurrentHiiHandle) ||
2572 (!CompareGuid (&Selection->FormSetGuid, &mCurrentFormSetGuid)) ||
2573 (Selection->FormId != mCurrentFormId))) {
2574
2575 Status = ProcessCallBackFunction (Selection, Selection->FormSet, Selection->Form, NULL, EFI_BROWSER_ACTION_FORM_CLOSE, FALSE);
2576 if (EFI_ERROR (Status)) {
2577 goto Done;
2578 }
2579 }
2580 } while (Selection->Action == UI_ACTION_REFRESH_FORM);
2581
2582 Done:
2583 //
2584 // Reset current form information to the initial setting when error happens or form exit.
2585 //
2586 if (EFI_ERROR (Status) || Selection->Action == UI_ACTION_EXIT) {
2587 mCurrentHiiHandle = NULL;
2588 CopyGuid (&mCurrentFormSetGuid, &gZeroGuid);
2589 mCurrentFormId = 0;
2590 }
2591
2592 //
2593 // Unregister notify for Form package update
2594 //
2595 mHiiDatabase->UnregisterPackageNotify (
2596 mHiiDatabase,
2597 NotifyHandle
2598 );
2599 return Status;
2600 }