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 ZeroMem (UserInput->InputValue.Buffer, (UINTN) UserInput->InputValue.BufferLen); 1620 FreePool (UserInput->InputValue.Buffer); 1621 // 1622 // Two password match, send it to Configuration Driver 1623 // 1624 if ((Statement->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) { 1625 PasswordCheck (NULL, UserInput->SelectedStatement, (CHAR16 *) Statement->BufferValue); 1626 // 1627 // Clean the value after saved it. 1628 // 1629 ZeroMem (Statement->BufferValue, (UINTN) UserInput->InputValue.BufferLen); 1630 HiiSetString (gCurrentSelection->FormSet->HiiHandle, Statement->HiiValue.Value.string, (CHAR16*)Statement->BufferValue, NULL); 1631 } else { 1632 SetQuestionValue (gCurrentSelection->FormSet, gCurrentSelection->Form, Statement, GetSetValueWithHiiDriver); 1633 } 1634 break; 1635 1636 case EFI_IFR_ORDERED_LIST_OP: 1637 CopyMem (Statement->BufferValue, UserInput->InputValue.Buffer, UserInput->InputValue.BufferLen); 1638 break; 1639 1640 default: 1641 CopyMem (&Statement->HiiValue, &UserInput->InputValue, sizeof (EFI_HII_VALUE)); 1642 break; 1643 } 1644 break; 1645 } 1646 } 1647 1648 return Status; 1649 } 1650 1651 /** 1652 1653 Display form and wait for user to select one menu option, then return it. 1654 1655 @retval EFI_SUCESSS This function always return successfully for now. 1656 1657 **/ 1658 EFI_STATUS 1659 DisplayForm ( 1660 VOID 1661 ) 1662 { 1663 EFI_STATUS Status; 1664 USER_INPUT UserInput; 1665 FORM_ENTRY_INFO *CurrentMenu; 1666 1667 ZeroMem (&UserInput, sizeof (USER_INPUT)); 1668 1669 // 1670 // Update the menu history data. 1671 // 1672 CurrentMenu = UiFindMenuList (gCurrentSelection->Handle, &gCurrentSelection->FormSetGuid, gCurrentSelection->FormId); 1673 if (CurrentMenu == NULL) { 1674 // 1675 // Current menu not found, add it to the menu tree 1676 // 1677 CurrentMenu = UiAddMenuList (gCurrentSelection->Handle, &gCurrentSelection->FormSetGuid, 1678 gCurrentSelection->FormId, gCurrentSelection->QuestionId); 1679 ASSERT (CurrentMenu != NULL); 1680 } 1681 1682 // 1683 // Back up the form view history data for this form. 1684 // 1685 UiCopyMenuList(&gCurrentSelection->Form->FormViewListHead, &mPrivateData.FormBrowserEx2.FormViewHistoryHead); 1686 1687 gCurrentSelection->CurrentMenu = CurrentMenu; 1688 1689 if (gCurrentSelection->QuestionId == 0) { 1690 // 1691 // Highlight not specified, fetch it from cached menu 1692 // 1693 gCurrentSelection->QuestionId = CurrentMenu->QuestionId; 1694 } 1695 1696 Status = EvaluateFormExpressions (gCurrentSelection->FormSet, gCurrentSelection->Form); 1697 if (EFI_ERROR (Status)) { 1698 return Status; 1699 } 1700 1701 UpdateDisplayFormData (); 1702 1703 ASSERT (gDisplayFormData.BrowserStatus == BROWSER_SUCCESS); 1704 Status = mFormDisplay->FormDisplay (&gDisplayFormData, &UserInput); 1705 if (EFI_ERROR (Status)) { 1706 FreeDisplayFormData(); 1707 return Status; 1708 } 1709 1710 Status = ProcessUserInput (&UserInput); 1711 FreeDisplayFormData(); 1712 return Status; 1713 } 1714 1715 /** 1716 Functions which are registered to receive notification of 1717 database events have this prototype. The actual event is encoded 1718 in NotifyType. The following table describes how PackageType, 1719 PackageGuid, Handle, and Package are used for each of the 1720 notification types. 1721 1722 @param PackageType Package type of the notification. 1723 1724 @param PackageGuid If PackageType is 1725 EFI_HII_PACKAGE_TYPE_GUID, then this is 1726 the pointer to the GUID from the Guid 1727 field of EFI_HII_PACKAGE_GUID_HEADER. 1728 Otherwise, it must be NULL. 1729 1730 @param Package Points to the package referred to by the 1731 notification Handle The handle of the package 1732 list which contains the specified package. 1733 1734 @param Handle The HII handle. 1735 1736 @param NotifyType The type of change concerning the 1737 database. See 1738 EFI_HII_DATABASE_NOTIFY_TYPE. 1739 1740 **/ 1741 EFI_STATUS 1742 EFIAPI 1743 FormUpdateNotify ( 1744 IN UINT8 PackageType, 1745 IN CONST EFI_GUID *PackageGuid, 1746 IN CONST EFI_HII_PACKAGE_HEADER *Package, 1747 IN EFI_HII_HANDLE Handle, 1748 IN EFI_HII_DATABASE_NOTIFY_TYPE NotifyType 1749 ) 1750 { 1751 mHiiPackageListUpdated = TRUE; 1752 1753 return EFI_SUCCESS; 1754 } 1755 1756 /** 1757 Update the NV flag info for this form set. 1758 1759 @param FormSet FormSet data structure. 1760 1761 **/ 1762 BOOLEAN 1763 IsNvUpdateRequiredForFormSet ( 1764 IN FORM_BROWSER_FORMSET *FormSet 1765 ) 1766 { 1767 LIST_ENTRY *Link; 1768 FORM_BROWSER_FORM *Form; 1769 BOOLEAN RetVal; 1770 1771 // 1772 // Not finished question initialization, return FALSE. 1773 // 1774 if (!FormSet->QuestionInited) { 1775 return FALSE; 1776 } 1777 1778 RetVal = FALSE; 1779 1780 Link = GetFirstNode (&FormSet->FormListHead); 1781 while (!IsNull (&FormSet->FormListHead, Link)) { 1782 Form = FORM_BROWSER_FORM_FROM_LINK (Link); 1783 1784 RetVal = IsNvUpdateRequiredForForm(Form); 1785 if (RetVal) { 1786 break; 1787 } 1788 1789 Link = GetNextNode (&FormSet->FormListHead, Link); 1790 } 1791 1792 return RetVal; 1793 } 1794 1795 /** 1796 Update the NvUpdateRequired flag for a form. 1797 1798 @param Form Form data structure. 1799 1800 **/ 1801 BOOLEAN 1802 IsNvUpdateRequiredForForm ( 1803 IN FORM_BROWSER_FORM *Form 1804 ) 1805 { 1806 LIST_ENTRY *Link; 1807 FORM_BROWSER_STATEMENT *Statement; 1808 1809 Link = GetFirstNode (&Form->StatementListHead); 1810 while (!IsNull (&Form->StatementListHead, Link)) { 1811 Statement = FORM_BROWSER_STATEMENT_FROM_LINK (Link); 1812 1813 if (Statement->ValueChanged) { 1814 return TRUE; 1815 } 1816 1817 Link = GetNextNode (&Form->StatementListHead, Link); 1818 } 1819 1820 return FALSE; 1821 } 1822 1823 /** 1824 Find menu which will show next time. 1825 1826 @param Selection On input, Selection tell setup browser the information 1827 about the Selection, form and formset to be displayed. 1828 On output, Selection return the screen item that is selected 1829 by user. 1830 @param SettingLevel Input Settting level, if it is FormLevel, just exit current form. 1831 else, we need to exit current formset. 1832 1833 @retval TRUE Exit current form. 1834 @retval FALSE User press ESC and keep in current form. 1835 **/ 1836 BOOLEAN 1837 FindNextMenu ( 1838 IN OUT UI_MENU_SELECTION *Selection, 1839 IN BROWSER_SETTING_SCOPE SettingLevel 1840 ) 1841 { 1842 FORM_ENTRY_INFO *CurrentMenu; 1843 FORM_ENTRY_INFO *ParentMenu; 1844 BROWSER_SETTING_SCOPE Scope; 1845 1846 CurrentMenu = Selection->CurrentMenu; 1847 Scope = FormSetLevel; 1848 1849 ParentMenu = UiFindParentMenu(CurrentMenu, SettingLevel); 1850 while (ParentMenu != NULL && !ValidateHiiHandle(ParentMenu->HiiHandle)) { 1851 ParentMenu = UiFindParentMenu(ParentMenu, SettingLevel); 1852 } 1853 1854 if (ParentMenu != NULL) { 1855 if (CompareGuid (&CurrentMenu->FormSetGuid, &ParentMenu->FormSetGuid)) { 1856 Scope = FormLevel; 1857 } else { 1858 Scope = FormSetLevel; 1859 } 1860 } 1861 1862 // 1863 // Form Level Check whether the data is changed. 1864 // 1865 if ((gBrowserSettingScope == FormLevel && IsNvUpdateRequiredForForm (Selection->Form)) || 1866 (gBrowserSettingScope == FormSetLevel && IsNvUpdateRequiredForFormSet(Selection->FormSet) && Scope == FormSetLevel)) { 1867 if (!ProcessChangedData(Selection, gBrowserSettingScope)) { 1868 return FALSE; 1869 } 1870 } 1871 1872 if (ParentMenu != NULL) { 1873 // 1874 // ParentMenu is found. Then, go to it. 1875 // 1876 if (Scope == FormLevel) { 1877 Selection->Action = UI_ACTION_REFRESH_FORM; 1878 } else { 1879 Selection->Action = UI_ACTION_REFRESH_FORMSET; 1880 CopyMem (&Selection->FormSetGuid, &ParentMenu->FormSetGuid, sizeof (EFI_GUID)); 1881 Selection->Handle = ParentMenu->HiiHandle; 1882 } 1883 1884 Selection->Statement = NULL; 1885 1886 Selection->FormId = ParentMenu->FormId; 1887 Selection->QuestionId = ParentMenu->QuestionId; 1888 1889 // 1890 // Clear highlight record for this menu 1891 // 1892 CurrentMenu->QuestionId = 0; 1893 return FALSE; 1894 } 1895 1896 // 1897 // Current in root page, exit the SendForm 1898 // 1899 Selection->Action = UI_ACTION_EXIT; 1900 1901 return TRUE; 1902 } 1903 1904 /** 1905 Reconnect the controller. 1906 1907 @param DriverHandle The controller handle which need to be reconnect. 1908 1909 @retval TRUE do the reconnect behavior success. 1910 @retval FALSE do the reconnect behavior failed. 1911 1912 **/ 1913 BOOLEAN 1914 ReconnectController ( 1915 IN EFI_HANDLE DriverHandle 1916 ) 1917 { 1918 EFI_STATUS Status; 1919 1920 Status = gBS->DisconnectController(DriverHandle, NULL, NULL); 1921 if (!EFI_ERROR (Status)) { 1922 Status = gBS->ConnectController(DriverHandle, NULL, NULL, TRUE); 1923 } 1924 1925 return Status == EFI_SUCCESS; 1926 } 1927 1928 /** 1929 Call the call back function for the question and process the return action. 1930 1931 @param Selection On input, Selection tell setup browser the information 1932 about the Selection, form and formset to be displayed. 1933 On output, Selection return the screen item that is selected 1934 by user. 1935 @param FormSet The formset this question belong to. 1936 @param Form The form this question belong to. 1937 @param Question The Question which need to call. 1938 @param Action The action request. 1939 @param SkipSaveOrDiscard Whether skip save or discard action. 1940 1941 @retval EFI_SUCCESS The call back function executes successfully. 1942 @return Other value if the call back function failed to execute. 1943 **/ 1944 EFI_STATUS 1945 ProcessCallBackFunction ( 1946 IN OUT UI_MENU_SELECTION *Selection, 1947 IN FORM_BROWSER_FORMSET *FormSet, 1948 IN FORM_BROWSER_FORM *Form, 1949 IN FORM_BROWSER_STATEMENT *Question, 1950 IN EFI_BROWSER_ACTION Action, 1951 IN BOOLEAN SkipSaveOrDiscard 1952 ) 1953 { 1954 EFI_STATUS Status; 1955 EFI_STATUS InternalStatus; 1956 EFI_BROWSER_ACTION_REQUEST ActionRequest; 1957 EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess; 1958 EFI_HII_VALUE *HiiValue; 1959 EFI_IFR_TYPE_VALUE *TypeValue; 1960 FORM_BROWSER_STATEMENT *Statement; 1961 BOOLEAN SubmitFormIsRequired; 1962 BOOLEAN DiscardFormIsRequired; 1963 BOOLEAN NeedExit; 1964 LIST_ENTRY *Link; 1965 BROWSER_SETTING_SCOPE SettingLevel; 1966 EFI_IFR_TYPE_VALUE BackUpValue; 1967 UINT8 *BackUpBuffer; 1968 CHAR16 *NewString; 1969 1970 ConfigAccess = FormSet->ConfigAccess; 1971 SubmitFormIsRequired = FALSE; 1972 SettingLevel = FormSetLevel; 1973 DiscardFormIsRequired = FALSE; 1974 NeedExit = FALSE; 1975 Status = EFI_SUCCESS; 1976 ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE; 1977 BackUpBuffer = NULL; 1978 1979 if (ConfigAccess == NULL) { 1980 return EFI_SUCCESS; 1981 } 1982 1983 Link = GetFirstNode (&Form->StatementListHead); 1984 while (!IsNull (&Form->StatementListHead, Link)) { 1985 Statement = FORM_BROWSER_STATEMENT_FROM_LINK (Link); 1986 Link = GetNextNode (&Form->StatementListHead, Link); 1987 1988 // 1989 // if Question != NULL, only process the question. Else, process all question in this form. 1990 // 1991 if ((Question != NULL) && (Statement != Question)) { 1992 continue; 1993 } 1994 1995 if ((Statement->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != EFI_IFR_FLAG_CALLBACK) { 1996 continue; 1997 } 1998 1999 // 2000 // Check whether Statement is disabled. 2001 // 2002 if (Statement->Expression != NULL) { 2003 if (EvaluateExpressionList(Statement->Expression, TRUE, FormSet, Form) == ExpressDisable) { 2004 continue; 2005 } 2006 } 2007 2008 HiiValue = &Statement->HiiValue; 2009 TypeValue = &HiiValue->Value; 2010 if (HiiValue->Type == EFI_IFR_TYPE_BUFFER) { 2011 // 2012 // For OrderedList, passing in the value buffer to Callback() 2013 // 2014 TypeValue = (EFI_IFR_TYPE_VALUE *) Statement->BufferValue; 2015 } 2016 2017 // 2018 // If EFI_BROWSER_ACTION_CHANGING type, back up the new question value. 2019 // 2020 if (Action == EFI_BROWSER_ACTION_CHANGING) { 2021 if (HiiValue->Type == EFI_IFR_TYPE_BUFFER) { 2022 BackUpBuffer = AllocateCopyPool(Statement->StorageWidth + sizeof(CHAR16), Statement->BufferValue); 2023 ASSERT (BackUpBuffer != NULL); 2024 } else { 2025 CopyMem (&BackUpValue, &HiiValue->Value, sizeof (EFI_IFR_TYPE_VALUE)); 2026 } 2027 } 2028 2029 ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE; 2030 Status = ConfigAccess->Callback ( 2031 ConfigAccess, 2032 Action, 2033 Statement->QuestionId, 2034 HiiValue->Type, 2035 TypeValue, 2036 &ActionRequest 2037 ); 2038 if (!EFI_ERROR (Status)) { 2039 // 2040 // Need to sync the value between Statement->HiiValue->Value and Statement->BufferValue 2041 // 2042 if (HiiValue->Type == EFI_IFR_TYPE_STRING) { 2043 NewString = GetToken (Statement->HiiValue.Value.string, FormSet->HiiHandle); 2044 ASSERT (NewString != NULL); 2045 2046 ASSERT (StrLen (NewString) * sizeof (CHAR16) <= Statement->StorageWidth); 2047 if (StrLen (NewString) * sizeof (CHAR16) <= Statement->StorageWidth) { 2048 ZeroMem (Statement->BufferValue, Statement->StorageWidth); 2049 CopyMem (Statement->BufferValue, NewString, StrSize (NewString)); 2050 } else { 2051 CopyMem (Statement->BufferValue, NewString, Statement->StorageWidth); 2052 } 2053 FreePool (NewString); 2054 } 2055 2056 // 2057 // Only for EFI_BROWSER_ACTION_CHANGED need to handle this ActionRequest. 2058 // 2059 switch (Action) { 2060 case EFI_BROWSER_ACTION_CHANGED: 2061 switch (ActionRequest) { 2062 case EFI_BROWSER_ACTION_REQUEST_RESET: 2063 DiscardFormIsRequired = TRUE; 2064 gResetRequired = TRUE; 2065 NeedExit = TRUE; 2066 break; 2067 2068 case EFI_BROWSER_ACTION_REQUEST_SUBMIT: 2069 SubmitFormIsRequired = TRUE; 2070 NeedExit = TRUE; 2071 break; 2072 2073 case EFI_BROWSER_ACTION_REQUEST_EXIT: 2074 DiscardFormIsRequired = TRUE; 2075 NeedExit = TRUE; 2076 break; 2077 2078 case EFI_BROWSER_ACTION_REQUEST_FORM_SUBMIT_EXIT: 2079 SubmitFormIsRequired = TRUE; 2080 SettingLevel = FormLevel; 2081 NeedExit = TRUE; 2082 break; 2083 2084 case EFI_BROWSER_ACTION_REQUEST_FORM_DISCARD_EXIT: 2085 DiscardFormIsRequired = TRUE; 2086 SettingLevel = FormLevel; 2087 NeedExit = TRUE; 2088 break; 2089 2090 case EFI_BROWSER_ACTION_REQUEST_FORM_APPLY: 2091 SubmitFormIsRequired = TRUE; 2092 SettingLevel = FormLevel; 2093 break; 2094 2095 case EFI_BROWSER_ACTION_REQUEST_FORM_DISCARD: 2096 DiscardFormIsRequired = TRUE; 2097 SettingLevel = FormLevel; 2098 break; 2099 2100 case EFI_BROWSER_ACTION_REQUEST_RECONNECT: 2101 gCallbackReconnect = TRUE; 2102 break; 2103 2104 default: 2105 break; 2106 } 2107 break; 2108 2109 case EFI_BROWSER_ACTION_CHANGING: 2110 // 2111 // Do the question validation. 2112 // 2113 Status = ValueChangedValidation (gCurrentSelection->FormSet, gCurrentSelection->Form, Statement); 2114 if (!EFI_ERROR (Status)) { 2115 // 2116 //check whether the question value changed compared with edit buffer before updating edit buffer 2117 // if changed, set the ValueChanged flag to TRUE,in order to trig the CHANGED callback function 2118 // 2119 IsQuestionValueChanged(gCurrentSelection->FormSet, gCurrentSelection->Form, Statement, GetSetValueWithEditBuffer); 2120 // 2121 // According the spec, return value from call back of "changing" and 2122 // "retrieve" should update to the question's temp buffer. 2123 // 2124 SetQuestionValue(FormSet, Form, Statement, GetSetValueWithEditBuffer); 2125 } 2126 break; 2127 2128 case EFI_BROWSER_ACTION_RETRIEVE: 2129 // 2130 // According the spec, return value from call back of "changing" and 2131 // "retrieve" should update to the question's temp buffer. 2132 // 2133 SetQuestionValue(FormSet, Form, Statement, GetSetValueWithEditBuffer); 2134 break; 2135 2136 default: 2137 break; 2138 } 2139 } else { 2140 // 2141 // If the callback returns EFI_UNSUPPORTED for EFI_BROWSER_ACTION_CHANGING, 2142 // then the browser will use the value passed to Callback() and ignore the 2143 // value returned by Callback(). 2144 // 2145 if (Action == EFI_BROWSER_ACTION_CHANGING && Status == EFI_UNSUPPORTED) { 2146 if (HiiValue->Type == EFI_IFR_TYPE_BUFFER) { 2147 CopyMem (Statement->BufferValue, BackUpBuffer, Statement->StorageWidth + sizeof(CHAR16)); 2148 } else { 2149 CopyMem (&HiiValue->Value, &BackUpValue, sizeof (EFI_IFR_TYPE_VALUE)); 2150 } 2151 2152 // 2153 // Do the question validation. 2154 // 2155 InternalStatus = ValueChangedValidation (gCurrentSelection->FormSet, gCurrentSelection->Form, Statement); 2156 if (!EFI_ERROR (InternalStatus)) { 2157 // 2158 //check whether the question value changed compared with edit buffer before updating edit buffer 2159 // if changed, set the ValueChanged flag to TRUE,in order to trig the CHANGED callback function 2160 // 2161 IsQuestionValueChanged(gCurrentSelection->FormSet, gCurrentSelection->Form, Statement, GetSetValueWithEditBuffer); 2162 SetQuestionValue(FormSet, Form, Statement, GetSetValueWithEditBuffer); 2163 } 2164 } 2165 2166 // 2167 // According the spec, return fail from call back of "changing" and 2168 // "retrieve", should restore the question's value. 2169 // 2170 if (Action == EFI_BROWSER_ACTION_CHANGING && Status != EFI_UNSUPPORTED) { 2171 if (Statement->Storage != NULL) { 2172 GetQuestionValue(FormSet, Form, Statement, GetSetValueWithEditBuffer); 2173 } else if ((Statement->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) { 2174 ProcessCallBackFunction (Selection, FormSet, Form, Question, EFI_BROWSER_ACTION_RETRIEVE, FALSE); 2175 } 2176 } 2177 2178 if (Action == EFI_BROWSER_ACTION_RETRIEVE) { 2179 GetQuestionValue(FormSet, Form, Statement, GetSetValueWithEditBuffer); 2180 } 2181 2182 if (Status == EFI_UNSUPPORTED) { 2183 // 2184 // If return EFI_UNSUPPORTED, also consider Hii driver suceess deal with it. 2185 // 2186 Status = EFI_SUCCESS; 2187 } 2188 } 2189 2190 if (BackUpBuffer != NULL) { 2191 FreePool (BackUpBuffer); 2192 } 2193 2194 // 2195 // If Question != NULL, means just process one question 2196 // and if code reach here means this question has finished 2197 // processing, so just break. 2198 // 2199 if (Question != NULL) { 2200 break; 2201 } 2202 } 2203 2204 if (gCallbackReconnect && (EFI_BROWSER_ACTION_CHANGED == Action)) { 2205 // 2206 // Confirm changes with user first. 2207 // 2208 if (IsNvUpdateRequiredForFormSet(FormSet)) { 2209 if (BROWSER_ACTION_DISCARD == PopupErrorMessage(BROWSER_RECONNECT_SAVE_CHANGES, NULL, NULL, NULL)) { 2210 gCallbackReconnect = FALSE; 2211 DiscardFormIsRequired = TRUE; 2212 } else { 2213 SubmitFormIsRequired = TRUE; 2214 } 2215 } else { 2216 PopupErrorMessage(BROWSER_RECONNECT_REQUIRED, NULL, NULL, NULL); 2217 } 2218 2219 // 2220 // Exit current formset before do the reconnect. 2221 // 2222 NeedExit = TRUE; 2223 SettingLevel = FormSetLevel; 2224 } 2225 2226 if (SubmitFormIsRequired && !SkipSaveOrDiscard) { 2227 SubmitForm (FormSet, Form, SettingLevel); 2228 } 2229 2230 if (DiscardFormIsRequired && !SkipSaveOrDiscard) { 2231 DiscardForm (FormSet, Form, SettingLevel); 2232 } 2233 2234 if (NeedExit) { 2235 FindNextMenu (Selection, SettingLevel); 2236 } 2237 2238 return Status; 2239 } 2240 2241 /** 2242 Call the retrieve type call back function for one question to get the initialize data. 2243 2244 This function only used when in the initialize stage, because in this stage, the 2245 Selection->Form is not ready. For other case, use the ProcessCallBackFunction instead. 2246 2247 @param ConfigAccess The config access protocol produced by the hii driver. 2248 @param Statement The Question which need to call. 2249 @param FormSet The formset this question belong to. 2250 2251 @retval EFI_SUCCESS The call back function executes successfully. 2252 @return Other value if the call back function failed to execute. 2253 **/ 2254 EFI_STATUS 2255 ProcessRetrieveForQuestion ( 2256 IN EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess, 2257 IN FORM_BROWSER_STATEMENT *Statement, 2258 IN FORM_BROWSER_FORMSET *FormSet 2259 ) 2260 { 2261 EFI_STATUS Status; 2262 EFI_BROWSER_ACTION_REQUEST ActionRequest; 2263 EFI_HII_VALUE *HiiValue; 2264 EFI_IFR_TYPE_VALUE *TypeValue; 2265 CHAR16 *NewString; 2266 2267 Status = EFI_SUCCESS; 2268 ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE; 2269 2270 if (((Statement->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != EFI_IFR_FLAG_CALLBACK) || ConfigAccess == NULL) { 2271 return EFI_UNSUPPORTED; 2272 } 2273 2274 HiiValue = &Statement->HiiValue; 2275 TypeValue = &HiiValue->Value; 2276 if (HiiValue->Type == EFI_IFR_TYPE_BUFFER) { 2277 // 2278 // For OrderedList, passing in the value buffer to Callback() 2279 // 2280 TypeValue = (EFI_IFR_TYPE_VALUE *) Statement->BufferValue; 2281 } 2282 2283 ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE; 2284 Status = ConfigAccess->Callback ( 2285 ConfigAccess, 2286 EFI_BROWSER_ACTION_RETRIEVE, 2287 Statement->QuestionId, 2288 HiiValue->Type, 2289 TypeValue, 2290 &ActionRequest 2291 ); 2292 if (!EFI_ERROR (Status) && HiiValue->Type == EFI_IFR_TYPE_STRING) { 2293 NewString = GetToken (Statement->HiiValue.Value.string, FormSet->HiiHandle); 2294 ASSERT (NewString != NULL); 2295 2296 ASSERT (StrLen (NewString) * sizeof (CHAR16) <= Statement->StorageWidth); 2297 if (StrLen (NewString) * sizeof (CHAR16) <= Statement->StorageWidth) { 2298 ZeroMem (Statement->BufferValue, Statement->StorageWidth); 2299 CopyMem (Statement->BufferValue, NewString, StrSize (NewString)); 2300 } else { 2301 CopyMem (Statement->BufferValue, NewString, Statement->StorageWidth); 2302 } 2303 FreePool (NewString); 2304 } 2305 2306 return Status; 2307 } 2308 2309 /** 2310 The worker function that send the displays to the screen. On output, 2311 the selection made by user is returned. 2312 2313 @param Selection On input, Selection tell setup browser the information 2314 about the Selection, form and formset to be displayed. 2315 On output, Selection return the screen item that is selected 2316 by user. 2317 2318 @retval EFI_SUCCESS The page is displayed successfully. 2319 @return Other value if the page failed to be diplayed. 2320 2321 **/ 2322 EFI_STATUS 2323 SetupBrowser ( 2324 IN OUT UI_MENU_SELECTION *Selection 2325 ) 2326 { 2327 EFI_STATUS Status; 2328 LIST_ENTRY *Link; 2329 EFI_HANDLE NotifyHandle; 2330 FORM_BROWSER_STATEMENT *Statement; 2331 EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess; 2332 2333 ConfigAccess = Selection->FormSet->ConfigAccess; 2334 2335 // 2336 // Register notify for Form package update 2337 // 2338 Status = mHiiDatabase->RegisterPackageNotify ( 2339 mHiiDatabase, 2340 EFI_HII_PACKAGE_FORMS, 2341 NULL, 2342 FormUpdateNotify, 2343 EFI_HII_DATABASE_NOTIFY_REMOVE_PACK, 2344 &NotifyHandle 2345 ); 2346 if (EFI_ERROR (Status)) { 2347 return Status; 2348 } 2349 2350 // 2351 // Initialize current settings of Questions in this FormSet 2352 // 2353 InitializeCurrentSetting (Selection->FormSet); 2354 2355 // 2356 // Initilize Action field. 2357 // 2358 Selection->Action = UI_ACTION_REFRESH_FORM; 2359 2360 // 2361 // Clean the mCurFakeQestId value is formset refreshed. 2362 // 2363 mCurFakeQestId = 0; 2364 2365 do { 2366 2367 // 2368 // Reset Status to prevent the next break from returning incorrect error status. 2369 // 2370 Status = EFI_SUCCESS; 2371 2372 // 2373 // IFR is updated, force to reparse the IFR binary 2374 // This check is shared by EFI_BROWSER_ACTION_FORM_CLOSE and 2375 // EFI_BROWSER_ACTION_RETRIEVE, so code place here. 2376 // 2377 if (mHiiPackageListUpdated) { 2378 Selection->Action = UI_ACTION_REFRESH_FORMSET; 2379 mHiiPackageListUpdated = FALSE; 2380 break; 2381 } 2382 2383 // 2384 // Initialize Selection->Form 2385 // 2386 if (Selection->FormId == 0) { 2387 // 2388 // Zero FormId indicates display the first Form in a FormSet 2389 // 2390 Link = GetFirstNode (&Selection->FormSet->FormListHead); 2391 2392 Selection->Form = FORM_BROWSER_FORM_FROM_LINK (Link); 2393 Selection->FormId = Selection->Form->FormId; 2394 } else { 2395 Selection->Form = IdToForm (Selection->FormSet, Selection->FormId); 2396 } 2397 2398 if (Selection->Form == NULL) { 2399 // 2400 // No Form to display 2401 // 2402 Status = EFI_NOT_FOUND; 2403 goto Done; 2404 } 2405 2406 // 2407 // Check Form is suppressed. 2408 // 2409 if (Selection->Form->SuppressExpression != NULL) { 2410 if (EvaluateExpressionList(Selection->Form->SuppressExpression, TRUE, Selection->FormSet, Selection->Form) == ExpressSuppress) { 2411 // 2412 // Form is suppressed. 2413 // 2414 PopupErrorMessage(BROWSER_FORM_SUPPRESS, NULL, NULL, NULL); 2415 Status = EFI_NOT_FOUND; 2416 goto Done; 2417 } 2418 } 2419 2420 // 2421 // Before display new form, invoke ConfigAccess.Callback() with EFI_BROWSER_ACTION_FORM_OPEN 2422 // for each question with callback flag. 2423 // New form may be the first form, or the different form after another form close. 2424 // 2425 if (((Selection->Handle != mCurrentHiiHandle) || 2426 (!CompareGuid (&Selection->FormSetGuid, &mCurrentFormSetGuid)) || 2427 (Selection->FormId != mCurrentFormId))) { 2428 // 2429 // Update Retrieve flag. 2430 // 2431 mFinishRetrieveCall = FALSE; 2432 2433 // 2434 // Keep current form information 2435 // 2436 mCurrentHiiHandle = Selection->Handle; 2437 CopyGuid (&mCurrentFormSetGuid, &Selection->FormSetGuid); 2438 mCurrentFormId = Selection->FormId; 2439 2440 if (ConfigAccess != NULL) { 2441 Status = ProcessCallBackFunction (Selection, Selection->FormSet, Selection->Form, NULL, EFI_BROWSER_ACTION_FORM_OPEN, FALSE); 2442 if (EFI_ERROR (Status)) { 2443 goto Done; 2444 } 2445 2446 // 2447 // IFR is updated during callback of EFI_BROWSER_ACTION_FORM_OPEN, force to reparse the IFR binary 2448 // 2449 if (mHiiPackageListUpdated) { 2450 Selection->Action = UI_ACTION_REFRESH_FORMSET; 2451 mHiiPackageListUpdated = FALSE; 2452 break; 2453 } 2454 } 2455 } 2456 2457 // 2458 // Load Questions' Value for display 2459 // 2460 Status = LoadFormSetConfig (Selection, Selection->FormSet); 2461 if (EFI_ERROR (Status)) { 2462 goto Done; 2463 } 2464 2465 if (!mFinishRetrieveCall) { 2466 // 2467 // Finish call RETRIEVE callback for this form. 2468 // 2469 mFinishRetrieveCall = TRUE; 2470 2471 if (ConfigAccess != NULL) { 2472 Status = ProcessCallBackFunction (Selection, Selection->FormSet, Selection->Form, NULL, EFI_BROWSER_ACTION_RETRIEVE, FALSE); 2473 if (EFI_ERROR (Status)) { 2474 goto Done; 2475 } 2476 2477 // 2478 // IFR is updated during callback of open form, force to reparse the IFR binary 2479 // 2480 if (mHiiPackageListUpdated) { 2481 Selection->Action = UI_ACTION_REFRESH_FORMSET; 2482 mHiiPackageListUpdated = FALSE; 2483 break; 2484 } 2485 } 2486 } 2487 2488 // 2489 // Display form 2490 // 2491 Status = DisplayForm (); 2492 if (EFI_ERROR (Status)) { 2493 goto Done; 2494 } 2495 2496 // 2497 // Check Selected Statement (if press ESC, Selection->Statement will be NULL) 2498 // 2499 Statement = Selection->Statement; 2500 if (Statement != NULL) { 2501 if ((ConfigAccess != NULL) && 2502 ((Statement->QuestionFlags & EFI_IFR_FLAG_CALLBACK) == EFI_IFR_FLAG_CALLBACK) && 2503 (Statement->Operand != EFI_IFR_PASSWORD_OP)) { 2504 Status = ProcessCallBackFunction(Selection, Selection->FormSet, Selection->Form, Statement, EFI_BROWSER_ACTION_CHANGING, FALSE); 2505 if (Statement->Operand == EFI_IFR_REF_OP) { 2506 // 2507 // Process dynamic update ref opcode. 2508 // 2509 if (!EFI_ERROR (Status)) { 2510 Status = ProcessGotoOpCode(Statement, Selection); 2511 } 2512 2513 // 2514 // Callback return error status or status return from process goto opcode. 2515 // 2516 if (EFI_ERROR (Status)) { 2517 // 2518 // Cross reference will not be taken, restore all essential field 2519 // 2520 Selection->Handle = mCurrentHiiHandle; 2521 CopyMem (&Selection->FormSetGuid, &mCurrentFormSetGuid, sizeof (EFI_GUID)); 2522 Selection->FormId = mCurrentFormId; 2523 Selection->QuestionId = 0; 2524 Selection->Action = UI_ACTION_REFRESH_FORM; 2525 } 2526 } 2527 2528 2529 if (!EFI_ERROR (Status) && 2530 (Statement->Operand != EFI_IFR_REF_OP) && 2531 ((Statement->Storage == NULL) || (Statement->Storage != NULL && Statement->ValueChanged))) { 2532 // 2533 // Only question value has been changed, browser will trig CHANGED callback. 2534 // 2535 ProcessCallBackFunction(Selection, Selection->FormSet, Selection->Form, Statement, EFI_BROWSER_ACTION_CHANGED, FALSE); 2536 // 2537 //check whether the question value changed compared with buffer value 2538 //if doesn't change ,set the ValueChanged flag to FALSE ,in order not to display the "configuration changed "information on the screen 2539 // 2540 IsQuestionValueChanged(gCurrentSelection->FormSet, gCurrentSelection->Form, Statement, GetSetValueWithBuffer); 2541 } 2542 } else { 2543 // 2544 // Do the question validation. 2545 // 2546 Status = ValueChangedValidation (gCurrentSelection->FormSet, gCurrentSelection->Form, Statement); 2547 if (!EFI_ERROR (Status) && (Statement->Operand != EFI_IFR_PASSWORD_OP)) { 2548 SetQuestionValue (gCurrentSelection->FormSet, gCurrentSelection->Form, Statement, GetSetValueWithEditBuffer); 2549 // 2550 // Verify whether question value has checked, update the ValueChanged flag in Question. 2551 // 2552 IsQuestionValueChanged(gCurrentSelection->FormSet, gCurrentSelection->Form, Statement, GetSetValueWithBuffer); 2553 } 2554 } 2555 2556 // 2557 // If question has EFI_IFR_FLAG_RESET_REQUIRED/EFI_IFR_FLAG_RECONNECT_REQUIRED flag and without storage 2558 // and process question success till here, trig the gResetFlag/gFlagReconnect. 2559 // 2560 if ((Status == EFI_SUCCESS) && 2561 (Statement->Storage == NULL)) { 2562 if ((Statement->QuestionFlags & EFI_IFR_FLAG_RESET_REQUIRED) != 0) { 2563 gResetRequired = TRUE; 2564 } 2565 2566 if ((Statement->QuestionFlags & EFI_IFR_FLAG_RECONNECT_REQUIRED) != 0) { 2567 gFlagReconnect = TRUE; 2568 } 2569 } 2570 } 2571 2572 // 2573 // Check whether Exit flag is TRUE. 2574 // 2575 if (gExitRequired) { 2576 switch (gBrowserSettingScope) { 2577 case SystemLevel: 2578 Selection->Action = UI_ACTION_EXIT; 2579 break; 2580 2581 case FormSetLevel: 2582 case FormLevel: 2583 FindNextMenu (Selection, gBrowserSettingScope); 2584 break; 2585 2586 default: 2587 break; 2588 } 2589 2590 gExitRequired = FALSE; 2591 } 2592 2593 // 2594 // Before exit the form, invoke ConfigAccess.Callback() with EFI_BROWSER_ACTION_FORM_CLOSE 2595 // for each question with callback flag. 2596 // 2597 if ((ConfigAccess != NULL) && 2598 ((Selection->Action == UI_ACTION_EXIT) || 2599 (Selection->Handle != mCurrentHiiHandle) || 2600 (!CompareGuid (&Selection->FormSetGuid, &mCurrentFormSetGuid)) || 2601 (Selection->FormId != mCurrentFormId))) { 2602 2603 Status = ProcessCallBackFunction (Selection, Selection->FormSet, Selection->Form, NULL, EFI_BROWSER_ACTION_FORM_CLOSE, FALSE); 2604 if (EFI_ERROR (Status)) { 2605 goto Done; 2606 } 2607 } 2608 } while (Selection->Action == UI_ACTION_REFRESH_FORM); 2609 2610 Done: 2611 // 2612 // Reset current form information to the initial setting when error happens or form exit. 2613 // 2614 if (EFI_ERROR (Status) || Selection->Action == UI_ACTION_EXIT) { 2615 mCurrentHiiHandle = NULL; 2616 CopyGuid (&mCurrentFormSetGuid, &gZeroGuid); 2617 mCurrentFormId = 0; 2618 } 2619 2620 // 2621 // Unregister notify for Form package update 2622 // 2623 mHiiDatabase->UnregisterPackageNotify ( 2624 mHiiDatabase, 2625 NotifyHandle 2626 ); 2627 return Status; 2628 } 2629