1 /** @file 2 Implementation of driver entry point and driver binding protocol. 3 4 Copyright (c) 2005 - 2012, Intel Corporation. All rights reserved.<BR> 5 This program and the accompanying materials 6 are licensed and made available under the terms and conditions 7 of the BSD License which accompanies this distribution. The full 8 text of the license may be found at<BR> 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 "MnpDriver.h" 17 #include "MnpImpl.h" 18 #include "MnpVlan.h" 19 20 EFI_DRIVER_BINDING_PROTOCOL gMnpDriverBinding = { 21 MnpDriverBindingSupported, 22 MnpDriverBindingStart, 23 MnpDriverBindingStop, 24 0xa, 25 NULL, 26 NULL 27 }; 28 29 /** 30 Callback function which provided by user to remove one node in NetDestroyLinkList process. 31 32 @param[in] Entry The entry to be removed. 33 @param[in] Context Pointer to the callback context corresponds to the Context in NetDestroyLinkList. 34 35 @retval EFI_SUCCESS The entry has been removed successfully. 36 @retval Others Fail to remove the entry. 37 38 **/ 39 EFI_STATUS 40 EFIAPI 41 MnpDestroyServiceDataEntry ( 42 IN LIST_ENTRY *Entry, 43 IN VOID *Context 44 ) 45 { 46 MNP_SERVICE_DATA *MnpServiceData; 47 48 MnpServiceData = MNP_SERVICE_DATA_FROM_LINK (Entry); 49 return MnpDestroyServiceData (MnpServiceData); 50 } 51 52 /** 53 Callback function which provided by user to remove one node in NetDestroyLinkList process. 54 55 @param[in] Entry The entry to be removed. 56 @param[in] Context Pointer to the callback context corresponds to the Context in NetDestroyLinkList. 57 58 @retval EFI_SUCCESS The entry has been removed successfully. 59 @retval Others Fail to remove the entry. 60 61 **/ 62 EFI_STATUS 63 EFIAPI 64 MnpDestroyServiceChildEntry ( 65 IN LIST_ENTRY *Entry, 66 IN VOID *Context 67 ) 68 { 69 MNP_SERVICE_DATA *MnpServiceData; 70 71 MnpServiceData = MNP_SERVICE_DATA_FROM_LINK (Entry); 72 return MnpDestroyServiceChild (MnpServiceData); 73 } 74 75 /** 76 Test to see if this driver supports ControllerHandle. This service 77 is called by the EFI boot service ConnectController(). In 78 order to make drivers as small as possible, there are a few calling 79 restrictions for this service. ConnectController() must 80 follow these calling restrictions. If any other agent wishes to call 81 Supported() it must also follow these calling restrictions. 82 83 @param[in] This Protocol instance pointer. 84 @param[in] ControllerHandle Handle of device to test. 85 @param[in] RemainingDevicePath Optional parameter use to pick a specific 86 child device to start. 87 88 @retval EFI_SUCCESS This driver supports this device. 89 @retval EFI_ALREADY_STARTED This driver is already running on this device. 90 @retval Others This driver does not support this device. 91 92 **/ 93 EFI_STATUS 94 EFIAPI 95 MnpDriverBindingSupported ( 96 IN EFI_DRIVER_BINDING_PROTOCOL *This, 97 IN EFI_HANDLE ControllerHandle, 98 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL 99 ) 100 { 101 EFI_STATUS Status; 102 EFI_SIMPLE_NETWORK_PROTOCOL *Snp; 103 104 // 105 // Test to open the Simple Network protocol BY_DRIVER. 106 // 107 Status = gBS->OpenProtocol ( 108 ControllerHandle, 109 &gEfiSimpleNetworkProtocolGuid, 110 (VOID **) &Snp, 111 This->DriverBindingHandle, 112 ControllerHandle, 113 EFI_OPEN_PROTOCOL_BY_DRIVER 114 ); 115 if (EFI_ERROR (Status)) { 116 return Status; 117 } 118 119 // 120 // Close the openned SNP protocol. 121 // 122 gBS->CloseProtocol ( 123 ControllerHandle, 124 &gEfiSimpleNetworkProtocolGuid, 125 This->DriverBindingHandle, 126 ControllerHandle 127 ); 128 129 return EFI_SUCCESS; 130 } 131 132 133 /** 134 Start this driver on ControllerHandle. This service is called by the 135 EFI boot service ConnectController(). In order to make drivers as small 136 as possible, there are a few calling restrictions for this service. 137 ConnectController() must follow these calling restrictions. If any other 138 agent wishes to call Start() it must also follow these calling restrictions. 139 140 @param[in] This Protocol instance pointer. 141 @param[in] ControllerHandle Handle of device to bind driver to. 142 @param[in] RemainingDevicePath Optional parameter use to pick a specific 143 child device to start. 144 145 @retval EFI_SUCCESS This driver is added to ControllerHandle. 146 @retval EFI_ALREADY_STARTED This driver is already running on ControllerHandle. 147 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory for Mnp Service Data. 148 @retval Others This driver does not support this device. 149 150 **/ 151 EFI_STATUS 152 EFIAPI 153 MnpDriverBindingStart ( 154 IN EFI_DRIVER_BINDING_PROTOCOL *This, 155 IN EFI_HANDLE ControllerHandle, 156 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL 157 ) 158 { 159 EFI_STATUS Status; 160 MNP_SERVICE_DATA *MnpServiceData; 161 MNP_DEVICE_DATA *MnpDeviceData; 162 LIST_ENTRY *Entry; 163 VLAN_TCI *VlanVariable; 164 UINTN NumberOfVlan; 165 UINTN Index; 166 167 VlanVariable = NULL; 168 169 // 170 // Initialize the Mnp Device Data 171 // 172 MnpDeviceData = AllocateZeroPool (sizeof (MNP_DEVICE_DATA)); 173 if (MnpDeviceData == NULL) { 174 DEBUG ((EFI_D_ERROR, "MnpDriverBindingStart(): Failed to allocate the Mnp Device Data.\n")); 175 176 return EFI_OUT_OF_RESOURCES; 177 } 178 179 Status = MnpInitializeDeviceData (MnpDeviceData, This->DriverBindingHandle, ControllerHandle); 180 if (EFI_ERROR (Status)) { 181 DEBUG ((EFI_D_ERROR, "MnpDriverBindingStart: MnpInitializeDeviceData failed, %r.\n", Status)); 182 183 FreePool (MnpDeviceData); 184 return Status; 185 } 186 187 // 188 // Check whether NIC driver has already produced VlanConfig protocol 189 // 190 Status = gBS->OpenProtocol ( 191 ControllerHandle, 192 &gEfiVlanConfigProtocolGuid, 193 NULL, 194 This->DriverBindingHandle, 195 ControllerHandle, 196 EFI_OPEN_PROTOCOL_TEST_PROTOCOL 197 ); 198 if (!EFI_ERROR (Status)) { 199 // 200 // NIC hardware already implement VLAN, 201 // no need to provide software VLAN implementation in MNP driver 202 // 203 MnpDeviceData->NumberOfVlan = 0; 204 ZeroMem (&MnpDeviceData->VlanConfig, sizeof (EFI_VLAN_CONFIG_PROTOCOL)); 205 MnpServiceData = MnpCreateServiceData (MnpDeviceData, 0, 0); 206 Status = (MnpServiceData != NULL) ? EFI_SUCCESS : EFI_OUT_OF_RESOURCES; 207 goto Exit; 208 } 209 210 // 211 // Install VLAN Config Protocol 212 // 213 Status = gBS->InstallMultipleProtocolInterfaces ( 214 &ControllerHandle, 215 &gEfiVlanConfigProtocolGuid, 216 &MnpDeviceData->VlanConfig, 217 NULL 218 ); 219 if (EFI_ERROR (Status)) { 220 goto Exit; 221 } 222 223 // 224 // Get current VLAN configuration from EFI Variable 225 // 226 NumberOfVlan = 0; 227 Status = MnpGetVlanVariable (MnpDeviceData, &NumberOfVlan, &VlanVariable); 228 if (EFI_ERROR (Status)) { 229 // 230 // No VLAN is set, create a default MNP service data for untagged frame 231 // 232 MnpDeviceData->NumberOfVlan = 0; 233 MnpServiceData = MnpCreateServiceData (MnpDeviceData, 0, 0); 234 Status = (MnpServiceData != NULL) ? EFI_SUCCESS : EFI_OUT_OF_RESOURCES; 235 goto Exit; 236 } 237 238 // 239 // Create MNP service data for each VLAN 240 // 241 MnpDeviceData->NumberOfVlan = NumberOfVlan; 242 for (Index = 0; Index < NumberOfVlan; Index++) { 243 MnpServiceData = MnpCreateServiceData ( 244 MnpDeviceData, 245 VlanVariable[Index].Bits.Vid, 246 (UINT8) VlanVariable[Index].Bits.Priority 247 ); 248 249 if (MnpServiceData == NULL) { 250 Status = EFI_OUT_OF_RESOURCES; 251 252 goto Exit; 253 } 254 } 255 256 Exit: 257 if (VlanVariable != NULL) { 258 FreePool (VlanVariable); 259 } 260 261 if (EFI_ERROR (Status)) { 262 // 263 // Destroy all MNP service data 264 // 265 while (!IsListEmpty (&MnpDeviceData->ServiceList)) { 266 Entry = GetFirstNode (&MnpDeviceData->ServiceList); 267 MnpServiceData = MNP_SERVICE_DATA_FROM_LINK (Entry); 268 MnpDestroyServiceData (MnpServiceData); 269 } 270 271 // 272 // Uninstall the VLAN Config Protocol if any 273 // 274 if (MnpDeviceData->VlanConfig.Set != NULL) { 275 gBS->UninstallMultipleProtocolInterfaces ( 276 MnpDeviceData->ControllerHandle, 277 &gEfiVlanConfigProtocolGuid, 278 &MnpDeviceData->VlanConfig, 279 NULL 280 ); 281 } 282 283 // 284 // Destroy Mnp Device Data 285 // 286 MnpDestroyDeviceData (MnpDeviceData, This->DriverBindingHandle); 287 FreePool (MnpDeviceData); 288 } 289 290 return Status; 291 } 292 293 /** 294 Stop this driver on ControllerHandle. This service is called by the 295 EFI boot service DisconnectController(). In order to make drivers as 296 small as possible, there are a few calling restrictions for this service. 297 DisconnectController() must follow these calling restrictions. If any other 298 agent wishes to call Stop() it must also follow these calling restrictions. 299 300 @param[in] This Protocol instance pointer. 301 @param[in] ControllerHandle Handle of device to stop driver on. 302 @param[in] NumberOfChildren Number of Handles in ChildHandleBuffer. If 303 number of children is zero stop the entire 304 bus driver. 305 @param[in] ChildHandleBuffer List of Child Handles to Stop. 306 307 @retval EFI_SUCCESS This driver is removed ControllerHandle. 308 @retval EFI_DEVICE_ERROR The device could not be stopped due to a device error. 309 310 **/ 311 EFI_STATUS 312 EFIAPI 313 MnpDriverBindingStop ( 314 IN EFI_DRIVER_BINDING_PROTOCOL *This, 315 IN EFI_HANDLE ControllerHandle, 316 IN UINTN NumberOfChildren, 317 IN EFI_HANDLE *ChildHandleBuffer OPTIONAL 318 ) 319 { 320 EFI_STATUS Status; 321 EFI_SERVICE_BINDING_PROTOCOL *ServiceBinding; 322 EFI_VLAN_CONFIG_PROTOCOL *VlanConfig; 323 MNP_DEVICE_DATA *MnpDeviceData; 324 MNP_SERVICE_DATA *MnpServiceData; 325 LIST_ENTRY *List; 326 UINTN ListLength; 327 328 // 329 // Try to retrieve MNP service binding protocol from the ControllerHandle 330 // 331 Status = gBS->OpenProtocol ( 332 ControllerHandle, 333 &gEfiManagedNetworkServiceBindingProtocolGuid, 334 (VOID **) &ServiceBinding, 335 This->DriverBindingHandle, 336 ControllerHandle, 337 EFI_OPEN_PROTOCOL_GET_PROTOCOL 338 ); 339 if (EFI_ERROR (Status)) { 340 // 341 // Retrieve VLAN Config Protocol from the ControllerHandle 342 // 343 Status = gBS->OpenProtocol ( 344 ControllerHandle, 345 &gEfiVlanConfigProtocolGuid, 346 (VOID **) &VlanConfig, 347 This->DriverBindingHandle, 348 ControllerHandle, 349 EFI_OPEN_PROTOCOL_GET_PROTOCOL 350 ); 351 if (EFI_ERROR (Status)) { 352 DEBUG ((EFI_D_ERROR, "MnpDriverBindingStop: try to stop unknown Controller.\n")); 353 return EFI_DEVICE_ERROR; 354 } 355 356 MnpDeviceData = MNP_DEVICE_DATA_FROM_THIS (VlanConfig); 357 } else { 358 MnpServiceData = MNP_SERVICE_DATA_FROM_THIS (ServiceBinding); 359 MnpDeviceData = MnpServiceData->MnpDeviceData; 360 } 361 362 if (NumberOfChildren == 0) { 363 // 364 // Destroy all MNP service data 365 // 366 List = &MnpDeviceData->ServiceList; 367 Status = NetDestroyLinkList ( 368 List, 369 MnpDestroyServiceDataEntry, 370 NULL, 371 &ListLength 372 ); 373 if (EFI_ERROR (Status) || ListLength !=0) { 374 return EFI_DEVICE_ERROR; 375 } 376 377 // 378 // Uninstall the VLAN Config Protocol if any 379 // 380 if (MnpDeviceData->VlanConfig.Set != NULL) { 381 gBS->UninstallMultipleProtocolInterfaces ( 382 MnpDeviceData->ControllerHandle, 383 &gEfiVlanConfigProtocolGuid, 384 &MnpDeviceData->VlanConfig, 385 NULL 386 ); 387 } 388 389 // 390 // Destroy Mnp Device Data 391 // 392 MnpDestroyDeviceData (MnpDeviceData, This->DriverBindingHandle); 393 FreePool (MnpDeviceData); 394 395 if (gMnpControllerNameTable != NULL) { 396 FreeUnicodeStringTable (gMnpControllerNameTable); 397 gMnpControllerNameTable = NULL; 398 } 399 return EFI_SUCCESS; 400 } 401 402 // 403 // Stop all MNP child 404 // 405 List = &MnpDeviceData->ServiceList; 406 Status = NetDestroyLinkList ( 407 List, 408 MnpDestroyServiceChildEntry, 409 NULL, 410 &ListLength 411 ); 412 if (EFI_ERROR (Status)) { 413 return EFI_DEVICE_ERROR; 414 } 415 416 return EFI_SUCCESS; 417 } 418 419 420 /** 421 Creates a child handle with a set of I/O services. 422 423 @param[in] This Protocol instance pointer. 424 @param[in, out] ChildHandle Pointer to the handle of the child to create. If 425 it is NULL, then a new handle is created. If 426 it is not NULL, then the I/O services are added 427 to the existing child handle. 428 429 @retval EFI_SUCCES The protocol was added to ChildHandle. 430 @retval EFI_INVALID_PARAMETER ChildHandle is NULL. 431 @retval EFI_OUT_OF_RESOURCES There are not enough resources availabe to 432 create the child. 433 @retval Others The child handle was not created. 434 435 **/ 436 EFI_STATUS 437 EFIAPI 438 MnpServiceBindingCreateChild ( 439 IN EFI_SERVICE_BINDING_PROTOCOL *This, 440 IN OUT EFI_HANDLE *ChildHandle 441 ) 442 { 443 EFI_STATUS Status; 444 MNP_SERVICE_DATA *MnpServiceData; 445 MNP_INSTANCE_DATA *Instance; 446 VOID *MnpSb; 447 EFI_TPL OldTpl; 448 449 if ((This == NULL) || (ChildHandle == NULL)) { 450 return EFI_INVALID_PARAMETER; 451 } 452 453 MnpServiceData = MNP_SERVICE_DATA_FROM_THIS (This); 454 455 // 456 // Allocate buffer for the new instance. 457 // 458 Instance = AllocateZeroPool (sizeof (MNP_INSTANCE_DATA)); 459 if (Instance == NULL) { 460 DEBUG ((EFI_D_ERROR, "MnpServiceBindingCreateChild: Faild to allocate memory for the new instance.\n")); 461 462 return EFI_OUT_OF_RESOURCES; 463 } 464 465 // 466 // Init the instance data. 467 // 468 MnpInitializeInstanceData (MnpServiceData, Instance); 469 470 Status = gBS->InstallMultipleProtocolInterfaces ( 471 ChildHandle, 472 &gEfiManagedNetworkProtocolGuid, 473 &Instance->ManagedNetwork, 474 NULL 475 ); 476 if (EFI_ERROR (Status)) { 477 DEBUG ( 478 (EFI_D_ERROR, 479 "MnpServiceBindingCreateChild: Failed to install the MNP protocol, %r.\n", 480 Status) 481 ); 482 483 goto ErrorExit; 484 } 485 486 // 487 // Save the instance's childhandle. 488 // 489 Instance->Handle = *ChildHandle; 490 491 Status = gBS->OpenProtocol ( 492 MnpServiceData->ServiceHandle, 493 &gEfiManagedNetworkServiceBindingProtocolGuid, 494 (VOID **) &MnpSb, 495 gMnpDriverBinding.DriverBindingHandle, 496 Instance->Handle, 497 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER 498 ); 499 if (EFI_ERROR (Status)) { 500 goto ErrorExit; 501 } 502 503 // 504 // Add the child instance into ChildrenList. 505 // 506 OldTpl = gBS->RaiseTPL (TPL_CALLBACK); 507 508 InsertTailList (&MnpServiceData->ChildrenList, &Instance->InstEntry); 509 MnpServiceData->ChildrenNumber++; 510 511 gBS->RestoreTPL (OldTpl); 512 513 ErrorExit: 514 515 if (EFI_ERROR (Status)) { 516 517 if (Instance->Handle != NULL) { 518 519 gBS->UninstallMultipleProtocolInterfaces ( 520 Instance->Handle, 521 &gEfiManagedNetworkProtocolGuid, 522 &Instance->ManagedNetwork, 523 NULL 524 ); 525 } 526 527 FreePool (Instance); 528 } 529 530 return Status; 531 } 532 533 534 /** 535 Destroys a child handle with a set of I/O services. 536 537 The DestroyChild() function does the opposite of CreateChild(). It removes a 538 protocol that was installed by CreateChild() from ChildHandle. If the removed 539 protocol is the last protocol on ChildHandle, then ChildHandle is destroyed. 540 541 @param[in] This Pointer to the EFI_SERVICE_BINDING_PROTOCOL 542 instance. 543 @param[in] ChildHandle Handle of the child to destroy. 544 545 @retval EFI_SUCCES The protocol was removed from ChildHandle. 546 @retval EFI_UNSUPPORTED ChildHandle does not support the protocol that 547 is being removed. 548 @retval EFI_INVALID_PARAMETER ChildHandle is NULL. 549 @retval EFI_ACCESS_DENIED The protocol could not be removed from the 550 ChildHandle because its services are being 551 used. 552 @retval Others The child handle was not destroyed. 553 554 **/ 555 EFI_STATUS 556 EFIAPI 557 MnpServiceBindingDestroyChild ( 558 IN EFI_SERVICE_BINDING_PROTOCOL *This, 559 IN EFI_HANDLE ChildHandle 560 ) 561 { 562 EFI_STATUS Status; 563 MNP_SERVICE_DATA *MnpServiceData; 564 EFI_MANAGED_NETWORK_PROTOCOL *ManagedNetwork; 565 MNP_INSTANCE_DATA *Instance; 566 EFI_TPL OldTpl; 567 568 if ((This == NULL) || (ChildHandle == NULL)) { 569 return EFI_INVALID_PARAMETER; 570 } 571 572 MnpServiceData = MNP_SERVICE_DATA_FROM_THIS (This); 573 574 // 575 // Try to retrieve ManagedNetwork Protocol from ChildHandle. 576 // 577 Status = gBS->OpenProtocol ( 578 ChildHandle, 579 &gEfiManagedNetworkProtocolGuid, 580 (VOID **) &ManagedNetwork, 581 gMnpDriverBinding.DriverBindingHandle, 582 ChildHandle, 583 EFI_OPEN_PROTOCOL_GET_PROTOCOL 584 ); 585 if (EFI_ERROR (Status)) { 586 return EFI_UNSUPPORTED; 587 } 588 589 Instance = MNP_INSTANCE_DATA_FROM_THIS (ManagedNetwork); 590 591 // 592 // MnpServiceBindingDestroyChild may be called twice: first called by 593 // MnpServiceBindingStop, second called by uninstalling the MNP protocol 594 // in this ChildHandle. Use destroyed to make sure the resource clean code 595 // will only excecute once. 596 // 597 if (Instance->Destroyed) { 598 return EFI_SUCCESS; 599 } 600 601 Instance->Destroyed = TRUE; 602 603 // 604 // Close the Simple Network protocol. 605 // 606 gBS->CloseProtocol ( 607 MnpServiceData->ServiceHandle, 608 &gEfiManagedNetworkServiceBindingProtocolGuid, 609 MnpServiceData->MnpDeviceData->ImageHandle, 610 ChildHandle 611 ); 612 613 // 614 // Uninstall the ManagedNetwork protocol. 615 // 616 Status = gBS->UninstallMultipleProtocolInterfaces ( 617 ChildHandle, 618 &gEfiManagedNetworkProtocolGuid, 619 &Instance->ManagedNetwork, 620 NULL 621 ); 622 if (EFI_ERROR (Status)) { 623 DEBUG ( 624 (EFI_D_ERROR, 625 "MnpServiceBindingDestroyChild: Failed to uninstall the ManagedNetwork protocol, %r.\n", 626 Status) 627 ); 628 629 Instance->Destroyed = FALSE; 630 return Status; 631 } 632 633 OldTpl = gBS->RaiseTPL (TPL_CALLBACK); 634 635 // 636 // Reset the configuration. 637 // 638 ManagedNetwork->Configure (ManagedNetwork, NULL); 639 640 // 641 // Try to flush the RcvdPacketQueue. 642 // 643 MnpFlushRcvdDataQueue (Instance); 644 645 // 646 // Clean the RxTokenMap. 647 // 648 NetMapClean (&Instance->RxTokenMap); 649 650 // 651 // Remove this instance from the ChildrenList. 652 // 653 RemoveEntryList (&Instance->InstEntry); 654 MnpServiceData->ChildrenNumber--; 655 656 gBS->RestoreTPL (OldTpl); 657 658 FreePool (Instance); 659 660 return Status; 661 } 662 663 /** 664 The entry point for Mnp driver which installs the driver binding and component 665 name protocol on its ImageHandle. 666 667 @param[in] ImageHandle The image handle of the driver. 668 @param[in] SystemTable The system table. 669 670 @retval EFI_SUCCES The driver binding and component name protocols are 671 successfully installed. 672 @retval Others Other errors as indicated. 673 674 **/ 675 EFI_STATUS 676 EFIAPI 677 MnpDriverEntryPoint ( 678 IN EFI_HANDLE ImageHandle, 679 IN EFI_SYSTEM_TABLE *SystemTable 680 ) 681 { 682 return EfiLibInstallDriverBindingComponentName2 ( 683 ImageHandle, 684 SystemTable, 685 &gMnpDriverBinding, 686 ImageHandle, 687 &gMnpComponentName, 688 &gMnpComponentName2 689 ); 690 } 691