1/** @file 2 HII Config Access protocol implementation of VLAN configuration module. 3 4Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.<BR> 5This program and the accompanying materials 6are licensed and made available under the terms and conditions 7of the BSD License which accompanies this distribution. The full 8text of the license may be found at<BR> 9http://opensource.org/licenses/bsd-license.php 10 11THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 12WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 13 14**/ 15 16#include "VlanConfigImpl.h" 17 18CHAR16 mVlanStorageName[] = L"VlanNvData"; 19EFI_HII_CONFIG_ROUTING_PROTOCOL *mHiiConfigRouting = NULL; 20 21VLAN_CONFIG_PRIVATE_DATA mVlanConfigPrivateDateTemplate = { 22 VLAN_CONFIG_PRIVATE_DATA_SIGNATURE, 23 { 24 VlanExtractConfig, 25 VlanRouteConfig, 26 VlanCallback 27 } 28}; 29 30VENDOR_DEVICE_PATH mHiiVendorDevicePathNode = { 31 { 32 HARDWARE_DEVICE_PATH, 33 HW_VENDOR_DP, 34 { 35 (UINT8) (sizeof (VENDOR_DEVICE_PATH)), 36 (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8) 37 } 38 }, 39 VLAN_CONFIG_FORM_SET_GUID 40}; 41 42/** 43 This function allows a caller to extract the current configuration for one 44 or more named elements from the target driver. 45 46 @param[in] This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL. 47 @param[in] Request A null-terminated Unicode string in 48 <ConfigRequest> format. 49 @param[out] Progress On return, points to a character in the Request 50 string. Points to the string's null terminator if 51 request was successful. Points to the most recent 52 '&' before the first failing name/value pair (or 53 the beginning of the string if the failure is in 54 the first name/value pair) if the request was not 55 successful. 56 @param[out] Results A null-terminated Unicode string in 57 <ConfigAltResp> format which has all values filled 58 in for the names in the Request string. String to 59 be allocated by the called function. 60 61 @retval EFI_SUCCESS The Results is filled with the requested values. 62 @retval EFI_OUT_OF_RESOURCES Not enough memory to store the results. 63 @retval EFI_INVALID_PARAMETER Request is illegal syntax, or unknown name. 64 @retval EFI_NOT_FOUND Routing data doesn't match any storage in this 65 driver. 66 67**/ 68EFI_STATUS 69EFIAPI 70VlanExtractConfig ( 71 IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This, 72 IN CONST EFI_STRING Request, 73 OUT EFI_STRING *Progress, 74 OUT EFI_STRING *Results 75 ) 76{ 77 EFI_STATUS Status; 78 UINTN BufferSize; 79 VLAN_CONFIGURATION Configuration; 80 VLAN_CONFIG_PRIVATE_DATA *PrivateData; 81 EFI_STRING ConfigRequestHdr; 82 EFI_STRING ConfigRequest; 83 BOOLEAN AllocatedRequest; 84 UINTN Size; 85 86 if (Progress == NULL || Results == NULL) { 87 return EFI_INVALID_PARAMETER; 88 } 89 90 *Progress = Request; 91 if ((Request != NULL) && !HiiIsConfigHdrMatch (Request, &gVlanConfigFormSetGuid, mVlanStorageName)) { 92 return EFI_NOT_FOUND; 93 } 94 95 ConfigRequestHdr = NULL; 96 ConfigRequest = NULL; 97 AllocatedRequest = FALSE; 98 Size = 0; 99 100 // 101 // Retrieve the pointer to the UEFI HII Config Routing Protocol 102 // 103 if (mHiiConfigRouting == NULL) { 104 gBS->LocateProtocol (&gEfiHiiConfigRoutingProtocolGuid, NULL, (VOID **) &mHiiConfigRouting); 105 } 106 ASSERT (mHiiConfigRouting != NULL); 107 108 // 109 // Convert buffer data to <ConfigResp> by helper function BlockToConfig() 110 // 111 PrivateData = VLAN_CONFIG_PRIVATE_DATA_FROM_THIS (This); 112 ZeroMem (&Configuration, sizeof (VLAN_CONFIGURATION)); 113 BufferSize = sizeof (Configuration); 114 ConfigRequest = Request; 115 if ((Request == NULL) || (StrStr (Request, L"OFFSET") == NULL)) { 116 // 117 // Request has no request element, construct full request string. 118 // Allocate and fill a buffer large enough to hold the <ConfigHdr> template 119 // followed by "&OFFSET=0&WIDTH=WWWWWWWWWWWWWWWW" followed by a Null-terminator 120 // 121 ConfigRequestHdr = HiiConstructConfigHdr (&gVlanConfigFormSetGuid, mVlanStorageName, PrivateData->DriverHandle); 122 Size = (StrLen (ConfigRequestHdr) + 32 + 1) * sizeof (CHAR16); 123 ConfigRequest = AllocateZeroPool (Size); 124 ASSERT (ConfigRequest != NULL); 125 AllocatedRequest = TRUE; 126 UnicodeSPrint (ConfigRequest, Size, L"%s&OFFSET=0&WIDTH=%016LX", ConfigRequestHdr, (UINT64)BufferSize); 127 FreePool (ConfigRequestHdr); 128 } 129 130 Status = mHiiConfigRouting->BlockToConfig ( 131 mHiiConfigRouting, 132 ConfigRequest, 133 (UINT8 *) &Configuration, 134 BufferSize, 135 Results, 136 Progress 137 ); 138 // 139 // Free the allocated config request string. 140 // 141 if (AllocatedRequest) { 142 FreePool (ConfigRequest); 143 ConfigRequest = NULL; 144 } 145 // 146 // Set Progress string to the original request string. 147 // 148 if (Request == NULL) { 149 *Progress = NULL; 150 } else if (StrStr (Request, L"OFFSET") == NULL) { 151 *Progress = Request + StrLen (Request); 152 } 153 154 return Status; 155} 156 157 158/** 159 This function processes the results of changes in configuration. 160 161 @param[in] This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL. 162 @param[in] Configuration A null-terminated Unicode string in <ConfigResp> 163 format. 164 @param[out] Progress A pointer to a string filled in with the offset of 165 the most recent '&' before the first failing 166 name/value pair (or the beginning of the string if 167 the failure is in the first name/value pair) or 168 the terminating NULL if all was successful. 169 170 @retval EFI_SUCCESS The Results is processed successfully. 171 @retval EFI_INVALID_PARAMETER Configuration is NULL. 172 @retval EFI_NOT_FOUND Routing data doesn't match any storage in this 173 driver. 174 175**/ 176EFI_STATUS 177EFIAPI 178VlanRouteConfig ( 179 IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This, 180 IN CONST EFI_STRING Configuration, 181 OUT EFI_STRING *Progress 182 ) 183{ 184 if (Configuration == NULL || Progress == NULL) { 185 return EFI_INVALID_PARAMETER; 186 } 187 188 *Progress = Configuration; 189 if (!HiiIsConfigHdrMatch (Configuration, &gVlanConfigFormSetGuid, mVlanStorageName)) { 190 return EFI_NOT_FOUND; 191 } 192 193 *Progress = Configuration + StrLen (Configuration); 194 return EFI_SUCCESS; 195} 196 197/** 198 This function processes the results of changes in configuration. 199 200 @param[in] This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL. 201 @param[in] Action Specifies the type of action taken by the browser. 202 @param[in] QuestionId A unique value which is sent to the original 203 exporting driver so that it can identify the type 204 of data to expect. 205 @param[in] Type The type of value for the question. 206 @param[in] Value A pointer to the data being sent to the original 207 exporting driver. 208 @param[out] ActionRequest On return, points to the action requested by the 209 callback function. 210 211 @retval EFI_SUCCESS The callback successfully handled the action. 212 @retval EFI_OUT_OF_RESOURCES Not enough storage is available to hold the 213 variable and its data. 214 @retval EFI_DEVICE_ERROR The variable could not be saved. 215 @retval EFI_UNSUPPORTED The specified Action is not supported by the 216 callback. 217 218**/ 219EFI_STATUS 220EFIAPI 221VlanCallback ( 222 IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This, 223 IN EFI_BROWSER_ACTION Action, 224 IN EFI_QUESTION_ID QuestionId, 225 IN UINT8 Type, 226 IN EFI_IFR_TYPE_VALUE *Value, 227 OUT EFI_BROWSER_ACTION_REQUEST *ActionRequest 228 ) 229{ 230 VLAN_CONFIG_PRIVATE_DATA *PrivateData; 231 VLAN_CONFIGURATION *Configuration; 232 EFI_VLAN_CONFIG_PROTOCOL *VlanConfig; 233 UINTN Index; 234 EFI_HANDLE VlanHandle; 235 236 PrivateData = VLAN_CONFIG_PRIVATE_DATA_FROM_THIS (This); 237 238 if ((Action == EFI_BROWSER_ACTION_FORM_OPEN) || (Action == EFI_BROWSER_ACTION_FORM_CLOSE)) { 239 return EFI_SUCCESS; 240 } 241 242 if ((Action != EFI_BROWSER_ACTION_CHANGED) && (Action != EFI_BROWSER_ACTION_CHANGING)) { 243 // 244 // All other action return unsupported. 245 // 246 return EFI_UNSUPPORTED; 247 } 248 249 // 250 // Get Browser data 251 // 252 Configuration = AllocateZeroPool (sizeof (VLAN_CONFIGURATION)); 253 ASSERT (Configuration != NULL); 254 HiiGetBrowserData (&gVlanConfigFormSetGuid, mVlanStorageName, sizeof (VLAN_CONFIGURATION), (UINT8 *) Configuration); 255 256 VlanConfig = PrivateData->VlanConfig; 257 258 if (Action == EFI_BROWSER_ACTION_CHANGED) { 259 switch (QuestionId) { 260 case VLAN_ADD_QUESTION_ID: 261 // 262 // Add a VLAN 263 // 264 VlanConfig->Set (VlanConfig, Configuration->VlanId, Configuration->Priority); 265 VlanUpdateForm (PrivateData); 266 267 // 268 // Connect the newly created VLAN device 269 // 270 VlanHandle = NetLibGetVlanHandle (PrivateData->ControllerHandle, Configuration->VlanId); 271 if (VlanHandle == NULL) { 272 // 273 // There may be no child handle created for VLAN ID 0, connect the parent handle 274 // 275 VlanHandle = PrivateData->ControllerHandle; 276 } 277 gBS->ConnectController (VlanHandle, NULL, NULL, TRUE); 278 279 // 280 // Clear UI data 281 // 282 *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_APPLY; 283 Configuration->VlanId = 0; 284 Configuration->Priority = 0; 285 break; 286 287 case VLAN_REMOVE_QUESTION_ID: 288 // 289 // Remove VLAN 290 // 291 ASSERT (PrivateData->NumberOfVlan <= MAX_VLAN_NUMBER); 292 for (Index = 0; Index < PrivateData->NumberOfVlan; Index++) { 293 if (Configuration->VlanList[Index] != 0) { 294 // 295 // Checkbox is selected, need remove this VLAN 296 // 297 VlanConfig->Remove (VlanConfig, PrivateData->VlanId[Index]); 298 } 299 } 300 301 VlanUpdateForm (PrivateData); 302 if (PrivateData->NumberOfVlan == 0) { 303 // 304 // No VLAN device now, connect the physical NIC handle. 305 // Note: PrivateData->NumberOfVlan has been updated by VlanUpdateForm() 306 // 307 gBS->ConnectController (PrivateData->ControllerHandle, NULL, NULL, TRUE); 308 } 309 310 *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_APPLY; 311 ZeroMem (Configuration->VlanList, MAX_VLAN_NUMBER); 312 break; 313 314 default: 315 break; 316 } 317 } else if (Action == EFI_BROWSER_ACTION_CHANGING) { 318 switch (QuestionId) { 319 case VLAN_UPDATE_QUESTION_ID: 320 // 321 // Update current VLAN list into Form. 322 // 323 VlanUpdateForm (PrivateData); 324 break; 325 326 default: 327 break; 328 } 329 } 330 331 HiiSetBrowserData (&gVlanConfigFormSetGuid, mVlanStorageName, sizeof (VLAN_CONFIGURATION), (UINT8 *) Configuration, NULL); 332 FreePool (Configuration); 333 return EFI_SUCCESS; 334} 335 336 337/** 338 This function update VLAN list in the VLAN configuration Form. 339 340 @param[in, out] PrivateData Points to VLAN configuration private data. 341 342**/ 343VOID 344VlanUpdateForm ( 345 IN OUT VLAN_CONFIG_PRIVATE_DATA *PrivateData 346 ) 347{ 348 EFI_VLAN_CONFIG_PROTOCOL *VlanConfig; 349 UINT16 NumberOfVlan; 350 UINTN Index; 351 EFI_VLAN_FIND_DATA *VlanData; 352 VOID *StartOpCodeHandle; 353 EFI_IFR_GUID_LABEL *StartLabel; 354 VOID *EndOpCodeHandle; 355 EFI_IFR_GUID_LABEL *EndLabel; 356 CHAR16 *String; 357 CHAR16 VlanStr[30]; 358 CHAR16 VlanIdStr[6]; 359 UINTN DigitalCount; 360 EFI_STRING_ID StringId; 361 362 // 363 // Find current VLAN configuration 364 // 365 VlanData = NULL; 366 NumberOfVlan = 0; 367 VlanConfig = PrivateData->VlanConfig; 368 VlanConfig->Find (VlanConfig, NULL, &NumberOfVlan, &VlanData); 369 370 // 371 // Update VLAN configuration in PrivateData 372 // 373 if (NumberOfVlan > MAX_VLAN_NUMBER) { 374 NumberOfVlan = MAX_VLAN_NUMBER; 375 } 376 PrivateData->NumberOfVlan = NumberOfVlan; 377 378 // 379 // Init OpCode Handle 380 // 381 StartOpCodeHandle = HiiAllocateOpCodeHandle (); 382 ASSERT (StartOpCodeHandle != NULL); 383 384 EndOpCodeHandle = HiiAllocateOpCodeHandle (); 385 ASSERT (EndOpCodeHandle != NULL); 386 387 // 388 // Create Hii Extend Label OpCode as the start opcode 389 // 390 StartLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode ( 391 StartOpCodeHandle, 392 &gEfiIfrTianoGuid, 393 NULL, 394 sizeof (EFI_IFR_GUID_LABEL) 395 ); 396 StartLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL; 397 StartLabel->Number = LABEL_VLAN_LIST; 398 399 // 400 // Create Hii Extend Label OpCode as the end opcode 401 // 402 EndLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode ( 403 EndOpCodeHandle, 404 &gEfiIfrTianoGuid, 405 NULL, 406 sizeof (EFI_IFR_GUID_LABEL) 407 ); 408 EndLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL; 409 EndLabel->Number = LABEL_END; 410 411 ZeroMem (PrivateData->VlanId, MAX_VLAN_NUMBER); 412 for (Index = 0; Index < NumberOfVlan; Index++) { 413 String = VlanStr; 414 415 StrCpyS (String, (sizeof (VlanStr) /sizeof (CHAR16)), L" VLAN ID:"); 416 String += 10; 417 // 418 // Pad VlanId string up to 4 characters with space 419 // 420 DigitalCount = UnicodeValueToString (VlanIdStr, 0, VlanData[Index].VlanId, 5); 421 SetMem16 (String, (4 - DigitalCount) * sizeof (CHAR16), L' '); 422 StrCpyS (String + 4 - DigitalCount, (sizeof (VlanStr) /sizeof (CHAR16)) - 10 - (4 - DigitalCount), VlanIdStr); 423 String += 4; 424 425 StrCpyS (String, (sizeof (VlanStr) /sizeof (CHAR16)) - 10 - (4 - DigitalCount) - 4, L", Priority:"); 426 String += 11; 427 String += UnicodeValueToString (String, 0, VlanData[Index].Priority, 4); 428 *String = 0; 429 430 StringId = HiiSetString (PrivateData->HiiHandle, 0, VlanStr, NULL); 431 ASSERT (StringId != 0); 432 433 HiiCreateCheckBoxOpCode ( 434 StartOpCodeHandle, 435 (EFI_QUESTION_ID) (VLAN_LIST_VAR_OFFSET + Index), 436 VLAN_CONFIGURATION_VARSTORE_ID, 437 (UINT16) (VLAN_LIST_VAR_OFFSET + Index), 438 StringId, 439 STRING_TOKEN (STR_VLAN_VLAN_LIST_HELP), 440 0, 441 0, 442 NULL 443 ); 444 445 // 446 // Save VLAN id to private data 447 // 448 PrivateData->VlanId[Index] = VlanData[Index].VlanId; 449 } 450 451 HiiUpdateForm ( 452 PrivateData->HiiHandle, // HII handle 453 &gVlanConfigFormSetGuid, // Formset GUID 454 VLAN_CONFIGURATION_FORM_ID, // Form ID 455 StartOpCodeHandle, // Label for where to insert opcodes 456 EndOpCodeHandle // Replace data 457 ); 458 459 HiiFreeOpCodeHandle (StartOpCodeHandle); 460 HiiFreeOpCodeHandle (EndOpCodeHandle); 461 462 if (VlanData != NULL) { 463 FreePool (VlanData); 464 } 465} 466 467 468/** 469 This function publish the VLAN configuration Form for a network device. The 470 HII Config Access protocol will be installed on a child handle of the network 471 device. 472 473 @param[in, out] PrivateData Points to VLAN configuration private data. 474 475 @retval EFI_SUCCESS HII Form is installed for this network device. 476 @retval EFI_OUT_OF_RESOURCES Not enough resource for HII Form installation. 477 @retval Others Other errors as indicated. 478 479**/ 480EFI_STATUS 481InstallVlanConfigForm ( 482 IN OUT VLAN_CONFIG_PRIVATE_DATA *PrivateData 483 ) 484{ 485 EFI_STATUS Status; 486 EFI_HII_HANDLE HiiHandle; 487 EFI_HANDLE DriverHandle; 488 CHAR16 Str[26 + sizeof (EFI_MAC_ADDRESS) * 2 + 1]; 489 CHAR16 *MacString; 490 EFI_DEVICE_PATH_PROTOCOL *ChildDevicePath; 491 EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess; 492 EFI_VLAN_CONFIG_PROTOCOL *VlanConfig; 493 494 // 495 // Create child handle and install HII Config Access Protocol 496 // 497 ChildDevicePath = AppendDevicePathNode ( 498 PrivateData->ParentDevicePath, 499 (CONST EFI_DEVICE_PATH_PROTOCOL *) &mHiiVendorDevicePathNode 500 ); 501 if (ChildDevicePath == NULL) { 502 return EFI_OUT_OF_RESOURCES; 503 } 504 PrivateData->ChildDevicePath = ChildDevicePath; 505 506 DriverHandle = NULL; 507 ConfigAccess = &PrivateData->ConfigAccess; 508 Status = gBS->InstallMultipleProtocolInterfaces ( 509 &DriverHandle, 510 &gEfiDevicePathProtocolGuid, 511 ChildDevicePath, 512 &gEfiHiiConfigAccessProtocolGuid, 513 ConfigAccess, 514 NULL 515 ); 516 if (EFI_ERROR (Status)) { 517 return Status; 518 } 519 PrivateData->DriverHandle = DriverHandle; 520 521 // 522 // Establish the parent-child relationship between the new created 523 // child handle and the ControllerHandle. 524 // 525 Status = gBS->OpenProtocol ( 526 PrivateData->ControllerHandle, 527 &gEfiVlanConfigProtocolGuid, 528 (VOID **)&VlanConfig, 529 PrivateData->ImageHandle, 530 PrivateData->DriverHandle, 531 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER 532 ); 533 if (EFI_ERROR (Status)) { 534 return Status; 535 } 536 537 // 538 // Publish the HII package list 539 // 540 HiiHandle = HiiAddPackages ( 541 &gVlanConfigFormSetGuid, 542 DriverHandle, 543 VlanConfigDxeStrings, 544 VlanConfigBin, 545 NULL 546 ); 547 if (HiiHandle == NULL) { 548 return EFI_OUT_OF_RESOURCES; 549 } 550 PrivateData->HiiHandle = HiiHandle; 551 552 // 553 // Update formset title help string. 554 // 555 MacString = NULL; 556 Status = NetLibGetMacString (PrivateData->ControllerHandle, PrivateData->ImageHandle, &MacString); 557 if (EFI_ERROR (Status)) { 558 return Status; 559 } 560 PrivateData->MacString = MacString; 561 562 StrCpyS (Str, sizeof (Str) / sizeof (CHAR16), L"VLAN Configuration (MAC:"); 563 StrCatS (Str, sizeof (Str) / sizeof (CHAR16), MacString); 564 StrCatS (Str, sizeof (Str) / sizeof (CHAR16), L")"); 565 HiiSetString ( 566 HiiHandle, 567 STRING_TOKEN (STR_VLAN_FORM_SET_TITLE_HELP), 568 Str, 569 NULL 570 ); 571 572 // 573 // Update form title help string. 574 // 575 HiiSetString ( 576 HiiHandle, 577 STRING_TOKEN (STR_VLAN_FORM_HELP), 578 Str, 579 NULL 580 ); 581 582 return EFI_SUCCESS; 583} 584 585/** 586 This function remove the VLAN configuration Form for a network device. The 587 child handle for HII Config Access protocol will be destroyed. 588 589 @param[in, out] PrivateData Points to VLAN configuration private data. 590 591 @retval EFI_SUCCESS HII Form has been uninstalled successfully. 592 @retval Others Other errors as indicated. 593 594**/ 595EFI_STATUS 596UninstallVlanConfigForm ( 597 IN OUT VLAN_CONFIG_PRIVATE_DATA *PrivateData 598 ) 599{ 600 EFI_STATUS Status; 601 EFI_VLAN_CONFIG_PROTOCOL *VlanConfig; 602 603 // 604 // End the parent-child relationship. 605 // 606 Status = gBS->CloseProtocol ( 607 PrivateData->ControllerHandle, 608 &gEfiVlanConfigProtocolGuid, 609 PrivateData->ImageHandle, 610 PrivateData->DriverHandle 611 ); 612 if (EFI_ERROR (Status)) { 613 return Status; 614 } 615 616 // 617 // Uninstall HII Config Access Protocol 618 // 619 if (PrivateData->DriverHandle != NULL) { 620 Status = gBS->UninstallMultipleProtocolInterfaces ( 621 PrivateData->DriverHandle, 622 &gEfiDevicePathProtocolGuid, 623 PrivateData->ChildDevicePath, 624 &gEfiHiiConfigAccessProtocolGuid, 625 &PrivateData->ConfigAccess, 626 NULL 627 ); 628 if (EFI_ERROR (Status)) { 629 gBS->OpenProtocol ( 630 PrivateData->ControllerHandle, 631 &gEfiVlanConfigProtocolGuid, 632 (VOID **)&VlanConfig, 633 PrivateData->ImageHandle, 634 PrivateData->DriverHandle, 635 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER 636 ); 637 return Status; 638 } 639 PrivateData->DriverHandle = NULL; 640 641 if (PrivateData->ChildDevicePath != NULL) { 642 FreePool (PrivateData->ChildDevicePath); 643 PrivateData->ChildDevicePath = NULL; 644 } 645 } 646 647 // 648 // Free MAC string 649 // 650 if (PrivateData->MacString != NULL) { 651 FreePool (PrivateData->MacString); 652 PrivateData->MacString = NULL; 653 } 654 655 // 656 // Uninstall HII package list 657 // 658 if (PrivateData->HiiHandle != NULL) { 659 HiiRemovePackages (PrivateData->HiiHandle); 660 PrivateData->HiiHandle = NULL; 661 } 662 return EFI_SUCCESS; 663} 664