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