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