]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/SetupBrowserDxe/Presentation.c
Rollback the change 15021.
[mirror_edk2.git] / MdeModulePkg / Universal / SetupBrowserDxe / Presentation.c
1 /** @file
2 Utility functions for UI presentation.
3
4 Copyright (c) 2004 - 2013, 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
968 Process the action request in user input.
969
970 @param Action The user input action request info.
971 @param DefaultId The user input default Id info.
972
973 @retval EFI_SUCESSS This function always return successfully for now.
974
975 **/
976 EFI_STATUS
977 ProcessAction (
978 IN UINT32 Action,
979 IN UINT16 DefaultId
980 )
981 {
982 EFI_STATUS Status;
983
984 //
985 // This is caused by use press ESC, and it should not combine with other action type.
986 //
987 if ((Action & BROWSER_ACTION_FORM_EXIT) == BROWSER_ACTION_FORM_EXIT) {
988 FindNextMenu (gCurrentSelection, FormLevel);
989 return EFI_SUCCESS;
990 }
991
992 //
993 // Below is normal hotkey trigged action, these action maybe combine with each other.
994 //
995 if ((Action & BROWSER_ACTION_DISCARD) == BROWSER_ACTION_DISCARD) {
996 DiscardForm (gCurrentSelection->FormSet, gCurrentSelection->Form, gBrowserSettingScope);
997 }
998
999 if ((Action & BROWSER_ACTION_DEFAULT) == BROWSER_ACTION_DEFAULT) {
1000 ExtractDefault (gCurrentSelection->FormSet, gCurrentSelection->Form, DefaultId, gBrowserSettingScope, GetDefaultForAll, NULL, FALSE);
1001 }
1002
1003 if ((Action & BROWSER_ACTION_SUBMIT) == BROWSER_ACTION_SUBMIT) {
1004 Status = SubmitForm (gCurrentSelection->FormSet, gCurrentSelection->Form, gBrowserSettingScope);
1005 if (EFI_ERROR (Status)) {
1006 gBrowserStatus = BROWSER_SUBMIT_FAIL;
1007 }
1008 }
1009
1010 if ((Action & BROWSER_ACTION_RESET) == BROWSER_ACTION_RESET) {
1011 gResetRequired = TRUE;
1012 }
1013
1014 if ((Action & BROWSER_ACTION_EXIT) == BROWSER_ACTION_EXIT) {
1015 //
1016 // Form Exit without saving, Similar to ESC Key.
1017 // FormSet Exit without saving, Exit SendForm.
1018 // System Exit without saving, CallExitHandler and Exit SendForm.
1019 //
1020 DiscardForm (gCurrentSelection->FormSet, gCurrentSelection->Form, gBrowserSettingScope);
1021 if (gBrowserSettingScope == FormLevel || gBrowserSettingScope == FormSetLevel) {
1022 FindNextMenu (gCurrentSelection, gBrowserSettingScope);
1023 } else if (gBrowserSettingScope == SystemLevel) {
1024 if (ExitHandlerFunction != NULL) {
1025 ExitHandlerFunction ();
1026 }
1027 gCurrentSelection->Action = UI_ACTION_EXIT;
1028 }
1029 }
1030
1031 return EFI_SUCCESS;
1032 }
1033
1034 /**
1035 Check whether the formset guid is in this Hii package list.
1036
1037 @param HiiHandle The HiiHandle for this HII package list.
1038 @param FormSetGuid The formset guid for the request formset.
1039
1040 @retval TRUE Find the formset guid.
1041 @retval FALSE Not found the formset guid.
1042
1043 **/
1044 BOOLEAN
1045 GetFormsetGuidFromHiiHandle (
1046 IN EFI_HII_HANDLE HiiHandle,
1047 IN EFI_GUID *FormSetGuid
1048 )
1049 {
1050 EFI_HII_PACKAGE_LIST_HEADER *HiiPackageList;
1051 UINTN BufferSize;
1052 UINT32 Offset;
1053 UINT32 Offset2;
1054 UINT32 PackageListLength;
1055 EFI_HII_PACKAGE_HEADER PackageHeader;
1056 UINT8 *Package;
1057 UINT8 *OpCodeData;
1058 EFI_STATUS Status;
1059 BOOLEAN FindGuid;
1060
1061 BufferSize = 0;
1062 HiiPackageList = NULL;
1063 FindGuid = FALSE;
1064
1065 Status = mHiiDatabase->ExportPackageLists (mHiiDatabase, HiiHandle, &BufferSize, HiiPackageList);
1066 if (Status == EFI_BUFFER_TOO_SMALL) {
1067 HiiPackageList = AllocatePool (BufferSize);
1068 ASSERT (HiiPackageList != NULL);
1069
1070 Status = mHiiDatabase->ExportPackageLists (mHiiDatabase, HiiHandle, &BufferSize, HiiPackageList);
1071 }
1072 if (EFI_ERROR (Status) || HiiPackageList == NULL) {
1073 return FALSE;
1074 }
1075
1076 //
1077 // Get Form package from this HII package List
1078 //
1079 Offset = sizeof (EFI_HII_PACKAGE_LIST_HEADER);
1080 Offset2 = 0;
1081 CopyMem (&PackageListLength, &HiiPackageList->PackageLength, sizeof (UINT32));
1082
1083 while (Offset < PackageListLength) {
1084 Package = ((UINT8 *) HiiPackageList) + Offset;
1085 CopyMem (&PackageHeader, Package, sizeof (EFI_HII_PACKAGE_HEADER));
1086 Offset += PackageHeader.Length;
1087
1088 if (PackageHeader.Type == EFI_HII_PACKAGE_FORMS) {
1089 //
1090 // Search FormSet in this Form Package
1091 //
1092 Offset2 = sizeof (EFI_HII_PACKAGE_HEADER);
1093 while (Offset2 < PackageHeader.Length) {
1094 OpCodeData = Package + Offset2;
1095
1096 if (((EFI_IFR_OP_HEADER *) OpCodeData)->OpCode == EFI_IFR_FORM_SET_OP) {
1097 if (CompareGuid (FormSetGuid, (EFI_GUID *)(OpCodeData + sizeof (EFI_IFR_OP_HEADER)))){
1098 FindGuid = TRUE;
1099 break;
1100 }
1101 }
1102
1103 Offset2 += ((EFI_IFR_OP_HEADER *) OpCodeData)->Length;
1104 }
1105 }
1106 if (FindGuid) {
1107 break;
1108 }
1109 }
1110
1111 FreePool (HiiPackageList);
1112
1113 return FindGuid;
1114 }
1115
1116 /**
1117 Find HII Handle in the HII database associated with given Device Path.
1118
1119 If DevicePath is NULL, then ASSERT.
1120
1121 @param DevicePath Device Path associated with the HII package list
1122 handle.
1123 @param FormsetGuid The formset guid for this formset.
1124
1125 @retval Handle HII package list Handle associated with the Device
1126 Path.
1127 @retval NULL Hii Package list handle is not found.
1128
1129 **/
1130 EFI_HII_HANDLE
1131 DevicePathToHiiHandle (
1132 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
1133 IN EFI_GUID *FormsetGuid
1134 )
1135 {
1136 EFI_STATUS Status;
1137 EFI_DEVICE_PATH_PROTOCOL *TmpDevicePath;
1138 UINTN Index;
1139 EFI_HANDLE Handle;
1140 EFI_HANDLE DriverHandle;
1141 EFI_HII_HANDLE *HiiHandles;
1142 EFI_HII_HANDLE HiiHandle;
1143
1144 ASSERT (DevicePath != NULL);
1145
1146 TmpDevicePath = DevicePath;
1147 //
1148 // Locate Device Path Protocol handle buffer
1149 //
1150 Status = gBS->LocateDevicePath (
1151 &gEfiDevicePathProtocolGuid,
1152 &TmpDevicePath,
1153 &DriverHandle
1154 );
1155 if (EFI_ERROR (Status) || !IsDevicePathEnd (TmpDevicePath)) {
1156 return NULL;
1157 }
1158
1159 //
1160 // Retrieve all HII Handles from HII database
1161 //
1162 HiiHandles = HiiGetHiiHandles (NULL);
1163 if (HiiHandles == NULL) {
1164 return NULL;
1165 }
1166
1167 //
1168 // Search Hii Handle by Driver Handle
1169 //
1170 HiiHandle = NULL;
1171 for (Index = 0; HiiHandles[Index] != NULL; Index++) {
1172 Status = mHiiDatabase->GetPackageListHandle (
1173 mHiiDatabase,
1174 HiiHandles[Index],
1175 &Handle
1176 );
1177 if (!EFI_ERROR (Status) && (Handle == DriverHandle)) {
1178 if (GetFormsetGuidFromHiiHandle(HiiHandles[Index], FormsetGuid)) {
1179 HiiHandle = HiiHandles[Index];
1180 break;
1181 }
1182
1183 if (HiiHandle != NULL) {
1184 break;
1185 }
1186 }
1187 }
1188
1189 FreePool (HiiHandles);
1190 return HiiHandle;
1191 }
1192
1193 /**
1194 Find HII Handle in the HII database associated with given form set guid.
1195
1196 If FormSetGuid is NULL, then ASSERT.
1197
1198 @param ComparingGuid FormSet Guid associated with the HII package list
1199 handle.
1200
1201 @retval Handle HII package list Handle associated with the Device
1202 Path.
1203 @retval NULL Hii Package list handle is not found.
1204
1205 **/
1206 EFI_HII_HANDLE
1207 FormSetGuidToHiiHandle (
1208 EFI_GUID *ComparingGuid
1209 )
1210 {
1211 EFI_HII_HANDLE *HiiHandles;
1212 EFI_HII_HANDLE HiiHandle;
1213 UINTN Index;
1214
1215 ASSERT (ComparingGuid != NULL);
1216
1217 HiiHandle = NULL;
1218 //
1219 // Get all the Hii handles
1220 //
1221 HiiHandles = HiiGetHiiHandles (NULL);
1222 ASSERT (HiiHandles != NULL);
1223
1224 //
1225 // Search for formset of each class type
1226 //
1227 for (Index = 0; HiiHandles[Index] != NULL; Index++) {
1228 if (GetFormsetGuidFromHiiHandle(HiiHandles[Index], ComparingGuid)) {
1229 HiiHandle = HiiHandles[Index];
1230 break;
1231 }
1232
1233 if (HiiHandle != NULL) {
1234 break;
1235 }
1236 }
1237
1238 FreePool (HiiHandles);
1239
1240 return HiiHandle;
1241 }
1242
1243 /**
1244 check how to process the changed data in current form or form set.
1245
1246 @param Selection On input, Selection tell setup browser the information
1247 about the Selection, form and formset to be displayed.
1248 On output, Selection return the screen item that is selected
1249 by user.
1250
1251 @param Scope Data save or discard scope, form or formset.
1252
1253 @retval TRUE Success process the changed data, will return to the parent form.
1254 @retval FALSE Reject to process the changed data, will stay at current form.
1255 **/
1256 BOOLEAN
1257 ProcessChangedData (
1258 IN OUT UI_MENU_SELECTION *Selection,
1259 IN BROWSER_SETTING_SCOPE Scope
1260 )
1261 {
1262 BOOLEAN RetValue;
1263
1264 RetValue = TRUE;
1265 switch (mFormDisplay->ConfirmDataChange()) {
1266 case BROWSER_ACTION_DISCARD:
1267 DiscardForm (Selection->FormSet, Selection->Form, Scope);
1268 break;
1269
1270 case BROWSER_ACTION_SUBMIT:
1271 SubmitForm (Selection->FormSet, Selection->Form, Scope);
1272 break;
1273
1274 case BROWSER_ACTION_NONE:
1275 RetValue = FALSE;
1276 break;
1277
1278 default:
1279 //
1280 // if Invalid value return, process same as BROWSER_ACTION_NONE.
1281 //
1282 RetValue = FALSE;
1283 break;
1284 }
1285
1286 return RetValue;
1287 }
1288
1289 /**
1290 Find parent formset menu(the first menu which has different formset) for current menu.
1291 If not find, just return to the first menu.
1292
1293 @param Selection The selection info.
1294
1295 **/
1296 VOID
1297 FindParentFormSet (
1298 IN OUT UI_MENU_SELECTION *Selection
1299 )
1300 {
1301 FORM_ENTRY_INFO *CurrentMenu;
1302 FORM_ENTRY_INFO *ParentMenu;
1303
1304 CurrentMenu = Selection->CurrentMenu;
1305 ParentMenu = UiFindParentMenu(CurrentMenu);
1306
1307 //
1308 // Find a menu which has different formset guid with current.
1309 //
1310 while (ParentMenu != NULL && CompareGuid (&CurrentMenu->FormSetGuid, &ParentMenu->FormSetGuid)) {
1311 CurrentMenu = ParentMenu;
1312 ParentMenu = UiFindParentMenu(CurrentMenu);
1313 }
1314
1315 if (ParentMenu != NULL) {
1316 CopyMem (&Selection->FormSetGuid, &ParentMenu->FormSetGuid, sizeof (EFI_GUID));
1317 Selection->Handle = ParentMenu->HiiHandle;
1318 Selection->FormId = ParentMenu->FormId;
1319 Selection->QuestionId = ParentMenu->QuestionId;
1320 } else {
1321 Selection->FormId = CurrentMenu->FormId;
1322 Selection->QuestionId = CurrentMenu->QuestionId;
1323 }
1324
1325 Selection->Statement = NULL;
1326 }
1327
1328 /**
1329 Process the goto op code, update the info in the selection structure.
1330
1331 @param Statement The statement belong to goto op code.
1332 @param Selection The selection info.
1333
1334 @retval EFI_SUCCESS The menu process successfully.
1335 @return Other value if the process failed.
1336 **/
1337 EFI_STATUS
1338 ProcessGotoOpCode (
1339 IN OUT FORM_BROWSER_STATEMENT *Statement,
1340 IN OUT UI_MENU_SELECTION *Selection
1341 )
1342 {
1343 CHAR16 *StringPtr;
1344 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
1345 FORM_BROWSER_FORM *RefForm;
1346 EFI_STATUS Status;
1347 EFI_HII_HANDLE HiiHandle;
1348
1349 Status = EFI_SUCCESS;
1350 StringPtr = NULL;
1351 HiiHandle = NULL;
1352
1353 //
1354 // Prepare the device path check, get the device path info first.
1355 //
1356 if (Statement->HiiValue.Value.ref.DevicePath != 0) {
1357 StringPtr = GetToken (Statement->HiiValue.Value.ref.DevicePath, Selection->FormSet->HiiHandle);
1358 }
1359
1360 //
1361 // Check whether the device path string is a valid string.
1362 //
1363 if (Statement->HiiValue.Value.ref.DevicePath != 0 && StringPtr != NULL && StringPtr[0] != L'\0') {
1364 if (Selection->Form->ModalForm) {
1365 return Status;
1366 }
1367
1368 //
1369 // Goto another Hii Package list
1370 //
1371 if (mPathFromText != NULL) {
1372 DevicePath = mPathFromText->ConvertTextToDevicePath(StringPtr);
1373 if (DevicePath != NULL) {
1374 HiiHandle = DevicePathToHiiHandle (DevicePath, &Statement->HiiValue.Value.ref.FormSetGuid);
1375 FreePool (DevicePath);
1376 }
1377 FreePool (StringPtr);
1378 } else {
1379 //
1380 // Not found the EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL protocol.
1381 //
1382 gBrowserStatus = BROWSER_PROTOCOL_NOT_FOUND;
1383 FreePool (StringPtr);
1384 return Status;
1385 }
1386
1387 if (HiiHandle != Selection->Handle) {
1388 //
1389 // Goto another Formset, check for uncommitted data
1390 //
1391 if ((gBrowserSettingScope == FormLevel || gBrowserSettingScope == FormSetLevel) &&
1392 IsNvUpdateRequiredForFormSet(Selection->FormSet)) {
1393 if (!ProcessChangedData(Selection, FormSetLevel)) {
1394 return EFI_SUCCESS;
1395 }
1396 }
1397 }
1398
1399 Selection->Action = UI_ACTION_REFRESH_FORMSET;
1400 Selection->Handle = HiiHandle;
1401 if (Selection->Handle == NULL) {
1402 //
1403 // If target Hii Handle not found, exit current formset.
1404 //
1405 FindParentFormSet(Selection);
1406 return EFI_SUCCESS;
1407 }
1408
1409 CopyMem (&Selection->FormSetGuid,&Statement->HiiValue.Value.ref.FormSetGuid, sizeof (EFI_GUID));
1410 Selection->FormId = Statement->HiiValue.Value.ref.FormId;
1411 Selection->QuestionId = Statement->HiiValue.Value.ref.QuestionId;
1412 } else if (!CompareGuid (&Statement->HiiValue.Value.ref.FormSetGuid, &gZeroGuid)) {
1413 if (Selection->Form->ModalForm) {
1414 return Status;
1415 }
1416 if (!CompareGuid (&Statement->HiiValue.Value.ref.FormSetGuid, &Selection->FormSetGuid)) {
1417 //
1418 // Goto another Formset, check for uncommitted data
1419 //
1420 if ((gBrowserSettingScope == FormLevel || gBrowserSettingScope == FormSetLevel) &&
1421 IsNvUpdateRequiredForFormSet(Selection->FormSet)) {
1422 if (!ProcessChangedData(Selection, FormSetLevel)) {
1423 return EFI_SUCCESS;
1424 }
1425 }
1426 }
1427
1428 Selection->Action = UI_ACTION_REFRESH_FORMSET;
1429 Selection->Handle = FormSetGuidToHiiHandle(&Statement->HiiValue.Value.ref.FormSetGuid);
1430 if (Selection->Handle == NULL) {
1431 //
1432 // If target Hii Handle not found, exit current formset.
1433 //
1434 FindParentFormSet(Selection);
1435 return EFI_SUCCESS;
1436 }
1437
1438 CopyMem (&Selection->FormSetGuid, &Statement->HiiValue.Value.ref.FormSetGuid, sizeof (EFI_GUID));
1439 Selection->FormId = Statement->HiiValue.Value.ref.FormId;
1440 Selection->QuestionId = Statement->HiiValue.Value.ref.QuestionId;
1441 } else if (Statement->HiiValue.Value.ref.FormId != 0) {
1442 //
1443 // Goto another Form, check for uncommitted data
1444 //
1445 if (Statement->HiiValue.Value.ref.FormId != Selection->FormId) {
1446 if ((gBrowserSettingScope == FormLevel && IsNvUpdateRequiredForForm(Selection->Form))) {
1447 if (!ProcessChangedData (Selection, FormLevel)) {
1448 return EFI_SUCCESS;
1449 }
1450 }
1451 }
1452
1453 RefForm = IdToForm (Selection->FormSet, Statement->HiiValue.Value.ref.FormId);
1454 if ((RefForm != NULL) && (RefForm->SuppressExpression != NULL)) {
1455 if (EvaluateExpressionList(RefForm->SuppressExpression, TRUE, Selection->FormSet, RefForm) != ExpressFalse) {
1456 //
1457 // Form is suppressed.
1458 //
1459 gBrowserStatus = BROWSER_FORM_SUPPRESS;
1460 return EFI_SUCCESS;
1461 }
1462 }
1463
1464 Selection->FormId = Statement->HiiValue.Value.ref.FormId;
1465 Selection->QuestionId = Statement->HiiValue.Value.ref.QuestionId;
1466 } else if (Statement->HiiValue.Value.ref.QuestionId != 0) {
1467 Selection->QuestionId = Statement->HiiValue.Value.ref.QuestionId;
1468 }
1469
1470 return Status;
1471 }
1472
1473
1474 /**
1475 Process Question Config.
1476
1477 @param Selection The UI menu selection.
1478 @param Question The Question to be peocessed.
1479
1480 @retval EFI_SUCCESS Question Config process success.
1481 @retval Other Question Config process fail.
1482
1483 **/
1484 EFI_STATUS
1485 ProcessQuestionConfig (
1486 IN UI_MENU_SELECTION *Selection,
1487 IN FORM_BROWSER_STATEMENT *Question
1488 )
1489 {
1490 EFI_STATUS Status;
1491 CHAR16 *ConfigResp;
1492 CHAR16 *Progress;
1493
1494 if (Question->QuestionConfig == 0) {
1495 return EFI_SUCCESS;
1496 }
1497
1498 //
1499 // Get <ConfigResp>
1500 //
1501 ConfigResp = GetToken (Question->QuestionConfig, Selection->FormSet->HiiHandle);
1502 if (ConfigResp == NULL) {
1503 return EFI_NOT_FOUND;
1504 }
1505
1506 //
1507 // Send config to Configuration Driver
1508 //
1509 Status = mHiiConfigRouting->RouteConfig (
1510 mHiiConfigRouting,
1511 ConfigResp,
1512 &Progress
1513 );
1514
1515 return Status;
1516 }
1517
1518 /**
1519
1520 Process the user input data.
1521
1522 @param UserInput The user input data.
1523 @param ChangeHighlight Whether need to change the highlight statement.
1524
1525 @retval EFI_SUCESSS This function always return successfully for now.
1526
1527 **/
1528 EFI_STATUS
1529 ProcessUserInput (
1530 IN USER_INPUT *UserInput,
1531 IN BOOLEAN ChangeHighlight
1532 )
1533 {
1534 EFI_STATUS Status;
1535 FORM_BROWSER_STATEMENT *Statement;
1536
1537 Status = EFI_SUCCESS;
1538
1539 //
1540 // When Exit from FormDisplay function, one of the below two cases must be true.
1541 //
1542 ASSERT (UserInput->Action != 0 || UserInput->SelectedStatement != NULL);
1543
1544 //
1545 // Remove the last highligh question id, this id will update when show next form.
1546 //
1547 gCurrentSelection->QuestionId = 0;
1548
1549 //
1550 // First process the Action field in USER_INPUT.
1551 //
1552 if (UserInput->Action != 0) {
1553 Status = ProcessAction (UserInput->Action, UserInput->DefaultId);
1554 if (EFI_ERROR (Status)) {
1555 return Status;
1556 }
1557
1558 //
1559 // Clear the highlight info.
1560 //
1561 gCurrentSelection->Statement = NULL;
1562
1563 if (UserInput->SelectedStatement != NULL) {
1564 Statement = GetBrowserStatement(UserInput->SelectedStatement);
1565 ASSERT (Statement != NULL);
1566 //
1567 // Save the current highlight menu in the menu history data.
1568 // which will be used when later browse back to this form.
1569 //
1570 gCurrentSelection->CurrentMenu->QuestionId = Statement->QuestionId;
1571 //
1572 // For statement like text, actio, it not has question id.
1573 // So use FakeQuestionId to save the question.
1574 //
1575 if (gCurrentSelection->CurrentMenu->QuestionId == 0) {
1576 mCurFakeQestId = Statement->FakeQuestionId;
1577 } else {
1578 mCurFakeQestId = 0;
1579 }
1580 }
1581 } else {
1582 Statement = GetBrowserStatement(UserInput->SelectedStatement);
1583 ASSERT (Statement != NULL);
1584
1585 gCurrentSelection->Statement = Statement;
1586
1587 if (ChangeHighlight) {
1588 //
1589 // This question is the current user select one,record it and later
1590 // show it as the highlight question.
1591 //
1592 gCurrentSelection->CurrentMenu->QuestionId = Statement->QuestionId;
1593 //
1594 // For statement like text, actio, it not has question id.
1595 // So use FakeQuestionId to save the question.
1596 //
1597 if (gCurrentSelection->CurrentMenu->QuestionId == 0) {
1598 mCurFakeQestId = Statement->FakeQuestionId;
1599 } else {
1600 mCurFakeQestId = 0;
1601 }
1602 }
1603
1604 switch (Statement->Operand) {
1605 case EFI_IFR_REF_OP:
1606 Status = ProcessGotoOpCode(Statement, gCurrentSelection);
1607 break;
1608
1609 case EFI_IFR_ACTION_OP:
1610 //
1611 // Process the Config string <ConfigResp>
1612 //
1613 Status = ProcessQuestionConfig (gCurrentSelection, Statement);
1614 break;
1615
1616 case EFI_IFR_RESET_BUTTON_OP:
1617 //
1618 // Reset Question to default value specified by DefaultId
1619 //
1620 Status = ExtractDefault (gCurrentSelection->FormSet, NULL, Statement->DefaultId, FormSetLevel, GetDefaultForAll, NULL, FALSE);
1621 break;
1622
1623 default:
1624 switch (Statement->Operand) {
1625 case EFI_IFR_STRING_OP:
1626 DeleteString(Statement->HiiValue.Value.string, gCurrentSelection->FormSet->HiiHandle);
1627 Statement->HiiValue.Value.string = UserInput->InputValue.Value.string;
1628 CopyMem (Statement->BufferValue, UserInput->InputValue.Buffer, (UINTN) UserInput->InputValue.BufferLen);
1629 FreePool (UserInput->InputValue.Buffer);
1630 break;
1631
1632 case EFI_IFR_PASSWORD_OP:
1633 if (UserInput->InputValue.Buffer == NULL) {
1634 //
1635 // User not input new password, just return.
1636 //
1637 break;
1638 }
1639
1640 DeleteString(Statement->HiiValue.Value.string, gCurrentSelection->FormSet->HiiHandle);
1641 Statement->HiiValue.Value.string = UserInput->InputValue.Value.string;
1642 CopyMem (Statement->BufferValue, UserInput->InputValue.Buffer, (UINTN) UserInput->InputValue.BufferLen);
1643 FreePool (UserInput->InputValue.Buffer);
1644 //
1645 // Two password match, send it to Configuration Driver
1646 //
1647 if ((Statement->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) {
1648 PasswordCheck (NULL, UserInput->SelectedStatement, (CHAR16 *) Statement->BufferValue);
1649 //
1650 // Clean the value after saved it.
1651 //
1652 ZeroMem (Statement->BufferValue, (UINTN) UserInput->InputValue.BufferLen);
1653 HiiSetString (gCurrentSelection->FormSet->HiiHandle, Statement->HiiValue.Value.string, (CHAR16*)Statement->BufferValue, NULL);
1654 } else {
1655 SetQuestionValue (gCurrentSelection->FormSet, gCurrentSelection->Form, Statement, GetSetValueWithHiiDriver);
1656 }
1657 break;
1658
1659 case EFI_IFR_ORDERED_LIST_OP:
1660 CopyMem (Statement->BufferValue, UserInput->InputValue.Buffer, UserInput->InputValue.BufferLen);
1661 break;
1662
1663 default:
1664 CopyMem (&Statement->HiiValue, &UserInput->InputValue, sizeof (EFI_HII_VALUE));
1665 break;
1666 }
1667 break;
1668 }
1669 }
1670
1671 return Status;
1672 }
1673
1674 /**
1675
1676 Display form and wait for user to select one menu option, then return it.
1677
1678 @retval EFI_SUCESSS This function always return successfully for now.
1679
1680 **/
1681 EFI_STATUS
1682 DisplayForm (
1683 VOID
1684 )
1685 {
1686 EFI_STATUS Status;
1687 USER_INPUT UserInput;
1688 FORM_ENTRY_INFO *CurrentMenu;
1689 BOOLEAN ChangeHighlight;
1690
1691 ZeroMem (&UserInput, sizeof (USER_INPUT));
1692
1693 //
1694 // Update the menu history data.
1695 //
1696 CurrentMenu = UiFindMenuList (gCurrentSelection->Handle, &gCurrentSelection->FormSetGuid, gCurrentSelection->FormId);
1697 if (CurrentMenu == NULL) {
1698 //
1699 // Current menu not found, add it to the menu tree
1700 //
1701 CurrentMenu = UiAddMenuList (gCurrentSelection->Handle, &gCurrentSelection->FormSetGuid,
1702 gCurrentSelection->FormId, gCurrentSelection->QuestionId);
1703 ASSERT (CurrentMenu != NULL);
1704 }
1705 gCurrentSelection->CurrentMenu = CurrentMenu;
1706
1707 //
1708 // Find currrent highlight statement.
1709 //
1710 if (gCurrentSelection->QuestionId == 0) {
1711 //
1712 // Highlight not specified, fetch it from cached menu
1713 //
1714 gCurrentSelection->QuestionId = CurrentMenu->QuestionId;
1715 }
1716
1717 //
1718 // Evaluate all the Expressions in this Form
1719 //
1720 Status = EvaluateFormExpressions (gCurrentSelection->FormSet, gCurrentSelection->Form);
1721 if (EFI_ERROR (Status)) {
1722 return Status;
1723 }
1724
1725 UpdateDisplayFormData ();
1726
1727 //
1728 // Three possible status maybe return.
1729 //
1730 // EFI_INVALID_PARAMETER: The input dimension info is not valid.
1731 // EFI_NOT_FOUND: The input value for oneof/orderedlist opcode is not valid
1732 // and an valid value has return.
1733 // EFI_SUCCESS: Success shows form and get user input in UserInput paramenter.
1734 //
1735 Status = mFormDisplay->FormDisplay (&gDisplayFormData, &UserInput);
1736 if (EFI_ERROR (Status) && Status != EFI_NOT_FOUND) {
1737 FreeDisplayFormData();
1738 return Status;
1739 }
1740
1741 //
1742 // If status is EFI_SUCCESS, means user has change the highlight menu and new user input return.
1743 // in this case, browser need to change the highlight menu.
1744 // If status is EFI_NOT_FOUND, means the input DisplayFormData has error for oneof/orderedlist
1745 // opcode and new valid value has return, browser core need to adjust
1746 // value for this opcode and shows this form again.
1747 //
1748 ChangeHighlight = (Status == EFI_SUCCESS ? TRUE :FALSE);
1749
1750 Status = ProcessUserInput (&UserInput, ChangeHighlight);
1751
1752 FreeDisplayFormData();
1753
1754 return Status;
1755 }
1756
1757 /**
1758 Functions which are registered to receive notification of
1759 database events have this prototype. The actual event is encoded
1760 in NotifyType. The following table describes how PackageType,
1761 PackageGuid, Handle, and Package are used for each of the
1762 notification types.
1763
1764 @param PackageType Package type of the notification.
1765
1766 @param PackageGuid If PackageType is
1767 EFI_HII_PACKAGE_TYPE_GUID, then this is
1768 the pointer to the GUID from the Guid
1769 field of EFI_HII_PACKAGE_GUID_HEADER.
1770 Otherwise, it must be NULL.
1771
1772 @param Package Points to the package referred to by the
1773 notification Handle The handle of the package
1774 list which contains the specified package.
1775
1776 @param Handle The HII handle.
1777
1778 @param NotifyType The type of change concerning the
1779 database. See
1780 EFI_HII_DATABASE_NOTIFY_TYPE.
1781
1782 **/
1783 EFI_STATUS
1784 EFIAPI
1785 FormUpdateNotify (
1786 IN UINT8 PackageType,
1787 IN CONST EFI_GUID *PackageGuid,
1788 IN CONST EFI_HII_PACKAGE_HEADER *Package,
1789 IN EFI_HII_HANDLE Handle,
1790 IN EFI_HII_DATABASE_NOTIFY_TYPE NotifyType
1791 )
1792 {
1793 mHiiPackageListUpdated = TRUE;
1794
1795 return EFI_SUCCESS;
1796 }
1797
1798 /**
1799 Update the NV flag info for this form set.
1800
1801 @param FormSet FormSet data structure.
1802
1803 **/
1804 BOOLEAN
1805 IsNvUpdateRequiredForFormSet (
1806 IN FORM_BROWSER_FORMSET *FormSet
1807 )
1808 {
1809 LIST_ENTRY *Link;
1810 FORM_BROWSER_FORM *Form;
1811 BOOLEAN RetVal;
1812
1813 //
1814 // Not finished question initialization, return FALSE.
1815 //
1816 if (!FormSet->QuestionInited) {
1817 return FALSE;
1818 }
1819
1820 RetVal = FALSE;
1821
1822 Link = GetFirstNode (&FormSet->FormListHead);
1823 while (!IsNull (&FormSet->FormListHead, Link)) {
1824 Form = FORM_BROWSER_FORM_FROM_LINK (Link);
1825
1826 RetVal = IsNvUpdateRequiredForForm(Form);
1827 if (RetVal) {
1828 break;
1829 }
1830
1831 Link = GetNextNode (&FormSet->FormListHead, Link);
1832 }
1833
1834 return RetVal;
1835 }
1836
1837 /**
1838 Update the NvUpdateRequired flag for a form.
1839
1840 @param Form Form data structure.
1841
1842 **/
1843 BOOLEAN
1844 IsNvUpdateRequiredForForm (
1845 IN FORM_BROWSER_FORM *Form
1846 )
1847 {
1848 LIST_ENTRY *Link;
1849 FORM_BROWSER_STATEMENT *Statement;
1850
1851 Link = GetFirstNode (&Form->StatementListHead);
1852 while (!IsNull (&Form->StatementListHead, Link)) {
1853 Statement = FORM_BROWSER_STATEMENT_FROM_LINK (Link);
1854
1855 if (Statement->ValueChanged) {
1856 return TRUE;
1857 }
1858
1859 Link = GetNextNode (&Form->StatementListHead, Link);
1860 }
1861
1862 return FALSE;
1863 }
1864
1865 /**
1866 Check whether the storage data for current form set is changed.
1867
1868 @param FormSet FormSet data structure.
1869
1870 @retval TRUE Data is changed.
1871 @retval FALSE Data is not changed.
1872 **/
1873 BOOLEAN
1874 IsStorageDataChangedForFormSet (
1875 IN FORM_BROWSER_FORMSET *FormSet
1876 )
1877 {
1878 LIST_ENTRY *Link;
1879 FORMSET_STORAGE *Storage;
1880 BROWSER_STORAGE *BrowserStorage;
1881 CHAR16 *ConfigRespNew;
1882 CHAR16 *ConfigRespOld;
1883 BOOLEAN RetVal;
1884
1885 RetVal = FALSE;
1886 ConfigRespNew = NULL;
1887 ConfigRespOld = NULL;
1888
1889 //
1890 // Request current settings from Configuration Driver
1891 //
1892 Link = GetFirstNode (&FormSet->StorageListHead);
1893 while (!IsNull (&FormSet->StorageListHead, Link)) {
1894 Storage = FORMSET_STORAGE_FROM_LINK (Link);
1895 Link = GetNextNode (&FormSet->StorageListHead, Link);
1896
1897 BrowserStorage = Storage->BrowserStorage;
1898
1899 if (BrowserStorage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {
1900 continue;
1901 }
1902
1903 if (Storage->ElementCount == 0) {
1904 continue;
1905 }
1906
1907 StorageToConfigResp (BrowserStorage, &ConfigRespNew, Storage->ConfigRequest, TRUE);
1908 StorageToConfigResp (BrowserStorage, &ConfigRespOld, Storage->ConfigRequest, FALSE);
1909 ASSERT (ConfigRespNew != NULL && ConfigRespOld != NULL);
1910
1911 if (StrCmp (ConfigRespNew, ConfigRespOld) != 0) {
1912 RetVal = TRUE;
1913 }
1914
1915 FreePool (ConfigRespNew);
1916 ConfigRespNew = NULL;
1917
1918 FreePool (ConfigRespOld);
1919 ConfigRespOld = NULL;
1920
1921 if (RetVal) {
1922 break;
1923 }
1924 }
1925
1926 return RetVal;
1927 }
1928
1929 /**
1930 Find menu which will show next time.
1931
1932 @param Selection On input, Selection tell setup browser the information
1933 about the Selection, form and formset to be displayed.
1934 On output, Selection return the screen item that is selected
1935 by user.
1936 @param SettingLevel Input Settting level, if it is FormLevel, just exit current form.
1937 else, we need to exit current formset.
1938
1939 @retval TRUE Exit current form.
1940 @retval FALSE User press ESC and keep in current form.
1941 **/
1942 BOOLEAN
1943 FindNextMenu (
1944 IN OUT UI_MENU_SELECTION *Selection,
1945 IN BROWSER_SETTING_SCOPE SettingLevel
1946 )
1947 {
1948 FORM_ENTRY_INFO *CurrentMenu;
1949 FORM_ENTRY_INFO *ParentMenu;
1950 BROWSER_SETTING_SCOPE Scope;
1951
1952 CurrentMenu = Selection->CurrentMenu;
1953 ParentMenu = NULL;
1954 Scope = FormSetLevel;
1955
1956 if (CurrentMenu != NULL && (ParentMenu = UiFindParentMenu(CurrentMenu)) != NULL) {
1957 //
1958 // we have a parent, so go to the parent menu
1959 //
1960 if (CompareGuid (&CurrentMenu->FormSetGuid, &ParentMenu->FormSetGuid)) {
1961 if (SettingLevel == FormSetLevel) {
1962 //
1963 // Find a menu which has different formset guid with current.
1964 //
1965 while (CompareGuid (&CurrentMenu->FormSetGuid, &ParentMenu->FormSetGuid)) {
1966 CurrentMenu = ParentMenu;
1967 if ((ParentMenu = UiFindParentMenu(CurrentMenu)) == NULL) {
1968 break;
1969 }
1970 }
1971
1972 if (ParentMenu != NULL) {
1973 Scope = FormSetLevel;
1974 }
1975 } else {
1976 Scope = FormLevel;
1977 }
1978 } else {
1979 Scope = FormSetLevel;
1980 }
1981 }
1982
1983 //
1984 // Form Level Check whether the data is changed.
1985 //
1986 if ((gBrowserSettingScope == FormLevel && IsNvUpdateRequiredForForm (Selection->Form)) ||
1987 (gBrowserSettingScope == FormSetLevel && IsNvUpdateRequiredForFormSet(Selection->FormSet) && Scope == FormSetLevel)) {
1988 if (!ProcessChangedData(Selection, Scope)) {
1989 return FALSE;
1990 }
1991 }
1992
1993 if (ParentMenu != NULL) {
1994 //
1995 // ParentMenu is found. Then, go to it.
1996 //
1997 if (Scope == FormLevel) {
1998 Selection->Action = UI_ACTION_REFRESH_FORM;
1999 } else {
2000 Selection->Action = UI_ACTION_REFRESH_FORMSET;
2001 CopyMem (&Selection->FormSetGuid, &ParentMenu->FormSetGuid, sizeof (EFI_GUID));
2002 Selection->Handle = ParentMenu->HiiHandle;
2003 }
2004
2005 Selection->Statement = NULL;
2006
2007 Selection->FormId = ParentMenu->FormId;
2008 Selection->QuestionId = ParentMenu->QuestionId;
2009
2010 //
2011 // Clear highlight record for this menu
2012 //
2013 CurrentMenu->QuestionId = 0;
2014 return FALSE;
2015 }
2016
2017 //
2018 // Current in root page, exit the SendForm
2019 //
2020 Selection->Action = UI_ACTION_EXIT;
2021
2022 return TRUE;
2023 }
2024
2025 /**
2026 Call the call back function for the question and process the return action.
2027
2028 @param Selection On input, Selection tell setup browser the information
2029 about the Selection, form and formset to be displayed.
2030 On output, Selection return the screen item that is selected
2031 by user.
2032 @param FormSet The formset this question belong to.
2033 @param Form The form this question belong to.
2034 @param Question The Question which need to call.
2035 @param Action The action request.
2036 @param SkipSaveOrDiscard Whether skip save or discard action.
2037
2038 @retval EFI_SUCCESS The call back function excutes successfully.
2039 @return Other value if the call back function failed to excute.
2040 **/
2041 EFI_STATUS
2042 ProcessCallBackFunction (
2043 IN OUT UI_MENU_SELECTION *Selection,
2044 IN FORM_BROWSER_FORMSET *FormSet,
2045 IN FORM_BROWSER_FORM *Form,
2046 IN FORM_BROWSER_STATEMENT *Question,
2047 IN EFI_BROWSER_ACTION Action,
2048 IN BOOLEAN SkipSaveOrDiscard
2049 )
2050 {
2051 EFI_STATUS Status;
2052 EFI_BROWSER_ACTION_REQUEST ActionRequest;
2053 EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess;
2054 EFI_HII_VALUE *HiiValue;
2055 EFI_IFR_TYPE_VALUE *TypeValue;
2056 FORM_BROWSER_STATEMENT *Statement;
2057 BOOLEAN SubmitFormIsRequired;
2058 BOOLEAN DiscardFormIsRequired;
2059 BOOLEAN NeedExit;
2060 LIST_ENTRY *Link;
2061 BROWSER_SETTING_SCOPE SettingLevel;
2062 EFI_IFR_TYPE_VALUE BackUpValue;
2063 UINT8 *BackUpBuffer;
2064
2065 ConfigAccess = FormSet->ConfigAccess;
2066 SubmitFormIsRequired = FALSE;
2067 SettingLevel = FormSetLevel;
2068 DiscardFormIsRequired = FALSE;
2069 NeedExit = FALSE;
2070 Status = EFI_SUCCESS;
2071 ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;
2072 BackUpBuffer = NULL;
2073
2074 if (ConfigAccess == NULL) {
2075 return EFI_SUCCESS;
2076 }
2077
2078 Link = GetFirstNode (&Form->StatementListHead);
2079 while (!IsNull (&Form->StatementListHead, Link)) {
2080 Statement = FORM_BROWSER_STATEMENT_FROM_LINK (Link);
2081 Link = GetNextNode (&Form->StatementListHead, Link);
2082
2083 //
2084 // if Question != NULL, only process the question. Else, process all question in this form.
2085 //
2086 if ((Question != NULL) && (Statement != Question)) {
2087 continue;
2088 }
2089
2090 if ((Statement->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != EFI_IFR_FLAG_CALLBACK) {
2091 continue;
2092 }
2093
2094 //
2095 // Check whether Statement is disabled.
2096 //
2097 if (Statement->Expression != NULL) {
2098 if (EvaluateExpressionList(Statement->Expression, TRUE, FormSet, Form) == ExpressDisable) {
2099 continue;
2100 }
2101 }
2102
2103 HiiValue = &Statement->HiiValue;
2104 TypeValue = &HiiValue->Value;
2105 if (HiiValue->Type == EFI_IFR_TYPE_BUFFER) {
2106 //
2107 // For OrderedList, passing in the value buffer to Callback()
2108 //
2109 TypeValue = (EFI_IFR_TYPE_VALUE *) Statement->BufferValue;
2110 }
2111
2112 //
2113 // If EFI_BROWSER_ACTION_CHANGING type, back up the new question value.
2114 //
2115 if (Action == EFI_BROWSER_ACTION_CHANGING) {
2116 if (HiiValue->Type == EFI_IFR_TYPE_BUFFER) {
2117 BackUpBuffer = AllocateCopyPool(Statement->StorageWidth + sizeof(CHAR16), Statement->BufferValue);
2118 } else {
2119 CopyMem (&BackUpValue, &HiiValue->Value, sizeof (EFI_IFR_TYPE_VALUE));
2120 }
2121 }
2122
2123 ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;
2124 Status = ConfigAccess->Callback (
2125 ConfigAccess,
2126 Action,
2127 Statement->QuestionId,
2128 HiiValue->Type,
2129 TypeValue,
2130 &ActionRequest
2131 );
2132 if (!EFI_ERROR (Status)) {
2133 //
2134 // Only for EFI_BROWSER_ACTION_CHANGED need to handle this ActionRequest.
2135 //
2136 if (Action == EFI_BROWSER_ACTION_CHANGED) {
2137 switch (ActionRequest) {
2138 case EFI_BROWSER_ACTION_REQUEST_RESET:
2139 DiscardFormIsRequired = TRUE;
2140 gResetRequired = TRUE;
2141 NeedExit = TRUE;
2142 break;
2143
2144 case EFI_BROWSER_ACTION_REQUEST_SUBMIT:
2145 SubmitFormIsRequired = TRUE;
2146 NeedExit = TRUE;
2147 break;
2148
2149 case EFI_BROWSER_ACTION_REQUEST_EXIT:
2150 DiscardFormIsRequired = TRUE;
2151 NeedExit = TRUE;
2152 break;
2153
2154 case EFI_BROWSER_ACTION_REQUEST_FORM_SUBMIT_EXIT:
2155 SubmitFormIsRequired = TRUE;
2156 SettingLevel = FormLevel;
2157 NeedExit = TRUE;
2158 break;
2159
2160 case EFI_BROWSER_ACTION_REQUEST_FORM_DISCARD_EXIT:
2161 DiscardFormIsRequired = TRUE;
2162 SettingLevel = FormLevel;
2163 NeedExit = TRUE;
2164 break;
2165
2166 case EFI_BROWSER_ACTION_REQUEST_FORM_APPLY:
2167 SubmitFormIsRequired = TRUE;
2168 SettingLevel = FormLevel;
2169 break;
2170
2171 case EFI_BROWSER_ACTION_REQUEST_FORM_DISCARD:
2172 DiscardFormIsRequired = TRUE;
2173 SettingLevel = FormLevel;
2174 break;
2175
2176 default:
2177 break;
2178 }
2179 }
2180
2181 //
2182 // According the spec, return value from call back of "changing" and
2183 // "retrieve" should update to the question's temp buffer.
2184 //
2185 if (Action == EFI_BROWSER_ACTION_CHANGING || Action == EFI_BROWSER_ACTION_RETRIEVE) {
2186 SetQuestionValue(FormSet, Form, Statement, GetSetValueWithEditBuffer);
2187 }
2188 } else {
2189 //
2190 // If the callback returns EFI_UNSUPPORTED for EFI_BROWSER_ACTION_CHANGING,
2191 // then the browser will use the value passed to Callback() and ignore the
2192 // value returned by Callback().
2193 //
2194 if (Action == EFI_BROWSER_ACTION_CHANGING && Status == EFI_UNSUPPORTED) {
2195 if (HiiValue->Type == EFI_IFR_TYPE_BUFFER) {
2196 CopyMem (Statement->BufferValue, BackUpBuffer, Statement->StorageWidth + sizeof(CHAR16));
2197 } else {
2198 CopyMem (&HiiValue->Value, &BackUpValue, sizeof (EFI_IFR_TYPE_VALUE));
2199 }
2200
2201 SetQuestionValue(FormSet, Form, Statement, GetSetValueWithEditBuffer);
2202 }
2203
2204 //
2205 // According the spec, return fail from call back of "changing" and
2206 // "retrieve", should restore the question's value.
2207 //
2208 if ((Action == EFI_BROWSER_ACTION_CHANGING && Status != EFI_UNSUPPORTED) ||
2209 Action == EFI_BROWSER_ACTION_RETRIEVE) {
2210 GetQuestionValue(FormSet, Form, Statement, GetSetValueWithEditBuffer);
2211 }
2212
2213 if (Status == EFI_UNSUPPORTED) {
2214 //
2215 // If return EFI_UNSUPPORTED, also consider Hii driver suceess deal with it.
2216 //
2217 Status = EFI_SUCCESS;
2218 }
2219 }
2220
2221 if (BackUpBuffer != NULL) {
2222 FreePool (BackUpBuffer);
2223 }
2224 }
2225
2226 if (SubmitFormIsRequired && !SkipSaveOrDiscard) {
2227 SubmitForm (FormSet, Form, SettingLevel);
2228 }
2229
2230 if (DiscardFormIsRequired && !SkipSaveOrDiscard) {
2231 DiscardForm (FormSet, Form, SettingLevel);
2232 }
2233
2234 if (NeedExit) {
2235 FindNextMenu (Selection, SettingLevel);
2236 }
2237
2238 return Status;
2239 }
2240
2241 /**
2242 Call the retrieve type call back function for one question to get the initialize data.
2243
2244 This function only used when in the initialize stage, because in this stage, the
2245 Selection->Form is not ready. For other case, use the ProcessCallBackFunction instead.
2246
2247 @param ConfigAccess The config access protocol produced by the hii driver.
2248 @param Statement The Question which need to call.
2249
2250 @retval EFI_SUCCESS The call back function excutes successfully.
2251 @return Other value if the call back function failed to excute.
2252 **/
2253 EFI_STATUS
2254 ProcessRetrieveForQuestion (
2255 IN EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess,
2256 IN FORM_BROWSER_STATEMENT *Statement
2257 )
2258 {
2259 EFI_STATUS Status;
2260 EFI_BROWSER_ACTION_REQUEST ActionRequest;
2261 EFI_HII_VALUE *HiiValue;
2262 EFI_IFR_TYPE_VALUE *TypeValue;
2263
2264 Status = EFI_SUCCESS;
2265 ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;
2266
2267 if ((Statement->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != EFI_IFR_FLAG_CALLBACK) {
2268 return EFI_UNSUPPORTED;
2269 }
2270
2271 HiiValue = &Statement->HiiValue;
2272 TypeValue = &HiiValue->Value;
2273 if (HiiValue->Type == EFI_IFR_TYPE_BUFFER) {
2274 //
2275 // For OrderedList, passing in the value buffer to Callback()
2276 //
2277 TypeValue = (EFI_IFR_TYPE_VALUE *) Statement->BufferValue;
2278 }
2279
2280 ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;
2281 Status = ConfigAccess->Callback (
2282 ConfigAccess,
2283 EFI_BROWSER_ACTION_RETRIEVE,
2284 Statement->QuestionId,
2285 HiiValue->Type,
2286 TypeValue,
2287 &ActionRequest
2288 );
2289 return Status;
2290 }
2291
2292 /**
2293 The worker function that send the displays to the screen. On output,
2294 the selection made by user is returned.
2295
2296 @param Selection On input, Selection tell setup browser the information
2297 about the Selection, form and formset to be displayed.
2298 On output, Selection return the screen item that is selected
2299 by user.
2300
2301 @retval EFI_SUCCESS The page is displayed successfully.
2302 @return Other value if the page failed to be diplayed.
2303
2304 **/
2305 EFI_STATUS
2306 SetupBrowser (
2307 IN OUT UI_MENU_SELECTION *Selection
2308 )
2309 {
2310 EFI_STATUS Status;
2311 LIST_ENTRY *Link;
2312 EFI_HANDLE NotifyHandle;
2313 FORM_BROWSER_STATEMENT *Statement;
2314 EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess;
2315
2316 ConfigAccess = Selection->FormSet->ConfigAccess;
2317
2318 //
2319 // Register notify for Form package update
2320 //
2321 Status = mHiiDatabase->RegisterPackageNotify (
2322 mHiiDatabase,
2323 EFI_HII_PACKAGE_FORMS,
2324 NULL,
2325 FormUpdateNotify,
2326 EFI_HII_DATABASE_NOTIFY_REMOVE_PACK,
2327 &NotifyHandle
2328 );
2329 if (EFI_ERROR (Status)) {
2330 return Status;
2331 }
2332
2333 if ((Selection->Handle != mCurrentHiiHandle) ||
2334 (!CompareGuid (&Selection->FormSetGuid, &mCurrentFormSetGuid))) {
2335 gFinishRetrieveCall = FALSE;
2336 }
2337
2338 //
2339 // Initialize current settings of Questions in this FormSet
2340 //
2341 InitializeCurrentSetting (Selection->FormSet);
2342
2343 //
2344 // Initilize Action field.
2345 //
2346 Selection->Action = UI_ACTION_REFRESH_FORM;
2347
2348 //
2349 // Clean the mCurFakeQestId value is formset refreshed.
2350 //
2351 mCurFakeQestId = 0;
2352
2353 do {
2354 //
2355 // IFR is updated, force to reparse the IFR binary
2356 //
2357 if (mHiiPackageListUpdated) {
2358 Selection->Action = UI_ACTION_REFRESH_FORMSET;
2359 mHiiPackageListUpdated = FALSE;
2360 break;
2361 }
2362
2363 //
2364 // Initialize Selection->Form
2365 //
2366 if (Selection->FormId == 0) {
2367 //
2368 // Zero FormId indicates display the first Form in a FormSet
2369 //
2370 Link = GetFirstNode (&Selection->FormSet->FormListHead);
2371
2372 Selection->Form = FORM_BROWSER_FORM_FROM_LINK (Link);
2373 Selection->FormId = Selection->Form->FormId;
2374 } else {
2375 Selection->Form = IdToForm (Selection->FormSet, Selection->FormId);
2376 }
2377
2378 if (Selection->Form == NULL) {
2379 //
2380 // No Form to display
2381 //
2382 Status = EFI_NOT_FOUND;
2383 goto Done;
2384 }
2385
2386 //
2387 // Check Form is suppressed.
2388 //
2389 if (Selection->Form->SuppressExpression != NULL) {
2390 if (EvaluateExpressionList(Selection->Form->SuppressExpression, TRUE, Selection->FormSet, Selection->Form) == ExpressSuppress) {
2391 //
2392 // Form is suppressed.
2393 //
2394 gBrowserStatus = BROWSER_FORM_SUPPRESS;
2395 Status = EFI_NOT_FOUND;
2396 goto Done;
2397 }
2398 }
2399
2400 //
2401 // Before display new form, invoke ConfigAccess.Callback() with EFI_BROWSER_ACTION_FORM_OPEN
2402 // for each question with callback flag.
2403 // New form may be the first form, or the different form after another form close.
2404 //
2405 if ((ConfigAccess != NULL) &&
2406 ((Selection->Handle != mCurrentHiiHandle) ||
2407 (!CompareGuid (&Selection->FormSetGuid, &mCurrentFormSetGuid)) ||
2408 (Selection->FormId != mCurrentFormId))) {
2409 //
2410 // Keep current form information
2411 //
2412 mCurrentHiiHandle = Selection->Handle;
2413 CopyGuid (&mCurrentFormSetGuid, &Selection->FormSetGuid);
2414 mCurrentFormId = Selection->FormId;
2415
2416 Status = ProcessCallBackFunction (Selection, gCurrentSelection->FormSet, Selection->Form, NULL, EFI_BROWSER_ACTION_FORM_OPEN, FALSE);
2417 if (EFI_ERROR (Status)) {
2418 goto Done;
2419 }
2420
2421 //
2422 // IFR is updated during callback of open form, force to reparse the IFR binary
2423 //
2424 if (mHiiPackageListUpdated) {
2425 Selection->Action = UI_ACTION_REFRESH_FORMSET;
2426 mHiiPackageListUpdated = FALSE;
2427 break;
2428 }
2429 }
2430
2431 //
2432 // Load Questions' Value for display
2433 //
2434 Status = LoadFormSetConfig (Selection, Selection->FormSet);
2435 if (EFI_ERROR (Status)) {
2436 goto Done;
2437 }
2438
2439 //
2440 // Finish call RETRIEVE callback for this formset.
2441 //
2442 gFinishRetrieveCall = TRUE;
2443
2444 //
2445 // IFR is updated during callback of read value, force to reparse the IFR binary
2446 //
2447 if (mHiiPackageListUpdated) {
2448 Selection->Action = UI_ACTION_REFRESH_FORMSET;
2449 mHiiPackageListUpdated = FALSE;
2450 break;
2451 }
2452
2453 //
2454 // Display form
2455 //
2456 Status = DisplayForm ();
2457 if (EFI_ERROR (Status)) {
2458 goto Done;
2459 }
2460
2461 //
2462 // Check Selected Statement (if press ESC, Selection->Statement will be NULL)
2463 //
2464 Statement = Selection->Statement;
2465 if (Statement != NULL) {
2466 if ((ConfigAccess != NULL) &&
2467 ((Statement->QuestionFlags & EFI_IFR_FLAG_CALLBACK) == EFI_IFR_FLAG_CALLBACK) &&
2468 (Statement->Operand != EFI_IFR_PASSWORD_OP)) {
2469 Status = ProcessCallBackFunction(Selection, Selection->FormSet, Selection->Form, Statement, EFI_BROWSER_ACTION_CHANGING, FALSE);
2470 if (Statement->Operand == EFI_IFR_REF_OP) {
2471 //
2472 // Process dynamic update ref opcode.
2473 //
2474 if (!EFI_ERROR (Status)) {
2475 Status = ProcessGotoOpCode(Statement, Selection);
2476 }
2477
2478 //
2479 // Callback return error status or status return from process goto opcode.
2480 //
2481 if (EFI_ERROR (Status)) {
2482 //
2483 // Cross reference will not be taken
2484 //
2485 Selection->FormId = Selection->Form->FormId;
2486 Selection->QuestionId = 0;
2487 }
2488 }
2489
2490 if (!EFI_ERROR (Status) && Statement->Operand != EFI_IFR_REF_OP) {
2491 ProcessCallBackFunction(Selection, Selection->FormSet, Selection->Form, Statement, EFI_BROWSER_ACTION_CHANGED, FALSE);
2492 }
2493 } else if (Statement->Operand != EFI_IFR_PASSWORD_OP) {
2494 SetQuestionValue (gCurrentSelection->FormSet, gCurrentSelection->Form, Statement, GetSetValueWithEditBuffer);
2495 }
2496 }
2497
2498 //
2499 // Check whether Exit flag is TRUE.
2500 //
2501 if (gExitRequired) {
2502 switch (gBrowserSettingScope) {
2503 case SystemLevel:
2504 Selection->Action = UI_ACTION_EXIT;
2505 break;
2506
2507 case FormSetLevel:
2508 case FormLevel:
2509 FindNextMenu (Selection, gBrowserSettingScope);
2510 break;
2511
2512 default:
2513 break;
2514 }
2515
2516 gExitRequired = FALSE;
2517 }
2518
2519 //
2520 // Before exit the form, invoke ConfigAccess.Callback() with EFI_BROWSER_ACTION_FORM_CLOSE
2521 // for each question with callback flag.
2522 //
2523 if ((ConfigAccess != NULL) &&
2524 ((Selection->Action == UI_ACTION_EXIT) ||
2525 (Selection->Handle != mCurrentHiiHandle) ||
2526 (!CompareGuid (&Selection->FormSetGuid, &mCurrentFormSetGuid)) ||
2527 (Selection->FormId != mCurrentFormId))) {
2528
2529 Status = ProcessCallBackFunction (Selection, Selection->FormSet, Selection->Form, NULL, EFI_BROWSER_ACTION_FORM_CLOSE, FALSE);
2530 if (EFI_ERROR (Status)) {
2531 goto Done;
2532 }
2533 }
2534 } while (Selection->Action == UI_ACTION_REFRESH_FORM);
2535
2536 Done:
2537 //
2538 // Reset current form information to the initial setting when error happens or form exit.
2539 //
2540 if (EFI_ERROR (Status) || Selection->Action == UI_ACTION_EXIT) {
2541 mCurrentHiiHandle = NULL;
2542 CopyGuid (&mCurrentFormSetGuid, &gZeroGuid);
2543 mCurrentFormId = 0;
2544 }
2545
2546 //
2547 // Unregister notify for Form package update
2548 //
2549 mHiiDatabase->UnregisterPackageNotify (
2550 mHiiDatabase,
2551 NotifyHandle
2552 );
2553 return Status;
2554 }