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