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