]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/SetupBrowserDxe/Presentation.c
Sync value for string opcode after call the Callback 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 CHAR16 *NewString;
2096
2097 ConfigAccess = FormSet->ConfigAccess;
2098 SubmitFormIsRequired = FALSE;
2099 SettingLevel = FormSetLevel;
2100 DiscardFormIsRequired = FALSE;
2101 NeedExit = FALSE;
2102 Status = EFI_SUCCESS;
2103 ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;
2104 BackUpBuffer = NULL;
2105
2106 if (ConfigAccess == NULL) {
2107 return EFI_SUCCESS;
2108 }
2109
2110 Link = GetFirstNode (&Form->StatementListHead);
2111 while (!IsNull (&Form->StatementListHead, Link)) {
2112 Statement = FORM_BROWSER_STATEMENT_FROM_LINK (Link);
2113 Link = GetNextNode (&Form->StatementListHead, Link);
2114
2115 //
2116 // if Question != NULL, only process the question. Else, process all question in this form.
2117 //
2118 if ((Question != NULL) && (Statement != Question)) {
2119 continue;
2120 }
2121
2122 if ((Statement->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != EFI_IFR_FLAG_CALLBACK) {
2123 continue;
2124 }
2125
2126 //
2127 // Check whether Statement is disabled.
2128 //
2129 if (Statement->Expression != NULL) {
2130 if (EvaluateExpressionList(Statement->Expression, TRUE, FormSet, Form) == ExpressDisable) {
2131 continue;
2132 }
2133 }
2134
2135 HiiValue = &Statement->HiiValue;
2136 TypeValue = &HiiValue->Value;
2137 if (HiiValue->Type == EFI_IFR_TYPE_BUFFER) {
2138 //
2139 // For OrderedList, passing in the value buffer to Callback()
2140 //
2141 TypeValue = (EFI_IFR_TYPE_VALUE *) Statement->BufferValue;
2142 }
2143
2144 //
2145 // If EFI_BROWSER_ACTION_CHANGING type, back up the new question value.
2146 //
2147 if (Action == EFI_BROWSER_ACTION_CHANGING) {
2148 if (HiiValue->Type == EFI_IFR_TYPE_BUFFER) {
2149 BackUpBuffer = AllocateCopyPool(Statement->StorageWidth + sizeof(CHAR16), Statement->BufferValue);
2150 } else {
2151 CopyMem (&BackUpValue, &HiiValue->Value, sizeof (EFI_IFR_TYPE_VALUE));
2152 }
2153 }
2154
2155 ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;
2156 Status = ConfigAccess->Callback (
2157 ConfigAccess,
2158 Action,
2159 Statement->QuestionId,
2160 HiiValue->Type,
2161 TypeValue,
2162 &ActionRequest
2163 );
2164 if (!EFI_ERROR (Status)) {
2165 //
2166 // Only for EFI_BROWSER_ACTION_CHANGED need to handle this ActionRequest.
2167 //
2168 if (Action == EFI_BROWSER_ACTION_CHANGED) {
2169 switch (ActionRequest) {
2170 case EFI_BROWSER_ACTION_REQUEST_RESET:
2171 DiscardFormIsRequired = TRUE;
2172 gResetRequired = TRUE;
2173 NeedExit = TRUE;
2174 break;
2175
2176 case EFI_BROWSER_ACTION_REQUEST_SUBMIT:
2177 SubmitFormIsRequired = TRUE;
2178 NeedExit = TRUE;
2179 break;
2180
2181 case EFI_BROWSER_ACTION_REQUEST_EXIT:
2182 DiscardFormIsRequired = TRUE;
2183 NeedExit = TRUE;
2184 break;
2185
2186 case EFI_BROWSER_ACTION_REQUEST_FORM_SUBMIT_EXIT:
2187 SubmitFormIsRequired = TRUE;
2188 SettingLevel = FormLevel;
2189 NeedExit = TRUE;
2190 break;
2191
2192 case EFI_BROWSER_ACTION_REQUEST_FORM_DISCARD_EXIT:
2193 DiscardFormIsRequired = TRUE;
2194 SettingLevel = FormLevel;
2195 NeedExit = TRUE;
2196 break;
2197
2198 case EFI_BROWSER_ACTION_REQUEST_FORM_APPLY:
2199 SubmitFormIsRequired = TRUE;
2200 SettingLevel = FormLevel;
2201 break;
2202
2203 case EFI_BROWSER_ACTION_REQUEST_FORM_DISCARD:
2204 DiscardFormIsRequired = TRUE;
2205 SettingLevel = FormLevel;
2206 break;
2207
2208 default:
2209 break;
2210 }
2211 }
2212
2213 //
2214 // Need to sync the value between Statement->HiiValue->Value and Statement->BufferValue
2215 //
2216 if (HiiValue->Type == EFI_IFR_TYPE_STRING) {
2217 NewString = GetToken (Statement->HiiValue.Value.string, FormSet->HiiHandle);
2218 ASSERT (NewString != NULL);
2219
2220 ASSERT (StrLen (NewString) * sizeof (CHAR16) <= Statement->StorageWidth);
2221 if (StrLen (NewString) * sizeof (CHAR16) <= Statement->StorageWidth) {
2222 CopyMem (Statement->BufferValue, NewString, StrSize (NewString));
2223 } else {
2224 CopyMem (Statement->BufferValue, NewString, Statement->StorageWidth);
2225 }
2226 FreePool (NewString);
2227 }
2228
2229 //
2230 // According the spec, return value from call back of "changing" and
2231 // "retrieve" should update to the question's temp buffer.
2232 //
2233 if (Action == EFI_BROWSER_ACTION_CHANGING || Action == EFI_BROWSER_ACTION_RETRIEVE) {
2234 SetQuestionValue(FormSet, Form, Statement, GetSetValueWithEditBuffer);
2235 }
2236 } else {
2237 //
2238 // If the callback returns EFI_UNSUPPORTED for EFI_BROWSER_ACTION_CHANGING,
2239 // then the browser will use the value passed to Callback() and ignore the
2240 // value returned by Callback().
2241 //
2242 if (Action == EFI_BROWSER_ACTION_CHANGING && Status == EFI_UNSUPPORTED) {
2243 if (HiiValue->Type == EFI_IFR_TYPE_BUFFER) {
2244 CopyMem (Statement->BufferValue, BackUpBuffer, Statement->StorageWidth + sizeof(CHAR16));
2245 } else {
2246 CopyMem (&HiiValue->Value, &BackUpValue, sizeof (EFI_IFR_TYPE_VALUE));
2247 }
2248
2249 SetQuestionValue(FormSet, Form, Statement, GetSetValueWithEditBuffer);
2250 }
2251
2252 //
2253 // According the spec, return fail from call back of "changing" and
2254 // "retrieve", should restore the question's value.
2255 //
2256 if ((Action == EFI_BROWSER_ACTION_CHANGING && Status != EFI_UNSUPPORTED) ||
2257 Action == EFI_BROWSER_ACTION_RETRIEVE) {
2258 GetQuestionValue(FormSet, Form, Statement, GetSetValueWithEditBuffer);
2259 }
2260
2261 if (Status == EFI_UNSUPPORTED) {
2262 //
2263 // If return EFI_UNSUPPORTED, also consider Hii driver suceess deal with it.
2264 //
2265 Status = EFI_SUCCESS;
2266 }
2267 }
2268
2269 if (BackUpBuffer != NULL) {
2270 FreePool (BackUpBuffer);
2271 }
2272 }
2273
2274 if (SubmitFormIsRequired && !SkipSaveOrDiscard) {
2275 SubmitForm (FormSet, Form, SettingLevel);
2276 }
2277
2278 if (DiscardFormIsRequired && !SkipSaveOrDiscard) {
2279 DiscardForm (FormSet, Form, SettingLevel);
2280 }
2281
2282 if (NeedExit) {
2283 FindNextMenu (Selection, SettingLevel);
2284 }
2285
2286 return Status;
2287 }
2288
2289 /**
2290 Call the retrieve type call back function for one question to get the initialize data.
2291
2292 This function only used when in the initialize stage, because in this stage, the
2293 Selection->Form is not ready. For other case, use the ProcessCallBackFunction instead.
2294
2295 @param ConfigAccess The config access protocol produced by the hii driver.
2296 @param Statement The Question which need to call.
2297 @param FormSet The formset this question belong to.
2298
2299 @retval EFI_SUCCESS The call back function excutes successfully.
2300 @return Other value if the call back function failed to excute.
2301 **/
2302 EFI_STATUS
2303 ProcessRetrieveForQuestion (
2304 IN EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess,
2305 IN FORM_BROWSER_STATEMENT *Statement,
2306 IN FORM_BROWSER_FORMSET *FormSet
2307 )
2308 {
2309 EFI_STATUS Status;
2310 EFI_BROWSER_ACTION_REQUEST ActionRequest;
2311 EFI_HII_VALUE *HiiValue;
2312 EFI_IFR_TYPE_VALUE *TypeValue;
2313 CHAR16 *NewString;
2314
2315 Status = EFI_SUCCESS;
2316 ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;
2317
2318 if (((Statement->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != EFI_IFR_FLAG_CALLBACK) || ConfigAccess == NULL) {
2319 return EFI_UNSUPPORTED;
2320 }
2321
2322 HiiValue = &Statement->HiiValue;
2323 TypeValue = &HiiValue->Value;
2324 if (HiiValue->Type == EFI_IFR_TYPE_BUFFER) {
2325 //
2326 // For OrderedList, passing in the value buffer to Callback()
2327 //
2328 TypeValue = (EFI_IFR_TYPE_VALUE *) Statement->BufferValue;
2329 }
2330
2331 ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;
2332 Status = ConfigAccess->Callback (
2333 ConfigAccess,
2334 EFI_BROWSER_ACTION_RETRIEVE,
2335 Statement->QuestionId,
2336 HiiValue->Type,
2337 TypeValue,
2338 &ActionRequest
2339 );
2340 if (!EFI_ERROR (Status) && HiiValue->Type == EFI_IFR_TYPE_STRING) {
2341 NewString = GetToken (Statement->HiiValue.Value.string, FormSet->HiiHandle);
2342 ASSERT (NewString != NULL);
2343
2344 ASSERT (StrLen (NewString) * sizeof (CHAR16) <= Statement->StorageWidth);
2345 if (StrLen (NewString) * sizeof (CHAR16) <= Statement->StorageWidth) {
2346 CopyMem (Statement->BufferValue, NewString, StrSize (NewString));
2347 } else {
2348 CopyMem (Statement->BufferValue, NewString, Statement->StorageWidth);
2349 }
2350 FreePool (NewString);
2351 }
2352
2353 return Status;
2354 }
2355
2356 /**
2357 The worker function that send the displays to the screen. On output,
2358 the selection made by user is returned.
2359
2360 @param Selection On input, Selection tell setup browser the information
2361 about the Selection, form and formset to be displayed.
2362 On output, Selection return the screen item that is selected
2363 by user.
2364
2365 @retval EFI_SUCCESS The page is displayed successfully.
2366 @return Other value if the page failed to be diplayed.
2367
2368 **/
2369 EFI_STATUS
2370 SetupBrowser (
2371 IN OUT UI_MENU_SELECTION *Selection
2372 )
2373 {
2374 EFI_STATUS Status;
2375 LIST_ENTRY *Link;
2376 EFI_HANDLE NotifyHandle;
2377 FORM_BROWSER_STATEMENT *Statement;
2378 EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess;
2379
2380 ConfigAccess = Selection->FormSet->ConfigAccess;
2381
2382 //
2383 // Register notify for Form package update
2384 //
2385 Status = mHiiDatabase->RegisterPackageNotify (
2386 mHiiDatabase,
2387 EFI_HII_PACKAGE_FORMS,
2388 NULL,
2389 FormUpdateNotify,
2390 EFI_HII_DATABASE_NOTIFY_REMOVE_PACK,
2391 &NotifyHandle
2392 );
2393 if (EFI_ERROR (Status)) {
2394 return Status;
2395 }
2396
2397 if ((Selection->Handle != mCurrentHiiHandle) ||
2398 (!CompareGuid (&Selection->FormSetGuid, &mCurrentFormSetGuid))) {
2399 gFinishRetrieveCall = FALSE;
2400 }
2401
2402 //
2403 // Initialize current settings of Questions in this FormSet
2404 //
2405 InitializeCurrentSetting (Selection->FormSet);
2406
2407 //
2408 // Initilize Action field.
2409 //
2410 Selection->Action = UI_ACTION_REFRESH_FORM;
2411
2412 //
2413 // Clean the mCurFakeQestId value is formset refreshed.
2414 //
2415 mCurFakeQestId = 0;
2416
2417 do {
2418 //
2419 // IFR is updated, force to reparse the IFR binary
2420 //
2421 if (mHiiPackageListUpdated) {
2422 Selection->Action = UI_ACTION_REFRESH_FORMSET;
2423 mHiiPackageListUpdated = FALSE;
2424 break;
2425 }
2426
2427 //
2428 // Initialize Selection->Form
2429 //
2430 if (Selection->FormId == 0) {
2431 //
2432 // Zero FormId indicates display the first Form in a FormSet
2433 //
2434 Link = GetFirstNode (&Selection->FormSet->FormListHead);
2435
2436 Selection->Form = FORM_BROWSER_FORM_FROM_LINK (Link);
2437 Selection->FormId = Selection->Form->FormId;
2438 } else {
2439 Selection->Form = IdToForm (Selection->FormSet, Selection->FormId);
2440 }
2441
2442 if (Selection->Form == NULL) {
2443 //
2444 // No Form to display
2445 //
2446 Status = EFI_NOT_FOUND;
2447 goto Done;
2448 }
2449
2450 //
2451 // Check Form is suppressed.
2452 //
2453 if (Selection->Form->SuppressExpression != NULL) {
2454 if (EvaluateExpressionList(Selection->Form->SuppressExpression, TRUE, Selection->FormSet, Selection->Form) == ExpressSuppress) {
2455 //
2456 // Form is suppressed.
2457 //
2458 gBrowserStatus = BROWSER_FORM_SUPPRESS;
2459 Status = EFI_NOT_FOUND;
2460 goto Done;
2461 }
2462 }
2463
2464 //
2465 // Before display new form, invoke ConfigAccess.Callback() with EFI_BROWSER_ACTION_FORM_OPEN
2466 // for each question with callback flag.
2467 // New form may be the first form, or the different form after another form close.
2468 //
2469 if (((Selection->Handle != mCurrentHiiHandle) ||
2470 (!CompareGuid (&Selection->FormSetGuid, &mCurrentFormSetGuid)) ||
2471 (Selection->FormId != mCurrentFormId))) {
2472 //
2473 // Keep current form information
2474 //
2475 mCurrentHiiHandle = Selection->Handle;
2476 CopyGuid (&mCurrentFormSetGuid, &Selection->FormSetGuid);
2477 mCurrentFormId = Selection->FormId;
2478
2479 if (ConfigAccess != NULL) {
2480 Status = ProcessCallBackFunction (Selection, gCurrentSelection->FormSet, Selection->Form, NULL, EFI_BROWSER_ACTION_FORM_OPEN, FALSE);
2481 if (EFI_ERROR (Status)) {
2482 goto Done;
2483 }
2484
2485 //
2486 // IFR is updated during callback of open form, force to reparse the IFR binary
2487 //
2488 if (mHiiPackageListUpdated) {
2489 Selection->Action = UI_ACTION_REFRESH_FORMSET;
2490 mHiiPackageListUpdated = FALSE;
2491 break;
2492 }
2493 }
2494 }
2495
2496 //
2497 // Load Questions' Value for display
2498 //
2499 Status = LoadFormSetConfig (Selection, Selection->FormSet);
2500 if (EFI_ERROR (Status)) {
2501 goto Done;
2502 }
2503
2504 //
2505 // Finish call RETRIEVE callback for this formset.
2506 //
2507 gFinishRetrieveCall = TRUE;
2508
2509 //
2510 // IFR is updated during callback of read value, force to reparse the IFR binary
2511 //
2512 if (mHiiPackageListUpdated) {
2513 Selection->Action = UI_ACTION_REFRESH_FORMSET;
2514 mHiiPackageListUpdated = FALSE;
2515 break;
2516 }
2517
2518 //
2519 // Display form
2520 //
2521 Status = DisplayForm ();
2522 if (EFI_ERROR (Status)) {
2523 goto Done;
2524 }
2525
2526 //
2527 // Check Selected Statement (if press ESC, Selection->Statement will be NULL)
2528 //
2529 Statement = Selection->Statement;
2530 if (Statement != NULL) {
2531 if ((ConfigAccess != NULL) &&
2532 ((Statement->QuestionFlags & EFI_IFR_FLAG_CALLBACK) == EFI_IFR_FLAG_CALLBACK) &&
2533 (Statement->Operand != EFI_IFR_PASSWORD_OP)) {
2534 Status = ProcessCallBackFunction(Selection, Selection->FormSet, Selection->Form, Statement, EFI_BROWSER_ACTION_CHANGING, FALSE);
2535 if (Statement->Operand == EFI_IFR_REF_OP) {
2536 //
2537 // Process dynamic update ref opcode.
2538 //
2539 if (!EFI_ERROR (Status)) {
2540 Status = ProcessGotoOpCode(Statement, Selection);
2541 }
2542
2543 //
2544 // Callback return error status or status return from process goto opcode.
2545 //
2546 if (EFI_ERROR (Status)) {
2547 //
2548 // Cross reference will not be taken
2549 //
2550 Selection->FormId = Selection->Form->FormId;
2551 Selection->QuestionId = 0;
2552 }
2553 }
2554
2555 //
2556 // Verify whether question value has checked, update the ValueChanged flag in Question.
2557 //
2558 IsQuestionValueChanged(gCurrentSelection->FormSet, gCurrentSelection->Form, Statement, GetSetValueWithBuffer);
2559
2560 if (!EFI_ERROR (Status) && Statement->Operand != EFI_IFR_REF_OP) {
2561 ProcessCallBackFunction(Selection, Selection->FormSet, Selection->Form, Statement, EFI_BROWSER_ACTION_CHANGED, FALSE);
2562 }
2563 } else if (Statement->Operand != EFI_IFR_PASSWORD_OP) {
2564 SetQuestionValue (gCurrentSelection->FormSet, gCurrentSelection->Form, Statement, GetSetValueWithEditBuffer);
2565 //
2566 // Verify whether question value has checked, update the ValueChanged flag in Question.
2567 //
2568 IsQuestionValueChanged(gCurrentSelection->FormSet, gCurrentSelection->Form, Statement, GetSetValueWithBuffer);
2569 }
2570
2571 //
2572 // If question has EFI_IFR_FLAG_RESET_REQUIRED flag and without storage and process question success till here,
2573 // trig the gResetFlag.
2574 //
2575 if ((Status == EFI_SUCCESS) &&
2576 (Statement->Storage == NULL) &&
2577 ((Statement->QuestionFlags & EFI_IFR_FLAG_RESET_REQUIRED) != 0)) {
2578 gResetRequired = TRUE;
2579 }
2580 }
2581
2582 //
2583 // Check whether Exit flag is TRUE.
2584 //
2585 if (gExitRequired) {
2586 switch (gBrowserSettingScope) {
2587 case SystemLevel:
2588 Selection->Action = UI_ACTION_EXIT;
2589 break;
2590
2591 case FormSetLevel:
2592 case FormLevel:
2593 FindNextMenu (Selection, gBrowserSettingScope);
2594 break;
2595
2596 default:
2597 break;
2598 }
2599
2600 gExitRequired = FALSE;
2601 }
2602
2603 //
2604 // Before exit the form, invoke ConfigAccess.Callback() with EFI_BROWSER_ACTION_FORM_CLOSE
2605 // for each question with callback flag.
2606 //
2607 if ((ConfigAccess != NULL) &&
2608 ((Selection->Action == UI_ACTION_EXIT) ||
2609 (Selection->Handle != mCurrentHiiHandle) ||
2610 (!CompareGuid (&Selection->FormSetGuid, &mCurrentFormSetGuid)) ||
2611 (Selection->FormId != mCurrentFormId))) {
2612
2613 Status = ProcessCallBackFunction (Selection, Selection->FormSet, Selection->Form, NULL, EFI_BROWSER_ACTION_FORM_CLOSE, FALSE);
2614 if (EFI_ERROR (Status)) {
2615 goto Done;
2616 }
2617 }
2618 } while (Selection->Action == UI_ACTION_REFRESH_FORM);
2619
2620 Done:
2621 //
2622 // Reset current form information to the initial setting when error happens or form exit.
2623 //
2624 if (EFI_ERROR (Status) || Selection->Action == UI_ACTION_EXIT) {
2625 mCurrentHiiHandle = NULL;
2626 CopyGuid (&mCurrentFormSetGuid, &gZeroGuid);
2627 mCurrentFormId = 0;
2628 }
2629
2630 //
2631 // Unregister notify for Form package update
2632 //
2633 mHiiDatabase->UnregisterPackageNotify (
2634 mHiiDatabase,
2635 NotifyHandle
2636 );
2637 return Status;
2638 }