git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@8130 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			1012 lines
		
	
	
		
			30 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1012 lines
		
	
	
		
			30 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/** @file
 | 
						|
    Implementation of driver entry point and driver binding protocol.
 | 
						|
 
 | 
						|
Copyright (c) 2004 - 2009, Intel Corporation. <BR> 
 | 
						|
All rights reserved. This program and the accompanying materials are licensed 
 | 
						|
and made available under the terms and conditions of the BSD License which 
 | 
						|
accompanies this distribution. The full text of the license may be found at 
 | 
						|
http://opensource.org/licenses/bsd-license.php 
 | 
						|
 | 
						|
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
 | 
						|
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 | 
						|
 | 
						|
**/
 | 
						|
 | 
						|
#include "Snp.h"
 | 
						|
 | 
						|
//
 | 
						|
//  Module global variables needed to support undi 3.0 interface
 | 
						|
//
 | 
						|
EFI_PCI_IO_PROTOCOL         *mPciIo;
 | 
						|
V2P                         *mV2p = NULL; // undi3.0 map_list head
 | 
						|
// End Global variables
 | 
						|
//
 | 
						|
 | 
						|
/**
 | 
						|
  One notified function to stop UNDI device when gBS->ExitBootServices() called.
 | 
						|
 | 
						|
  @param  Event                   Pointer to this event
 | 
						|
  @param  Context                 Event hanlder private data
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
EFIAPI
 | 
						|
SnpNotifyExitBootServices (
 | 
						|
  EFI_EVENT Event,
 | 
						|
  VOID      *Context
 | 
						|
  )
 | 
						|
{
 | 
						|
  SNP_DRIVER             *Snp;
 | 
						|
 | 
						|
  Snp  = (SNP_DRIVER *)Context;
 | 
						|
 | 
						|
  //
 | 
						|
  // Shutdown and stop UNDI driver
 | 
						|
  //
 | 
						|
  PxeShutdown (Snp);
 | 
						|
  PxeStop (Snp);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Send command to UNDI. It does nothing currently.
 | 
						|
  
 | 
						|
  @param Cdb   command to be sent to UNDI.
 | 
						|
   
 | 
						|
  @retval EFI_INVALID_PARAMETER  The command is 0. 
 | 
						|
  @retval EFI_UNSUPPORTED        Default return status because it's not 
 | 
						|
                                 supported currently.
 | 
						|
   
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
IssueHwUndiCommand (
 | 
						|
  UINT64 Cdb
 | 
						|
  )
 | 
						|
{
 | 
						|
  DEBUG ((EFI_D_ERROR, "\nIssueHwUndiCommand() - This should not be called!"));
 | 
						|
 | 
						|
  if (Cdb == 0) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
 | 
						|
  }
 | 
						|
  //
 | 
						|
  //  %%TBD - For now, nothing is done.
 | 
						|
  //
 | 
						|
  return EFI_UNSUPPORTED;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Compute 8-bit checksum of a buffer.
 | 
						|
 | 
						|
  @param  Buffer               Pointer to buffer.
 | 
						|
  @param  Length               Length of buffer in bytes.
 | 
						|
 | 
						|
  @return 8-bit checksum of all bytes in buffer, or zero if ptr is NULL or len 
 | 
						|
          is zero.
 | 
						|
 | 
						|
**/
 | 
						|
UINT8
 | 
						|
