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