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