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