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