]> git.proxmox.com Git - mirror_edk2.git/blobdiff - InOsEmuPkg/EmuSnpDxe/EmuSnpDxe.c
InOsEmuPkg: Add the EFI parts of the Simple Network Protocol
[mirror_edk2.git] / InOsEmuPkg / EmuSnpDxe / EmuSnpDxe.c
diff --git a/InOsEmuPkg/EmuSnpDxe/EmuSnpDxe.c b/InOsEmuPkg/EmuSnpDxe/EmuSnpDxe.c
new file mode 100644 (file)
index 0000000..a83fde8
--- /dev/null
@@ -0,0 +1,957 @@
+/** @file\r
+\r
+ Copyright (c) 2010, Apple, Inc. All rights reserved.<BR>\r
+\r
+    This program and the accompanying materials\r
+    are licensed and made available under the terms and conditions of the BSD License\r
+    which accompanies this distribution. The full text of the license may be found at\r
+    http://opensource.org/licenses/bsd-license.php\r
+\r
+    THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+    WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+Module Name:\r
+\r
+  EmuSnp.c\r
+\r
+Abstract:\r
+\r
+-**/\r
+\r
+#include "EmuSnpDxe.h"\r
+\r
+\r
+\r
+EFI_SIMPLE_NETWORK_PROTOCOL gEmuSnpTemplate = {\r
+  EFI_SIMPLE_NETWORK_PROTOCOL_REVISION,  \r
+  EmuSnpStart,             \r
+  EmuSnpStop,              \r
+  EmuSnpInitialize,       \r
+  EmuSnpReset,              \r
+  EmuSnpShutdown,            \r
+  EmuSnpReceiveFilters,          \r
+  EmuSnpStationAddress,          \r
+  EmuSnpStatistics,            \r
+  EmuSnpMcastIptoMac,          \r
+  EmuSnpNvdata,              \r
+  EmuSnpGetStatus,            \r
+  EmuSnpTransmit,            \r
+  EmuSnpReceive,              \r
+  NULL,                     // WaitForPacket\r
+  NULL                      // Mode\r
+ };\r
+\r
+\r
+\r
+\r
+/**\r
+  Changes the state of a network interface from "stopped" to "started".\r
+\r
+  @param  This Protocol instance pointer.\r
+\r
+  @retval EFI_SUCCESS           Always succeeds.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EmuSnpStart(\r
+  IN EFI_SIMPLE_NETWORK_PROTOCOL    *This\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+  EMU_SNP_PRIVATE_DATA    *Private;\r
+\r
+  Private = EMU_SNP_PRIVATE_DATA_FROM_SNP_THIS (This);\r
+\r
+  Status = Private->Io->Start (Private->Io);\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Changes the state of a network interface from "started" to "stopped".\r
+\r
+  @param  This Protocol instance pointer.\r
+\r
+  @retval EFI_SUCCESS           Always succeeds.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EmuSnpStop (\r
+  IN EFI_SIMPLE_NETWORK_PROTOCOL    *This\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+  EMU_SNP_PRIVATE_DATA    *Private;\r
+\r
+  Private = EMU_SNP_PRIVATE_DATA_FROM_SNP_THIS (This);\r
+\r
+  Status = Private->Io->Stop (Private->Io);\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Resets a network adapter and allocates the transmit and receive buffers \r
+  required by the network interface; optionally, also requests allocation \r
+  of additional transmit and receive buffers.\r
+\r
+  @param  This              Protocol instance pointer.\r
+  @param  ExtraRxBufferSize The size, in bytes, of the extra receive buffer space\r
+                            that the driver should allocate for the network interface.\r
+                            Some network interfaces will not be able to use the extra\r
+                            buffer, and the caller will not know if it is actually\r
+                            being used.\r
+  @param  ExtraTxBufferSize The size, in bytes, of the extra transmit buffer space\r
+                            that the driver should allocate for the network interface.\r
+                            Some network interfaces will not be able to use the extra\r
+                            buffer, and the caller will not know if it is actually\r
+                            being used.\r
+\r
+  @retval EFI_SUCCESS           Always succeeds.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EmuSnpInitialize (\r
+  IN EFI_SIMPLE_NETWORK_PROTOCOL    *This,\r
+  IN UINTN                          ExtraRxBufferSize OPTIONAL,\r
+  IN UINTN                          ExtraTxBufferSize OPTIONAL\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+  EMU_SNP_PRIVATE_DATA    *Private;\r
+\r
+  Private = EMU_SNP_PRIVATE_DATA_FROM_SNP_THIS (This);\r
+\r
+  Status = Private->Io->Initialize (Private->Io, ExtraRxBufferSize, ExtraTxBufferSize);\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Resets a network adapter and re-initializes it with the parameters that were \r
+  provided in the previous call to Initialize().  \r
+\r
+  @param  This                 Protocol instance pointer.\r
+  @param  ExtendedVerification Indicates that the driver may perform a more\r
+                               exhaustive verification operation of the device\r
+                               during reset.\r
+\r
+  @retval EFI_SUCCESS           Always succeeds.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EmuSnpReset (\r
+  IN EFI_SIMPLE_NETWORK_PROTOCOL    *This,\r
+  IN BOOLEAN                        ExtendedVerification\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+  EMU_SNP_PRIVATE_DATA    *Private;\r
+\r
+  Private = EMU_SNP_PRIVATE_DATA_FROM_SNP_THIS (This);\r
+\r
+  Status = Private->Io->Reset (Private->Io, ExtendedVerification);\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Resets a network adapter and leaves it in a state that is safe for \r
+  another driver to initialize.\r
+\r
+  @param  This Protocol instance pointer.\r
+\r
+  @retval EFI_SUCCESS           Always succeeds.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EmuSnpShutdown (\r
+  IN EFI_SIMPLE_NETWORK_PROTOCOL    *This\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+  EMU_SNP_PRIVATE_DATA    *Private;\r
+\r
+  Private = EMU_SNP_PRIVATE_DATA_FROM_SNP_THIS (This);\r
+\r
+  Status = Private->Io->Shutdown (Private->Io);\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Manages the multicast receive filters of a network interface.\r
+\r
+  @param  This               Protocol instance pointer.\r
+  @param  EnableBits         A bit mask of receive filters to enable on the network interface.\r
+  @param  DisableBits        A bit mask of receive filters to disable on the network interface.\r
+  @param  ResetMcastFilter   Set to TRUE to reset the contents of the multicast receive\r
+                             filters on the network interface to their default values.\r
+  @param  McastFilterCount   Number of multicast HW MAC addresses in the new\r
+                             MCastFilter list. This value must be less than or equal to\r
+                             the MCastFilterCnt field of EFI_SIMPLE_NETWORK_MODE. This\r
+                             field is optional if ResetMCastFilter is TRUE.\r
+  @param  McastFilter        A pointer to a list of new multicast receive filter HW MAC\r
+                             addresses. This list will replace any existing multicast\r
+                             HW MAC address list. This field is optional if\r
+                             ResetMCastFilter is TRUE.\r
+\r
+  @retval EFI_SUCCESS           The multicast receive filter list was updated.\r
+  @retval EFI_DEVICE_ERROR      The command could not be sent to the network interface.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EmuSnpReceiveFilters (\r
+  IN EFI_SIMPLE_NETWORK_PROTOCOL    *This,\r
+  IN UINT32                         EnableBits,\r
+  IN UINT32                         DisableBits,\r
+  IN BOOLEAN                        ResetMcastFilter,\r
+  IN UINTN                          McastFilterCount OPTIONAL,\r
+  IN EFI_MAC_ADDRESS                *McastFilter OPTIONAL\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+  EMU_SNP_PRIVATE_DATA    *Private;\r
+\r
+  Private = EMU_SNP_PRIVATE_DATA_FROM_SNP_THIS (This);\r
+\r
+  Status = Private->Io->ReceiveFilters (\r
+                          Private->Io,\r
+                          EnableBits,\r
+                          DisableBits,\r
+                          ResetMcastFilter,\r
+                          McastFilterCount,\r
+                          McastFilter\r
+                          );\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Modifies or resets the current station address, if supported.\r
+\r
+  @param  This         Protocol instance pointer.\r
+  @param  Reset        Flag used to reset the station address to the network interfaces\r
+                       permanent address.\r
+  @param  NewMacAddr   New station address to be used for the network interface.\r
+\r
+  @retval EFI_UNSUPPORTED       Not supported yet.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EmuSnpStationAddress (\r
+  IN EFI_SIMPLE_NETWORK_PROTOCOL    *This,\r
+  IN BOOLEAN                        Reset,\r
+  IN EFI_MAC_ADDRESS                *NewMacAddr OPTIONAL\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+  EMU_SNP_PRIVATE_DATA    *Private;\r
+\r
+  Private = EMU_SNP_PRIVATE_DATA_FROM_SNP_THIS (This);\r
+\r
+  Status = Private->Io->StationAddress (Private->Io, Reset, NewMacAddr);\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Resets or collects the statistics on a network interface.\r
+\r
+  @param  This            Protocol instance pointer.\r
+  @param  Reset           Set to TRUE to reset the statistics for the network interface.\r
+  @param  StatisticsSize  On input the size, in bytes, of StatisticsTable. On\r
+                          output the size, in bytes, of the resulting table of\r
+                          statistics.\r
+  @param  StatisticsTable A pointer to the EFI_NETWORK_STATISTICS structure that\r
+                          contains the statistics.\r
+\r
+  @retval EFI_SUCCESS           The statistics were collected from the network interface.\r
+  @retval EFI_NOT_STARTED       The network interface has not been started.\r
+  @retval EFI_BUFFER_TOO_SMALL  The Statistics buffer was too small. The current buffer\r
+                                size needed to hold the statistics is returned in\r
+                                StatisticsSize.\r
+  @retval EFI_UNSUPPORTED       Not supported yet.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EmuSnpStatistics (\r
+  IN EFI_SIMPLE_NETWORK_PROTOCOL    *This,\r
+  IN BOOLEAN                        Reset,\r
+  IN OUT UINTN                      *StatisticsSize OPTIONAL,\r
+  OUT EFI_NETWORK_STATISTICS        *StatisticsTable OPTIONAL\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+  EMU_SNP_PRIVATE_DATA    *Private;\r
+\r
+  Private = EMU_SNP_PRIVATE_DATA_FROM_SNP_THIS (This);\r
+\r
+  Status = Private->Io->Statistics (Private->Io, Reset, StatisticsSize, StatisticsTable);\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Converts a multicast IP address to a multicast HW MAC address.\r
+\r
+  @param  This Protocol instance pointer.\r
+  @param  Ipv6 Set to TRUE if the multicast IP address is IPv6 [RFC 2460]. Set\r
+               to FALSE if the multicast IP address is IPv4 [RFC 791].\r
+  @param  Ip   The multicast IP address that is to be converted to a multicast\r
+               HW MAC address.\r
+  @param  Mac  The multicast HW MAC address that is to be generated from IP.\r
+\r
+  @retval EFI_SUCCESS           The multicast IP address was mapped to the multicast\r
+                                HW MAC address.\r
+  @retval EFI_NOT_STARTED       The network interface has not been started.\r
+  @retval EFI_BUFFER_TOO_SMALL  The Statistics buffer was too small. The current buffer\r
+                                size needed to hold the statistics is returned in\r
+                                StatisticsSize.\r
+  @retval EFI_UNSUPPORTED       Not supported yet.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EmuSnpMcastIptoMac (\r
+  IN EFI_SIMPLE_NETWORK_PROTOCOL    *This,\r
+  IN BOOLEAN                        Ipv6,\r
+  IN EFI_IP_ADDRESS                 *Ip,\r
+  OUT EFI_MAC_ADDRESS               *Mac\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+  EMU_SNP_PRIVATE_DATA    *Private;\r
+\r
+  Private = EMU_SNP_PRIVATE_DATA_FROM_SNP_THIS (This);\r
+\r
+  Status = Private->Io->MCastIpToMac (Private->Io, Ipv6, Ip, Mac);\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Performs read and write operations on the NVRAM device attached to a \r
+  network interface.\r
+\r
+  @param  This         Protocol instance pointer.\r
+  @param  ReadOrWrite  TRUE for read operations, FALSE for write operations.\r
+  @param  Offset       Byte offset in the NVRAM device at which to start the read or\r
+                       write operation. This must be a multiple of NvRamAccessSize and\r
+                       less than NvRamSize.\r
+  @param  BufferSize   The number of bytes to read or write from the NVRAM device.\r
+                       This must also be a multiple of NvramAccessSize.\r
+  @param  Buffer       A pointer to the data buffer.\r
+\r
+  @retval EFI_UNSUPPORTED       Not supported yet.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EmuSnpNvdata (\r
+  IN EFI_SIMPLE_NETWORK_PROTOCOL    *This,\r
+  IN BOOLEAN                        ReadOrWrite,\r
+  IN UINTN                          Offset,\r
+  IN UINTN                          BufferSize,\r
+  IN OUT VOID                       *Buffer\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+  EMU_SNP_PRIVATE_DATA    *Private;\r
+\r
+  Private = EMU_SNP_PRIVATE_DATA_FROM_SNP_THIS (This);\r
+\r
+  Status = Private->Io->NvData (Private->Io, ReadOrWrite, Offset, BufferSize, Buffer);\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Reads the current interrupt status and recycled transmit buffer status from \r
+  a network interface.\r
+\r
+  @param  This            Protocol instance pointer.\r
+  @param  InterruptStatus A pointer to the bit mask of the currently active interrupts\r
+                          If this is NULL, the interrupt status will not be read from\r
+                          the device. If this is not NULL, the interrupt status will\r
+                          be read from the device. When the  interrupt status is read,\r
+                          it will also be cleared. Clearing the transmit  interrupt\r
+                          does not empty the recycled transmit buffer array.\r
+  @param  TxBuffer        Recycled transmit buffer address. The network interface will\r
+                          not transmit if its internal recycled transmit buffer array\r
+                          is full. Reading the transmit buffer does not clear the\r
+                          transmit interrupt. If this is NULL, then the transmit buffer\r
+                          status will not be read. If there are no transmit buffers to\r
+                          recycle and TxBuf is not NULL, * TxBuf will be set to NULL.\r
+\r
+  @retval EFI_SUCCESS           Always succeeds.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EmuSnpGetStatus (\r
+  IN EFI_SIMPLE_NETWORK_PROTOCOL    *This,\r
+  OUT UINT32                        *InterruptStatus,\r
+  OUT VOID                          **TxBuffer\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+  EMU_SNP_PRIVATE_DATA    *Private;\r
+\r
+  Private = EMU_SNP_PRIVATE_DATA_FROM_SNP_THIS (This);\r
+\r
+  Status = Private->Io->GetStatus (Private->Io, InterruptStatus, TxBuffer);\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Places a packet in the transmit queue of a network interface.\r
+\r
+  @param  This       Protocol instance pointer.\r
+  @param  HeaderSize The size, in bytes, of the media header to be filled in by\r
+                     the Transmit() function. If HeaderSize is non-zero, then it\r
+                     must be equal to This->Mode->MediaHeaderSize and the DestAddr\r
+                     and Protocol parameters must not be NULL.\r
+  @param  BufferSize The size, in bytes, of the entire packet (media header and\r
+                     data) to be transmitted through the network interface.\r
+  @param  Buffer     A pointer to the packet (media header followed by data) to be\r
+                     transmitted. This parameter cannot be NULL. If HeaderSize is zero,\r
+                     then the media header in Buffer must already be filled in by the\r
+                     caller. If HeaderSize is non-zero, then the media header will be\r
+                     filled in by the Transmit() function.\r
+  @param  SrcAddr    The source HW MAC address. If HeaderSize is zero, then this parameter\r
+                     is ignored. If HeaderSize is non-zero and SrcAddr is NULL, then\r
+                     This->Mode->CurrentAddress is used for the source HW MAC address.\r
+  @param  DestAddr   The destination HW MAC address. If HeaderSize is zero, then this\r
+                     parameter is ignored.\r
+  @param  Protocol   The type of header to build. If HeaderSize is zero, then this\r
+                     parameter is ignored. See RFC 1700, section "Ether Types", for\r
+                     examples.\r
+\r
+  @retval EFI_SUCCESS           The packet was placed on the transmit queue.\r
+  @retval EFI_DEVICE_ERROR      The command could not be sent to the network interface.\r
+  @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.\r
+  @retval EFI_NOT_STARTED       The network interface has not been started.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EmuSnpTransmit (\r
+  IN EFI_SIMPLE_NETWORK_PROTOCOL    *This,\r
+  IN UINTN                          HeaderSize,\r
+  IN UINTN                          BufferSize,\r
+  IN VOID*                          Buffer,\r
+  IN EFI_MAC_ADDRESS                *SrcAddr OPTIONAL,\r
+  IN EFI_MAC_ADDRESS                *DestAddr OPTIONAL,\r
+  IN UINT16                         *Protocol OPTIONAL\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+  EMU_SNP_PRIVATE_DATA    *Private;\r
+\r
+  Private = EMU_SNP_PRIVATE_DATA_FROM_SNP_THIS (This);\r
+\r
+  Status = Private->Io->Transmit (\r
+                          Private->Io,\r
+                          HeaderSize,\r
+                          BufferSize,\r
+                          Buffer,\r
+                          SrcAddr,\r
+                          DestAddr,\r
+                          Protocol\r
+                          );\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Receives a packet from a network interface.\r
+\r
+  @param  This             Protocol instance pointer.\r
+  @param  HeaderSize       The size, in bytes, of the media header received on the network\r
+                           interface. If this parameter is NULL, then the media header size\r
+                           will not be returned.\r
+  @param  BuffSize         On entry, the size, in bytes, of Buffer. On exit, the size, in\r
+                           bytes, of the packet that was received on the network interface.\r
+  @param  Buffer           A pointer to the data buffer to receive both the media header and\r
+                           the data.\r
+  @param  SourceAddr       The source HW MAC address. If this parameter is NULL, the\r
+                           HW MAC source address will not be extracted from the media\r
+                           header.\r
+  @param  DestinationAddr  The destination HW MAC address. If this parameter is NULL,\r
+                           the HW MAC destination address will not be extracted from the\r
+                           media header.\r
+  @param  Protocol         The media header type. If this parameter is NULL, then the\r
+                           protocol will not be extracted from the media header. See\r
+                           RFC 1700 section "Ether Types" for examples.\r
+\r
+  @retval EFI_SUCCESS           The received data was stored in Buffer, and BufferSize has\r
+                                been updated to the number of bytes received.\r
+  @retval EFI_NOT_READY         The network interface is too busy to accept this transmit\r
+                                request.\r
+  @retval EFI_NOT_STARTED       The network interface has not been started.\r
+  @retval EFI_BUFFER_TOO_SMALL  The BufferSize parameter is too small.\r
+  @retval EFI_DEVICE_ERROR      The command could not be sent to the network interface.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EmuSnpReceive (\r
+  IN EFI_SIMPLE_NETWORK_PROTOCOL    *This,\r
+  OUT UINTN                         *HeaderSize OPTIONAL,\r
+  IN OUT UINTN                      *BuffSize,\r
+  OUT VOID                          *Buffer,\r
+  OUT EFI_MAC_ADDRESS               *SourceAddr OPTIONAL,\r
+  OUT EFI_MAC_ADDRESS               *DestinationAddr OPTIONAL,\r
+  OUT UINT16                        *Protocol OPTIONAL\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+  EMU_SNP_PRIVATE_DATA    *Private;\r
+\r
+  Private = EMU_SNP_PRIVATE_DATA_FROM_SNP_THIS (This);\r
+\r
+  Status = Private->Io->Receive (\r
+                          Private->Io,\r
+                          HeaderSize,\r
+                          BuffSize,\r
+                          Buffer,\r
+                          SourceAddr,\r
+                          DestinationAddr,\r
+                          Protocol\r
+                          );\r
+  return Status;\r
+}\r
+\r
+\r
+\r
+/**\r
+  Test to see if this driver supports ControllerHandle. This service\r
+  is called by the EFI boot service ConnectController(). In\r
+  order to make drivers as small as possible, there are a few calling\r
+  restrictions for this service. ConnectController() must\r
+  follow these calling restrictions. If any other agent wishes to call\r
+  Supported() it must also follow these calling restrictions.\r
+\r
+  @param  This                Protocol instance pointer.\r
+  @param  ControllerHandle    Handle of device to test\r
+  @param  RemainingDevicePath Optional parameter use to pick a specific child\r
+                              device to start.\r
+\r
+  @retval EFI_SUCCESS         This driver supports this device\r
+  @retval EFI_UNSUPPORTED     This driver does not support this device\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EmuSnpDriverBindingSupported (\r
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,\r
+  IN EFI_HANDLE                   ControllerHandle,\r
+  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath OPTIONAL\r
+  )\r
+{\r
+  EFI_STATUS                Status;\r
+  EMU_IO_THUNK_PROTOCOL     *EmuIoThunk;\r
+  MAC_ADDR_DEVICE_PATH      *Node;\r
+  EFI_DEVICE_PATH_PROTOCOL  *ParentDevicePath;\r
+\r
+  if (RemainingDevicePath != NULL) {\r
+    if (!IsDevicePathEnd (RemainingDevicePath)) {\r
+      Node = (MAC_ADDR_DEVICE_PATH *)RemainingDevicePath;\r
+      if (Node->Header.Type != MESSAGING_DEVICE_PATH ||\r
+          Node->Header.SubType != MSG_MAC_ADDR_DP) {\r
+        // If the remaining device path does not match we don't support the request\r
+        return EFI_UNSUPPORTED;\r
+      }\r
+    }\r
+  }\r
+  \r
+  \r
+  //\r
+  // Open the IO Abstraction(s) needed to perform the supported test\r
+  //\r
+  Status = gBS->OpenProtocol (\r
+                  ControllerHandle,\r
+                  &gEmuIoThunkProtocolGuid,\r
+                  (VOID **)&EmuIoThunk,\r
+                  This->DriverBindingHandle,\r
+                  ControllerHandle,\r
+                  EFI_OPEN_PROTOCOL_BY_DRIVER\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Make sure GUID is for a File System handle.\r
+  //\r
+  Status = EFI_UNSUPPORTED;\r
+  if (CompareGuid (EmuIoThunk->Protocol, &gEmuSnpProtocolGuid)) {\r
+    Status = EFI_SUCCESS;\r
+  }\r
+\r
+  //\r
+  // Close the I/O Abstraction(s) used to perform the supported test\r
+  //\r
+  gBS->CloseProtocol (\r
+        ControllerHandle,\r
+        &gEmuIoThunkProtocolGuid,\r
+        This->DriverBindingHandle,\r
+        ControllerHandle\r
+        );\r
+        \r
+        \r
+  //\r
+  // Open the EFI Device Path protocol needed to perform the supported test\r
+  //\r
+  Status = gBS->OpenProtocol (\r
+                  ControllerHandle,\r
+                  &gEfiDevicePathProtocolGuid,\r
+                  (VOID **) &ParentDevicePath,\r
+                  This->DriverBindingHandle,\r
+                  ControllerHandle,\r
+                  EFI_OPEN_PROTOCOL_BY_DRIVER\r
+                  );\r
+  if (Status == EFI_ALREADY_STARTED) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Close protocol, don't use device path protocol in the Support() function\r
+  //\r
+  gBS->CloseProtocol (\r
+        ControllerHandle,\r
+        &gEfiDevicePathProtocolGuid,\r
+        This->DriverBindingHandle,\r
+        ControllerHandle\r
+        );\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Start this driver on ControllerHandle. This service is called by the\r
+  EFI boot service ConnectController(). In order to make\r
+  drivers as small as possible, there are a few calling restrictions for\r
+  this service. ConnectController() must follow these\r
+  calling restrictions. If any other agent wishes to call Start() it\r
+  must also follow these calling restrictions.\r
+\r
+  @param  This                 Protocol instance pointer.\r
+  @param  ControllerHandle     Handle of device to bind driver to\r
+  @param  RemainingDevicePath  Optional parameter use to pick a specific child\r
+                               device to start.\r
+\r
+  @retval EFI_SUCCESS          Always succeeds.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EmuSnpDriverBindingStart (\r
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,\r
+  IN EFI_HANDLE                   ControllerHandle,\r
+  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath OPTIONAL\r
+  )\r
+{\r
+  EFI_STATUS                  Status;\r
+  EMU_IO_THUNK_PROTOCOL       *EmuIoThunk;\r
+  EMU_SNP_PRIVATE_DATA        *Private;\r
+  MAC_ADDR_DEVICE_PATH        Node;\r
+  EFI_DEVICE_PATH_PROTOCOL    *ParentDevicePath;\r
+\r
+  //\r
+  // Grab the protocols we need\r
+  //\r
+  \r
+  Status = gBS->OpenProtocol(\r
+                  ControllerHandle,\r
+                  &gEfiDevicePathProtocolGuid,\r
+                  ( VOID ** ) &ParentDevicePath,\r
+                  This->DriverBindingHandle,\r
+                  ControllerHandle,\r
+                  EFI_OPEN_PROTOCOL_BY_DRIVER\r
+                  );\r
+  if (EFI_ERROR (Status) && Status) {\r
+    return Status;\r
+  }\r
+\r
+  Status = gBS->OpenProtocol (\r
+                  ControllerHandle,\r
+                  &gEmuIoThunkProtocolGuid,\r
+                  (VOID **)&EmuIoThunk,\r
+                  This->DriverBindingHandle,\r
+                  ControllerHandle,\r
+                  EFI_OPEN_PROTOCOL_BY_DRIVER\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  if (!CompareGuid (EmuIoThunk->Protocol, &gEmuSnpProtocolGuid)) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  Status = EmuIoThunk->Open (EmuIoThunk);\r
+  if (EFI_ERROR (Status)) {\r
+    goto Done;\r
+  }\r
+\r
+  //\r
+  //  Allocate the private data.\r
+  //\r
+  Private = AllocateZeroPool (sizeof (EMU_SNP_PRIVATE_DATA));\r
+  if (Private == NULL) {\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto Done;\r
+  }\r
+\r
+  CopyMem (&Private->Snp, &gEmuSnpTemplate, sizeof (EFI_SIMPLE_NETWORK_PROTOCOL));\r
+\r
+  Private->Signature    = EMU_SNP_PRIVATE_DATA_SIGNATURE;\r
+  Private->IoThunk      = EmuIoThunk;\r
+  Private->Io           = EmuIoThunk->Interface;\r
+  Private->EfiHandle    = ControllerHandle;\r
+  Private->DeviceHandle = NULL;\r
+  Private->Snp.Mode     = &Private->Mode;\r
+  Private->ControllerNameTable = NULL;\r
+\r
+  \r
+  Status = Private->Io->CreateMapping (Private->Io, &Private->Mode);\r
+  if (EFI_ERROR (Status)) {\r
+    goto Done;\r
+  }\r
+\r
+  //\r
+  // Build the device path by appending the MAC node to the ParentDevicePath\r
+  // from the EmuIo handle.\r
+  //\r
+  ZeroMem (&Node, sizeof (MAC_ADDR_DEVICE_PATH));\r
+\r
+  Node.Header.Type     = MESSAGING_DEVICE_PATH;\r
+  Node.Header.SubType  = MSG_MAC_ADDR_DP;\r
+  Node.IfType          = Private->Mode.IfType;\r
+\r
+  SetDevicePathNodeLength ((EFI_DEVICE_PATH_PROTOCOL * )&Node, sizeof (MAC_ADDR_DEVICE_PATH));\r
+\r
+  CopyMem (&Node.MacAddress, &Private->Mode.CurrentAddress, sizeof (EFI_MAC_ADDRESS));\r
+\r
+  //\r
+  // Build the device path by appending the MAC node to the ParentDevicePath from the EmuIo handle.\r
+  //\r
+  Private->DevicePath = AppendDevicePathNode (ParentDevicePath, (EFI_DEVICE_PATH_PROTOCOL *)&Node);\r
+  if ( Private->DevicePath == NULL ) {\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto Done;\r
+  }\r
+\r
+  AddUnicodeString2 (\r
+    "eng",\r
+    gEmuSnpDriverComponentName.SupportedLanguages,\r
+    &Private->ControllerNameTable,\r
+    EmuIoThunk->ConfigString,\r
+    TRUE\r
+    );\r
+    \r
+  AddUnicodeString2 (\r
+    "en",\r
+    gEmuSnpDriverComponentName2.SupportedLanguages,\r
+    &Private->ControllerNameTable,\r
+    EmuIoThunk->ConfigString,\r
+    FALSE\r
+    );\r
+\r
+  //\r
+  // Create Child Handle\r
+  //\r
+  Status = gBS->InstallMultipleProtocolInterfaces(\r
+                  &Private->DeviceHandle,\r
+                  &gEfiSimpleNetworkProtocolGuid, &Private->Snp,\r
+                  &gEfiDevicePathProtocolGuid,    Private->DevicePath,\r
+                  NULL\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    goto Done;\r
+  }\r
+\r
+  //\r
+  // Open For Child Device\r
+  //\r
+  Status = gBS->OpenProtocol (\r
+                  ControllerHandle,\r
+                  &gEmuIoThunkProtocolGuid,\r
+                  (VOID **)&EmuIoThunk,\r
+                  This->DriverBindingHandle,\r
+                  Private->DeviceHandle,\r
+                  EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
+                  );\r
+\r
+Done:\r
+  if (EFI_ERROR (Status)) {\r
+    if (Private != NULL) {\r
+      FreePool (Private);\r
+    }\r
+    if (ParentDevicePath != NULL) {\r
+      gBS->CloseProtocol(\r
+            ControllerHandle,\r
+            &gEfiDevicePathProtocolGuid,\r
+            This->DriverBindingHandle,\r
+            ControllerHandle\r
+            );\r
+    }\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Stop this driver on ControllerHandle. This service is called by the\r
+  EFI boot service DisconnectController(). In order to\r
+  make drivers as small as possible, there are a few calling\r
+  restrictions for this service. DisconnectController()\r
+  must follow these calling restrictions. If any other agent wishes\r
+  to call Stop() it must also follow these calling restrictions.\r
+  \r
+  @param  This              Protocol instance pointer.\r
+  @param  ControllerHandle  Handle of device to stop driver on\r
+  @param  NumberOfChildren  Number of Handles in ChildHandleBuffer. If number of\r
+                            children is zero stop the entire bus driver.\r
+  @param  ChildHandleBuffer List of Child Handles to Stop.\r
+\r
+  @retval EFI_SUCCESS       Always succeeds.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EmuSnpDriverBindingStop (\r
+  IN EFI_DRIVER_BINDING_PROTOCOL    *This,\r
+  IN EFI_HANDLE                     ControllerHandle,\r
+  IN UINTN                          NumberOfChildren,\r
+  IN EFI_HANDLE                     *ChildHandleBuffer\r
+  )\r
+{\r
+  EFI_STATUS                  Status;\r
+  EMU_SNP_PRIVATE_DATA        *Private = NULL;\r
+  EFI_SIMPLE_NETWORK_PROTOCOL *Snp;\r
+  EFI_DEVICE_PATH_PROTOCOL    *ParentDevicePath;\r
+\r
+  //\r
+  // Complete all outstanding transactions to Controller.\r
+  // Don't allow any new transaction to Controller to be started.\r
+  //\r
+  if (NumberOfChildren == 0) {\r
+    //\r
+    // Close the bus driver\r
+    //\r
+    Status = gBS->CloseProtocol (\r
+                    ControllerHandle,\r
+                    &gEmuIoThunkProtocolGuid,\r
+                    This->DriverBindingHandle,\r
+                    ControllerHandle\r
+                    );\r
+\r
+    Status = gBS->CloseProtocol (\r
+                    ControllerHandle,\r
+                    &gEfiDevicePathProtocolGuid,\r
+                    This->DriverBindingHandle,\r
+                    ControllerHandle\r
+                    );\r
+    return Status;\r
+  }\r
+\r
+  ASSERT (NumberOfChildren == 1);\r
+  \r
+  \r
+  //\r
+  // Get our context back.\r
+  //\r
+  Status = gBS->OpenProtocol(\r
+                  ChildHandleBuffer[0],\r
+                  &gEfiSimpleNetworkProtocolGuid,\r
+                  ( VOID ** ) &Snp,\r
+                  This->DriverBindingHandle,\r
+                  ControllerHandle,\r
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  Private = EMU_SNP_PRIVATE_DATA_FROM_SNP_THIS (Snp);\r
+  Status = Private->IoThunk->Close (Private->IoThunk);\r
+\r
+  Status = gBS->CloseProtocol(\r
+                  ChildHandleBuffer[0],\r
+                  &gEmuIoThunkProtocolGuid,\r
+                  This->DriverBindingHandle,\r
+                  Private->DeviceHandle\r
+                  );\r
+\r
+  Status = gBS->UninstallMultipleProtocolInterfaces(\r
+                  ChildHandleBuffer[0],\r
+                  &gEfiSimpleNetworkProtocolGuid,   &Private->Snp,\r
+                  &gEfiDevicePathProtocolGuid,      Private->DevicePath,\r
+                  NULL\r
+                  );\r
+\r
+  FreePool (Private->DevicePath);\r
+  FreeUnicodeStringTable (Private->ControllerNameTable);\r
+  FreePool (Private);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+EFI_DRIVER_BINDING_PROTOCOL gEmuSnpDriverBinding = {\r
+  EmuSnpDriverBindingSupported,\r
+  EmuSnpDriverBindingStart,\r
+  EmuSnpDriverBindingStop,\r
+  0xA,\r
+  NULL,\r
+  NULL\r
+};\r
+\r
+\r
+\r
+/**\r
+  This is the declaration of an EFI image entry point. This entry point is\r
+  the same for UEFI Applications, UEFI OS Loaders, and UEFI Drivers including\r
+  both device drivers and bus drivers.\r
+\r
+  @param  ImageHandle           The firmware allocated handle for the UEFI image.\r
+  @param  SystemTable           A pointer to the EFI System Table.\r
+\r
+  @retval EFI_SUCCESS           The operation completed successfully.\r
+  @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a lack of resources.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+InitializeEmuSnpDriver (\r
+  IN EFI_HANDLE        ImageHandle,\r
+  IN EFI_SYSTEM_TABLE   *SystemTable\r
+  )\r
+{\r
+  EFI_STATUS            Status;\r
+\r
+  //\r
+  // Install the Driver Protocols\r
+  //\r
+\r
+  Status = EfiLibInstallDriverBindingComponentName2(\r
+              ImageHandle,\r
+              SystemTable,\r
+              &gEmuSnpDriverBinding,\r
+              ImageHandle,\r
+              &gEmuSnpDriverComponentName,\r
+              &gEmuSnpDriverComponentName2\r
+              );\r
+\r
+  return Status;\r
+}\r