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