1 /** @file 2 Implementation of driver entry point and driver binding protocol. 3 4 Copyright (c) 2004 - 2016, Intel Corporation. All rights reserved.<BR> 5 This program and the accompanying materials are licensed 6 and made available under the terms and conditions of the BSD License which 7 accompanies this distribution. The full text of the license may be found at 8 http://opensource.org/licenses/bsd-license.php 9 10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 12 13 **/ 14 15 #include "Snp.h" 16 17 /** 18 One notified function to stop UNDI device when gBS->ExitBootServices() called. 19 20 @param Event Pointer to this event 21 @param Context Event handler private data 22 23 **/ 24 VOID 25 EFIAPI 26 SnpNotifyExitBootServices ( 27 EFI_EVENT Event, 28 VOID *Context 29 ) 30 { 31 SNP_DRIVER *Snp; 32 33 Snp = (SNP_DRIVER *)Context; 34 35 // 36 // Shutdown and stop UNDI driver 37 // 38 PxeShutdown (Snp); 39 PxeStop (Snp); 40 } 41 42 /** 43 Send command to UNDI. It does nothing currently. 44 45 @param Cdb command to be sent to UNDI. 46 47 @retval EFI_INVALID_PARAMETER The command is 0. 48 @retval EFI_UNSUPPORTED Default return status because it's not 49 supported currently. 50 51 **/ 52 EFI_STATUS 53 EFIAPI 54 IssueHwUndiCommand ( 55 UINT64 Cdb 56 ) 57 { 58 DEBUG ((EFI_D_ERROR, "\nIssueHwUndiCommand() - This should not be called!")); 59 60 if (Cdb == 0) { 61 return EFI_INVALID_PARAMETER; 62 63 } 64 // 65 // %%TBD - For now, nothing is done. 66 // 67 return EFI_UNSUPPORTED; 68 } 69 70 71 /** 72 Compute 8-bit checksum of a buffer. 73 74 @param Buffer Pointer to buffer. 75 @param Length Length of buffer in bytes. 76 77 @return 8-bit checksum of all bytes in buffer, or zero if ptr is NULL or len 78 is zero. 79 80 **/ 81 UINT8 82 Calc8BitCksum ( 83 VOID *Buffer, 84 UINTN Length 85 ) 86 { 87 UINT8 *Ptr; 88 UINT8 Cksum; 89 90 Ptr = Buffer; 91 Cksum = 0; 92 93 if (Ptr == NULL || Length == 0) { 94 return 0; 95 } 96 97 while (Length-- != 0) { 98 Cksum = (UINT8) (Cksum + *Ptr++); 99 } 100 101 return Cksum; 102 } 103 104 /** 105 Test to see if this driver supports ControllerHandle. This service 106 is called by the EFI boot service ConnectController(). In 107 order to make drivers as small as possible, there are a few calling 108 restrictions for this service. ConnectController() must 109 follow these calling restrictions. If any other agent wishes to call 110 Supported() it must also follow these calling restrictions. 111 112 @param This Protocol instance pointer. 113 @param ControllerHandle Handle of device to test. 114 @param RemainingDevicePath Optional parameter use to pick a specific child 115 device to start. 116 117 @retval EFI_SUCCESS This driver supports this device. 118 @retval EFI_ALREADY_STARTED This driver is already running on this device. 119 @retval other This driver does not support this device. 120 121 **/ 122 EFI_STATUS 123 EFIAPI 124 SimpleNetworkDriverSupported ( 125 IN EFI_DRIVER_BINDING_PROTOCOL *This, 126 IN EFI_HANDLE Controller, 127 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath 128 ) 129 { 130 EFI_STATUS Status; 131 EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL *NiiProtocol; 132 PXE_UNDI *Pxe; 133 134 Status = gBS->OpenProtocol ( 135 Controller, 136 &gEfiDevicePathProtocolGuid, 137 NULL, 138 This->DriverBindingHandle, 139 Controller, 140 EFI_OPEN_PROTOCOL_TEST_PROTOCOL 141 ); 142 if (EFI_ERROR (Status)) { 143 return Status; 144 } 145 146 Status = gBS->OpenProtocol ( 147 Controller, 148 &gEfiNetworkInterfaceIdentifierProtocolGuid_31, 149 (VOID **) &NiiProtocol, 150 This->DriverBindingHandle, 151 Controller, 152 EFI_OPEN_PROTOCOL_BY_DRIVER 153 ); 154 155 if (EFI_ERROR (Status)) { 156 if (Status == EFI_ALREADY_STARTED) { 157 DEBUG ((EFI_D_INFO, "Support(): Already Started. on handle %p\n", Controller)); 158 } 159 return Status; 160 } 161 162 DEBUG ((EFI_D_INFO, "Support(): UNDI3.1 found on handle %p\n", Controller)); 163 164 // 165 // check the version, we don't want to connect to the undi16 166 // 167 if (NiiProtocol->Type != EfiNetworkInterfaceUndi) { 168 Status = EFI_UNSUPPORTED; 169 goto Done; 170 } 171 // 172 // Check to see if !PXE structure is valid. Paragraph alignment of !PXE structure is required. 173 // 174 if ((NiiProtocol->Id & 0x0F) != 0) { 175 DEBUG ((EFI_D_NET, "\n!PXE structure is not paragraph aligned.\n")); 176 Status = EFI_UNSUPPORTED; 177 goto Done; 178 } 179 180 Pxe = (PXE_UNDI *) (UINTN) (NiiProtocol->Id); 181 182 // 183 // Verify !PXE revisions. 184 // 185 if (Pxe->hw.Signature != PXE_ROMID_SIGNATURE) { 186 DEBUG ((EFI_D_NET, "\n!PXE signature is not valid.\n")); 187 Status = EFI_UNSUPPORTED; 188 goto Done; 189 } 190 191 if (Pxe->hw.Rev < PXE_ROMID_REV) { 192 DEBUG ((EFI_D_NET, "\n!PXE.Rev is not supported.\n")); 193 Status = EFI_UNSUPPORTED; 194 goto Done; 195 } 196 197 if (Pxe->hw.MajorVer < PXE_ROMID_MAJORVER) { 198 199 DEBUG ((EFI_D_NET, "\n!PXE.MajorVer is not supported.\n")); 200 Status = EFI_UNSUPPORTED; 201 goto Done; 202 203 } else if (Pxe->hw.MajorVer == PXE_ROMID_MAJORVER && Pxe->hw.MinorVer < PXE_ROMID_MINORVER) { 204 DEBUG ((EFI_D_NET, "\n!PXE.MinorVer is not supported.")); 205 Status = EFI_UNSUPPORTED; 206 goto Done; 207 } 208 // 209 // Do S/W UNDI specific checks. 210 // 211 if ((Pxe->hw.Implementation & PXE_ROMID_IMP_HW_UNDI) == 0) { 212 if (Pxe->sw.EntryPoint < Pxe->sw.Len) { 213 DEBUG ((EFI_D_NET, "\n!PXE S/W entry point is not valid.")); 214 Status = EFI_UNSUPPORTED; 215 goto Done; 216 } 217 218 if (Pxe->sw.BusCnt == 0) { 219 DEBUG ((EFI_D_NET, "\n!PXE.BusCnt is zero.")); 220 Status = EFI_UNSUPPORTED; 221 goto Done; 222 } 223 } 224 225 Status = EFI_SUCCESS; 226 DEBUG ((EFI_D_INFO, "Support(): supported on %p\n", Controller)); 227 228 Done: 229 gBS->CloseProtocol ( 230 Controller, 231 &gEfiNetworkInterfaceIdentifierProtocolGuid_31, 232 This->DriverBindingHandle, 233 Controller 234 ); 235 236 return Status; 237 } 238 239 /** 240 Start this driver on ControllerHandle. This service is called by the 241 EFI boot service ConnectController(). In order to make 242 drivers as small as possible, there are a few calling restrictions for 243 this service. ConnectController() must follow these 244 calling restrictions. If any other agent wishes to call Start() it 245 must also follow these calling restrictions. 246 247 @param This Protocol instance pointer. 248 @param ControllerHandle Handle of device to bind driver to. 249 @param RemainingDevicePath Optional parameter use to pick a specific child 250 device to start. 251 252 @retval EFI_SUCCESS This driver is added to ControllerHandle 253 @retval EFI_DEVICE_ERROR This driver could not be started due to a device error 254 @retval other This driver does not support this device 255 256 **/ 257 EFI_STATUS 258 EFIAPI 259 SimpleNetworkDriverStart ( 260 IN EFI_DRIVER_BINDING_PROTOCOL *This, 261 IN EFI_HANDLE Controller, 262 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath 263 ) 264 { 265 EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL *Nii; 266 EFI_DEVICE_PATH_PROTOCOL *NiiDevicePath; 267 EFI_STATUS Status; 268 PXE_UNDI *Pxe; 269 SNP_DRIVER *Snp; 270 VOID *Address; 271 EFI_HANDLE Handle; 272 UINT8 BarIndex; 273 PXE_STATFLAGS InitStatFlags; 274 EFI_PCI_IO_PROTOCOL *PciIo; 275 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *BarDesc; 276 BOOLEAN FoundIoBar; 277 BOOLEAN FoundMemoryBar; 278 279 DEBUG ((EFI_D_NET, "\nSnpNotifyNetworkInterfaceIdentifier() ")); 280 281 Status = gBS->OpenProtocol ( 282 Controller, 283 &gEfiDevicePathProtocolGuid, 284 (VOID **) &NiiDevicePath, 285 This->DriverBindingHandle, 286 Controller, 287 EFI_OPEN_PROTOCOL_BY_DRIVER 288 ); 289 290 if (EFI_ERROR (Status)) { 291 return Status; 292 } 293 294 Status = gBS->LocateDevicePath ( 295 &gEfiPciIoProtocolGuid, 296 &NiiDevicePath, 297 &Handle 298 ); 299 300 if (EFI_ERROR (Status)) { 301 return Status; 302 } 303 304 Status = gBS->OpenProtocol ( 305 Handle, 306 &gEfiPciIoProtocolGuid, 307 (VOID **) &PciIo, 308 This->DriverBindingHandle, 309 Controller, 310 EFI_OPEN_PROTOCOL_GET_PROTOCOL 311 ); 312 if (EFI_ERROR (Status)) { 313 return Status; 314 } 315 // 316 // Get the NII interface. 317 // 318 Status = gBS->OpenProtocol ( 319 Controller, 320 &gEfiNetworkInterfaceIdentifierProtocolGuid_31, 321 (VOID **) &Nii, 322 This->DriverBindingHandle, 323 Controller, 324 EFI_OPEN_PROTOCOL_BY_DRIVER 325 ); 326 if (EFI_ERROR (Status)) { 327 gBS->CloseProtocol ( 328 Controller, 329 &gEfiDevicePathProtocolGuid, 330 This->DriverBindingHandle, 331 Controller 332 ); 333 return Status; 334 } 335 336 DEBUG ((EFI_D_INFO, "Start(): UNDI3.1 found\n")); 337 338 Pxe = (PXE_UNDI *) (UINTN) (Nii->Id); 339 340 if (Calc8BitCksum (Pxe, Pxe->hw.Len) != 0) { 341 DEBUG ((EFI_D_NET, "\n!PXE checksum is not correct.\n")); 342 goto NiiError; 343 } 344 345 if ((Pxe->hw.Implementation & PXE_ROMID_IMP_PROMISCUOUS_RX_SUPPORTED) != 0) { 346 // 347 // We can get any packets. 348 // 349 } else if ((Pxe->hw.Implementation & PXE_ROMID_IMP_BROADCAST_RX_SUPPORTED) != 0) { 350 // 351 // We need to be able to get broadcast packets for DHCP. 352 // If we do not have promiscuous support, we must at least have 353 // broadcast support or we cannot do DHCP! 354 // 355 } else { 356 DEBUG ((EFI_D_NET, "\nUNDI does not have promiscuous or broadcast support.")); 357 goto NiiError; 358 } 359 // 360 // OK, we like this UNDI, and we know snp is not already there on this handle 361 // Allocate and initialize a new simple network protocol structure. 362 // 363 Status = PciIo->AllocateBuffer ( 364 PciIo, 365 AllocateAnyPages, 366 EfiBootServicesData, 367 SNP_MEM_PAGES (sizeof (SNP_DRIVER)), 368 &Address, 369 0 370 ); 371 372 if (Status != EFI_SUCCESS) { 373 DEBUG ((EFI_D_NET, "\nCould not allocate SNP_DRIVER structure.\n")); 374 goto NiiError; 375 } 376 377 Snp = (SNP_DRIVER *) (UINTN) Address; 378 379 ZeroMem (Snp, sizeof (SNP_DRIVER)); 380 381 Snp->PciIo = PciIo; 382 Snp->Signature = SNP_DRIVER_SIGNATURE; 383 384 EfiInitializeLock (&Snp->Lock, TPL_NOTIFY); 385 386 Snp->Snp.Revision = EFI_SIMPLE_NETWORK_PROTOCOL_REVISION; 387 Snp->Snp.Start = SnpUndi32Start; 388 Snp->Snp.Stop = SnpUndi32Stop; 389 Snp->Snp.Initialize = SnpUndi32Initialize; 390 Snp->Snp.Reset = SnpUndi32Reset; 391 Snp->Snp.Shutdown = SnpUndi32Shutdown; 392 Snp->Snp.ReceiveFilters = SnpUndi32ReceiveFilters; 393 Snp->Snp.StationAddress = SnpUndi32StationAddress; 394 Snp->Snp.Statistics = SnpUndi32Statistics; 395 Snp->Snp.MCastIpToMac = SnpUndi32McastIpToMac; 396 Snp->Snp.NvData = SnpUndi32NvData; 397 Snp->Snp.GetStatus = SnpUndi32GetStatus; 398 Snp->Snp.Transmit = SnpUndi32Transmit; 399 Snp->Snp.Receive = SnpUndi32Receive; 400 Snp->Snp.WaitForPacket = NULL; 401 402 Snp->Snp.Mode = &Snp->Mode; 403 404 Snp->TxRxBufferSize = 0; 405 Snp->TxRxBuffer = NULL; 406 407 Snp->RecycledTxBuf = AllocatePool (sizeof (UINT64) * SNP_TX_BUFFER_INCREASEMENT); 408 if (Snp->RecycledTxBuf == NULL) { 409 Status = EFI_OUT_OF_RESOURCES; 410 goto Error_DeleteSNP; 411 } 412 Snp->MaxRecycledTxBuf = SNP_TX_BUFFER_INCREASEMENT; 413 Snp->RecycledTxBufCount = 0; 414 415 if (Nii->Revision >= EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL_REVISION) { 416 Snp->IfNum = Nii->IfNum; 417 418 } else { 419 Snp->IfNum = (UINT8) (Nii->IfNum & 0xFF); 420 } 421 422 if ((Pxe->hw.Implementation & PXE_ROMID_IMP_HW_UNDI) != 0) { 423 Snp->IsSwUndi = FALSE; 424 Snp->IssueUndi32Command = &IssueHwUndiCommand; 425 } else { 426 Snp->IsSwUndi = TRUE; 427 428 if ((Pxe->sw.Implementation & PXE_ROMID_IMP_SW_VIRT_ADDR) != 0) { 429 Snp->IssueUndi32Command = (ISSUE_UNDI32_COMMAND) (UINTN) Pxe->sw.EntryPoint; 430 } else { 431 Snp->IssueUndi32Command = (ISSUE_UNDI32_COMMAND) (UINTN) ((UINT8) (UINTN) Pxe + Pxe->sw.EntryPoint); 432 } 433 } 434 // 435 // Allocate a global CPB and DB buffer for this UNDI interface. 436 // we do this because: 437 // 438 // -UNDI 3.0 wants all the addresses passed to it (even the cpb and db) to be 439 // within 2GB limit, create them here and map them so that when undi calls 440 // v2p callback to check if the physical address is < 2gb, we will pass. 441 // 442 // -This is not a requirement for 3.1 or later UNDIs but the code looks 443 // simpler if we use the same cpb, db variables for both old and new undi 444 // interfaces from all the SNP interface calls (we don't map the buffers 445 // for the newer undi interfaces though) 446 // . 447 // -it is OK to allocate one global set of CPB, DB pair for each UNDI 448 // interface as EFI does not multi-task and so SNP will not be re-entered! 449 // 450 Status = PciIo->AllocateBuffer ( 451 PciIo, 452 AllocateAnyPages, 453 EfiBootServicesData, 454 SNP_MEM_PAGES (4096), 455 &Address, 456 0 457 ); 458 459 if (Status != EFI_SUCCESS) { 460 DEBUG ((EFI_D_NET, "\nCould not allocate CPB and DB structures.\n")); 461 goto Error_DeleteSNP; 462 } 463 464 Snp->Cpb = (VOID *) (UINTN) Address; 465 Snp->Db = (VOID *) ((UINTN) Address + 2048); 466 467 // 468 // Find the correct BAR to do IO. 469 // 470 // Enumerate through the PCI BARs for the device to determine which one is 471 // the IO BAR. Save the index of the BAR into the adapter info structure. 472 // for regular 32bit BARs, 0 is memory mapped, 1 is io mapped 473 // 474 Snp->MemoryBarIndex = 0; 475 Snp->IoBarIndex = 1; 476 FoundMemoryBar = FALSE; 477 FoundIoBar = FALSE; 478 for (BarIndex = 0; BarIndex < PCI_MAX_BAR; BarIndex++) { 479 Status = PciIo->GetBarAttributes ( 480 PciIo, 481 BarIndex, 482 NULL, 483 (VOID**) &BarDesc 484 ); 485 if (Status == EFI_UNSUPPORTED) { 486 continue; 487 } else if (EFI_ERROR (Status)) { 488 goto Error_DeleteSNP; 489 } 490 491 if ((!FoundMemoryBar) && (BarDesc->ResType == ACPI_ADDRESS_SPACE_TYPE_MEM)) { 492 Snp->MemoryBarIndex = BarIndex; 493 FoundMemoryBar = TRUE; 494 } else if ((!FoundIoBar) && (BarDesc->ResType == ACPI_ADDRESS_SPACE_TYPE_IO)) { 495 Snp->IoBarIndex = BarIndex; 496 FoundIoBar = TRUE; 497 } 498 499 FreePool (BarDesc); 500 501 if (FoundMemoryBar && FoundIoBar) { 502 break; 503 } 504 } 505 506 Status = PxeStart (Snp); 507 508 if (Status != EFI_SUCCESS) { 509 goto Error_DeleteSNP; 510 } 511 512 Snp->Cdb.OpCode = PXE_OPCODE_GET_INIT_INFO; 513 Snp->Cdb.OpFlags = PXE_OPFLAGS_NOT_USED; 514 515 Snp->Cdb.CPBsize = PXE_CPBSIZE_NOT_USED; 516 Snp->Cdb.CPBaddr = PXE_DBADDR_NOT_USED; 517 518 Snp->Cdb.DBsize = (UINT16) sizeof (Snp->InitInfo); 519 Snp->Cdb.DBaddr = (UINT64)(UINTN) (&Snp->InitInfo); 520 521 Snp->Cdb.StatCode = PXE_STATCODE_INITIALIZE; 522 Snp->Cdb.StatFlags = PXE_STATFLAGS_INITIALIZE; 523 524 Snp->Cdb.IFnum = Snp->IfNum; 525 Snp->Cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST; 526 527 DEBUG ((EFI_D_NET, "\nSnp->undi.get_init_info() ")); 528 529 (*Snp->IssueUndi32Command) ((UINT64)(UINTN) &Snp->Cdb); 530 531 // 532 // Save the INIT Stat Code... 533 // 534 InitStatFlags = Snp->Cdb.StatFlags; 535 536 if (Snp->Cdb.StatCode != PXE_STATCODE_SUCCESS) { 537 DEBUG ((EFI_D_NET, "\nSnp->undi.init_info() %xh:%xh\n", Snp->Cdb.StatFlags, Snp->Cdb.StatCode)); 538 PxeStop (Snp); 539 goto Error_DeleteSNP; 540 } 541 542 // 543 // Initialize simple network protocol mode structure 544 // 545 Snp->Mode.State = EfiSimpleNetworkStopped; 546 Snp->Mode.HwAddressSize = Snp->InitInfo.HWaddrLen; 547 Snp->Mode.MediaHeaderSize = Snp->InitInfo.MediaHeaderLen; 548 Snp->Mode.MaxPacketSize = Snp->InitInfo.FrameDataLen; 549 Snp->Mode.NvRamAccessSize = Snp->InitInfo.NvWidth; 550 Snp->Mode.NvRamSize = Snp->InitInfo.NvCount * Snp->Mode.NvRamAccessSize; 551 Snp->Mode.IfType = Snp->InitInfo.IFtype; 552 Snp->Mode.MaxMCastFilterCount = Snp->InitInfo.MCastFilterCnt; 553 Snp->Mode.MCastFilterCount = 0; 554 555 switch (InitStatFlags & PXE_STATFLAGS_CABLE_DETECT_MASK) { 556 case PXE_STATFLAGS_CABLE_DETECT_SUPPORTED: 557 Snp->Mode.MediaPresentSupported = TRUE; 558 break; 559 560 case PXE_STATFLAGS_CABLE_DETECT_NOT_SUPPORTED: 561 default: 562 Snp->Mode.MediaPresentSupported = FALSE; 563 } 564 565 switch (InitStatFlags & PXE_STATFLAGS_GET_STATUS_NO_MEDIA_MASK) { 566 case PXE_STATFLAGS_GET_STATUS_NO_MEDIA_SUPPORTED: 567 Snp->MediaStatusSupported = TRUE; 568 break; 569 570 case PXE_STATFLAGS_GET_STATUS_NO_MEDIA_NOT_SUPPORTED: 571 default: 572 Snp->MediaStatusSupported = FALSE; 573 } 574 575 if ((Pxe->hw.Implementation & PXE_ROMID_IMP_STATION_ADDR_SETTABLE) != 0) { 576 Snp->Mode.MacAddressChangeable = TRUE; 577 } else { 578 Snp->Mode.MacAddressChangeable = FALSE; 579 } 580 581 if ((Pxe->hw.Implementation & PXE_ROMID_IMP_MULTI_FRAME_SUPPORTED) != 0) { 582 Snp->Mode.MultipleTxSupported = TRUE; 583 } else { 584 Snp->Mode.MultipleTxSupported = FALSE; 585 } 586 587 Snp->Mode.ReceiveFilterMask = EFI_SIMPLE_NETWORK_RECEIVE_UNICAST; 588 589 if ((Pxe->hw.Implementation & PXE_ROMID_IMP_PROMISCUOUS_MULTICAST_RX_SUPPORTED) != 0) { 590 Snp->Mode.ReceiveFilterMask |= EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST; 591 592 } 593 594 if ((Pxe->hw.Implementation & PXE_ROMID_IMP_PROMISCUOUS_RX_SUPPORTED) != 0) { 595 Snp->Mode.ReceiveFilterMask |= EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS; 596 597 } 598 599 if ((Pxe->hw.Implementation & PXE_ROMID_IMP_BROADCAST_RX_SUPPORTED) != 0) { 600 Snp->Mode.ReceiveFilterMask |= EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST; 601 602 } 603 604 if ((Pxe->hw.Implementation & PXE_ROMID_IMP_FILTERED_MULTICAST_RX_SUPPORTED) != 0) { 605 Snp->Mode.ReceiveFilterMask |= EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST; 606 607 } 608 609 if ((Pxe->hw.Implementation & PXE_ROMID_IMP_PROMISCUOUS_MULTICAST_RX_SUPPORTED) != 0) { 610 Snp->Mode.ReceiveFilterMask |= EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST; 611 612 } 613 614 Snp->Mode.ReceiveFilterSetting = 0; 615 616 // 617 // need to get the station address to save in the mode structure. we need to 618 // initialize the UNDI first for this. 619 // 620 Snp->TxRxBufferSize = Snp->InitInfo.MemoryRequired; 621 Status = PxeInit (Snp, PXE_OPFLAGS_INITIALIZE_DO_NOT_DETECT_CABLE); 622 623 if (EFI_ERROR (Status)) { 624 PxeStop (Snp); 625 goto Error_DeleteSNP; 626 } 627 628 Status = PxeGetStnAddr (Snp); 629 630 if (Status != EFI_SUCCESS) { 631 DEBUG ((EFI_D_ERROR, "\nSnp->undi.get_station_addr() failed.\n")); 632 PxeShutdown (Snp); 633 PxeStop (Snp); 634 goto Error_DeleteSNP; 635 } 636 637 Snp->Mode.MediaPresent = FALSE; 638 639 // 640 // We should not leave UNDI started and initialized here. this DriverStart() 641 // routine must only find and attach the SNP interface to UNDI layer that it 642 // finds on the given handle! 643 // The UNDI layer will be started when upper layers call Snp->start. 644 // How ever, this DriverStart() must fill up the snp mode structure which 645 // contains the MAC address of the NIC. For this reason we started and 646 // initialized UNDI here, now we are done, do a shutdown and stop of the 647 // UNDI interface! 648 // 649 PxeShutdown (Snp); 650 PxeStop (Snp); 651 652 // 653 // Create EXIT_BOOT_SERIVES Event 654 // 655 Status = gBS->CreateEventEx ( 656 EVT_NOTIFY_SIGNAL, 657 TPL_NOTIFY, 658 SnpNotifyExitBootServices, 659 Snp, 660 &gEfiEventExitBootServicesGuid, 661 &Snp->ExitBootServicesEvent 662 ); 663 if (EFI_ERROR (Status)) { 664 goto Error_DeleteSNP; 665 } 666 667 // 668 // add SNP to the undi handle 669 // 670 Status = gBS->InstallProtocolInterface ( 671 &Controller, 672 &gEfiSimpleNetworkProtocolGuid, 673 EFI_NATIVE_INTERFACE, 674 &(Snp->Snp) 675 ); 676 677 if (!EFI_ERROR (Status)) { 678 return Status; 679 } 680 681 PciIo->FreeBuffer ( 682 PciIo, 683 SNP_MEM_PAGES (4096), 684 Snp->Cpb 685 ); 686 687 Error_DeleteSNP: 688 689 if (Snp->RecycledTxBuf != NULL) { 690 FreePool (Snp->RecycledTxBuf); 691 } 692 693 PciIo->FreeBuffer ( 694 PciIo, 695 SNP_MEM_PAGES (sizeof (SNP_DRIVER)), 696 Snp 697 ); 698 NiiError: 699 gBS->CloseProtocol ( 700 Controller, 701 &gEfiNetworkInterfaceIdentifierProtocolGuid_31, 702 This->DriverBindingHandle, 703 Controller 704 ); 705 706 gBS->CloseProtocol ( 707 Controller, 708 &gEfiDevicePathProtocolGuid, 709 This->DriverBindingHandle, 710 Controller 711 ); 712 713 // 714 // If we got here that means we are in error state. 715 // 716 if (!EFI_ERROR (Status)) { 717 Status = EFI_DEVICE_ERROR; 718 } 719 720 return Status; 721 } 722 723 /** 724 Stop this driver on ControllerHandle. This service is called by the 725 EFI boot service DisconnectController(). In order to 726 make drivers as small as possible, there are a few calling 727 restrictions for this service. DisconnectController() 728 must follow these calling restrictions. If any other agent wishes 729 to call Stop() it must also follow these calling restrictions. 730 731 @param This Protocol instance pointer. 732 @param ControllerHandle Handle of device to stop driver on 733 @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of 734 children is zero stop the entire bus driver. 735 @param ChildHandleBuffer List of Child Handles to Stop. 736 737 @retval EFI_SUCCESS This driver is removed ControllerHandle 738 @retval other This driver was not removed from this device 739 740 **/ 741 EFI_STATUS 742 EFIAPI 743 SimpleNetworkDriverStop ( 744 IN EFI_DRIVER_BINDING_PROTOCOL *This, 745 IN EFI_HANDLE Controller, 746 IN UINTN NumberOfChildren, 747 IN EFI_HANDLE *ChildHandleBuffer 748 ) 749 { 750 EFI_STATUS Status; 751 EFI_SIMPLE_NETWORK_PROTOCOL *SnpProtocol; 752 SNP_DRIVER *Snp; 753 EFI_PCI_IO_PROTOCOL *PciIo; 754 755 // 756 // Get our context back. 757 // 758 Status = gBS->OpenProtocol ( 759 Controller, 760 &gEfiSimpleNetworkProtocolGuid, 761 (VOID **) &SnpProtocol, 762 This->DriverBindingHandle, 763 Controller, 764 EFI_OPEN_PROTOCOL_GET_PROTOCOL 765 ); 766 767 if (EFI_ERROR (Status)) { 768 return EFI_UNSUPPORTED; 769 } 770 771 Snp = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (SnpProtocol); 772 773 Status = gBS->UninstallProtocolInterface ( 774 Controller, 775 &gEfiSimpleNetworkProtocolGuid, 776 &Snp->Snp 777 ); 778 779 if (EFI_ERROR (Status)) { 780 return Status; 781 } 782 783 // 784 // Close EXIT_BOOT_SERIVES Event 785 // 786 gBS->CloseEvent (Snp->ExitBootServicesEvent); 787 788 Status = gBS->CloseProtocol ( 789 Controller, 790 &gEfiNetworkInterfaceIdentifierProtocolGuid_31, 791 This->DriverBindingHandle, 792 Controller 793 ); 794 795 Status = gBS->CloseProtocol ( 796 Controller, 797 &gEfiDevicePathProtocolGuid, 798 This->DriverBindingHandle, 799 Controller 800 ); 801 802 PxeShutdown (Snp); 803 PxeStop (Snp); 804 805 FreePool (Snp->RecycledTxBuf); 806 807 PciIo = Snp->PciIo; 808 PciIo->FreeBuffer ( 809 PciIo, 810 SNP_MEM_PAGES (4096), 811 Snp->Cpb 812 ); 813 814 PciIo->FreeBuffer ( 815 PciIo, 816 SNP_MEM_PAGES (sizeof (SNP_DRIVER)), 817 Snp 818 ); 819 820 return Status; 821 } 822 823 // 824 // Simple Network Protocol Driver Global Variables 825 // 826 EFI_DRIVER_BINDING_PROTOCOL gSimpleNetworkDriverBinding = { 827 SimpleNetworkDriverSupported, 828 SimpleNetworkDriverStart, 829 SimpleNetworkDriverStop, 830 0xa, 831 NULL, 832 NULL 833 }; 834 835 /** 836 The SNP driver entry point. 837 838 @param ImageHandle The driver image handle. 839 @param SystemTable The system table. 840 841 @retval EFI_SUCEESS Initialization routine has found UNDI hardware, 842 loaded it's ROM, and installed a notify event for 843 the Network Indentifier Interface Protocol 844 successfully. 845 @retval Other Return value from HandleProtocol for 846 DeviceIoProtocol or LoadedImageProtocol 847 848 **/ 849 EFI_STATUS 850 EFIAPI 851 InitializeSnpNiiDriver ( 852 IN EFI_HANDLE ImageHandle, 853 IN EFI_SYSTEM_TABLE *SystemTable 854 ) 855 { 856 return EfiLibInstallDriverBindingComponentName2 ( 857 ImageHandle, 858 SystemTable, 859 &gSimpleNetworkDriverBinding, 860 ImageHandle, 861 &gSimpleNetworkComponentName, 862 &gSimpleNetworkComponentName2 863 ); 864 } 865