]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/SetupBrowserDxe/Presentation.c
Refine question value update logic.
[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, Statement, EFI_BROWSER_ACTION_CHANGING, 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 @param HostDisplayStatement Pointer to the display Statement data strucure which is an host statement.
391 **/
392 VOID
393 InitializeDisplayStatement (
394 IN OUT FORM_DISPLAY_ENGINE_STATEMENT *DisplayStatement,
395 IN FORM_BROWSER_STATEMENT *Statement,
396 IN FORM_DISPLAY_ENGINE_STATEMENT *HostDisplayStatement
397 )
398 {
399 LIST_ENTRY *Link;
400 QUESTION_OPTION *Option;
401 DISPLAY_QUESTION_OPTION *DisplayOption;
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->InSubtitle) {
506 InsertTailList(&HostDisplayStatement->NestStatementList, &DisplayStatement->DisplayLink);
507 } else {
508 InsertTailList(&gDisplayFormData.StatementListHead, &DisplayStatement->DisplayLink);
509 }
510 }
511
512 /**
513 Process for the refresh interval statement.
514
515 @param Event The Event need to be process
516 @param Context The context of the event.
517
518 **/
519 VOID
520 EFIAPI
521 RefreshIntervalProcess (
522 IN EFI_EVENT Event,
523 IN VOID *Context
524 )
525 {
526 FORM_BROWSER_STATEMENT *Statement;
527 LIST_ENTRY *Link;
528
529 Link = GetFirstNode (&gCurrentSelection->Form->StatementListHead);
530 while (!IsNull (&gCurrentSelection->Form->StatementListHead, Link)) {
531 Statement = FORM_BROWSER_STATEMENT_FROM_LINK (Link);
532 Link = GetNextNode (&gCurrentSelection->Form->StatementListHead, Link);
533
534 if (Statement->RefreshInterval == 0) {
535 continue;
536 }
537
538 UpdateStatement(Statement);
539 }
540
541 gBS->SignalEvent (mValueChangedEvent);
542 }
543
544 /**
545
546 Make a copy of the global hotkey info.
547
548 **/
549 VOID
550 UpdateHotkeyList (
551 VOID
552 )
553 {
554 BROWSER_HOT_KEY *HotKey;
555 BROWSER_HOT_KEY *CopyKey;
556 LIST_ENTRY *Link;
557
558 Link = GetFirstNode (&gBrowserHotKeyList);
559 while (!IsNull (&gBrowserHotKeyList, Link)) {
560 HotKey = BROWSER_HOT_KEY_FROM_LINK (Link);
561
562 CopyKey = AllocateCopyPool(sizeof (BROWSER_HOT_KEY), HotKey);
563 CopyKey->KeyData = AllocateCopyPool(sizeof (EFI_INPUT_KEY), HotKey->KeyData);
564 CopyKey->HelpString = AllocateCopyPool(StrSize (HotKey->HelpString), HotKey->HelpString);
565
566 InsertTailList(&gDisplayFormData.HotKeyListHead, &CopyKey->Link);
567
568 Link = GetNextNode (&gBrowserHotKeyList, Link);
569 }
570 }
571
572 /**
573
574 Enum all statement in current form, find all the statement can be display and
575 add to the display form.
576
577 **/
578 VOID
579 AddStatementToDisplayForm (
580 VOID
581 )
582 {
583 EFI_STATUS Status;
584 LIST_ENTRY *Link;
585 FORM_BROWSER_STATEMENT *Statement;
586 FORM_DISPLAY_ENGINE_STATEMENT *DisplayStatement;
587 FORM_DISPLAY_ENGINE_STATEMENT *HostDisplayStatement;
588 UINT8 MinRefreshInterval;
589 EFI_EVENT RefreshIntervalEvent;
590 FORM_BROWSER_REFRESH_EVENT_NODE *EventNode;
591 BOOLEAN FormEditable;
592
593 HostDisplayStatement = NULL;
594 MinRefreshInterval = 0;
595 FormEditable = FALSE;
596
597 //
598 // Process the statement outside the form, these statements are not recognized
599 // by browser core.
600 //
601 Link = GetFirstNode (&gCurrentSelection->FormSet->StatementListOSF);
602 while (!IsNull (&gCurrentSelection->FormSet->StatementListOSF, Link)) {
603 Statement = FORM_BROWSER_STATEMENT_FROM_LINK (Link);
604 Link = GetNextNode (&gCurrentSelection->FormSet->StatementListOSF, Link);
605
606 DisplayStatement = AllocateZeroPool (sizeof (FORM_DISPLAY_ENGINE_STATEMENT));
607 ASSERT (DisplayStatement != NULL);
608 DisplayStatement->Signature = FORM_DISPLAY_ENGINE_STATEMENT_SIGNATURE;
609 DisplayStatement->Version = FORM_DISPLAY_ENGINE_STATEMENT_VERSION_1;
610 DisplayStatement->OpCode = Statement->OpCode;
611
612 InitializeListHead (&DisplayStatement->NestStatementList);
613 InitializeListHead (&DisplayStatement->OptionListHead);
614
615 InsertTailList(&gDisplayFormData.StatementListOSF, &DisplayStatement->DisplayLink);
616 }
617
618 //
619 // Process the statement in this form.
620 //
621 Link = GetFirstNode (&gCurrentSelection->Form->StatementListHead);
622 while (!IsNull (&gCurrentSelection->Form->StatementListHead, Link)) {
623 Statement = FORM_BROWSER_STATEMENT_FROM_LINK (Link);
624 Link = GetNextNode (&gCurrentSelection->Form->StatementListHead, Link);
625
626 //
627 // This statement can't be show, skip it.
628 //
629 if (EvaluateExpressionList(Statement->Expression, FALSE, NULL, NULL) > ExpressGrayOut) {
630 continue;
631 }
632
633 DisplayStatement = AllocateZeroPool (sizeof (FORM_DISPLAY_ENGINE_STATEMENT));
634 ASSERT (DisplayStatement != NULL);
635
636 //
637 // Initialize this statement and add it to the display form.
638 //
639 InitializeDisplayStatement(DisplayStatement, Statement, HostDisplayStatement);
640
641 //
642 // Save the Host statement info.
643 // Host statement may has nest statement follow it.
644 //
645 if (!Statement->InSubtitle) {
646 HostDisplayStatement = DisplayStatement;
647 }
648
649 if (Statement->Storage != NULL) {
650 FormEditable = TRUE;
651 }
652
653 //
654 // Get the minimal refresh interval value for later use.
655 //
656 if ((Statement->RefreshInterval != 0) &&
657 (MinRefreshInterval == 0 || Statement->RefreshInterval < MinRefreshInterval)) {
658 MinRefreshInterval = Statement->RefreshInterval;
659 }
660 }
661
662 //
663 // Create the periodic timer for refresh interval statement.
664 //
665 if (MinRefreshInterval != 0) {
666 Status = gBS->CreateEvent (EVT_TIMER | EVT_NOTIFY_SIGNAL, TPL_CALLBACK, RefreshIntervalProcess, NULL, &RefreshIntervalEvent);
667 ASSERT_EFI_ERROR (Status);
668 Status = gBS->SetTimer (RefreshIntervalEvent, TimerPeriodic, MinRefreshInterval * ONE_SECOND);
669 ASSERT_EFI_ERROR (Status);
670
671 EventNode = AllocateZeroPool (sizeof (FORM_BROWSER_REFRESH_EVENT_NODE));
672 ASSERT (EventNode != NULL);
673 EventNode->RefreshEvent = RefreshIntervalEvent;
674 InsertTailList(&mRefreshEventList, &EventNode->Link);
675 }
676
677 //
678 // Update hotkey list field.
679 //
680 if (gBrowserSettingScope == SystemLevel || FormEditable) {
681 UpdateHotkeyList();
682 }
683 }
684
685 /**
686
687 Initialize the SettingChangedFlag variable in the display form.
688
689 **/
690 VOID
691 UpdateDataChangedFlag (
692 VOID
693 )
694 {
695 LIST_ENTRY *Link;
696 FORM_BROWSER_FORMSET *LocalFormSet;
697
698 gDisplayFormData.SettingChangedFlag = FALSE;
699
700 if (IsNvUpdateRequiredForForm (gCurrentSelection->Form)) {
701 gDisplayFormData.SettingChangedFlag = TRUE;
702 return;
703 }
704
705 //
706 // Base on the system level to check whether need to show the NV flag.
707 //
708 switch (gBrowserSettingScope) {
709 case SystemLevel:
710 //
711 // Check the maintain list to see whether there is any change.
712 //
713 Link = GetFirstNode (&gBrowserFormSetList);
714 while (!IsNull (&gBrowserFormSetList, Link)) {
715 LocalFormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link);
716 if (IsNvUpdateRequiredForFormSet(LocalFormSet)) {
717 gDisplayFormData.SettingChangedFlag = TRUE;
718 return;
719 }
720 Link = GetNextNode (&gBrowserFormSetList, Link);
721 }
722 break;
723
724 case FormSetLevel:
725 if (IsNvUpdateRequiredForFormSet(gCurrentSelection->FormSet)) {
726 gDisplayFormData.SettingChangedFlag = TRUE;
727 return;
728 }
729 break;
730
731 default:
732 break;
733 }
734 }
735
736 /**
737
738 Initialize the Display form structure data.
739
740 **/
741 VOID
742 InitializeDisplayFormData (
743 VOID
744 )
745 {
746 EFI_STATUS Status;
747
748 gDisplayFormData.Signature = FORM_DISPLAY_ENGINE_FORM_SIGNATURE;
749 gDisplayFormData.Version = FORM_DISPLAY_ENGINE_VERSION_1;
750 gDisplayFormData.ImageId = 0;
751 gDisplayFormData.AnimationId = 0;
752
753 InitializeListHead (&gDisplayFormData.StatementListHead);
754 InitializeListHead (&gDisplayFormData.StatementListOSF);
755 InitializeListHead (&gDisplayFormData.HotKeyListHead);
756
757 Status = gBS->CreateEvent (
758 EVT_NOTIFY_WAIT,
759 TPL_CALLBACK,
760 SetupBrowserEmptyFunction,
761 NULL,
762 &mValueChangedEvent
763 );
764 ASSERT_EFI_ERROR (Status);
765 }
766
767 /**
768
769 Free the kotkey info saved in form data.
770
771 **/
772 VOID
773 FreeHotkeyList (
774 VOID
775 )
776 {
777 BROWSER_HOT_KEY *HotKey;
778 LIST_ENTRY *Link;
779
780 while (!IsListEmpty (&gDisplayFormData.HotKeyListHead)) {
781 Link = GetFirstNode (&gDisplayFormData.HotKeyListHead);
782 HotKey = BROWSER_HOT_KEY_FROM_LINK (Link);
783
784 RemoveEntryList (&HotKey->Link);
785
786 FreePool (HotKey->KeyData);
787 FreePool (HotKey->HelpString);
788 FreePool (HotKey);
789 }
790 }
791
792 /**
793
794 Update the Display form structure data.
795
796 **/
797 VOID
798 UpdateDisplayFormData (
799 VOID
800 )
801 {
802 gDisplayFormData.FormTitle = gCurrentSelection->Form->FormTitle;
803 gDisplayFormData.FormId = gCurrentSelection->FormId;
804 gDisplayFormData.HiiHandle = gCurrentSelection->Handle;
805 CopyGuid (&gDisplayFormData.FormSetGuid, &gCurrentSelection->FormSetGuid);
806
807 gDisplayFormData.Attribute = 0;
808 gDisplayFormData.Attribute |= gCurrentSelection->Form->ModalForm ? HII_DISPLAY_MODAL : 0;
809 gDisplayFormData.Attribute |= gCurrentSelection->Form->Locked ? HII_DISPLAY_LOCK : 0;
810
811 gDisplayFormData.FormRefreshEvent = NULL;
812 gDisplayFormData.HighLightedStatement = NULL;
813
814 gDisplayFormData.BrowserStatus = gBrowserStatus;
815 gDisplayFormData.ErrorString = gErrorInfo;
816
817 gBrowserStatus = BROWSER_SUCCESS;
818 gErrorInfo = NULL;
819
820 UpdateDataChangedFlag ();
821
822 AddStatementToDisplayForm ();
823 }
824
825 /**
826
827 Free the Display Statement structure data.
828
829 @param StatementList Point to the statement list which need to be free.
830
831 **/
832 VOID
833 FreeStatementData (
834 LIST_ENTRY *StatementList
835 )
836 {
837 LIST_ENTRY *Link;
838 LIST_ENTRY *OptionLink;
839 FORM_DISPLAY_ENGINE_STATEMENT *Statement;
840 DISPLAY_QUESTION_OPTION *Option;
841
842 //
843 // Free Statements/Questions
844 //
845 while (!IsListEmpty (StatementList)) {
846 Link = GetFirstNode (StatementList);
847 Statement = FORM_DISPLAY_ENGINE_STATEMENT_FROM_LINK (Link);
848
849 //
850 // Free Options List
851 //
852 while (!IsListEmpty (&Statement->OptionListHead)) {
853 OptionLink = GetFirstNode (&Statement->OptionListHead);
854 Option = DISPLAY_QUESTION_OPTION_FROM_LINK (OptionLink);
855 RemoveEntryList (&Option->Link);
856 FreePool (Option);
857 }
858
859 //
860 // Free nest statement List
861 //
862 if (!IsListEmpty (&Statement->NestStatementList)) {
863 FreeStatementData(&Statement->NestStatementList);
864 }
865
866 RemoveEntryList (&Statement->DisplayLink);
867 FreePool (Statement);
868 }
869 }
870
871 /**
872
873 Free the Display form structure data.
874
875 **/
876 VOID
877 FreeDisplayFormData (
878 VOID
879 )
880 {
881 FreeStatementData (&gDisplayFormData.StatementListHead);
882 FreeStatementData (&gDisplayFormData.StatementListOSF);
883
884 FreeRefreshEvent();
885
886 FreeHotkeyList();
887 }
888
889 /**
890
891 Get FORM_BROWSER_STATEMENT from FORM_DISPLAY_ENGINE_STATEMENT based on the OpCode info.
892
893 @param DisplayStatement The input FORM_DISPLAY_ENGINE_STATEMENT.
894
895 @retval FORM_BROWSER_STATEMENT The return FORM_BROWSER_STATEMENT info.
896
897 **/
898 FORM_BROWSER_STATEMENT *
899 GetBrowserStatement (
900 IN FORM_DISPLAY_ENGINE_STATEMENT *DisplayStatement
901 )
902 {
903 FORM_BROWSER_STATEMENT *Statement;
904 LIST_ENTRY *Link;
905
906 Link = GetFirstNode (&gCurrentSelection->Form->StatementListHead);
907 while (!IsNull (&gCurrentSelection->Form->StatementListHead, Link)) {
908 Statement = FORM_BROWSER_STATEMENT_FROM_LINK (Link);
909
910 if (Statement->OpCode == DisplayStatement->OpCode) {
911 return Statement;
912 }
913
914 Link = GetNextNode (&gCurrentSelection->Form->StatementListHead, Link);
915 }
916
917 return NULL;
918 }
919
920 /**
921
922 Process the action request in user input.
923
924 @param Action The user input action request info.
925 @param DefaultId The user input default Id info.
926
927 @retval EFI_SUCESSS This function always return successfully for now.
928
929 **/
930 EFI_STATUS
931 ProcessAction (
932 IN UINT32 Action,
933 IN UINT16 DefaultId
934 )
935 {
936 EFI_STATUS Status;
937
938 //
939 // This is caused by use press ESC, and it should not combine with other action type.
940 //
941 if ((Action & BROWSER_ACTION_FORM_EXIT) == BROWSER_ACTION_FORM_EXIT) {
942 FindNextMenu (gCurrentSelection, FormLevel);
943 return EFI_SUCCESS;
944 }
945
946 //
947 // Below is normal hotkey trigged action, these action maybe combine with each other.
948 //
949 if ((Action & BROWSER_ACTION_DISCARD) == BROWSER_ACTION_DISCARD) {
950 DiscardForm (gCurrentSelection->FormSet, gCurrentSelection->Form, gBrowserSettingScope);
951 }
952
953 if ((Action & BROWSER_ACTION_DEFAULT) == BROWSER_ACTION_DEFAULT) {
954 ExtractDefault (gCurrentSelection->FormSet, gCurrentSelection->Form, DefaultId, gBrowserSettingScope, GetDefaultForAll, NULL, FALSE);
955 }
956
957 if ((Action & BROWSER_ACTION_SUBMIT) == BROWSER_ACTION_SUBMIT) {
958 Status = SubmitForm (gCurrentSelection->FormSet, gCurrentSelection->Form, gBrowserSettingScope);
959 if (EFI_ERROR (Status)) {
960 gBrowserStatus = BROWSER_SUBMIT_FAIL;
961 }
962 }
963
964 if ((Action & BROWSER_ACTION_RESET) == BROWSER_ACTION_RESET) {
965 gResetRequired = TRUE;
966 }
967
968 if ((Action & BROWSER_ACTION_EXIT) == BROWSER_ACTION_EXIT) {
969 //
970 // Form Exit without saving, Similar to ESC Key.
971 // FormSet Exit without saving, Exit SendForm.
972 // System Exit without saving, CallExitHandler and Exit SendForm.
973 //
974 DiscardForm (gCurrentSelection->FormSet, gCurrentSelection->Form, gBrowserSettingScope);
975 if (gBrowserSettingScope == FormLevel || gBrowserSettingScope == FormSetLevel) {
976 FindNextMenu (gCurrentSelection, gBrowserSettingScope);
977 } else if (gBrowserSettingScope == SystemLevel) {
978 if (ExitHandlerFunction != NULL) {
979 ExitHandlerFunction ();
980 }
981 gCurrentSelection->Action = UI_ACTION_EXIT;
982 }
983 }
984
985 return EFI_SUCCESS;
986 }
987
988
989 /**
990 Find HII Handle in the HII database associated with given Device Path.
991
992 If DevicePath is NULL, then ASSERT.
993
994 @param DevicePath Device Path associated with the HII package list
995 handle.
996
997 @retval Handle HII package list Handle associated with the Device
998 Path.
999 @retval NULL Hii Package list handle is not found.
1000
1001 **/
1002 EFI_HII_HANDLE
1003 EFIAPI
1004 DevicePathToHiiHandle (
1005 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
1006 )
1007 {
1008 EFI_STATUS Status;
1009 EFI_DEVICE_PATH_PROTOCOL *TmpDevicePath;
1010 UINTN BufferSize;
1011 UINTN HandleCount;
1012 UINTN Index;
1013 EFI_HANDLE Handle;
1014 EFI_HANDLE DriverHandle;
1015 EFI_HII_HANDLE *HiiHandles;
1016 EFI_HII_HANDLE HiiHandle;
1017
1018 ASSERT (DevicePath != NULL);
1019
1020 TmpDevicePath = DevicePath;
1021 //
1022 // Locate Device Path Protocol handle buffer
1023 //
1024 Status = gBS->LocateDevicePath (
1025 &gEfiDevicePathProtocolGuid,
1026 &TmpDevicePath,
1027 &DriverHandle
1028 );
1029 if (EFI_ERROR (Status) || !IsDevicePathEnd (TmpDevicePath)) {
1030 return NULL;
1031 }
1032
1033 //
1034 // Retrieve all HII Handles from HII database
1035 //
1036 BufferSize = 0x1000;
1037 HiiHandles = AllocatePool (BufferSize);
1038 ASSERT (HiiHandles != NULL);
1039 Status = mHiiDatabase->ListPackageLists (
1040 mHiiDatabase,
1041 EFI_HII_PACKAGE_TYPE_ALL,
1042 NULL,
1043 &BufferSize,
1044 HiiHandles
1045 );
1046 if (Status == EFI_BUFFER_TOO_SMALL) {
1047 FreePool (HiiHandles);
1048 HiiHandles = AllocatePool (BufferSize);
1049 ASSERT (HiiHandles != NULL);
1050
1051 Status = mHiiDatabase->ListPackageLists (
1052 mHiiDatabase,
1053 EFI_HII_PACKAGE_TYPE_ALL,
1054 NULL,
1055 &BufferSize,
1056 HiiHandles
1057 );
1058 }
1059
1060 if (EFI_ERROR (Status)) {
1061 FreePool (HiiHandles);
1062 return NULL;
1063 }
1064
1065 //
1066 // Search Hii Handle by Driver Handle
1067 //
1068 HiiHandle = NULL;
1069 HandleCount = BufferSize / sizeof (EFI_HII_HANDLE);
1070 for (Index = 0; Index < HandleCount; Index++) {
1071 Status = mHiiDatabase->GetPackageListHandle (
1072 mHiiDatabase,
1073 HiiHandles[Index],
1074 &Handle
1075 );
1076 if (!EFI_ERROR (Status) && (Handle == DriverHandle)) {
1077 HiiHandle = HiiHandles[Index];
1078 break;
1079 }
1080 }
1081
1082 FreePool (HiiHandles);
1083 return HiiHandle;
1084 }
1085
1086 /**
1087 Find HII Handle in the HII database associated with given form set guid.
1088
1089 If FormSetGuid is NULL, then ASSERT.
1090
1091 @param ComparingGuid FormSet Guid associated with the HII package list
1092 handle.
1093
1094 @retval Handle HII package list Handle associated with the Device
1095 Path.
1096 @retval NULL Hii Package list handle is not found.
1097
1098 **/
1099 EFI_HII_HANDLE
1100 FormSetGuidToHiiHandle (
1101 EFI_GUID *ComparingGuid
1102 )
1103 {
1104 EFI_HII_HANDLE *HiiHandles;
1105 UINTN Index;
1106 EFI_HII_PACKAGE_LIST_HEADER *HiiPackageList;
1107 UINTN BufferSize;
1108 UINT32 Offset;
1109 UINT32 Offset2;
1110 UINT32 PackageListLength;
1111 EFI_HII_PACKAGE_HEADER PackageHeader;
1112 UINT8 *Package;
1113 UINT8 *OpCodeData;
1114 EFI_STATUS Status;
1115 EFI_HII_HANDLE HiiHandle;
1116
1117 ASSERT (ComparingGuid != NULL);
1118
1119 HiiHandle = NULL;
1120 //
1121 // Get all the Hii handles
1122 //
1123 HiiHandles = HiiGetHiiHandles (NULL);
1124 ASSERT (HiiHandles != NULL);
1125
1126 //
1127 // Search for formset of each class type
1128 //
1129 for (Index = 0; HiiHandles[Index] != NULL; Index++) {
1130 BufferSize = 0;
1131 HiiPackageList = NULL;
1132 Status = mHiiDatabase->ExportPackageLists (mHiiDatabase, HiiHandles[Index], &BufferSize, HiiPackageList);
1133 if (Status == EFI_BUFFER_TOO_SMALL) {
1134 HiiPackageList = AllocatePool (BufferSize);
1135 ASSERT (HiiPackageList != NULL);
1136
1137 Status = mHiiDatabase->ExportPackageLists (mHiiDatabase, HiiHandles[Index], &BufferSize, HiiPackageList);
1138 }
1139 if (EFI_ERROR (Status) || HiiPackageList == NULL) {
1140 return NULL;
1141 }
1142
1143 //
1144 // Get Form package from this HII package List
1145 //
1146 Offset = sizeof (EFI_HII_PACKAGE_LIST_HEADER);
1147 Offset2 = 0;
1148 CopyMem (&PackageListLength, &HiiPackageList->PackageLength, sizeof (UINT32));
1149
1150 while (Offset < PackageListLength) {
1151 Package = ((UINT8 *) HiiPackageList) + Offset;
1152 CopyMem (&PackageHeader, Package, sizeof (EFI_HII_PACKAGE_HEADER));
1153
1154 if (PackageHeader.Type == EFI_HII_PACKAGE_FORMS) {
1155 //
1156 // Search FormSet in this Form Package
1157 //
1158 Offset2 = sizeof (EFI_HII_PACKAGE_HEADER);
1159 while (Offset2 < PackageHeader.Length) {
1160 OpCodeData = Package + Offset2;
1161
1162 if (((EFI_IFR_OP_HEADER *) OpCodeData)->OpCode == EFI_IFR_FORM_SET_OP) {
1163 //
1164 // Try to compare against formset GUID
1165 //
1166 if (CompareGuid (ComparingGuid, (EFI_GUID *)(OpCodeData + sizeof (EFI_IFR_OP_HEADER)))) {
1167 HiiHandle = HiiHandles[Index];
1168 break;
1169 }
1170 }
1171
1172 Offset2 += ((EFI_IFR_OP_HEADER *) OpCodeData)->Length;
1173 }
1174 }
1175 if (HiiHandle != NULL) {
1176 break;
1177 }
1178 Offset += PackageHeader.Length;
1179 }
1180
1181 FreePool (HiiPackageList);
1182 if (HiiHandle != NULL) {
1183 break;
1184 }
1185 }
1186
1187 FreePool (HiiHandles);
1188
1189 return HiiHandle;
1190 }
1191
1192 /**
1193 check how to process the changed data in current form or form set.
1194
1195 @param Selection On input, Selection tell setup browser the information
1196 about the Selection, form and formset to be displayed.
1197 On output, Selection return the screen item that is selected
1198 by user.
1199
1200 @param Scope Data save or discard scope, form or formset.
1201
1202 @retval TRUE Success process the changed data, will return to the parent form.
1203 @retval FALSE Reject to process the changed data, will stay at current form.
1204 **/
1205 BOOLEAN
1206 ProcessChangedData (
1207 IN OUT UI_MENU_SELECTION *Selection,
1208 IN BROWSER_SETTING_SCOPE Scope
1209 )
1210 {
1211 BOOLEAN RetValue;
1212
1213 RetValue = TRUE;
1214 switch (mFormDisplay->ConfirmDataChange()) {
1215 case BROWSER_ACTION_DISCARD:
1216 DiscardForm (Selection->FormSet, Selection->Form, Scope);
1217 break;
1218
1219 case BROWSER_ACTION_SUBMIT:
1220 SubmitForm (Selection->FormSet, Selection->Form, Scope);
1221 break;
1222
1223 case BROWSER_ACTION_NONE:
1224 RetValue = FALSE;
1225 break;
1226
1227 default:
1228 //
1229 // if Invalid value return, process same as BROWSER_ACTION_NONE.
1230 //
1231 RetValue = FALSE;
1232 break;
1233 }
1234
1235 return RetValue;
1236 }
1237
1238 /**
1239 Find parent formset menu(the first menu which has different formset) for current menu.
1240 If not find, just return to the first menu.
1241
1242 @param Selection The selection info.
1243
1244 **/
1245 VOID
1246 FindParentFormSet (
1247 IN OUT UI_MENU_SELECTION *Selection
1248 )
1249 {
1250 FORM_ENTRY_INFO *CurrentMenu;
1251 FORM_ENTRY_INFO *ParentMenu;
1252
1253 CurrentMenu = Selection->CurrentMenu;
1254 ParentMenu = UiFindParentMenu(CurrentMenu);
1255
1256 //
1257 // Find a menu which has different formset guid with current.
1258 //
1259 while (ParentMenu != NULL && CompareGuid (&CurrentMenu->FormSetGuid, &ParentMenu->FormSetGuid)) {
1260 CurrentMenu = ParentMenu;
1261 ParentMenu = UiFindParentMenu(CurrentMenu);
1262 }
1263
1264 if (ParentMenu != NULL) {
1265 CopyMem (&Selection->FormSetGuid, &ParentMenu->FormSetGuid, sizeof (EFI_GUID));
1266 Selection->Handle = ParentMenu->HiiHandle;
1267 Selection->FormId = ParentMenu->FormId;
1268 Selection->QuestionId = ParentMenu->QuestionId;
1269 } else {
1270 Selection->FormId = CurrentMenu->FormId;
1271 Selection->QuestionId = CurrentMenu->QuestionId;
1272 }
1273
1274 Selection->Statement = NULL;
1275 }
1276
1277 /**
1278 Process the goto op code, update the info in the selection structure.
1279
1280 @param Statement The statement belong to goto op code.
1281 @param Selection The selection info.
1282
1283 @retval EFI_SUCCESS The menu process successfully.
1284 @return Other value if the process failed.
1285 **/
1286 EFI_STATUS
1287 ProcessGotoOpCode (
1288 IN OUT FORM_BROWSER_STATEMENT *Statement,
1289 IN OUT UI_MENU_SELECTION *Selection
1290 )
1291 {
1292 CHAR16 *StringPtr;
1293 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
1294 FORM_BROWSER_FORM *RefForm;
1295 EFI_STATUS Status;
1296 EFI_HII_HANDLE HiiHandle;
1297
1298 Status = EFI_SUCCESS;
1299 StringPtr = NULL;
1300 HiiHandle = NULL;
1301
1302 //
1303 // Prepare the device path check, get the device path info first.
1304 //
1305 if (Statement->HiiValue.Value.ref.DevicePath != 0) {
1306 StringPtr = GetToken (Statement->HiiValue.Value.ref.DevicePath, Selection->FormSet->HiiHandle);
1307 }
1308
1309 //
1310 // Check whether the device path string is a valid string.
1311 //
1312 if (Statement->HiiValue.Value.ref.DevicePath != 0 && StringPtr != NULL) {
1313 if (Selection->Form->ModalForm) {
1314 return Status;
1315 }
1316
1317 //
1318 // Goto another Hii Package list
1319 //
1320 if (mPathFromText != NULL) {
1321 DevicePath = mPathFromText->ConvertTextToDevicePath(StringPtr);
1322 if (DevicePath != NULL) {
1323 HiiHandle = DevicePathToHiiHandle (DevicePath);
1324 FreePool (DevicePath);
1325 }
1326 FreePool (StringPtr);
1327 } else {
1328 //
1329 // Not found the EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL protocol.
1330 //
1331 gBrowserStatus = BROWSER_PROTOCOL_NOT_FOUND;
1332 FreePool (StringPtr);
1333 return Status;
1334 }
1335
1336 if (HiiHandle != Selection->Handle) {
1337 //
1338 // Goto another Formset, check for uncommitted data
1339 //
1340 if ((gBrowserSettingScope == FormLevel || gBrowserSettingScope == FormSetLevel) &&
1341 IsNvUpdateRequiredForFormSet(Selection->FormSet)) {
1342 if (!ProcessChangedData(Selection, FormSetLevel)) {
1343 return EFI_SUCCESS;
1344 }
1345 }
1346 }
1347
1348 Selection->Action = UI_ACTION_REFRESH_FORMSET;
1349 Selection->Handle = HiiHandle;
1350 if (Selection->Handle == NULL) {
1351 //
1352 // If target Hii Handle not found, exit current formset.
1353 //
1354 FindParentFormSet(Selection);
1355 return EFI_SUCCESS;
1356 }
1357
1358 CopyMem (&Selection->FormSetGuid,&Statement->HiiValue.Value.ref.FormSetGuid, sizeof (EFI_GUID));
1359 Selection->FormId = Statement->HiiValue.Value.ref.FormId;
1360 Selection->QuestionId = Statement->HiiValue.Value.ref.QuestionId;
1361 } else if (!CompareGuid (&Statement->HiiValue.Value.ref.FormSetGuid, &gZeroGuid)) {
1362 if (Selection->Form->ModalForm) {
1363 return Status;
1364 }
1365 if (!CompareGuid (&Statement->HiiValue.Value.ref.FormSetGuid, &Selection->FormSetGuid)) {
1366 //
1367 // Goto another Formset, check for uncommitted data
1368 //
1369 if ((gBrowserSettingScope == FormLevel || gBrowserSettingScope == FormSetLevel) &&
1370 IsNvUpdateRequiredForFormSet(Selection->FormSet)) {
1371 if (!ProcessChangedData(Selection, FormSetLevel)) {
1372 return EFI_SUCCESS;
1373 }
1374 }
1375 }
1376
1377 Selection->Action = UI_ACTION_REFRESH_FORMSET;
1378 Selection->Handle = FormSetGuidToHiiHandle(&Statement->HiiValue.Value.ref.FormSetGuid);
1379 if (Selection->Handle == NULL) {
1380 //
1381 // If target Hii Handle not found, exit current formset.
1382 //
1383 FindParentFormSet(Selection);
1384 return EFI_SUCCESS;
1385 }
1386
1387 CopyMem (&Selection->FormSetGuid, &Statement->HiiValue.Value.ref.FormSetGuid, sizeof (EFI_GUID));
1388 Selection->FormId = Statement->HiiValue.Value.ref.FormId;
1389 Selection->QuestionId = Statement->HiiValue.Value.ref.QuestionId;
1390 } else if (Statement->HiiValue.Value.ref.FormId != 0) {
1391 //
1392 // Goto another Form, check for uncommitted data
1393 //
1394 if (Statement->HiiValue.Value.ref.FormId != Selection->FormId) {
1395 if ((gBrowserSettingScope == FormLevel && IsNvUpdateRequiredForForm(Selection->Form))) {
1396 if (!ProcessChangedData (Selection, FormLevel)) {
1397 return EFI_SUCCESS;
1398 }
1399 }
1400 }
1401
1402 RefForm = IdToForm (Selection->FormSet, Statement->HiiValue.Value.ref.FormId);
1403 if ((RefForm != NULL) && (RefForm->SuppressExpression != NULL)) {
1404 if (EvaluateExpressionList(RefForm->SuppressExpression, TRUE, Selection->FormSet, RefForm) != ExpressFalse) {
1405 //
1406 // Form is suppressed.
1407 //
1408 gBrowserStatus = BROWSER_FORM_SUPPRESS;
1409 return EFI_SUCCESS;
1410 }
1411 }
1412
1413 Selection->FormId = Statement->HiiValue.Value.ref.FormId;
1414 Selection->QuestionId = Statement->HiiValue.Value.ref.QuestionId;
1415 } else if (Statement->HiiValue.Value.ref.QuestionId != 0) {
1416 Selection->QuestionId = Statement->HiiValue.Value.ref.QuestionId;
1417 }
1418
1419 return Status;
1420 }
1421
1422
1423 /**
1424 Process Question Config.
1425
1426 @param Selection The UI menu selection.
1427 @param Question The Question to be peocessed.
1428
1429 @retval EFI_SUCCESS Question Config process success.
1430 @retval Other Question Config process fail.
1431
1432 **/
1433 EFI_STATUS
1434 ProcessQuestionConfig (
1435 IN UI_MENU_SELECTION *Selection,
1436 IN FORM_BROWSER_STATEMENT *Question
1437 )
1438 {
1439 EFI_STATUS Status;
1440 CHAR16 *ConfigResp;
1441 CHAR16 *Progress;
1442 EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess;
1443
1444 if (Question->QuestionConfig == 0) {
1445 return EFI_SUCCESS;
1446 }
1447
1448 //
1449 // Get <ConfigResp>
1450 //
1451 ConfigResp = GetToken (Question->QuestionConfig, Selection->FormSet->HiiHandle);
1452 if (ConfigResp == NULL) {
1453 return EFI_NOT_FOUND;
1454 }
1455
1456 //
1457 // Send config to Configuration Driver
1458 //
1459 ConfigAccess = Selection->FormSet->ConfigAccess;
1460 if (ConfigAccess == NULL) {
1461 return EFI_UNSUPPORTED;
1462 }
1463 Status = ConfigAccess->RouteConfig (
1464 ConfigAccess,
1465 ConfigResp,
1466 &Progress
1467 );
1468
1469 return Status;
1470 }
1471
1472 /**
1473
1474 Process the user input data.
1475
1476 @param UserInput The user input data.
1477 @param ChangeHighlight Whether need to change the highlight statement.
1478
1479 @retval EFI_SUCESSS This function always return successfully for now.
1480
1481 **/
1482 EFI_STATUS
1483 ProcessUserInput (
1484 IN USER_INPUT *UserInput,
1485 IN BOOLEAN ChangeHighlight
1486 )
1487 {
1488 EFI_STATUS Status;
1489 FORM_BROWSER_STATEMENT *Statement;
1490
1491 Status = EFI_SUCCESS;
1492
1493 //
1494 // When Exit from FormDisplay function, one of the below two cases must be true.
1495 //
1496 ASSERT (UserInput->Action != 0 || UserInput->SelectedStatement != NULL);
1497
1498 //
1499 // Remove the last highligh question id, this id will update when show next form.
1500 //
1501 gCurrentSelection->QuestionId = 0;
1502
1503 //
1504 // First process the Action field in USER_INPUT.
1505 //
1506 if (UserInput->Action != 0) {
1507 Status = ProcessAction (UserInput->Action, UserInput->DefaultId);
1508 if (EFI_ERROR (Status)) {
1509 return Status;
1510 }
1511
1512 //
1513 // Clear the highlight info.
1514 //
1515 gCurrentSelection->Statement = NULL;
1516
1517 if (UserInput->SelectedStatement != NULL) {
1518 Statement = GetBrowserStatement(UserInput->SelectedStatement);
1519 ASSERT (Statement != NULL);
1520 //
1521 // Save the current highlight menu in the menu history data.
1522 // which will be used when later browse back to this form.
1523 //
1524 gCurrentSelection->CurrentMenu->QuestionId = Statement->QuestionId;
1525 //
1526 // For statement like text, actio, it not has question id.
1527 // So use FakeQuestionId to save the question.
1528 //
1529 if (gCurrentSelection->CurrentMenu->QuestionId == 0) {
1530 mCurFakeQestId = Statement->FakeQuestionId;
1531 } else {
1532 mCurFakeQestId = 0;
1533 }
1534 }
1535 } else {
1536 Statement = GetBrowserStatement(UserInput->SelectedStatement);
1537 ASSERT (Statement != NULL);
1538
1539 gCurrentSelection->Statement = Statement;
1540
1541 if (ChangeHighlight) {
1542 //
1543 // This question is the current user select one,record it and later
1544 // show it as the highlight question.
1545 //
1546 gCurrentSelection->CurrentMenu->QuestionId = Statement->QuestionId;
1547 //
1548 // For statement like text, actio, it not has question id.
1549 // So use FakeQuestionId to save the question.
1550 //
1551 if (gCurrentSelection->CurrentMenu->QuestionId == 0) {
1552 mCurFakeQestId = Statement->FakeQuestionId;
1553 } else {
1554 mCurFakeQestId = 0;
1555 }
1556 }
1557
1558 switch (Statement->Operand) {
1559 case EFI_IFR_REF_OP:
1560 Status = ProcessGotoOpCode(Statement, gCurrentSelection);
1561 break;
1562
1563 case EFI_IFR_ACTION_OP:
1564 //
1565 // Process the Config string <ConfigResp>
1566 //
1567 Status = ProcessQuestionConfig (gCurrentSelection, Statement);
1568 break;
1569
1570 case EFI_IFR_RESET_BUTTON_OP:
1571 //
1572 // Reset Question to default value specified by DefaultId
1573 //
1574 Status = ExtractDefault (gCurrentSelection->FormSet, NULL, Statement->DefaultId, FormSetLevel, GetDefaultForAll, NULL, FALSE);
1575 break;
1576
1577 default:
1578 switch (Statement->Operand) {
1579 case EFI_IFR_STRING_OP:
1580 DeleteString(Statement->HiiValue.Value.string, gCurrentSelection->FormSet->HiiHandle);
1581 Statement->HiiValue.Value.string = UserInput->InputValue.Value.string;
1582 CopyMem (Statement->BufferValue, UserInput->InputValue.Buffer, (UINTN) UserInput->InputValue.BufferLen);
1583 FreePool (UserInput->InputValue.Buffer);
1584 break;
1585
1586 case EFI_IFR_PASSWORD_OP:
1587 if (UserInput->InputValue.Buffer == NULL) {
1588 //
1589 // User not input new password, just return.
1590 //
1591 break;
1592 }
1593
1594 DeleteString(Statement->HiiValue.Value.string, gCurrentSelection->FormSet->HiiHandle);
1595 Statement->HiiValue.Value.string = UserInput->InputValue.Value.string;
1596 CopyMem (Statement->BufferValue, UserInput->InputValue.Buffer, (UINTN) UserInput->InputValue.BufferLen);
1597 FreePool (UserInput->InputValue.Buffer);
1598 //
1599 // Two password match, send it to Configuration Driver
1600 //
1601 if ((Statement->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) {
1602 PasswordCheck (NULL, UserInput->SelectedStatement, (CHAR16 *) Statement->BufferValue);
1603 //
1604 // Clean the value after saved it.
1605 //
1606 ZeroMem (Statement->BufferValue, (UINTN) UserInput->InputValue.BufferLen);
1607 HiiSetString (gCurrentSelection->FormSet->HiiHandle, Statement->HiiValue.Value.string, (CHAR16*)Statement->BufferValue, NULL);
1608 } else {
1609 SetQuestionValue (gCurrentSelection->FormSet, gCurrentSelection->Form, Statement, GetSetValueWithHiiDriver);
1610 }
1611 break;
1612
1613 case EFI_IFR_ORDERED_LIST_OP:
1614 CopyMem (Statement->BufferValue, UserInput->InputValue.Buffer, UserInput->InputValue.BufferLen);
1615 break;
1616
1617 default:
1618 CopyMem (&Statement->HiiValue, &UserInput->InputValue, sizeof (EFI_HII_VALUE));
1619 break;
1620 }
1621 break;
1622 }
1623 }
1624
1625 return Status;
1626 }
1627
1628 /**
1629
1630 Display form and wait for user to select one menu option, then return it.
1631
1632 @retval EFI_SUCESSS This function always return successfully for now.
1633
1634 **/
1635 EFI_STATUS
1636 DisplayForm (
1637 VOID
1638 )
1639 {
1640 EFI_STATUS Status;
1641 USER_INPUT UserInput;
1642 FORM_ENTRY_INFO *CurrentMenu;
1643 BOOLEAN ChangeHighlight;
1644
1645 ZeroMem (&UserInput, sizeof (USER_INPUT));
1646
1647 //
1648 // Update the menu history data.
1649 //
1650 CurrentMenu = UiFindMenuList (gCurrentSelection->Handle, &gCurrentSelection->FormSetGuid, gCurrentSelection->FormId);
1651 if (CurrentMenu == NULL) {
1652 //
1653 // Current menu not found, add it to the menu tree
1654 //
1655 CurrentMenu = UiAddMenuList (gCurrentSelection->Handle, &gCurrentSelection->FormSetGuid,
1656 gCurrentSelection->FormId, gCurrentSelection->QuestionId);
1657 ASSERT (CurrentMenu != NULL);
1658 }
1659 gCurrentSelection->CurrentMenu = CurrentMenu;
1660
1661 //
1662 // Find currrent highlight statement.
1663 //
1664 if (gCurrentSelection->QuestionId == 0) {
1665 //
1666 // Highlight not specified, fetch it from cached menu
1667 //
1668 gCurrentSelection->QuestionId = CurrentMenu->QuestionId;
1669 }
1670
1671 //
1672 // Evaluate all the Expressions in this Form
1673 //
1674 Status = EvaluateFormExpressions (gCurrentSelection->FormSet, gCurrentSelection->Form);
1675 if (EFI_ERROR (Status)) {
1676 return Status;
1677 }
1678
1679 UpdateDisplayFormData ();
1680
1681 //
1682 // Three possible status maybe return.
1683 //
1684 // EFI_INVALID_PARAMETER: The input dimension info is not valid.
1685 // EFI_NOT_FOUND: The input value for oneof/orderedlist opcode is not valid
1686 // and an valid value has return.
1687 // EFI_SUCCESS: Success shows form and get user input in UserInput paramenter.
1688 //
1689 Status = mFormDisplay->FormDisplay (&gDisplayFormData, &UserInput);
1690 if (EFI_ERROR (Status) && Status != EFI_NOT_FOUND) {
1691 FreeDisplayFormData();
1692 return Status;
1693 }
1694
1695 //
1696 // If status is EFI_SUCCESS, means user has change the highlight menu and new user input return.
1697 // in this case, browser need to change the highlight menu.
1698 // If status is EFI_NOT_FOUND, means the input DisplayFormData has error for oneof/orderedlist
1699 // opcode and new valid value has return, browser core need to adjust
1700 // value for this opcode and shows this form again.
1701 //
1702 ChangeHighlight = (Status == EFI_SUCCESS ? TRUE :FALSE);
1703
1704 Status = ProcessUserInput (&UserInput, ChangeHighlight);
1705
1706 FreeDisplayFormData();
1707
1708 return Status;
1709 }
1710
1711 /**
1712 Functions which are registered to receive notification of
1713 database events have this prototype. The actual event is encoded
1714 in NotifyType. The following table describes how PackageType,
1715 PackageGuid, Handle, and Package are used for each of the
1716 notification types.
1717
1718 @param PackageType Package type of the notification.
1719
1720 @param PackageGuid If PackageType is
1721 EFI_HII_PACKAGE_TYPE_GUID, then this is
1722 the pointer to the GUID from the Guid
1723 field of EFI_HII_PACKAGE_GUID_HEADER.
1724 Otherwise, it must be NULL.
1725
1726 @param Package Points to the package referred to by the
1727 notification Handle The handle of the package
1728 list which contains the specified package.
1729
1730 @param Handle The HII handle.
1731
1732 @param NotifyType The type of change concerning the
1733 database. See
1734 EFI_HII_DATABASE_NOTIFY_TYPE.
1735
1736 **/
1737 EFI_STATUS
1738 EFIAPI
1739 FormUpdateNotify (
1740 IN UINT8 PackageType,
1741 IN CONST EFI_GUID *PackageGuid,
1742 IN CONST EFI_HII_PACKAGE_HEADER *Package,
1743 IN EFI_HII_HANDLE Handle,
1744 IN EFI_HII_DATABASE_NOTIFY_TYPE NotifyType
1745 )
1746 {
1747 mHiiPackageListUpdated = TRUE;
1748
1749 return EFI_SUCCESS;
1750 }
1751
1752 /**
1753 Update the NV flag info for this form set.
1754
1755 @param FormSet FormSet data structure.
1756
1757 **/
1758 BOOLEAN
1759 IsNvUpdateRequiredForFormSet (
1760 IN FORM_BROWSER_FORMSET *FormSet
1761 )
1762 {
1763 LIST_ENTRY *Link;
1764 FORM_BROWSER_FORM *Form;
1765 BOOLEAN RetVal;
1766
1767 //
1768 // Not finished question initialization, return FALSE.
1769 //
1770 if (!FormSet->QuestionInited) {
1771 return FALSE;
1772 }
1773
1774 RetVal = FALSE;
1775
1776 Link = GetFirstNode (&FormSet->FormListHead);
1777 while (!IsNull (&FormSet->FormListHead, Link)) {
1778 Form = FORM_BROWSER_FORM_FROM_LINK (Link);
1779
1780 RetVal = IsNvUpdateRequiredForForm(Form);
1781 if (RetVal) {
1782 break;
1783 }
1784
1785 Link = GetNextNode (&FormSet->FormListHead, Link);
1786 }
1787
1788 return RetVal;
1789 }
1790
1791 /**
1792 Update the NvUpdateRequired flag for a form.
1793
1794 @param Form Form data structure.
1795
1796 **/
1797 BOOLEAN
1798 IsNvUpdateRequiredForForm (
1799 IN FORM_BROWSER_FORM *Form
1800 )
1801 {
1802 LIST_ENTRY *Link;
1803 FORM_BROWSER_STATEMENT *Statement;
1804
1805 Link = GetFirstNode (&Form->StatementListHead);
1806 while (!IsNull (&Form->StatementListHead, Link)) {
1807 Statement = FORM_BROWSER_STATEMENT_FROM_LINK (Link);
1808
1809 if (Statement->ValueChanged) {
1810 return TRUE;
1811 }
1812
1813 Link = GetNextNode (&Form->StatementListHead, Link);
1814 }
1815
1816 return FALSE;
1817 }
1818
1819 /**
1820 Check whether the storage data for current form set is changed.
1821
1822 @param FormSet FormSet data structure.
1823
1824 @retval TRUE Data is changed.
1825 @retval FALSE Data is not changed.
1826 **/
1827 BOOLEAN
1828 IsStorageDataChangedForFormSet (
1829 IN FORM_BROWSER_FORMSET *FormSet
1830 )
1831 {
1832 LIST_ENTRY *Link;
1833 FORMSET_STORAGE *Storage;
1834 BROWSER_STORAGE *BrowserStorage;
1835 CHAR16 *ConfigRespNew;
1836 CHAR16 *ConfigRespOld;
1837 BOOLEAN RetVal;
1838
1839 RetVal = FALSE;
1840 ConfigRespNew = NULL;
1841 ConfigRespOld = NULL;
1842
1843 //
1844 // Request current settings from Configuration Driver
1845 //
1846 Link = GetFirstNode (&FormSet->StorageListHead);
1847 while (!IsNull (&FormSet->StorageListHead, Link)) {
1848 Storage = FORMSET_STORAGE_FROM_LINK (Link);
1849 Link = GetNextNode (&FormSet->StorageListHead, Link);
1850
1851 BrowserStorage = Storage->BrowserStorage;
1852
1853 if (BrowserStorage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {
1854 continue;
1855 }
1856
1857 if (Storage->ElementCount == 0) {
1858 continue;
1859 }
1860
1861 StorageToConfigResp (BrowserStorage, &ConfigRespNew, Storage->ConfigRequest, TRUE);
1862 StorageToConfigResp (BrowserStorage, &ConfigRespOld, Storage->ConfigRequest, FALSE);
1863 ASSERT (ConfigRespNew != NULL && ConfigRespOld != NULL);
1864
1865 if (StrCmp (ConfigRespNew, ConfigRespOld) != 0) {
1866 RetVal = TRUE;
1867 }
1868
1869 FreePool (ConfigRespNew);
1870 ConfigRespNew = NULL;
1871
1872 FreePool (ConfigRespOld);
1873 ConfigRespOld = NULL;
1874
1875 if (RetVal) {
1876 break;
1877 }
1878 }
1879
1880 return RetVal;
1881 }
1882
1883 /**
1884 Find menu which will show next time.
1885
1886 @param Selection On input, Selection tell setup browser the information
1887 about the Selection, form and formset to be displayed.
1888 On output, Selection return the screen item that is selected
1889 by user.
1890 @param SettingLevel Input Settting level, if it is FormLevel, just exit current form.
1891 else, we need to exit current formset.
1892
1893 @retval TRUE Exit current form.
1894 @retval FALSE User press ESC and keep in current form.
1895 **/
1896 BOOLEAN
1897 FindNextMenu (
1898 IN OUT UI_MENU_SELECTION *Selection,
1899 IN BROWSER_SETTING_SCOPE SettingLevel
1900 )
1901 {
1902 FORM_ENTRY_INFO *CurrentMenu;
1903 FORM_ENTRY_INFO *ParentMenu;
1904 BROWSER_SETTING_SCOPE Scope;
1905
1906 CurrentMenu = Selection->CurrentMenu;
1907 ParentMenu = NULL;
1908 Scope = FormSetLevel;
1909
1910 if (CurrentMenu != NULL && (ParentMenu = UiFindParentMenu(CurrentMenu)) != NULL) {
1911 //
1912 // we have a parent, so go to the parent menu
1913 //
1914 if (CompareGuid (&CurrentMenu->FormSetGuid, &ParentMenu->FormSetGuid)) {
1915 if (SettingLevel == FormSetLevel) {
1916 //
1917 // Find a menu which has different formset guid with current.
1918 //
1919 while (CompareGuid (&CurrentMenu->FormSetGuid, &ParentMenu->FormSetGuid)) {
1920 CurrentMenu = ParentMenu;
1921 if ((ParentMenu = UiFindParentMenu(CurrentMenu)) == NULL) {
1922 break;
1923 }
1924 }
1925
1926 if (ParentMenu != NULL) {
1927 Scope = FormSetLevel;
1928 }
1929 } else {
1930 Scope = FormLevel;
1931 }
1932 } else {
1933 Scope = FormSetLevel;
1934 }
1935 }
1936
1937 //
1938 // Form Level Check whether the data is changed.
1939 //
1940 if ((gBrowserSettingScope == FormLevel && IsNvUpdateRequiredForForm (Selection->Form)) ||
1941 (gBrowserSettingScope == FormSetLevel && IsNvUpdateRequiredForFormSet(Selection->FormSet) && Scope == FormSetLevel)) {
1942 if (!ProcessChangedData(Selection, Scope)) {
1943 return FALSE;
1944 }
1945 }
1946
1947 if (ParentMenu != NULL) {
1948 //
1949 // ParentMenu is found. Then, go to it.
1950 //
1951 if (Scope == FormLevel) {
1952 Selection->Action = UI_ACTION_REFRESH_FORM;
1953 } else {
1954 Selection->Action = UI_ACTION_REFRESH_FORMSET;
1955 CopyMem (&Selection->FormSetGuid, &ParentMenu->FormSetGuid, sizeof (EFI_GUID));
1956 Selection->Handle = ParentMenu->HiiHandle;
1957 }
1958
1959 Selection->Statement = NULL;
1960
1961 Selection->FormId = ParentMenu->FormId;
1962 Selection->QuestionId = ParentMenu->QuestionId;
1963
1964 //
1965 // Clear highlight record for this menu
1966 //
1967 CurrentMenu->QuestionId = 0;
1968 return FALSE;
1969 }
1970
1971 //
1972 // Current in root page, exit the SendForm
1973 //
1974 Selection->Action = UI_ACTION_EXIT;
1975
1976 return TRUE;
1977 }
1978
1979 /**
1980 Call the call back function for the question and process the return action.
1981
1982 @param Selection On input, Selection tell setup browser the information
1983 about the Selection, form and formset to be displayed.
1984 On output, Selection return the screen item that is selected
1985 by user.
1986 @param Question The Question which need to call.
1987 @param Action The action request.
1988 @param SkipSaveOrDiscard Whether skip save or discard action.
1989
1990 @retval EFI_SUCCESS The call back function excutes successfully.
1991 @return Other value if the call back function failed to excute.
1992 **/
1993 EFI_STATUS
1994 ProcessCallBackFunction (
1995 IN OUT UI_MENU_SELECTION *Selection,
1996 IN FORM_BROWSER_STATEMENT *Question,
1997 IN EFI_BROWSER_ACTION Action,
1998 IN BOOLEAN SkipSaveOrDiscard
1999 )
2000 {
2001 EFI_STATUS Status;
2002 EFI_BROWSER_ACTION_REQUEST ActionRequest;
2003 EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess;
2004 EFI_HII_VALUE *HiiValue;
2005 EFI_IFR_TYPE_VALUE *TypeValue;
2006 FORM_BROWSER_STATEMENT *Statement;
2007 BOOLEAN SubmitFormIsRequired;
2008 BOOLEAN DiscardFormIsRequired;
2009 BOOLEAN NeedExit;
2010 LIST_ENTRY *Link;
2011 BROWSER_SETTING_SCOPE SettingLevel;
2012 EFI_IFR_TYPE_VALUE BackUpValue;
2013 UINT8 *BackUpBuffer;
2014
2015 ConfigAccess = Selection->FormSet->ConfigAccess;
2016 SubmitFormIsRequired = FALSE;
2017 SettingLevel = FormSetLevel;
2018 DiscardFormIsRequired = FALSE;
2019 NeedExit = FALSE;
2020 Status = EFI_SUCCESS;
2021 ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;
2022 BackUpBuffer = NULL;
2023
2024 if (ConfigAccess == NULL) {
2025 return EFI_SUCCESS;
2026 }
2027
2028 Link = GetFirstNode (&Selection->Form->StatementListHead);
2029 while (!IsNull (&Selection->Form->StatementListHead, Link)) {
2030 Statement = FORM_BROWSER_STATEMENT_FROM_LINK (Link);
2031 Link = GetNextNode (&Selection->Form->StatementListHead, Link);
2032
2033 //
2034 // if Question != NULL, only process the question. Else, process all question in this form.
2035 //
2036 if ((Question != NULL) && (Statement != Question)) {
2037 continue;
2038 }
2039
2040 if ((Statement->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != EFI_IFR_FLAG_CALLBACK) {
2041 continue;
2042 }
2043
2044 //
2045 // Check whether Statement is disabled.
2046 //
2047 if (Statement->Expression != NULL) {
2048 if (EvaluateExpressionList(Statement->Expression, TRUE, Selection->FormSet, Selection->Form) == ExpressDisable) {
2049 continue;
2050 }
2051 }
2052
2053 HiiValue = &Statement->HiiValue;
2054 TypeValue = &HiiValue->Value;
2055 if (HiiValue->Type == EFI_IFR_TYPE_BUFFER) {
2056 //
2057 // For OrderedList, passing in the value buffer to Callback()
2058 //
2059 TypeValue = (EFI_IFR_TYPE_VALUE *) Statement->BufferValue;
2060 }
2061
2062 //
2063 // If EFI_BROWSER_ACTION_CHANGING type, back up the new question value.
2064 //
2065 if (Action == EFI_BROWSER_ACTION_CHANGING) {
2066 if (HiiValue->Type == EFI_IFR_TYPE_BUFFER) {
2067 BackUpBuffer = AllocateCopyPool(Statement->StorageWidth + sizeof(CHAR16), Statement->BufferValue);
2068 } else {
2069 CopyMem (&BackUpValue, &HiiValue->Value, sizeof (EFI_IFR_TYPE_VALUE));
2070 }
2071 }
2072
2073 ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;
2074 Status = ConfigAccess->Callback (
2075 ConfigAccess,
2076 Action,
2077 Statement->QuestionId,
2078 HiiValue->Type,
2079 TypeValue,
2080 &ActionRequest
2081 );
2082 if (!EFI_ERROR (Status)) {
2083 //
2084 // Only for EFI_BROWSER_ACTION_CHANGED need to handle this ActionRequest.
2085 //
2086 if (Action == EFI_BROWSER_ACTION_CHANGED) {
2087 switch (ActionRequest) {
2088 case EFI_BROWSER_ACTION_REQUEST_RESET:
2089 DiscardFormIsRequired = TRUE;
2090 gResetRequired = TRUE;
2091 NeedExit = TRUE;
2092 break;
2093
2094 case EFI_BROWSER_ACTION_REQUEST_SUBMIT:
2095 SubmitFormIsRequired = TRUE;
2096 NeedExit = TRUE;
2097 break;
2098
2099 case EFI_BROWSER_ACTION_REQUEST_EXIT:
2100 DiscardFormIsRequired = TRUE;
2101 NeedExit = TRUE;
2102 break;
2103
2104 case EFI_BROWSER_ACTION_REQUEST_FORM_SUBMIT_EXIT:
2105 SubmitFormIsRequired = TRUE;
2106 SettingLevel = FormLevel;
2107 NeedExit = TRUE;
2108 break;
2109
2110 case EFI_BROWSER_ACTION_REQUEST_FORM_DISCARD_EXIT:
2111 DiscardFormIsRequired = TRUE;
2112 SettingLevel = FormLevel;
2113 NeedExit = TRUE;
2114 break;
2115
2116 case EFI_BROWSER_ACTION_REQUEST_FORM_APPLY:
2117 SubmitFormIsRequired = TRUE;
2118 SettingLevel = FormLevel;
2119 break;
2120
2121 case EFI_BROWSER_ACTION_REQUEST_FORM_DISCARD:
2122 DiscardFormIsRequired = TRUE;
2123 SettingLevel = FormLevel;
2124 break;
2125
2126 default:
2127 break;
2128 }
2129 }
2130
2131 //
2132 // According the spec, return value from call back of "changing" and
2133 // "retrieve" should update to the question's temp buffer.
2134 //
2135 if (Action == EFI_BROWSER_ACTION_CHANGING || Action == EFI_BROWSER_ACTION_RETRIEVE) {
2136 SetQuestionValue(Selection->FormSet, Selection->Form, Statement, GetSetValueWithEditBuffer);
2137 }
2138 } else {
2139 //
2140 // If the callback returns EFI_UNSUPPORTED for EFI_BROWSER_ACTION_CHANGING,
2141 // then the browser will use the value passed to Callback() and ignore the
2142 // value returned by Callback().
2143 //
2144 if (Action == EFI_BROWSER_ACTION_CHANGING && Status == EFI_UNSUPPORTED) {
2145 if (HiiValue->Type == EFI_IFR_TYPE_BUFFER) {
2146 CopyMem (Statement->BufferValue, BackUpBuffer, Statement->StorageWidth + sizeof(CHAR16));
2147 } else {
2148 CopyMem (&HiiValue->Value, &BackUpValue, sizeof (EFI_IFR_TYPE_VALUE));
2149 }
2150
2151 SetQuestionValue(Selection->FormSet, Selection->Form, Statement, GetSetValueWithEditBuffer);
2152 }
2153
2154 //
2155 // According the spec, return fail from call back of "changing" and
2156 // "retrieve", should restore the question's value.
2157 //
2158 if ((Action == EFI_BROWSER_ACTION_CHANGING && Status != EFI_UNSUPPORTED) ||
2159 Action == EFI_BROWSER_ACTION_RETRIEVE) {
2160 GetQuestionValue(Selection->FormSet, Selection->Form, Statement, GetSetValueWithEditBuffer);
2161 }
2162
2163 if (Status == EFI_UNSUPPORTED) {
2164 //
2165 // If return EFI_UNSUPPORTED, also consider Hii driver suceess deal with it.
2166 //
2167 Status = EFI_SUCCESS;
2168 }
2169 }
2170
2171 if (BackUpBuffer != NULL) {
2172 FreePool (BackUpBuffer);
2173 }
2174 }
2175
2176 if (SubmitFormIsRequired && !SkipSaveOrDiscard) {
2177 SubmitForm (Selection->FormSet, Selection->Form, SettingLevel);
2178 }
2179
2180 if (DiscardFormIsRequired && !SkipSaveOrDiscard) {
2181 DiscardForm (Selection->FormSet, Selection->Form, SettingLevel);
2182 }
2183
2184 if (NeedExit) {
2185 FindNextMenu (Selection, SettingLevel);
2186 }
2187
2188 return Status;
2189 }
2190
2191 /**
2192 Call the retrieve type call back function for one question to get the initialize data.
2193
2194 This function only used when in the initialize stage, because in this stage, the
2195 Selection->Form is not ready. For other case, use the ProcessCallBackFunction instead.
2196
2197 @param ConfigAccess The config access protocol produced by the hii driver.
2198 @param Statement The Question which need to call.
2199
2200 @retval EFI_SUCCESS The call back function excutes successfully.
2201 @return Other value if the call back function failed to excute.
2202 **/
2203 EFI_STATUS
2204 ProcessRetrieveForQuestion (
2205 IN EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess,
2206 IN FORM_BROWSER_STATEMENT *Statement
2207 )
2208 {
2209 EFI_STATUS Status;
2210 EFI_BROWSER_ACTION_REQUEST ActionRequest;
2211 EFI_HII_VALUE *HiiValue;
2212 EFI_IFR_TYPE_VALUE *TypeValue;
2213
2214 Status = EFI_SUCCESS;
2215 ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;
2216
2217 if ((Statement->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != EFI_IFR_FLAG_CALLBACK) {
2218 return EFI_UNSUPPORTED;
2219 }
2220
2221 HiiValue = &Statement->HiiValue;
2222 TypeValue = &HiiValue->Value;
2223 if (HiiValue->Type == EFI_IFR_TYPE_BUFFER) {
2224 //
2225 // For OrderedList, passing in the value buffer to Callback()
2226 //
2227 TypeValue = (EFI_IFR_TYPE_VALUE *) Statement->BufferValue;
2228 }
2229
2230 ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;
2231 Status = ConfigAccess->Callback (
2232 ConfigAccess,
2233 EFI_BROWSER_ACTION_RETRIEVE,
2234 Statement->QuestionId,
2235 HiiValue->Type,
2236 TypeValue,
2237 &ActionRequest
2238 );
2239 return Status;
2240 }
2241
2242 /**
2243 The worker function that send the displays to the screen. On output,
2244 the selection made by user is returned.
2245
2246 @param Selection On input, Selection tell setup browser the information
2247 about the Selection, form and formset to be displayed.
2248 On output, Selection return the screen item that is selected
2249 by user.
2250
2251 @retval EFI_SUCCESS The page is displayed successfully.
2252 @return Other value if the page failed to be diplayed.
2253
2254 **/
2255 EFI_STATUS
2256 SetupBrowser (
2257 IN OUT UI_MENU_SELECTION *Selection
2258 )
2259 {
2260 EFI_STATUS Status;
2261 LIST_ENTRY *Link;
2262 EFI_HANDLE NotifyHandle;
2263 FORM_BROWSER_STATEMENT *Statement;
2264 EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess;
2265
2266 ConfigAccess = Selection->FormSet->ConfigAccess;
2267
2268 //
2269 // Register notify for Form package update
2270 //
2271 Status = mHiiDatabase->RegisterPackageNotify (
2272 mHiiDatabase,
2273 EFI_HII_PACKAGE_FORMS,
2274 NULL,
2275 FormUpdateNotify,
2276 EFI_HII_DATABASE_NOTIFY_REMOVE_PACK,
2277 &NotifyHandle
2278 );
2279 if (EFI_ERROR (Status)) {
2280 return Status;
2281 }
2282
2283 //
2284 // Initialize current settings of Questions in this FormSet
2285 //
2286 InitializeCurrentSetting (Selection->FormSet);
2287
2288 //
2289 // Initilize Action field.
2290 //
2291 Selection->Action = UI_ACTION_REFRESH_FORM;
2292
2293 //
2294 // Clean the mCurFakeQestId value is formset refreshed.
2295 //
2296 mCurFakeQestId = 0;
2297
2298 do {
2299 //
2300 // IFR is updated, force to reparse the IFR binary
2301 //
2302 if (mHiiPackageListUpdated) {
2303 Selection->Action = UI_ACTION_REFRESH_FORMSET;
2304 mHiiPackageListUpdated = FALSE;
2305 break;
2306 }
2307
2308 //
2309 // Initialize Selection->Form
2310 //
2311 if (Selection->FormId == 0) {
2312 //
2313 // Zero FormId indicates display the first Form in a FormSet
2314 //
2315 Link = GetFirstNode (&Selection->FormSet->FormListHead);
2316
2317 Selection->Form = FORM_BROWSER_FORM_FROM_LINK (Link);
2318 Selection->FormId = Selection->Form->FormId;
2319 } else {
2320 Selection->Form = IdToForm (Selection->FormSet, Selection->FormId);
2321 }
2322
2323 if (Selection->Form == NULL) {
2324 //
2325 // No Form to display
2326 //
2327 Status = EFI_NOT_FOUND;
2328 goto Done;
2329 }
2330
2331 //
2332 // Check Form is suppressed.
2333 //
2334 if (Selection->Form->SuppressExpression != NULL) {
2335 if (EvaluateExpressionList(Selection->Form->SuppressExpression, TRUE, Selection->FormSet, Selection->Form) == ExpressSuppress) {
2336 //
2337 // Form is suppressed.
2338 //
2339 gBrowserStatus = BROWSER_FORM_SUPPRESS;
2340 Status = EFI_NOT_FOUND;
2341 goto Done;
2342 }
2343 }
2344
2345 //
2346 // Before display new form, invoke ConfigAccess.Callback() with EFI_BROWSER_ACTION_FORM_OPEN
2347 // for each question with callback flag.
2348 // New form may be the first form, or the different form after another form close.
2349 //
2350 if ((ConfigAccess != NULL) &&
2351 ((Selection->Handle != mCurrentHiiHandle) ||
2352 (!CompareGuid (&Selection->FormSetGuid, &mCurrentFormSetGuid)) ||
2353 (Selection->FormId != mCurrentFormId))) {
2354 //
2355 // Keep current form information
2356 //
2357 mCurrentHiiHandle = Selection->Handle;
2358 CopyGuid (&mCurrentFormSetGuid, &Selection->FormSetGuid);
2359 mCurrentFormId = Selection->FormId;
2360
2361 Status = ProcessCallBackFunction (Selection, NULL, EFI_BROWSER_ACTION_FORM_OPEN, FALSE);
2362 if (EFI_ERROR (Status)) {
2363 goto Done;
2364 }
2365
2366 //
2367 // IFR is updated during callback of open form, force to reparse the IFR binary
2368 //
2369 if (mHiiPackageListUpdated) {
2370 Selection->Action = UI_ACTION_REFRESH_FORMSET;
2371 mHiiPackageListUpdated = FALSE;
2372 break;
2373 }
2374 }
2375
2376 //
2377 // Load Questions' Value for display
2378 //
2379 Status = LoadFormSetConfig (Selection, Selection->FormSet);
2380 if (EFI_ERROR (Status)) {
2381 goto Done;
2382 }
2383
2384 //
2385 // IFR is updated during callback of read value, force to reparse the IFR binary
2386 //
2387 if (mHiiPackageListUpdated) {
2388 Selection->Action = UI_ACTION_REFRESH_FORMSET;
2389 mHiiPackageListUpdated = FALSE;
2390 break;
2391 }
2392
2393 //
2394 // Display form
2395 //
2396 Status = DisplayForm ();
2397 if (EFI_ERROR (Status)) {
2398 goto Done;
2399 }
2400
2401 //
2402 // Check Selected Statement (if press ESC, Selection->Statement will be NULL)
2403 //
2404 Statement = Selection->Statement;
2405 if (Statement != NULL) {
2406 if ((ConfigAccess != NULL) &&
2407 ((Statement->QuestionFlags & EFI_IFR_FLAG_CALLBACK) == EFI_IFR_FLAG_CALLBACK) &&
2408 (Statement->Operand != EFI_IFR_PASSWORD_OP)) {
2409 Status = ProcessCallBackFunction(Selection, Statement, EFI_BROWSER_ACTION_CHANGING, FALSE);
2410 if (Statement->Operand == EFI_IFR_REF_OP) {
2411 //
2412 // Process dynamic update ref opcode.
2413 //
2414 if (!EFI_ERROR (Status)) {
2415 Status = ProcessGotoOpCode(Statement, Selection);
2416 }
2417
2418 //
2419 // Callback return error status or status return from process goto opcode.
2420 //
2421 if (EFI_ERROR (Status)) {
2422 //
2423 // Cross reference will not be taken
2424 //
2425 Selection->FormId = Selection->Form->FormId;
2426 Selection->QuestionId = 0;
2427 }
2428 }
2429
2430 if (!EFI_ERROR (Status) && Statement->Operand != EFI_IFR_REF_OP) {
2431 ProcessCallBackFunction(Selection, Statement, EFI_BROWSER_ACTION_CHANGED, FALSE);
2432 }
2433 } else if (Statement->Operand != EFI_IFR_PASSWORD_OP) {
2434 SetQuestionValue (gCurrentSelection->FormSet, gCurrentSelection->Form, Statement, GetSetValueWithEditBuffer);
2435 }
2436 }
2437
2438 //
2439 // Check whether Exit flag is TRUE.
2440 //
2441 if (gExitRequired) {
2442 switch (gBrowserSettingScope) {
2443 case SystemLevel:
2444 Selection->Action = UI_ACTION_EXIT;
2445 break;
2446
2447 case FormSetLevel:
2448 case FormLevel:
2449 FindNextMenu (Selection, gBrowserSettingScope);
2450 break;
2451
2452 default:
2453 break;
2454 }
2455
2456 gExitRequired = FALSE;
2457 }
2458
2459 //
2460 // Before exit the form, invoke ConfigAccess.Callback() with EFI_BROWSER_ACTION_FORM_CLOSE
2461 // for each question with callback flag.
2462 //
2463 if ((ConfigAccess != NULL) &&
2464 ((Selection->Action == UI_ACTION_EXIT) ||
2465 (Selection->Handle != mCurrentHiiHandle) ||
2466 (!CompareGuid (&Selection->FormSetGuid, &mCurrentFormSetGuid)) ||
2467 (Selection->FormId != mCurrentFormId))) {
2468
2469 Status = ProcessCallBackFunction (Selection, NULL, EFI_BROWSER_ACTION_FORM_CLOSE, FALSE);
2470 if (EFI_ERROR (Status)) {
2471 goto Done;
2472 }
2473 }
2474 } while (Selection->Action == UI_ACTION_REFRESH_FORM);
2475
2476 Done:
2477 //
2478 // Reset current form information to the initial setting when error happens or form exit.
2479 //
2480 if (EFI_ERROR (Status) || Selection->Action == UI_ACTION_EXIT) {
2481 mCurrentHiiHandle = NULL;
2482 CopyGuid (&mCurrentFormSetGuid, &gZeroGuid);
2483 mCurrentFormId = 0;
2484 }
2485
2486 //
2487 // Unregister notify for Form package update
2488 //
2489 mHiiDatabase->UnregisterPackageNotify (
2490 mHiiDatabase,
2491 NotifyHandle
2492 );
2493 return Status;
2494 }