Calc8BitCksum (
 | 
						|
  VOID  *Buffer,
 | 
						|
  UINTN Length
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINT8 *Ptr;
 | 
						|
  UINT8 Cksum;
 | 
						|
 | 
						|
  Ptr   = Buffer;
 | 
						|
  Cksum = 0;
 | 
						|
 | 
						|
  if (Ptr == NULL || Length == 0) {
 | 
						|
    return 0;
 | 
						|
  }
 | 
						|
 | 
						|
  while (Length-- != 0) {
 | 
						|
    Cksum = (UINT8) (Cksum + *Ptr++);
 | 
						|
  }
 | 
						|
 | 
						|
  return Cksum;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Test to see if this driver supports ControllerHandle. This service
 | 
						|
  is called by the EFI boot service ConnectController(). In
 | 
						|
  order to make drivers as small as possible, there are a few calling
 | 
						|
  restrictions for this service. ConnectController() must
 | 
						|
  follow these calling restrictions. If any other agent wishes to call
 | 
						|
  Supported() it must also follow these calling restrictions.
 | 
						|
 | 
						|
  @param  This                Protocol instance pointer.
 | 
						|
  @param  ControllerHandle    Handle of device to test.
 | 
						|
  @param  RemainingDevicePath Optional parameter use to pick a specific child
 | 
						|
                              device to start.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS         This driver supports this device.
 | 
						|
  @retval EFI_ALREADY_STARTED This driver is already running on this device.
 | 
						|
  @retval other               This driver does not support this device.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
SimpleNetworkDriverSupported (
 | 
						|
  IN EFI_DRIVER_BINDING_PROTOCOL    *This,
 | 
						|
  IN EFI_HANDLE                     Controller,
 | 
						|
  IN EFI_DEVICE_PATH_PROTOCOL       *RemainingDevicePath
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                                Status;
 | 
						|
  EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL *NiiProtocol;
 | 
						|
  PXE_UNDI                                  *Pxe;
 | 
						|
 | 
						|
  Status = gBS->OpenProtocol (
 | 
						|
                  Controller,
 | 
						|
                  &gEfiDevicePathProtocolGuid,
 | 
						|
                  NULL,
 | 
						|
                  This->DriverBindingHandle,
 | 
						|
                  Controller,
 | 
						|
                  EFI_OPEN_PROTOCOL_TEST_PROTOCOL
 | 
						|
                  );
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  Status = gBS->OpenProtocol (
 | 
						|
                  Controller,
 | 
						|
                  &gEfiNetworkInterfaceIdentifierProtocolGuid_31,
 | 
						|
                  (VOID **) &NiiProtocol,
 | 
						|
                  This->DriverBindingHandle,
 | 
						|
                  Controller,
 | 
						|
                  EFI_OPEN_PROTOCOL_BY_DRIVER
 | 
						|
                  );
 | 
						|
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    if (Status == EFI_ALREADY_STARTED) {
 | 
						|
      DEBUG ((EFI_D_INFO, "Support(): Already Started. on handle %p\n", Controller));
 | 
						|
    }
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  DEBUG ((EFI_D_INFO, "Support(): UNDI3.1 found on handle %p\n", Controller));
 | 
						|
 | 
						|
  //
 | 
						|
  // check the version, we don't want to connect to the undi16
 | 
						|
  //
 | 
						|
  if (NiiProtocol->Type != EfiNetworkInterfaceUndi) {
 | 
						|
    Status = EFI_UNSUPPORTED;
 | 
						|
    goto Done;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // Check to see if !PXE structure is valid. Paragraph alignment of !PXE structure is required.
 | 
						|
  //
 | 
						|
  if (NiiProtocol->Id & 0x0F) {
 | 
						|
    DEBUG ((EFI_D_NET, "\n!PXE structure is not paragraph aligned.\n"));
 | 
						|
    Status = EFI_UNSUPPORTED;
 | 
						|
    goto Done;
 | 
						|
  }
 | 
						|
 | 
						|
  Pxe = (PXE_UNDI *) (UINTN) (NiiProtocol->Id);
 | 
						|
 | 
						|
  //
 | 
						|
  //  Verify !PXE revisions.
 | 
						|
  //
 | 
						|
  if (Pxe->hw.Signature != PXE_ROMID_SIGNATURE) {
 | 
						|
    DEBUG ((EFI_D_NET, "\n!PXE signature is not valid.\n"));
 | 
						|
    Status = EFI_UNSUPPORTED;
 | 
						|
    goto Done;
 | 
						|
  }
 | 
						|
 | 
						|
  if (Pxe->hw.Rev < PXE_ROMID_REV) {
 | 
						|
    DEBUG ((EFI_D_NET, "\n!PXE.Rev is not supported.\n"));
 | 
						|
    Status = EFI_UNSUPPORTED;
 | 
						|
    goto Done;
 | 
						|
  }
 | 
						|
 | 
						|
  if (Pxe->hw.MajorVer < PXE_ROMID_MAJORVER) {
 | 
						|
 | 
						|
    DEBUG ((EFI_D_NET, "\n!PXE.MajorVer is not supported.\n"));
 | 
						|
    Status = EFI_UNSUPPORTED;
 | 
						|
    goto Done;
 | 
						|
 | 
						|
  } else if (Pxe->hw.MajorVer == PXE_ROMID_MAJORVER && Pxe->hw.MinorVer < PXE_ROMID_MINORVER) {
 | 
						|
    DEBUG ((EFI_D_NET, "\n!PXE.MinorVer is not supported."));
 | 
						|
    Status = EFI_UNSUPPORTED;
 | 
						|
    goto Done;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // Do S/W UNDI specific checks.
 | 
						|
  //
 | 
						|
  if ((Pxe->hw.Implementation & PXE_ROMID_IMP_HW_UNDI) == 0) {
 | 
						|
    if (Pxe->sw.EntryPoint < Pxe->sw.Len) {
 | 
						|
      DEBUG ((EFI_D_NET, "\n!PXE S/W entry point is not valid."));
 | 
						|
      Status = EFI_UNSUPPORTED;
 | 
						|
      goto Done;
 | 
						|
    }
 | 
						|
 | 
						|
    if (Pxe->sw.BusCnt == 0) {
 | 
						|
      DEBUG ((EFI_D_NET, "\n!PXE.BusCnt is zero."));
 | 
						|
      Status = EFI_UNSUPPORTED;
 | 
						|
      goto Done;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  Status = EFI_SUCCESS;
 | 
						|
  DEBUG ((EFI_D_INFO, "Support(): supported on %p\n", Controller));
 | 
						|
 | 
						|
Done:
 | 
						|
  gBS->CloseProtocol (
 | 
						|
        Controller,
 | 
						|
        &gEfiNetworkInterfaceIdentifierProtocolGuid_31,
 | 
						|
        This->DriverBindingHandle,
 | 
						|
        Controller
 | 
						|
        );
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Start this driver on ControllerHandle. This service is called by the
 | 
						|
  EFI boot service ConnectController(). In order to make
 | 
						|
  drivers as small as possible, there are a few calling restrictions for
 | 
						|
  this service. ConnectController() must follow these
 | 
						|
  calling restrictions. If any other agent wishes to call Start() it
 | 
						|
  must also follow these calling restrictions.
 | 
						|
 | 
						|
  @param  This                 Protocol instance pointer.
 | 
						|
  @param  ControllerHandle     Handle of device to bind driver to.
 | 
						|
  @param  RemainingDevicePath  Optional parameter use to pick a specific child
 | 
						|
                               device to start.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS          This driver is added to ControllerHandle
 | 
						|
  @retval EFI_ALREADY_STARTED  This driver is already running on ControllerHandle
 | 
						|
  @retval other                This driver does not support this device
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
SimpleNetworkDriverStart (
 | 
						|
  IN EFI_DRIVER_BINDING_PROTOCOL    *This,
 | 
						|
  IN EFI_HANDLE                     Controller,
 | 
						|
  IN EFI_DEVICE_PATH_PROTOCOL       *RemainingDevicePath
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL *Nii;
 | 
						|
  EFI_DEVICE_PATH_PROTOCOL                  *NiiDevicePath;
 | 
						|
  EFI_STATUS                                Status;
 | 
						|
  PXE_UNDI                                  *Pxe;
 | 
						|
  SNP_DRIVER                                *Snp;
 | 
						|
  VOID                                      *Address;
 | 
						|
  EFI_HANDLE                                Handle;
 | 
						|
  PXE_PCI_CONFIG_INFO                       ConfigInfo;
 | 
						|
  PCI_TYPE00                                *ConfigHeader;
 | 
						|
  UINT32                                    *TempBar;
 | 
						|
  UINT8                                     BarIndex;
 | 
						|
  PXE_STATFLAGS                             InitStatFlags;
 | 
						|
 | 
						|
  DEBUG ((EFI_D_NET, "\nSnpNotifyNetworkInterfaceIdentifier()  "));
 | 
						|
 | 
						|
  Status = gBS->OpenProtocol (
 | 
						|
                  Controller,
 | 
						|
                  &gEfiDevicePathProtocolGuid,
 | 
						|
                  (VOID **) &NiiDevicePath,
 | 
						|
                  This->DriverBindingHandle,
 | 
						|
                  Controller,
 | 
						|
                  EFI_OPEN_PROTOCOL_BY_DRIVER
 | 
						|
                  );
 | 
						|
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  Status = gBS->LocateDevicePath (
 | 
						|
                  &gEfiPciIoProtocolGuid,
 | 
						|
                  &NiiDevicePath,
 | 
						|
                  &Handle
 | 
						|
                  );
 | 
						|
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  Status = gBS->OpenProtocol (
 | 
						|
                  Handle,
 | 
						|
                  &gEfiPciIoProtocolGuid,
 | 
						|
                  (VOID **) &mPciIo,
 | 
						|
                  This->DriverBindingHandle,
 | 
						|
                  Controller,
 | 
						|
                  EFI_OPEN_PROTOCOL_GET_PROTOCOL
 | 
						|
                  );
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // Get the NII interface.
 | 
						|
  //
 | 
						|
  Status = gBS->OpenProtocol (
 | 
						|
                  Controller,
 | 
						|
                  &gEfiNetworkInterfaceIdentifierProtocolGuid_31,
 | 
						|
                  (VOID **) &Nii,
 | 
						|
                  This->DriverBindingHandle,
 | 
						|
                  Controller,
 | 
						|
                  EFI_OPEN_PROTOCOL_BY_DRIVER
 | 
						|
                  );
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    gBS->CloseProtocol (
 | 
						|
          Controller,
 | 
						|
          &gEfiDevicePathProtocolGuid,
 | 
						|
          This->DriverBindingHandle,
 | 
						|
          Controller
 | 
						|
          );
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  DEBUG ((EFI_D_INFO, "Start(): UNDI3.1 found\n"));
 | 
						|
 | 
						|
  Pxe = (PXE_UNDI *) (UINTN) (Nii->Id);
 | 
						|
 | 
						|
  if (Calc8BitCksum (Pxe, Pxe->hw.Len) != 0) {
 | 
						|
    DEBUG ((EFI_D_NET, "\n!PXE checksum is not correct.\n"));
 | 
						|
    goto NiiError;
 | 
						|
  }
 | 
						|
 | 
						|
  if ((Pxe->hw.Implementation & PXE_ROMID_IMP_PROMISCUOUS_RX_SUPPORTED) != 0) {
 | 
						|
    //
 | 
						|
    //  We can get any packets.
 | 
						|
    //
 | 
						|
  } else if ((Pxe->hw.Implementation & PXE_ROMID_IMP_BROADCAST_RX_SUPPORTED) != 0) {
 | 
						|
    //
 | 
						|
    //  We need to be able to get broadcast packets for DHCP.
 | 
						|
    //  If we do not have promiscuous support, we must at least have
 | 
						|
    //  broadcast support or we cannot do DHCP!
 | 
						|
    //
 | 
						|
  } else {
 | 
						|
    DEBUG ((EFI_D_NET, "\nUNDI does not have promiscuous or broadcast support."));
 | 
						|
    goto NiiError;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // OK, we like this UNDI, and we know snp is not already there on this handle
 | 
						|
  // Allocate and initialize a new simple network protocol structure.
 | 
						|
  //
 | 
						|
  Status = mPciIo->AllocateBuffer (
 | 
						|
                        mPciIo,
 | 
						|
                        AllocateAnyPages,
 | 
						|
                        EfiBootServicesData,
 | 
						|
                        SNP_MEM_PAGES (sizeof (SNP_DRIVER)),
 | 
						|
                        &Address,
 | 
						|
                        0
 | 
						|
                        );
 | 
						|
 | 
						|
  if (Status != EFI_SUCCESS) {
 | 
						|
    DEBUG ((EFI_D_NET, "\nCould not allocate SNP_DRIVER structure.\n"));
 | 
						|
    goto NiiError;
 | 
						|
  }
 | 
						|
 | 
						|
  Snp = (SNP_DRIVER *) (UINTN) Address;
 | 
						|
 | 
						|
  ZeroMem (Snp, sizeof (SNP_DRIVER));
 | 
						|
 | 
						|
  Snp->PciIo      = mPciIo;
 | 
						|
  Snp->Signature  = SNP_DRIVER_SIGNATURE;
 | 
						|
 | 
						|
  EfiInitializeLock (&Snp->Lock, TPL_NOTIFY);
 | 
						|
 | 
						|
  Snp->Snp.Revision       = EFI_SIMPLE_NETWORK_PROTOCOL_REVISION;
 | 
						|
  Snp->Snp.Start          = SnpUndi32Start;
 | 
						|
  Snp->Snp.Stop           = SnpUndi32Stop;
 | 
						|
  Snp->Snp.Initialize     = SnpUndi32Initialize;
 | 
						|
  Snp->Snp.Reset          = SnpUndi32Reset;
 | 
						|
  Snp->Snp.Shutdown       = SnpUndi32Shutdown;
 | 
						|
  Snp->Snp.ReceiveFilters = SnpUndi32ReceiveFilters;
 | 
						|
  Snp->Snp.StationAddress = SnpUndi32StationAddress;
 | 
						|
  Snp->Snp.Statistics     = SnpUndi32Statistics;
 | 
						|
  Snp->Snp.MCastIpToMac   = SnpUndi32McastIpToMac;
 | 
						|
  Snp->Snp.NvData         = SnpUndi32NvData;
 | 
						|
  Snp->Snp.GetStatus      = SnpUndi32GetStatus;
 | 
						|
  Snp->Snp.Transmit       = SnpUndi32Transmit;
 | 
						|
  Snp->Snp.Receive        = SnpUndi32Receive;
 | 
						|
  Snp->Snp.WaitForPacket  = NULL;
 | 
						|
 | 
						|
  Snp->Snp.Mode           = &Snp->Mode;
 | 
						|
 | 
						|
  Snp->TxRxBufferSize     = 0;
 | 
						|
  Snp->TxRxBuffer         = NULL;
 | 
						|
 | 
						|
  Snp->IfNum              = Nii->IfNum;
 | 
						|
 | 
						|
  if ((Pxe->hw.Implementation & PXE_ROMID_IMP_HW_UNDI) != 0) {
 | 
						|
    Snp->IsSwUndi             = FALSE;
 | 
						|
    Snp->IssueUndi32Command   = &IssueHwUndiCommand;
 | 
						|
  } else {
 | 
						|
    Snp->IsSwUndi = TRUE;
 | 
						|
 | 
						|
    if ((Pxe->sw.Implementation & PXE_ROMID_IMP_SW_VIRT_ADDR) != 0) {
 | 
						|
      Snp->IssueUndi32Command = (ISSUE_UNDI32_COMMAND) (UINTN) Pxe->sw.EntryPoint;
 | 
						|
    } else {
 | 
						|
      Snp->IssueUndi32Command = (ISSUE_UNDI32_COMMAND) (UINTN) ((UINT8) (UINTN) Pxe + Pxe->sw.EntryPoint);
 | 
						|
    }
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // Allocate a global CPB and DB buffer for this UNDI interface.
 | 
						|
  // we do this because:
 | 
						|
  //
 | 
						|
  // -UNDI 3.0 wants all the addresses passed to it (even the cpb and db) to be
 | 
						|
  // within 2GB limit, create them here and map them so that when undi calls
 | 
						|
  // v2p callback to check if the physical address is < 2gb, we will pass.
 | 
						|
  //
 | 
						|
  // -This is not a requirement for 3.1 or later UNDIs but the code looks
 | 
						|
  // simpler if we use the same cpb, db variables for both old and new undi
 | 
						|
  // interfaces from all the SNP interface calls (we don't map the buffers
 | 
						|
  // for the newer undi interfaces though)
 | 
						|
  // .
 | 
						|
  // -it is OK to allocate one global set of CPB, DB pair for each UNDI
 | 
						|
  // interface as EFI does not multi-task and so SNP will not be re-entered!
 | 
						|
  //
 | 
						|
  Status = mPciIo->AllocateBuffer (
 | 
						|
                        mPciIo,
 | 
						|
                        AllocateAnyPages,
 | 
						|
                        EfiBootServicesData,
 | 
						|
                        SNP_MEM_PAGES (4096),
 | 
						|
                        &Address,
 | 
						|
                        0
 | 
						|
                        );
 | 
						|
 | 
						|
  if (Status != EFI_SUCCESS) {
 | 
						|
    DEBUG ((EFI_D_NET, "\nCould not allocate CPB and DB structures.\n"));
 | 
						|
    goto Error_DeleteSNP;
 | 
						|
  }
 | 
						|
 | 
						|
  Snp->Cpb  = (VOID *) (UINTN) Address;
 | 
						|
  Snp->Db   = (VOID *) ((UINTN) Address + 2048);
 | 
						|
 | 
						|
  //
 | 
						|
  // PxeStart call is going to give the callback functions to UNDI, these callback
 | 
						|
  // functions use the BarIndex values from the snp structure, so these must be initialized
 | 
						|
  // with default values before doing a PxeStart. The correct values can be obtained after
 | 
						|
  // getting the config information from UNDI
 | 
						|
  //
 | 
						|
  Snp->MemoryBarIndex = 0;
 | 
						|
  Snp->IoBarIndex     = 1;
 | 
						|
 | 
						|
  //
 | 
						|
  // we need the undi init information many times in this snp code, just get it
 | 
						|
  // once here and store it in the snp driver structure. to get Init Info
 | 
						|
  // from UNDI we have to start undi first.
 | 
						|
  //
 | 
						|
  Status = PxeStart (Snp);
 | 
						|
 | 
						|
  if (Status != EFI_SUCCESS) {
 | 
						|
    goto Error_DeleteSNP;
 | 
						|
  }
 | 
						|
 | 
						|
  Snp->Cdb.OpCode     = PXE_OPCODE_GET_INIT_INFO;
 | 
						|
  Snp->Cdb.OpFlags    = PXE_OPFLAGS_NOT_USED;
 | 
						|
 | 
						|
  Snp->Cdb.CPBsize    = PXE_CPBSIZE_NOT_USED;
 | 
						|
  Snp->Cdb.CPBaddr    = PXE_DBADDR_NOT_USED;
 | 
						|
 | 
						|
  Snp->Cdb.DBsize     = sizeof Snp->InitInfo;
 | 
						|
  Snp->Cdb.DBaddr     = (UINT64)(UINTN) &Snp->InitInfo;
 | 
						|
 | 
						|
  Snp->Cdb.StatCode   = PXE_STATCODE_INITIALIZE;
 | 
						|
  Snp->Cdb.StatFlags  = PXE_STATFLAGS_INITIALIZE;
 | 
						|
 | 
						|
  Snp->Cdb.IFnum      = Snp->IfNum;
 | 
						|
  Snp->Cdb.Control    = PXE_CONTROL_LAST_CDB_IN_LIST;
 | 
						|
 | 
						|
  DEBUG ((EFI_D_NET, "\nSnp->undi.get_init_info()  "));
 | 
						|
 | 
						|
  (*Snp->IssueUndi32Command) ((UINT64)(UINTN) &Snp->Cdb);
 | 
						|
 | 
						|
  //
 | 
						|
  // Save the INIT Stat Code...
 | 
						|
  //
 | 
						|
  InitStatFlags = Snp->Cdb.StatFlags;
 | 
						|
 | 
						|
  if (Snp->Cdb.StatCode != PXE_STATCODE_SUCCESS) {
 | 
						|
    DEBUG ((EFI_D_NET, "\nSnp->undi.init_info()  %xh:%xh\n", Snp->Cdb.StatFlags, Snp->Cdb.StatCode));
 | 
						|
    PxeStop (Snp);
 | 
						|
    goto Error_DeleteSNP;
 | 
						|
  }
 | 
						|
 | 
						|
  Snp->Cdb.OpCode     = PXE_OPCODE_GET_CONFIG_INFO;
 | 
						|
  Snp->Cdb.OpFlags    = PXE_OPFLAGS_NOT_USED;
 | 
						|
 | 
						|
  Snp->Cdb.CPBsize    = PXE_CPBSIZE_NOT_USED;
 | 
						|
  Snp->Cdb.CPBaddr    = PXE_DBADDR_NOT_USED;
 | 
						|
 | 
						|
  Snp->Cdb.DBsize     = sizeof ConfigInfo;
 | 
						|
  Snp->Cdb.DBaddr     = (UINT64)(UINTN) &ConfigInfo;
 | 
						|
 | 
						|
  Snp->Cdb.StatCode   = PXE_STATCODE_INITIALIZE;
 | 
						|
  Snp->Cdb.StatFlags  = PXE_STATFLAGS_INITIALIZE;
 | 
						|
 | 
						|
  Snp->Cdb.IFnum      = Snp->IfNum;
 | 
						|
  Snp->Cdb.Control    = PXE_CONTROL_LAST_CDB_IN_LIST;
 | 
						|
 | 
						|
  DEBUG ((EFI_D_NET, "\nSnp->undi.get_config_info()  "));
 | 
						|
 | 
						|
  (*Snp->IssueUndi32Command) ((UINT64)(UINTN) &Snp->Cdb);
 | 
						|
 | 
						|
  if (Snp->Cdb.StatCode != PXE_STATCODE_SUCCESS) {
 | 
						|
    DEBUG ((EFI_D_NET, "\nSnp->undi.config_info()  %xh:%xh\n", Snp->Cdb.StatFlags, Snp->Cdb.StatCode));
 | 
						|
    PxeStop (Snp);
 | 
						|
    goto Error_DeleteSNP;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // Find the correct BAR to do IO.
 | 
						|
  //
 | 
						|
  //
 | 
						|
  // Enumerate through the PCI BARs for the device to determine which one is
 | 
						|
  // the IO BAR.  Save the index of the BAR into the adapter info structure.
 | 
						|
  // for  regular 32bit BARs, 0 is memory mapped, 1 is io mapped
 | 
						|
  //
 | 
						|
  ConfigHeader  = (PCI_TYPE00 *) &ConfigInfo.Config.Byte[0];
 | 
						|
  TempBar       = (UINT32 *) &ConfigHeader->Device.Bar[0];
 | 
						|
  for (BarIndex = 0; BarIndex <= 5; BarIndex++) {
 | 
						|
    if ((*TempBar & PCI_BAR_MEM_MASK) == PCI_BAR_MEM_64BIT) {
 | 
						|
      //
 | 
						|
      // This is a 64-bit memory bar, skip this and the
 | 
						|
      // next bar as well.
 | 
						|
      //
 | 
						|
      TempBar++;
 | 
						|
    }
 | 
						|
 | 
						|
    if ((*TempBar & PCI_BAR_IO_MASK) == PCI_BAR_IO_MODE) {
 | 
						|
      Snp->IoBarIndex = BarIndex;
 | 
						|
      break;
 | 
						|
    }
 | 
						|
 | 
						|
    TempBar++;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  //  Initialize simple network protocol mode structure
 | 
						|
  //
 | 
						|
  Snp->Mode.State               = EfiSimpleNetworkStopped;
 | 
						|
  Snp->Mode.HwAddressSize       = Snp->InitInfo.HWaddrLen;
 | 
						|
  Snp->Mode.MediaHeaderSize     = Snp->InitInfo.MediaHeaderLen;
 | 
						|
  Snp->Mode.MaxPacketSize       = Snp->InitInfo.FrameDataLen;
 | 
						|
  Snp->Mode.NvRamAccessSize     = Snp->InitInfo.NvWidth;
 | 
						|
  Snp->Mode.NvRamSize           = Snp->InitInfo.NvCount * Snp->Mode.NvRamAccessSize;
 | 
						|
  Snp->Mode.IfType              = Snp->InitInfo.IFtype;
 | 
						|
  Snp->Mode.MaxMCastFilterCount = Snp->InitInfo.MCastFilterCnt;
 | 
						|
  Snp->Mode.MCastFilterCount    = 0;
 | 
						|
 | 
						|
  switch (InitStatFlags & PXE_STATFLAGS_CABLE_DETECT_MASK) {
 | 
						|
  case PXE_STATFLAGS_CABLE_DETECT_SUPPORTED:
 | 
						|
    Snp->Mode.MediaPresentSupported = TRUE;
 | 
						|
    break;
 | 
						|
 | 
						|
  case PXE_STATFLAGS_CABLE_DETECT_NOT_SUPPORTED:
 | 
						|
  default:
 | 
						|
    Snp->Mode.MediaPresentSupported = FALSE;
 | 
						|
  }
 | 
						|
 | 
						|
  if ((Pxe->hw.Implementation & PXE_ROMID_IMP_STATION_ADDR_SETTABLE) != 0) {
 | 
						|
    Snp->Mode.MacAddressChangeable = TRUE;
 | 
						|
  } else {
 | 
						|
    Snp->Mode.MacAddressChangeable = FALSE;
 | 
						|
  }
 | 
						|
 | 
						|
  if ((Pxe->hw.Implementation & PXE_ROMID_IMP_MULTI_FRAME_SUPPORTED) != 0) {
 | 
						|
    Snp->Mode.MultipleTxSupported = TRUE;
 | 
						|
  } else {
 | 
						|
    Snp->Mode.MultipleTxSupported = FALSE;
 | 
						|
  }
 | 
						|
 | 
						|
  Snp->Mode.ReceiveFilterMask = EFI_SIMPLE_NETWORK_RECEIVE_UNICAST;
 | 
						|
 | 
						|
  if ((Pxe->hw.Implementation & PXE_ROMID_IMP_PROMISCUOUS_MULTICAST_RX_SUPPORTED) != 0) {
 | 
						|
    Snp->Mode.ReceiveFilterMask |= EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST;
 | 
						|
 | 
						|
  }
 | 
						|
 | 
						|
  if ((Pxe->hw.Implementation & PXE_ROMID_IMP_PROMISCUOUS_RX_SUPPORTED) != 0) {
 | 
						|
    Snp->Mode.ReceiveFilterMask |= EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS;
 | 
						|
 | 
						|
  }
 | 
						|
 | 
						|
  if ((Pxe->hw.Implementation & PXE_ROMID_IMP_BROADCAST_RX_SUPPORTED) != 0) {
 | 
						|
    Snp->Mode.ReceiveFilterMask |= EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST;
 | 
						|
 | 
						|
  }
 | 
						|
 | 
						|
  if ((Pxe->hw.Implementation & PXE_ROMID_IMP_FILTERED_MULTICAST_RX_SUPPORTED) != 0) {
 | 
						|
    Snp->Mode.ReceiveFilterMask |= EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST;
 | 
						|
 | 
						|
  }
 | 
						|
 | 
						|
  if (Pxe->hw.Implementation & PXE_ROMID_IMP_PROMISCUOUS_MULTICAST_RX_SUPPORTED) {
 | 
						|
    Snp->Mode.ReceiveFilterMask |= EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST;
 | 
						|
 | 
						|
  }
 | 
						|
 | 
						|
  Snp->Mode.ReceiveFilterSetting = 0;
 | 
						|
 | 
						|
  //
 | 
						|
  //  need to get the station address to save in the mode structure. we need to
 | 
						|
  // initialize the UNDI first for this.
 | 
						|
  //
 | 
						|
  Snp->TxRxBufferSize = Snp->InitInfo.MemoryRequired;
 | 
						|
  Status              = PxeInit (Snp, PXE_OPFLAGS_INITIALIZE_DO_NOT_DETECT_CABLE);
 | 
						|
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    PxeStop (Snp);
 | 
						|
    goto Error_DeleteSNP;
 | 
						|
  }
 | 
						|
 | 
						|
  Status = PxeGetStnAddr (Snp);
 | 
						|
 | 
						|
  if (Status != EFI_SUCCESS) {
 | 
						|
    DEBUG ((EFI_D_ERROR, "\nSnp->undi.get_station_addr() failed.\n"));
 | 
						|
    PxeShutdown (Snp);
 | 
						|
    PxeStop (Snp);
 | 
						|
    goto Error_DeleteSNP;
 | 
						|
  }
 | 
						|
 | 
						|
  Snp->Mode.MediaPresent = FALSE;
 | 
						|
 | 
						|
  //
 | 
						|
  // We should not leave UNDI started and initialized here. this DriverStart()
 | 
						|
  // routine must only find and attach the SNP interface to UNDI layer that it
 | 
						|
  // finds on the given handle!
 | 
						|
  // The UNDI layer will be started when upper layers call Snp->start.
 | 
						|
  // How ever, this DriverStart() must fill up the snp mode structure which
 | 
						|
  // contains the MAC address of the NIC. For this reason we started and
 | 
						|
  // initialized UNDI here, now we are done, do a shutdown and stop of the
 | 
						|
  // UNDI interface!
 | 
						|
  //
 | 
						|
  PxeShutdown (Snp);
 | 
						|
  PxeStop (Snp);
 | 
						|
 | 
						|
  //
 | 
						|
  // Create EXIT_BOOT_SERIVES Event
 | 
						|
  //
 | 
						|
  Status = gBS->CreateEventEx (
 | 
						|
                  EVT_NOTIFY_SIGNAL,
 | 
						|
                  TPL_NOTIFY,
 | 
						|
                  SnpNotifyExitBootServices,
 | 
						|
                  Snp,
 | 
						|
                  &gEfiEventExitBootServicesGuid,
 | 
						|
                  &Snp->ExitBootServicesEvent
 | 
						|
                  );
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    goto Error_DeleteSNP;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  //  add SNP to the undi handle
 | 
						|
  //
 | 
						|
  Status = gBS->InstallProtocolInterface (
 | 
						|
                  &Controller,
 | 
						|
                  &gEfiSimpleNetworkProtocolGuid,
 | 
						|
                  EFI_NATIVE_INTERFACE,
 | 
						|
                  &(Snp->Snp)
 | 
						|
                  );
 | 
						|
 | 
						|
  if (!EFI_ERROR (Status)) {
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  Status = mPciIo->FreeBuffer (
 | 
						|
                        mPciIo,
 | 
						|
                        SNP_MEM_PAGES (4096),
 | 
						|
                        Snp->Cpb
 | 
						|
                        );
 | 
						|
 | 
						|
Error_DeleteSNP:
 | 
						|
 | 
						|
  mPciIo->FreeBuffer (
 | 
						|
                mPciIo,
 | 
						|
                SNP_MEM_PAGES (sizeof (SNP_DRIVER)),
 | 
						|
                Snp
 | 
						|
                );
 | 
						|
NiiError:
 | 
						|
  gBS->CloseProtocol (
 | 
						|
        Controller,
 | 
						|
        &gEfiNetworkInterfaceIdentifierProtocolGuid_31,
 | 
						|
        This->DriverBindingHandle,
 | 
						|
        Controller
 | 
						|
        );
 | 
						|
 | 
						|
  gBS->CloseProtocol (
 | 
						|
        Controller,
 | 
						|
        &gEfiDevicePathProtocolGuid,
 | 
						|
        This->DriverBindingHandle,
 | 
						|
        Controller
 | 
						|
        );
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Stop this driver on ControllerHandle. This service is called by the
 | 
						|
  EFI boot service DisconnectController(). In order to
 | 
						|
  make drivers as small as possible, there are a few calling
 | 
						|
  restrictions for this service. DisconnectController()
 | 
						|
  must follow these calling restrictions. If any other agent wishes
 | 
						|
  to call Stop() it must also follow these calling restrictions.
 | 
						|
  
 | 
						|
  @param  This              Protocol instance pointer.
 | 
						|
  @param  ControllerHandle  Handle of device to stop driver on
 | 
						|
  @param  NumberOfChildren  Number of Handles in ChildHandleBuffer. If number of
 | 
						|
                            children is zero stop the entire bus driver.
 | 
						|
  @param  ChildHandleBuffer List of Child Handles to Stop.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS       This driver is removed ControllerHandle
 | 
						|
  @retval other             This driver was not removed from this device
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
SimpleNetworkDriverStop (
 | 
						|
  IN  EFI_DRIVER_BINDING_PROTOCOL    *This,
 | 
						|
  IN  EFI_HANDLE                     Controller,
 | 
						|
  IN  UINTN                          NumberOfChildren,
 | 
						|
  IN  EFI_HANDLE                     *ChildHandleBuffer
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                  Status;
 | 
						|
  EFI_SIMPLE_NETWORK_PROTOCOL *SnpProtocol;
 | 
						|
  SNP_DRIVER                  *Snp;
 | 
						|
 | 
						|
  //
 | 
						|
  // Get our context back.
 | 
						|
  //
 | 
						|
  Status = gBS->OpenProtocol (
 | 
						|
                  Controller,
 | 
						|
                  &gEfiSimpleNetworkProtocolGuid,
 | 
						|
                  (VOID **) &SnpProtocol,
 | 
						|
                  This->DriverBindingHandle,
 | 
						|
                  Controller,
 | 
						|
                  EFI_OPEN_PROTOCOL_GET_PROTOCOL
 | 
						|
                  );
 | 
						|
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return EFI_UNSUPPORTED;
 | 
						|
  }
 | 
						|
 | 
						|
  Snp = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (SnpProtocol);
 | 
						|
 | 
						|
  Status = gBS->UninstallProtocolInterface (
 | 
						|
                  Controller,
 | 
						|
                  &gEfiSimpleNetworkProtocolGuid,
 | 
						|
                  &Snp->Snp
 | 
						|
                  );
 | 
						|
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Close EXIT_BOOT_SERIVES Event
 | 
						|
  //
 | 
						|
  gBS->CloseEvent (Snp->ExitBootServicesEvent);
 | 
						|
 | 
						|
  Status = gBS->CloseProtocol (
 | 
						|
                  Controller,
 | 
						|
                  &gEfiNetworkInterfaceIdentifierProtocolGuid_31,
 | 
						|
                  This->DriverBindingHandle,
 | 
						|
                  Controller
 | 
						|
                  );
 | 
						|
 | 
						|
  Status = gBS->CloseProtocol (
 | 
						|
                  Controller,
 | 
						|
                  &gEfiDevicePathProtocolGuid,
 | 
						|
                  This->DriverBindingHandle,
 | 
						|
                  Controller
 | 
						|
                  );
 | 
						|
 | 
						|
  PxeShutdown (Snp);
 | 
						|
  PxeStop (Snp);
 | 
						|
 | 
						|
  mPciIo->FreeBuffer (
 | 
						|
                mPciIo,
 | 
						|
                SNP_MEM_PAGES (4096),
 | 
						|
                Snp->Cpb
 | 
						|
                );
 | 
						|
 | 
						|
  mPciIo->FreeBuffer (
 | 
						|
                mPciIo,
 | 
						|
                SNP_MEM_PAGES (sizeof (SNP_DRIVER)),
 | 
						|
                Snp
 | 
						|
                );
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
//
 | 
						|
// Simple Network Protocol Driver Global Variables
 | 
						|
//
 | 
						|
EFI_DRIVER_BINDING_PROTOCOL mSimpleNetworkDriverBinding = {
 | 
						|
  SimpleNetworkDriverSupported,
 | 
						|
  SimpleNetworkDriverStart,
 | 
						|
  SimpleNetworkDriverStop,
 | 
						|
  0xa,
 | 
						|
  NULL,
 | 
						|
  NULL
 | 
						|
};
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  This routine maps the given CPU address to a Device address. It creates a
 | 
						|
  an entry in the map list with the virtual and physical addresses and the
 | 
						|
  un map cookie.
 | 
						|
 | 
						|
  @param  V2p                  pointer to return a map list node pointer.
 | 
						|
  @param  Type                 the direction in which the data flows from the given
 | 
						|
                               virtual address device->cpu or cpu->device or both
 | 
						|
                               ways.
 | 
						|
  @param  VirtualAddress       virtual address (or CPU address) to be mapped.
 | 
						|
  @param  BufferSize           size of the buffer to be mapped.
 | 
						|
 | 
						|
  @retval EFI_SUCEESS           routine has completed the mapping.
 | 
						|
  @retval EFI_INVALID_PARAMETER invalid parameter.
 | 
						|
  @retval EFI_OUT_OF_RESOURCES  out of resource.
 | 
						|
  @retval other                 error as indicated.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
AddV2P (
 | 
						|
  IN OUT V2P                    **V2p,
 | 
						|
  EFI_PCI_IO_PROTOCOL_OPERATION Type,
 | 
						|
  VOID                          *VirtualAddress,
 | 
						|
  UINTN                         BufferSize
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS  Status;
 | 
						|
 | 
						|
  if ((V2p == NULL) || (VirtualAddress == NULL) || (BufferSize == 0)) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  *V2p = AllocatePool (sizeof (V2P));
 | 
						|
  if (*V2p != NULL) {
 | 
						|
    return EFI_OUT_OF_RESOURCES;
 | 
						|
  }
 | 
						|
 | 
						|
  Status = mPciIo->Map (
 | 
						|
                     mPciIo,
 | 
						|
                     Type,
 | 
						|
                     VirtualAddress,
 | 
						|
                     &BufferSize,
 | 
						|
                     &(*V2p)->PhysicalAddress,
 | 
						|
                     &(*V2p)->Unmap
 | 
						|
                     );
 | 
						|
  if (Status != EFI_SUCCESS) {
 | 
						|
    FreePool (*V2p);
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
  (*V2p)->VirtualAddress = VirtualAddress;
 | 
						|
  (*V2p)->BufferSize     = BufferSize;
 | 
						|
  (*V2p)->Next           = mV2p;
 | 
						|
  mV2p                   = *V2p;
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  This routine searches the linked list of mapped address nodes (for undi3.0
 | 
						|
  interface) to find the node that corresponds to the given virtual address and
 | 
						|
  returns a pointer to that node.
 | 
						|
 | 
						|
  @param  V2p                  pointer to return a map list node pointer.
 | 
						|
  @param  VirtualAddr          virtual address (or CPU address) to be searched in
 | 
						|
                               the map list
 | 
						|
 | 
						|
  @retval EFI_SUCEESS          A match was found.
 | 
						|
  @retval Other                A match cannot be found.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
FindV2p (
 | 
						|
  V2P          **V2p,
 | 
						|
  VOID         *VirtualAddr
 | 
						|
  )
 | 
						|
{
 | 
						|
  V2P    *Ptr;
 | 
						|
 | 
						|
  if (V2p == NULL || VirtualAddr == NULL) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  for (Ptr = mV2p; Ptr != NULL; Ptr = Ptr->Next) {
 | 
						|
    if (Ptr->VirtualAddress == VirtualAddr) {
 | 
						|
      *V2p = Ptr;
 | 
						|
      return EFI_SUCCESS;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  return EFI_NOT_FOUND;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Unmap the given virtual address and free the memory allocated for the map list
 | 
						|
  node corresponding to that address.
 | 
						|
 | 
						|
  @param  VirtualAddress       virtual address (or CPU address) to be unmapped.
 | 
						|
 | 
						|
  @retval EFI_SUCEESS          Successfully unmapped.
 | 
						|
  @retval Other                Other errors as indicated.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
DelV2p (
 | 
						|
  VOID *VirtualAddress
 | 
						|
  )
 | 
						|
{
 | 
						|
  V2P           *Current;
 | 
						|
  V2P           *Next;
 | 
						|
  EFI_STATUS    Status;
 | 
						|
 | 
						|
  if (VirtualAddress == NULL) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  if (mV2p == NULL) {
 | 
						|
    return EFI_NOT_FOUND;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // Is our node at the head of the list??
 | 
						|
  //
 | 
						|
  if ((Current = mV2p)->VirtualAddress == VirtualAddress) {
 | 
						|
    mV2p    = mV2p->Next;
 | 
						|
 | 
						|
    Status  = mPciIo->Unmap (mPciIo, Current->Unmap);
 | 
						|
 | 
						|
    FreePool (Current);
 | 
						|
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      DEBUG ((EFI_D_ERROR, "Unmap failed with status = %r\n", Status));
 | 
						|
    }
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  for (; Current->Next != NULL; Current = Next) {
 | 
						|
    if ((Next = Current->Next)->VirtualAddress == VirtualAddress) {
 | 
						|
      Current->Next = Next->Next;
 | 
						|
      Status  = mPciIo->Unmap (mPciIo, Next->Unmap);
 | 
						|
      FreePool (Next);
 | 
						|
 | 
						|
      if (EFI_ERROR (Status)) {
 | 
						|
        DEBUG ((EFI_D_ERROR, "Unmap failed with status = %r\n", Status));
 | 
						|
      }
 | 
						|
      return Status;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  return EFI_NOT_FOUND;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  The SNP driver entry point.
 | 
						|
 | 
						|
  @param ImageHandle       The driver image handle.
 | 
						|
  @param SystemTable       The system table.
 | 
						|
 | 
						|
  @retval EFI_SUCEESS      Initialization routine has found UNDI hardware,
 | 
						|
                           loaded it's ROM, and installed a notify event for
 | 
						|
                           the Network Indentifier Interface Protocol
 | 
						|
                           successfully.
 | 
						|
  @retval Other            Return value from HandleProtocol for
 | 
						|
                           DeviceIoProtocol or LoadedImageProtocol
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
InitializeSnpNiiDriver (
 | 
						|
  IN EFI_HANDLE       ImageHandle,
 | 
						|
  IN EFI_SYSTEM_TABLE *SystemTable
 | 
						|
  )
 | 
						|
{
 | 
						|
  return EfiLibInstallDriverBindingComponentName2 (
 | 
						|
           ImageHandle,
 | 
						|
           SystemTable,
 | 
						|
           &mSimpleNetworkDriverBinding,
 | 
						|
           NULL,
 | 
						|
           &gSimpleNetworkComponentName,
 | 
						|
           &gSimpleNetworkComponentName2
 | 
						|
           );
 | 
						|
}
 |