[edk2-devel] [edk2-platform][PATCH v3 2/6] Drivers/ASIX: Add ASIX Ax88179 driver

Ni, Ray ray.ni at intel.com
Tue Jun 9 00:37:28 UTC 2020


Reviewed-by: Ray Ni <ray.ni at intel.com>

> -----Original Message-----
> From: Samer El-Haj-Mahmoud <Samer.El-Haj-Mahmoud at arm.com>
> Sent: Monday, June 8, 2020 9:38 PM
> To: devel at edk2.groups.io
> Cc: Ni, Ray <ray.ni at intel.com>; Leif Lindholm <leif at nuviainc.com>; Ard Biesheuvel <ard.biesheuvel at arm.com>; Kinney,
> Michael D <michael.d.kinney at intel.com>
> Subject: [edk2-platform][PATCH v3 2/6] Drivers/ASIX: Add ASIX Ax88179 driver
> 
> This is the initial revision of ASIX USB networking UEFI driver
> version 2.9.0 for Ax88179 and Ax88178a
> https://www.asix.com.tw/products.php?op=pItemdetail&PItemID=131;71;112
> 
> Original source code provided by ASIX is at:
> https://github.com/samerhaj/uefi_drivers/blob/master/UsbNetworking/Asix/
> zip/source/AX88179_178a_UEFI_v2.9.0_Source.zip
> 
> Cc: Ray Ni <ray.ni at intel.com>
> Cc: Leif Lindholm <leif at nuviainc.com>
> Cc: Ard Biesheuvel <ard.biesheuvel at arm.com>
> Cc: Michael D Kinney <michael.d.kinney at intel.com>
> 
> Signed-off-by: Samer El-Haj-Mahmoud <samer.el-haj-mahmoud at arm.com>
> ---
>  Drivers/ASIX/Asix.dsc                                      |    2 +-
>  Drivers/ASIX/Bus/Usb/UsbNetworking/Ax88179/Ax88179.inf     |   45 +
>  Drivers/ASIX/Bus/Usb/UsbNetworking/Ax88179/Ax88179.h       | 1053 +++++++++++++
>  Drivers/ASIX/Bus/Usb/UsbNetworking/Ax88179/Ax88179.c       | 1042 +++++++++++++
>  Drivers/ASIX/Bus/Usb/UsbNetworking/Ax88179/ComponentName.c |  223 +++
>  Drivers/ASIX/Bus/Usb/UsbNetworking/Ax88179/DriverBinding.c |  639 ++++++++
>  Drivers/ASIX/Bus/Usb/UsbNetworking/Ax88179/SimpleNetwork.c | 1548 ++++++++++++++++++++
>  7 files changed, 4551 insertions(+), 1 deletion(-)
> 
> diff --git a/Drivers/ASIX/Asix.dsc b/Drivers/ASIX/Asix.dsc
> index d65857bb1cd4..73b5cbd5a18f 100644
> --- a/Drivers/ASIX/Asix.dsc
> +++ b/Drivers/ASIX/Asix.dsc
> @@ -64,4 +64,4 @@ [PcdsFixedAtBuild]
>  #
>  ################################################################################
>  [Components]
> -
> +Drivers/ASIX/Bus/Usb/UsbNetworking/Ax88179/Ax88179.inf
> diff --git a/Drivers/ASIX/Bus/Usb/UsbNetworking/Ax88179/Ax88179.inf
> b/Drivers/ASIX/Bus/Usb/UsbNetworking/Ax88179/Ax88179.inf
> new file mode 100644
> index 000000000000..317ec538fa60
> --- /dev/null
> +++ b/Drivers/ASIX/Bus/Usb/UsbNetworking/Ax88179/Ax88179.inf
> @@ -0,0 +1,45 @@
> +## @file
> +# Component description file for ASIX AX88772 USB/Ethernet driver.
> +#
> +# This module provides support for the ASIX AX88772 USB/Ethernet adapter.
> +# Copyright (c) 2011, Intel Corporation
> +# Copyright (c) 2020, ARM Limited. All rights reserved.
> +#
> +#  SPDX-License-Identifier: BSD-2-Clause-Patent
> +#
> +##
> +
> +[Defines]
> +  INF_VERSION                    = 0x00010018
> +  BASE_NAME                      = Ax88179
> +  FILE_GUID                      = 27E5D3B6-7839-47C2-8618-5D2190729BC7
> +  MODULE_TYPE                    = UEFI_DRIVER
> +  VERSION_STRING                 = 1.0
> +
> +  ENTRY_POINT                    = EntryPoint
> +
> +[Sources.common]
> +  Ax88179.h
> +  Ax88179.c
> +  ComponentName.c
> +  DriverBinding.c
> +  SimpleNetwork.c
> +
> +
> +[Packages]
> +  MdePkg/MdePkg.dec
> +  MdeModulePkg/MdeModulePkg.dec
> +  NetworkPkg/NetworkPkg.dec
> +
> +[LibraryClasses]
> +  BaseMemoryLib
> +  DebugLib
> +  UefiBootServicesTableLib
> +  UefiDriverEntryPoint
> +  UefiLib
> +
> +[Protocols]
> +  gEfiDevicePathProtocolGuid           ## BY_START
> +  gEfiSimpleNetworkProtocolGuid        ## BY_START
> +  gEfiUsbIoProtocolGuid                ## TO_START
> +
> diff --git a/Drivers/ASIX/Bus/Usb/UsbNetworking/Ax88179/Ax88179.h
> b/Drivers/ASIX/Bus/Usb/UsbNetworking/Ax88179/Ax88179.h
> new file mode 100644
> index 000000000000..498212ec149b
> --- /dev/null
> +++ b/Drivers/ASIX/Bus/Usb/UsbNetworking/Ax88179/Ax88179.h
> @@ -0,0 +1,1053 @@
> +/** @file
> +  Definitions for ASIX AX88179 Ethernet adapter.
> +
> +  Copyright (c) 2011, Intel Corporation
> +  Copyright (c) 2020, ARM Limited. All rights reserved.
> +
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#ifndef AX88179_H_
> +#define AX88179_H_
> +
> +#include <Uefi.h>
> +
> +#include <Guid/EventGroup.h>
> +
> +#include <IndustryStandard/Pci.h>
> +
> +#include <Library/BaseMemoryLib.h>
> +#include <Library/DebugLib.h>
> +#include <Library/DevicePathLib.h>
> +#include <Library/NetLib.h>
> +#include <Library/UefiBootServicesTableLib.h>
> +#include <Library/UefiDriverEntryPoint.h>
> +#include <Library/UefiLib.h>
> +#include <Library/UefiRuntimeLib.h>
> +
> +#include <Protocol/DevicePath.h>
> +#include <Protocol/LoadedImage.h>
> +#include <Protocol/NetworkInterfaceIdentifier.h>
> +#include <Protocol/SimpleNetwork.h>
> +#include <Protocol/UsbIo.h>
> +
> +
> +#define FORCE_100Mbps 0
> +#define REPORTLINK    1
> +
> +
> +//------------------------------------------------------------------------------
> +//  Macros
> +//------------------------------------------------------------------------------
> +
> +#define USB_IS_IN_ENDPOINT(EndPointAddr)      (((EndPointAddr) & BIT7) != 0)  ///<  Return TRUE/FALSE for IN direction
> +#define USB_IS_OUT_ENDPOINT(EndPointAddr)     (((EndPointAddr) & BIT7) == 0)  ///<  Return TRUE/FALSE for OUT
> direction
> +#define USB_IS_BULK_ENDPOINT(Attribute)       (((Attribute) & (BIT0 | BIT1)) == USB_ENDPOINT_BULK)      ///<  Return
> TRUE/FALSE for BULK type
> +#define USB_IS_INTERRUPT_ENDPOINT(Attribute)  (((Attribute) & (BIT0 | BIT1)) == USB_ENDPOINT_INTERRUPT) ///<
> Return TRUE/FALSE for INTERRUPT type
> +
> +//------------------------------------------------------------------------------
> +//  Constants
> +//------------------------------------------------------------------------------
> +
> +#define DEBUG_RX_BROADCAST  0x40000000  ///<  Display RX broadcast messages
> +#define DEBUG_RX_MULTICAST  0x20000000  ///<  Display RX multicast messages
> +#define DEBUG_RX_UNICAST    0x10000000  ///<  Display RX unicast messages
> +#define DEBUG_MAC_ADDRESS   0x08000000  ///<  Display the MAC address
> +#define DEBUG_LINK          0x04000000  ///<  Display the link status
> +#define DEBUG_TX            0x02000000  ///<  Display the TX messages
> +#define DEBUG_PHY           0x01000000  ///<  Display the PHY register values
> +#define DEBUG_SROM          0x00800000  ///<  Display the SROM contents
> +#define DEBUG_TIMER         0x00400000  ///<  Display the timer routine entry/exit
> +#define DEBUG_TPL           0x00200000  ///<  Display the timer routine entry/exit
> +
> +
> +#define ETHERNET_HEADER_SIZE  sizeof (ETHERNET_HEADER)  ///<  Size in bytes of the Ethernet header
> +#define MIN_ETHERNET_PKT_SIZE 60    ///<  Minimum packet size including Ethernet header
> +#define MAX_ETHERNET_PKT_SIZE 1500
> +
> +#define USB_NETWORK_CLASS   0x09    ///<  USB Network class code
> +#define USB_BUS_TIMEOUT     1000    ///<  USB timeout in milliseconds
> +
> +#define AX88179_BULKIN_SIZE_INK     2
> +#define AX88179_MAX_BULKIN_SIZE    (1024 * AX88179_BULKIN_SIZE_INK)
> +#define AX88179_MAX_PKT_SIZE  2048
> +
> +#define HC_DEBUG        0
> +#define ADD_MACPATHNOD  1
> +#define BULKIN_TIMEOUT  3 //5000
> +#define TX_RETRY        0
> +#define AUTONEG_DELAY   1000000
> +
> +/**
> +  Verify new TPL value
> +
> +  This macro which is enabled when debug is enabled verifies that
> +  the new TPL value is >= the current TPL value.
> +**/
> +#ifdef VERIFY_TPL
> +#undef VERIFY_TPL
> +#endif  //  VERIFY_TPL
> +
> +#if !defined(MDEPKG_NDEBUG)
> +
> +#define VERIFY_TPL(tpl)                         \
> +{                                               \
> +  EFI_TPL PreviousTpl;                          \
> +                                                \
> +  PreviousTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL); \
> +  gBS->RestoreTPL (PreviousTpl);                \
> +  if (PreviousTpl > tpl) {                      \
> +    DEBUG ((DEBUG_ERROR, "Current TPL: %d, New TPL: %d\r\n", PreviousTpl, tpl));  \
> +    ASSERT (PreviousTpl <= tpl);                \
> +  }                                             \
> +}
> +
> +#else   //  MDEPKG_NDEBUG
> +
> +#define VERIFY_TPL(tpl)
> +
> +#endif  //  MDEPKG_NDEBUG
> +
> +//------------------------------------------------------------------------------
> +//  Hardware Definition
> +//------------------------------------------------------------------------------
> +
> +#define DEV_SIGNATURE     SIGNATURE_32 ('A','X','8','8')  ///<  Signature of data structures in memory
> +
> +#define VENDOR_ID         0x0B95  ///<  Vendor ID for Asix
> +#define PRODUCT_ID        0x1790  ///<  Product ID for the AX88179 USB 10/100 Ethernet controller
> +#define PRODUCT_ID_178A   0x178A
> +
> +#define RESET_MSEC        1000    ///<  Reset duration
> +#define PHY_RESET_MSEC    100     ///<  PHY reset duration
> +
> +//
> +//  RX Control register
> +//
> +
> +
> +//
> +//  Medium Status register
> +//
> +
> +
> +
> +//
> +//  Software PHY Select register
> +//
> +
> +#define SPHY_PSEL         0x01    ///<  Select internal PHY
> +#define SPHY_ASEL         0x02    ///<  1=Auto select, 0=Manual select
> +
> +//
> +//  Software Reset register
> +//
> +
> +#define SRR_RR            0x01    ///<  Clear receive frame length error
> +#define SRR_RT            0x02    ///<  Clear transmit frame length error
> +#define SRR_PRTE          0x04    ///<  External PHY reset pin tri-state enable
> +#define SRR_PRL           0x08    ///<  External PHY reset pin level
> +#define SRR_BZ            0x10    ///<  Force Bulk to return zero length packet
> +#define SRR_IPRL          0x20    ///<  Internal PHY reset control
> +#define SRR_IPPD          0x40    ///<  Internal PHY power down
> +
> +//
> +//  PHY ID values
> +//
> +
> +#define PHY_ID_INTERNAL   0x0003  ///<  Internal PHY
> +
> +//
> +//  USB Commands
> +//
> +
> +#define CMD_PHY_ACCESS_SOFTWARE   0x06  ///<  Software in control of PHY
> +#define CMD_PHY_REG_READ          0x07  ///<  Read PHY register, Value: PHY, Index: Register, Data: Register value
> +#define CMD_PHY_REG_WRITE         0x08  ///<  Write PHY register, Value: PHY, Index: Register, Data: New 16-bit value
> +#define CMD_PHY_ACCESS_HARDWARE   0x0a  ///<  Hardware in control of PHY
> +#define CMD_SROM_READ             0x0b  ///<  Read SROM register: Value: Address, Data: Value
> +#define CMD_RX_CONTROL_WRITE      0x10  ///<  Set the RX control register, Value: New value
> +#define CMD_GAPS_WRITE            0x12  ///<  Write the gaps register, Value: New value
> +#define CMD_MAC_ADDRESS_READ      0x11  ///<  Read the MAC address, Data: 6 byte MAC address
> +#define CMD_MAC_ADDRESS_WRITE     0x14  ///<  Set the MAC address, Data: New 6 byte MAC address
> +
> +#define CMD_MEDIUM_STATUS_READ    0x1a  ///<  Read medium status register, Data: Register value
> +#define CMD_MEDIUM_STATUS_WRITE   0x1b  ///<  Write medium status register, Value: New value
> +#define CMD_RESET                 0x20  ///<  Reset register, Value: New value
> +#define CMD_PHY_SELECT            0x22  ///<  PHY select register, Value: New value
> +
> +//------------------------------
> +//  USB Endpoints
> +//------------------------------
> +
> +#define CONTROL_ENDPOINT                0       ///<  Control endpoint
> +#define INTERRUPT_ENDPOINT              1       ///<  Interrupt endpoint
> +#define BULK_IN_ENDPOINT                2       ///<  Receive endpoint
> +#define BULK_OUT_ENDPOINT               3       ///<  Transmit endpoint
> +
> +//------------------------------
> +//  PHY Registers
> +//------------------------------
> +
> +#define PHY_ANER                        6       ///<  Autonegotiation expansion register
> +//  BSMR - Register 1
> +//  ANAR and ANLPAR Registers 4, 5
> +#define RXHDR_DROP 0x8000
> +#define RXHDR_CRCERR 0x2000
> +
> +
> +//------------------------------------------------------------------------------
> +//  Data Types
> +//------------------------------------------------------------------------------
> +
> +/**
> +  Ethernet header layout
> +
> +  IEEE 802.3-2002 Part 3 specification, section 3.1.1.
> +**/
> +#pragma pack(1)
> +typedef struct {
> +  UINT8  DestAddr[PXE_HWADDR_LEN_ETHER];  ///<  Destination LAN address
> +  UINT8  SrcAddr[PXE_HWADDR_LEN_ETHER];   ///<  Source LAN address
> +  UINT16 Type;                            ///<  Protocol or length
> +} ETHERNET_HEADER;
> +#pragma pack()
> +
> +/**
> +  Receive and Transmit packet structure
> +**/
> +#pragma pack(1)
> +typedef struct _TX_PACKET {
> +  UINT32  TxHdr1;
> +  UINT32  TxHdr2;
> +  UINT8   Data[AX88179_MAX_PKT_SIZE]; ///<  Received packet data
> +} TX_PACKET;
> +#pragma pack()
> +
> +#pragma pack(1)
> +typedef struct _RX_PACKET {
> +  struct _RX_PACKET *Next;
> +  UINT16            Length;
> +  UINT16            EEEE;
> +  UINT8             Data[AX88179_MAX_PKT_SIZE];
> +} RX_PACKET;
> +#pragma pack()
> +
> +/**
> +  AX88179 control structure
> +
> +  The driver uses this structure to manage the Asix AX88179 10/100
> +  Ethernet controller.
> +**/
> +typedef struct {
> +  UINTN                     Signature;         ///<  Structure identification
> +
> +  //
> +  //  USB data
> +  //
> +  EFI_HANDLE                Controller;        ///<  Controller handle
> +  EFI_USB_IO_PROTOCOL       *UsbIo;            ///<  USB driver interface
> +
> +  //
> +  //  Simple network protocol data
> +  //
> +  EFI_SIMPLE_NETWORK_PROTOCOL SimpleNetwork;     ///<  Driver's network stack interface
> +  EFI_SIMPLE_NETWORK_MODE     SimpleNetworkData; ///<  Data for simple network
> +
> +  //
> +  // Ethernet controller data
> +  //
> +  BOOLEAN                   Initialized;       ///<  Controller initialized
> +  UINT16                    PhyId;             ///<  PHY ID
> +
> +  //
> +  //  Link state
> +  //
> +  BOOLEAN                   LinkSpeed100Mbps;   ///<  Current link speed, FALSE = 10 Mbps
> +  BOOLEAN                   LinkSpeed1000Mbps;  ///<  Current link speed, FALSE = 100/10 bps
> +  BOOLEAN                   Complete;           ///<  Current state of auto-negotiation
> +  BOOLEAN                   FullDuplex;         ///<  Current duplex
> +  BOOLEAN                   LinkUp;             ///<  Current link state
> +  BOOLEAN                   LinkIdle;           ///<  TRUE = No received traffic
> +  EFI_EVENT                 Timer;              ///<  Timer to monitor link state and receive packets
> +  UINTN                     PollCount;          ///<  Number of times the autonegotiation status was polled
> +  UINTN                     SkipRXCnt;
> +
> +  UINT8                     *BulkInbuf;
> +  UINT16                    PktCnt;
> +  UINT8                     *CurPktHdrOff;
> +  UINT8                     *CurPktOff;
> +
> +  TX_PACKET                 *TxTest;
> +
> +  INT8                      MulticastHash[8];
> +  EFI_MAC_ADDRESS           MAC;
> +
> +  UINT16                    CurMediumStatus;
> +  UINT16                    CurRxControl;
> +  VOID *                    TxBuffer;
> +
> +  EFI_DEVICE_PATH_PROTOCOL  *MyDevPath;
> +  BOOLEAN                   Grub_f;
> +  BOOLEAN                   FirstRst;
> +  BOOLEAN                   SetZeroLen;
> +  UINT8                     RxBurst;
> +  UINTN                     UsbMaxPktSize;
> +} NIC_DEVICE;
> +
> +#define DEV_FROM_SIMPLE_NETWORK(a)  CR (a, NIC_DEVICE, SimpleNetwork, DEV_SIGNATURE)  ///< Locate NIC_DEVICE
> from Simple Network Protocol
> +
> +//------------------------------------------------------------------------------
> +// Simple Network Protocol
> +//------------------------------------------------------------------------------
> +
> +/**
> +  Reset the network adapter.
> +
> +  Resets a network adapter and reinitializes it with the parameters that
> +  were provided in the previous call to Initialize ().  The transmit and
> +  receive queues are cleared.  Receive filters, the station address, the
> +  statistics, and the multicast-IP-to-HW MAC addresses are not reset by
> +  this call.
> +
> +  This routine calls ::Ax88179Reset to perform the adapter specific
> +  reset operation.  This routine also starts the link negotiation
> +  by calling ::Ax88179NegotiateLinkStart.
> +
> +  @param [in] SimpleNetwork    Protocol instance pointer
> +  @param [in] ExtendedVerification  Indicates that the driver may perform a more
> +                                exhaustive verification operation of the device
> +                                during reset.
> +
> +  @retval EFI_SUCCESS           This operation was successful.
> +  @retval EFI_NOT_STARTED       The network interface was not started.
> +  @retval EFI_INVALID_PARAMETER SimpleNetwork parameter was NULL or did not point to a valid
> +                                EFI_SIMPLE_NETWORK_PROTOCOL structure.
> +  @retval EFI_DEVICE_ERROR      The command could not be sent to the network interface.
> +  @retval EFI_UNSUPPORTED       The increased buffer size feature is not supported.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +SN_Reset (
> +  IN EFI_SIMPLE_NETWORK_PROTOCOL *SimpleNetwork,
> +  IN BOOLEAN                     ExtendedVerification
> +  );
> +
> +/**
> +  Initialize the simple network protocol.
> +
> +  This routine calls ::Ax88179MacAddressGet to obtain the
> +  MAC address.
> +
> +  @param [in] NicDevice       NIC_DEVICE_INSTANCE pointer
> +
> +  @retval EFI_SUCCESS     Setup was successful
> +
> +**/
> +EFI_STATUS
> +SN_Setup (
> +  IN NIC_DEVICE *NicDevice
> +  );
> +
> +/**
> +  This routine starts the network interface.
> +
> +  @param [in] SimpleNetwork    Protocol instance pointer
> +
> +  @retval EFI_SUCCESS           This operation was successful.
> +  @retval EFI_ALREADY_STARTED   The network interface was already started.
> +  @retval EFI_INVALID_PARAMETER SimpleNetwork parameter was NULL or did not point to a valid
> +                                EFI_SIMPLE_NETWORK_PROTOCOL structure.
> +  @retval EFI_DEVICE_ERROR      The command could not be sent to the network interface.
> +  @retval EFI_UNSUPPORTED       The increased buffer size feature is not supported.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +SN_Start (
> +  IN EFI_SIMPLE_NETWORK_PROTOCOL *SimpleNetwork
> +  );
> +
> +/**
> +  Set the MAC address.
> +
> +  This function modifies or resets the current station address of a
> +  network interface.  If Reset is TRUE, then the current station address
> +  is set ot the network interface's permanent address.  If Reset if FALSE
> +  then the current station address is changed to the address specified by
> +  New.
> +
> +  This routine calls ::Ax88179MacAddressSet to update the MAC address
> +  in the network adapter.
> +
> +  @param [in] SimpleNetwork    Protocol instance pointer
> +  @param [in] Reset            Flag used to reset the station address to the
> +                                network interface's permanent address.
> +  @param [in] New              New station address to be used for the network
> +                                interface.
> +
> +  @retval EFI_SUCCESS           This operation was successful.
> +  @retval EFI_NOT_STARTED       The network interface was not started.
> +  @retval EFI_INVALID_PARAMETER SimpleNetwork parameter was NULL or did not point to a valid
> +                                EFI_SIMPLE_NETWORK_PROTOCOL structure.
> +  @retval EFI_DEVICE_ERROR      The command could not be sent to the network interface.
> +  @retval EFI_UNSUPPORTED       The increased buffer size feature is not supported.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +SN_StationAddress (
> +  IN EFI_SIMPLE_NETWORK_PROTOCOL *SimpleNetwork,
> +  IN BOOLEAN                     Reset,
> +  IN EFI_MAC_ADDRESS             *New
> +  );
> +
> +/**
> +  This function resets or collects the statistics on a network interface.
> +  If the size of the statistics table specified by StatisticsSize is not
> +  big enough for all of the statistics that are collected by the network
> +  interface, then a partial buffer of statistics is returned in
> +  StatisticsTable.
> +
> +  @param [in] SimpleNetwork    Protocol instance pointer
> +  @param [in] Reset            Set to TRUE to reset the statistics for the network interface.
> +  @param [in, out] StatisticsSize  On input the size, in bytes, of StatisticsTable.  On output
> +                                the size, in bytes, of the resulting table of statistics.
> +  @param [out] StatisticsTable A pointer to the EFI_NETWORK_STATISTICS structure that
> +                                conains the statistics.
> +
> +  @retval EFI_SUCCESS           This operation was successful.
> +  @retval EFI_NOT_STARTED       The network interface was not started.
> +  @retval EFI_BUFFER_TOO_SMALL  The StatisticsTable is NULL or the buffer is too small.
> +  @retval EFI_INVALID_PARAMETER SimpleNetwork parameter was NULL or did not point to a valid
> +                                EFI_SIMPLE_NETWORK_PROTOCOL structure.
> +  @retval EFI_DEVICE_ERROR      The command could not be sent to the network interface.
> +  @retval EFI_UNSUPPORTED       The increased buffer size feature is not supported.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +SN_Statistics (
> +  IN     EFI_SIMPLE_NETWORK_PROTOCOL *SimpleNetwork,
> +  IN     BOOLEAN                     Reset,
> +  IN OUT UINTN                       *StatisticsSize,
> +  OUT    EFI_NETWORK_STATISTICS      *StatisticsTable
> +  );
> +
> +/**
> +  This function stops a network interface.  This call is only valid
> +  if the network interface is in the started state.
> +
> +  @param [in] SimpleNetwork    Protocol instance pointer
> +
> +  @retval EFI_SUCCESS           This operation was successful.
> +  @retval EFI_NOT_STARTED       The network interface was not started.
> +  @retval EFI_INVALID_PARAMETER SimpleNetwork parameter was NULL or did not point to a valid
> +                                EFI_SIMPLE_NETWORK_PROTOCOL structure.
> +  @retval EFI_DEVICE_ERROR      The command could not be sent to the network interface.
> +  @retval EFI_UNSUPPORTED       The increased buffer size feature is not supported.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +SN_Stop (
> +  IN EFI_SIMPLE_NETWORK_PROTOCOL *SimpleNetwork
> +  );
> +
> +/**
> +  This function releases the memory buffers assigned in the Initialize() call.
> +  Ending transmits and receives are lost, and interrupts are cleared and disabled.
> +  After this call, only Initialize() and Stop() calls may be used.
> +
> +  @param [in] SimpleNetwork    Protocol instance pointer
> +
> +  @retval EFI_SUCCESS           This operation was successful.
> +  @retval EFI_NOT_STARTED       The network interface was not started.
> +  @retval EFI_INVALID_PARAMETER SimpleNetwork parameter was NULL or did not point to a valid
> +                                EFI_SIMPLE_NETWORK_PROTOCOL structure.
> +  @retval EFI_DEVICE_ERROR      The command could not be sent to the network interface.
> +  @retval EFI_UNSUPPORTED       The increased buffer size feature is not supported.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +SN_Shutdown (
> +  IN EFI_SIMPLE_NETWORK_PROTOCOL *SimpleNetwork
> +  );
> +
> +/**
> +  Send a packet over the network.
> +
> +  This function places the packet specified by Header and Buffer on
> +  the transmit queue.  This function performs a non-blocking transmit
> +  operation.  When the transmit is complete, the buffer is returned
> +  via the GetStatus() call.
> +
> +  This routine calls ::Ax88179Rx to empty the network adapter of
> +  receive packets.  The routine then passes the transmit packet
> +  to the network adapter.
> +
> +  @param [in] SimpleNetwork    Protocol instance pointer
> +  @param [in] HeaderSize        The size, in bytes, of the media header to be filled in by
> +                                the Transmit() function.  If HeaderSize is non-zero, then
> +                                it must be equal to SimpleNetwork->Mode->MediaHeaderSize
> +                                and DestAddr and Protocol parameters must not be NULL.
> +  @param [in] BufferSize        The size, in bytes, of the entire packet (media header and
> +                                data) to be transmitted through the network interface.
> +  @param [in] Buffer           A pointer to the packet (media header followed by data) to
> +                                to be transmitted.  This parameter can not be NULL.  If
> +                                HeaderSize is zero, then the media header is Buffer must
> +                                already be filled in by the caller.  If HeaderSize is nonzero,
> +                                then the media header will be filled in by the Transmit()
> +                                function.
> +  @param [in] SrcAddr          The source HW MAC address.  If HeaderSize is zero, then
> +                                this parameter is ignored.  If HeaderSize is nonzero and
> +                                SrcAddr is NULL, then SimpleNetwork->Mode->CurrentAddress
> +                                is used for the source HW MAC address.
> +  @param [in] DestAddr         The destination HW MAC address.  If HeaderSize is zero, then
> +                                this parameter is ignored.
> +  @param [in] Protocol         The type of header to build.  If HeaderSize is zero, then
> +                                this parameter is ignored.
> +
> +  @retval EFI_SUCCESS           This operation was successful.
> +  @retval EFI_NOT_STARTED       The network interface was not started.
> +  @retval EFI_NOT_READY         The network interface is too busy to accept this transmit request.
> +  @retval EFI_BUFFER_TOO_SMALL  The BufferSize parameter is too small.
> +  @retval EFI_INVALID_PARAMETER SimpleNetwork parameter was NULL or did not point to a valid
> +                                EFI_SIMPLE_NETWORK_PROTOCOL structure.
> +  @retval EFI_DEVICE_ERROR      The command could not be sent to the network interface.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +SN_Transmit (
> +  IN EFI_SIMPLE_NETWORK_PROTOCOL *SimpleNetwork,
> +  IN UINTN           HeaderSize,
> +  IN UINTN           BufferSize,
> +  IN VOID            *Buffer,
> +  IN EFI_MAC_ADDRESS *SrcAddr,
> +  IN EFI_MAC_ADDRESS *DestAddr,
> +  IN UINT16          *Protocol
> +  );
> +
> +//------------------------------------------------------------------------------
> +// Support Routines
> +//------------------------------------------------------------------------------
> +
> +/**
> +  Get the MAC address
> +
> +  This routine calls ::Ax88179UsbCommand to request the MAC
> +  address from the network adapter.
> +
> +  @param [in] NicDevice       Pointer to the NIC_DEVICE structure
> +  @param [out] MacAddress      Address of a six byte buffer to receive the MAC address.
> +
> +  @retval EFI_SUCCESS          The MAC address is available.
> +  @retval other                The MAC address is not valid.
> +
> +**/
> +EFI_STATUS
> +Ax88179MacAddressGet (
> +  IN NIC_DEVICE *NicDevice,
> +  OUT UINT8     *MacAddress
> +  );
> +
> +
> +/**
> +  Clear the multicast hash table
> +
> +  @param [in] NicDevice       Pointer to the NIC_DEVICE structure
> +
> +**/
> +VOID
> +Ax88179MulticastClear (
> +  IN NIC_DEVICE *NicDevice
> +  );
> +
> +/**
> +  Enable a multicast address in the multicast hash table
> +
> +  This routine calls ::Ax88179Crc to compute the hash bit for
> +  this MAC address.
> +
> +  @param [in] NicDevice       Pointer to the NIC_DEVICE structure
> +  @param [in] MacAddress      Address of a six byte buffer to containing the MAC address.
> +
> +**/
> +VOID
> +Ax88179MulticastSet (
> +  IN NIC_DEVICE *NicDevice,
> +  IN UINT8      *MacAddress
> +  );
> +
> +/**
> +  Start the link negotiation
> +
> +  This routine calls ::Ax88179PhyWrite to start the PHY's link
> +  negotiation.
> +
> +  @param [in] NicDevice       Pointer to the NIC_DEVICE structure
> +
> +  @retval EFI_SUCCESS          The link negotiation was started.
> +  @retval other                Failed to start the link negotiation.
> +
> +**/
> +EFI_STATUS
> +Ax88179NegotiateLinkStart (
> +  IN NIC_DEVICE *NicDevice
> +  );
> +
> +/**
> +  Complete the negotiation of the PHY link
> +
> +  This routine calls ::Ax88179PhyRead to determine if the
> +  link negotiation is complete.
> +
> +  @param [in] NicDevice       Pointer to the NIC_DEVICE structure
> +  @param [in, out] PollCount  Address of number of times this routine was polled
> +  @param [out] Complete      Address of boolean to receive complate status.
> +  @param [out] LinkUp        Address of boolean to receive link status, TRUE=up.
> +  @param [out] HiSpeed       Address of boolean to receive link speed, TRUE=100Mbps.
> +  @param [out] FullDuplex    Address of boolean to receive link duplex, TRUE=full.
> +
> +  @retval EFI_SUCCESS          The MAC address is available.
> +  @retval other                The MAC address is not valid.
> +
> +**/
> +EFI_STATUS
> +Ax88179NegotiateLinkComplete (
> +  IN     NIC_DEVICE *NicDevice,
> +  IN OUT UINTN      *PollCount,
> +  OUT    BOOLEAN    *Complete,
> +  OUT    BOOLEAN    *LinkUp,
> +  OUT    BOOLEAN    *HiSpeed,
> +  OUT    BOOLEAN    *GigaSpeed,
> +  OUT    BOOLEAN    *FullDuplex
> +  );
> +
> +/**
> +  Read a register from the PHY
> +
> +  This routine calls ::Ax88179UsbCommand to read a PHY register.
> +
> +  @param [in] NicDevice       Pointer to the NIC_DEVICE structure
> +  @param [in] RegisterAddress  Number of the register to read.
> +  @param [in, out] PhyData    Address of a buffer to receive the PHY register value
> +
> +  @retval EFI_SUCCESS          The PHY data is available.
> +  @retval other                The PHY data is not valid.
> +
> +**/
> +
> +
> +/**
> +  Reset the AX88179
> +
> +  This routine uses ::Ax88179UsbCommand to reset the network
> +  adapter.  This routine also uses ::Ax88179PhyWrite to reset
> +  the PHY.
> +
> +  @param [in] NicDevice       Pointer to the NIC_DEVICE structure
> +
> +  @retval EFI_SUCCESS          The MAC address is available.
> +  @retval other                The MAC address is not valid.
> +
> +**/
> +EFI_STATUS
> +Ax88179Reset (
> +  IN NIC_DEVICE *NicDevice
> +  );
> +
> +/**
> +  Enable or disable the receiver
> +
> +  This routine calls ::Ax88179UsbCommand to update the
> +  receiver state.  This routine also calls ::Ax88179MacAddressSet
> +  to establish the MAC address for the network adapter.
> +
> +  @param [in] NicDevice       Pointer to the NIC_DEVICE structure
> +  @param [in] RxFilter         Simple network RX filter mask value
> +
> +  @retval EFI_SUCCESS          The MAC address was set.
> +  @retval other                The MAC address was not set.
> +
> +**/
> +EFI_STATUS
> +Ax88179RxControl (
> +  IN NIC_DEVICE *NicDevice,
> +  IN UINT32     RxFilter
> +  );
> +
> +  EFI_STATUS
> +Ax88179ReloadSrom  (
> +  IN NIC_DEVICE *NicDevice
> +  );
> +
> +/**
> +  Read an SROM location
> +
> +  This routine calls ::Ax88179UsbCommand to read data from the
> +  SROM.
> +
> +  @param [in] NicDevice       Pointer to the NIC_DEVICE structure
> +  @param [in] Address          SROM address
> +  @param [out] Data           Buffer to receive the data
> +
> +  @retval EFI_SUCCESS          The read was successful
> +  @retval other                The read failed
> +
> +**/
> +EFI_STATUS
> +Ax88179SromRead (
> +  IN  NIC_DEVICE *NicDevice,
> +  IN  UINT32     Address,
> +  OUT UINT16     *Data
> +  );
> +
> +
> +EFI_STATUS
> +Ax88179EnableSromWrite  (
> +  IN NIC_DEVICE *NicDevice
> +  );
> +
> +
> +EFI_STATUS
> +Ax88179DisableSromWrite  (
> +  IN NIC_DEVICE *NicDevice
> +  );
> +
> +EFI_STATUS
> +Ax88179SromWrite (
> +  IN  NIC_DEVICE *NicDevice,
> +  IN  UINT32     Address,
> +  OUT UINT16     *Data
> +  );
> +
> +/**
> +  Send a command to the USB device.
> +
> +  @param [in] NicDevice       Pointer to the NIC_DEVICE structure
> +  @param [in] Request         Pointer to the request structure
> +  @param [in, out] Buffer     Data buffer address
> +
> +  @retval EFI_SUCCESS          The USB transfer was successful
> +  @retval other                The USB transfer failed
> +
> +**/
> +
> +EFI_STATUS
> +Ax88179UsbCommand (
> +  IN NIC_DEVICE         *NicDevice,
> +  IN USB_DEVICE_REQUEST *Request,
> +  IN OUT VOID           *Buffer
> +  );
> +
> +//------------------------------------------------------------------------------
> +// EFI Component Name Protocol Support
> +//------------------------------------------------------------------------------
> +extern EFI_DRIVER_BINDING_PROTOCOL   gDriverBinding;
> +extern EFI_COMPONENT_NAME_PROTOCOL   gComponentName;  ///<  Component name protocol declaration
> +extern EFI_COMPONENT_NAME2_PROTOCOL  gComponentName2; ///<  Component name 2 protocol declaration
> +
> +/**
> +  Retrieves a Unicode string that is the user readable name of the driver.
> +
> +  This function retrieves the user readable name of a driver in the form of a
> +  Unicode string. If the driver specified by This has a user readable name in
> +  the language specified by Language, then a pointer to the driver name is
> +  returned in DriverName, and EFI_SUCCESS is returned. If the driver specified
> +  by This does not support the language specified by Language,
> +  then EFI_UNSUPPORTED is returned.
> +
> +  @param [in] This             A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
> +                                EFI_COMPONENT_NAME_PROTOCOL instance.
> +  @param [in] Language         A pointer to a Null-terminated ASCII string
> +                                array indicating the language. This is the
> +                                language of the driver name that the caller is
> +                                requesting, and it must match one of the
> +                                languages specified in SupportedLanguages. The
> +                                number of languages supported by a driver is up
> +                                to the driver writer. Language is specified
> +                                in RFC 3066 or ISO 639-2 language code format.
> +  @param [out] DriverName     A pointer to the Unicode string to return.
> +                                This Unicode string is the name of the
> +                                driver specified by This in the language
> +                                specified by Language.
> +
> +  @retval EFI_SUCCESS           The Unicode string for the Driver specified by
> +                                This and the language specified by Language was
> +                                returned in DriverName.
> +  @retval EFI_INVALID_PARAMETER Language is NULL.
> +  @retval EFI_INVALID_PARAMETER DriverName is NULL.
> +  @retval EFI_UNSUPPORTED       The driver specified by This does not support
> +                                the language specified by Language.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +GetDriverName (
> +  IN  EFI_COMPONENT_NAME_PROTOCOL *This,
> +  IN  CHAR8                       *Language,
> +  OUT CHAR16                      **DriverName
> +  );
> +
> +
> +/**
> +  Retrieves a Unicode string that is the user readable name of the controller
> +  that is being managed by a driver.
> +
> +  This function retrieves the user readable name of the controller specified by
> +  ControllerHandle and ChildHandle in the form of a Unicode string. If the
> +  driver specified by This has a user readable name in the language specified by
> +  Language, then a pointer to the controller name is returned in ControllerName,
> +  and EFI_SUCCESS is returned.  If the driver specified by This is not currently
> +  managing the controller specified by ControllerHandle and ChildHandle,
> +  then EFI_UNSUPPORTED is returned.  If the driver specified by This does not
> +  support the language specified by Language, then EFI_UNSUPPORTED is returned.
> +
> +  @param [in] This             A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
> +                                EFI_COMPONENT_NAME_PROTOCOL instance.
> +  @param [in] ControllerHandle  The handle of a controller that the driver
> +                                specified by This is managing.  This handle
> +                                specifies the controller whose name is to be
> +                                returned.
> +  @param [in] ChildHandle       The handle of the child controller to retrieve
> +                                the name of.  This is an optional parameter that
> +                                may be NULL.  It will be NULL for device
> +                                drivers.  It will also be NULL for a bus drivers
> +                                that wish to retrieve the name of the bus
> +                                controller.  It will not be NULL for a bus
> +                                driver that wishes to retrieve the name of a
> +                                child controller.
> +  @param [in] Language         A pointer to a Null-terminated ASCII string
> +                                array indicating the language.  This is the
> +                                language of the driver name that the caller is
> +                                requesting, and it must match one of the
> +                                languages specified in SupportedLanguages. The
> +                                number of languages supported by a driver is up
> +                                to the driver writer. Language is specified in
> +                                RFC 3066 or ISO 639-2 language code format.
> +  @param [out] ControllerName A pointer to the Unicode string to return.
> +                                This Unicode string is the name of the
> +                                controller specified by ControllerHandle and
> +                                ChildHandle in the language specified by
> +                                Language from the point of view of the driver
> +                                specified by This.
> +
> +  @retval EFI_SUCCESS           The Unicode string for the user readable name in
> +                                the language specified by Language for the
> +                                driver specified by This was returned in
> +                                DriverName.
> +  @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE.
> +  @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid
> +                                EFI_HANDLE.
> +  @retval EFI_INVALID_PARAMETER Language is NULL.
> +  @retval EFI_INVALID_PARAMETER ControllerName is NULL.
> +  @retval EFI_UNSUPPORTED       The driver specified by This is not currently
> +                                managing the controller specified by
> +                                ControllerHandle and ChildHandle.
> +  @retval EFI_UNSUPPORTED       The driver specified by This does not support
> +                                the language specified by Language.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +GetControllerName (
> +  IN  EFI_COMPONENT_NAME_PROTOCOL *This,
> +  IN  EFI_HANDLE                  ControllerHandle,
> +  IN OPTIONAL EFI_HANDLE          ChildHandle,
> +  IN  CHAR8                       *Language,
> +  OUT CHAR16                      **ControllerName
> +  );
> +
> +EFI_STATUS
> +Ax88179SetMedium (
> +  IN NIC_DEVICE * NicDevice
> +  );
> +
> +//-----------------------------------------------------------------------------
> +
> +
> +#define ACCESS_MAC  0x01
> +#define ACCESS_PHY  0x02
> +
> +#define PLSR                0x02
> +  #define PLSR_USB_FS  0x01
> +  #define PLSR_USB_HS  0x02
> +  #define PLSR_USB_SS  0x04
> +
> +#define NODE_ID               0x10
> +
> +#define RXCTL                 0x0b
> +  #define RXCTL_PRO         0x0001  ///<  Receive all packets
> +  #define RXCTL_AMALL       0x0002  ///<  Receive all multicast packets
> +  #define RXCTL_SEP         0x0004  ///<  Save error packets
> +  #define RXCTL_AB          0x0008  ///<  Receive broadcast packets
> +  #define RXCTL_AM          0x0010  ///<  Use multicast destination address hash table
> +  #define RXCTL_AP          0x0020  ///<  Accept physical address from Multicast Filter
> +  #define RXCTL_ARP         0x0040  ///<  Accept runt packet
> +  #define RXCTL_SO          0x0080  ///<  Start operation
> +  #define RXCTL_DROPCRCERR  0x0100  ///<  RX header 1 formate selection
> +  #define RXCTL_IPE         0x0200  ///<  RX header 2 formate selection
> +  #define RXCTL_TXPADCRC    0x0400  ///<  RX header 3 formate selection
> +  #define RXCTL_LPBK        0x1000  ///<  MAC loop back for diagnostic
> +
> +#define MULCATFLTARRY       0x16  ///<  Write the multicast hash table, Data: New 8 byte value
> +
> +#define MEDIUMSTSMOD          0x22
> +  #define MEDIUMSTSMOD_GM   0x0001  ///<  Gigabit Mode
> +  #define MEDIUMSTSMOD_FD   0x0002  ///<  Full duplex
> +  #define MEDIUMSTSMOD_ONE  0x0004  ///<  Must be one
> +  #define MEDIUMSTSMOD_ENCK 0x0008  ///<  Add in 04h
> +  #define MEDIUMSTSMOD_RFC  0x0010  ///<  RX flow control enable
> +  #define MEDIUMSTSMOD_TFC  0x0020  ///<  TX flow control enable
> +  #define MEDIUMSTSMOD_JFE  0x0040  ///<  Pause frame enable
> +  #define MEDIUMSTSMOD_PF   0x0080  ///<  Pause frame enable
> +  #define MEDIUMSTSMOD_RE   0x0100  ///<  Receive enable
> +  #define MEDIUMSTSMOD_PS   0x0200  ///<  Port speed 1=100, 0=10 Mbps
> +  #define MEDIUMSTSMOD_SBP  0x0800  ///<  Stop back pressure
> +  #define MEDIUMSTSMOD_SM   0x1000  ///<  Super MAC support
> +
> +#define MONITORSTAUS          0x24
> +  #define  MONITORSTAUS_PMETYPE   0x40
> +  #define  MONITORSTAUS_PMEPOL    0x20
> +
> +#define PHYPWRRSTCTL          0x26
> +  #define PHYPWRRSTCTL_IPRL     0x20
> +  #define PHYPWRRSTCTL_OSCDSSEL 0x80
> +  #define PHYPWRRSTCTL_BZTYPE   0x4
> +  #define PHYPWRRSTCTL_BZ      0x10
> +
> +#define SISSR                 0x28
> +  #define SISSR_PSEL        0x01
> +  #define SISSR_ASEL        0x02
> +
> +#define RXBINQCTRL            0x2e
> +  #define RXBINQCTRL_TIMEN  0x01
> +  #define RXBINQCTRL_IFGEN  0x02
> +  #define RXBINQCTRL_SIZEN  0x04
> +
> +#define RXBINQTIMERL          0x2f
> +#define RXBINQTIMERH          0x30
> +#define RXBINQSIZE            0x31
> +#define RXBINQIFG             0x32
> +
> +#define CLKSELECT             0x33
> +  #define CLKSELECT_ACS       0x02
> +  #define CLKSELECT_BCS       0x01
> +
> +#define PAUSE_WATERLVL_HIGH   0x54
> +#define PAUSE_WATERLVL_LOW    0x55
> +
> +#define RXFREEBUF             0x57
> +  #define MAX_RXBUF_PAGE    0x067F
> +
> +#define PHY_BMCR                        0       ///<  Control register
> +  #define BMCR_RESET                      0x8000  ///<  1 = Reset the PHY, bit clears after reset
> +  #define BMCR_LOOPBACK                   0x4000  ///<  1 = Loopback enabled
> +  #define BMCR_AUTONEGOTIATION_ENABLE     0x1000  ///<  1 = Enable autonegotiation
> +  #define BMCR_POWER_DOWN                 0x0800  ///<  1 = Power down
> +  #define BMCR_ISOLATE                    0x0400  ///<  0 = Isolate PHY
> +  #define BMCR_RESTART_AUTONEGOTIATION    0x0200  ///<  1 = Restart autonegotiation
> +  #define BMCR_FULL_DUPLEX                0x0100  ///<  Full duplex operation
> +  #define BMCR_COLLISION_TEST             0x0080  ///<  1 = Collision test enabled
> +  #define BMCR_1000MBPS                   0x40  ///<  Forced mode in 1000Mbps
> +  #define BMCR_100MBPS                    0x2000    ///<  Forced mode in 10Mbps
> +
> +#define PHY_BMSR                        1       ///<  Status register
> +  #define BMSR_100BASET4                  0x8000  ///<  1 = 100BASE-T4 mode
> +  #define BMSR_100BASETX_FDX              0x4000  ///<  1 = 100BASE-TX full duplex
> +  #define BMSR_100BASETX_HDX              0x2000  ///<  1 = 100BASE-TX half duplex
> +  #define BMSR_10BASET_FDX                0x1000  ///<  1 = 10BASE-T full duplex
> +  #define BMSR_10BASET_HDX                0x0800  ///<  1 = 10BASE-T half duplex
> +  #define BMSR_MF                         0x0040  ///<  1 = PHY accepts frames with preamble suppressed
> +  #define BMSR_AUTONEG_CMPLT              0x0020  ///<  1 = Autonegotiation complete
> +  #define BMSR_RF                         0x0010  ///<  1 = Remote fault
> +  #define BMSR_AUTONEG                    0x0008  ///<  1 = Able to perform autonegotiation
> +  #define BMSR_LINKST                     0x0004  ///<  1 = Link up
> +  #define BMSR_JABBER_DETECT              0x0002  ///<  1 = jabber condition detected
> +  #define BMSR_EXTENDED_CAPABILITY        0x0001  ///<  1 = Extended register capable
> +
> +#define PHY_ANAR                        4       ///<  Autonegotiation advertisement register
> +  #define AN_NP                           0x8000  ///<  1 = Next page available
> +  #define AN_RF                           0x2000  ///<  1 = Remote fault indicated by link partner
> +  #define AN_FCS                          0x0400  ///<  1 = Flow control ability
> +  #define AN_T4                           0x0200  ///<  1 = 100BASE-T4 support
> +  #define AN_TX_FDX                       0x0100  ///<  1 = 100BASE-TX Full duplex
> +  #define AN_TX_HDX                       0x0080  ///<  1 = 100BASE-TX support
> +  #define AN_10_FDX                       0x0040  ///<  1 = 10BASE-T Full duplex
> +  #define AN_10_HDX                       0x0020  ///<  1 = 10BASE-T support
> +  #define AN_CSMA_CD                      0x0001  ///<  1 = IEEE 802.3 CSMA/CD support
> +
> +#define PHY_ANLPAR                      5       ///<  Autonegotiation link parter ability register
> +
> +#define PHY_PHYSR                       0x11
> +  #define PHYSR_SPEED_MASK                0xC000
> +  #define PHYSR_1000                      0x8000
> +  #define PHYSR_100                       0x4000
> +  #define PHYSR_FULLDUP                   0x2000
> +  #define PHYSR_LINK                      0x400
> +
> +EFI_STATUS
> +Ax88179PhyRead (
> +  IN     NIC_DEVICE *NicDevice,
> +  IN     UINT8      RegisterAddress,
> +  IN OUT UINT16     *PhyData
> +  );
> +
> +EFI_STATUS
> +Ax88179PhyWrite (
> +  IN NIC_DEVICE *NicDevice,
> +  IN UINT8      RegisterAddress,
> +  IN UINT16     PhyData
> +  );
> +
> +EFI_STATUS
> +Ax88179MacRead (
> +  IN            UINT8 Offset,
> +  IN            UINT8 Length,
> +  IN            NIC_DEVICE * NicDevice,
> +  IN  OUT  VOID *Data
> +  );
> +
> +EFI_STATUS
> +Ax88179SetIInInterval (
> +  IN  NIC_DEVICE *NicDevice,
> +  IN  UINT8      Offset
> +  );
> +
> +EFI_STATUS
> +Ax88179MacWrite (
> +  IN      UINT8      Offset,
> +  IN      UINT8      Length,
> +  IN      NIC_DEVICE *NicDevice,
> +  IN  OUT VOID       *Data
> +  );
> +
> +EFI_STATUS
> +Ax88179MacAddressGet (
> +  IN  NIC_DEVICE *NicDevice,
> +  OUT UINT8      *MacAddress
> +  );
> +
> +EFI_STATUS
> +Ax88179MacAddressSet (
> +  IN  NIC_DEVICE *NicDevice,
> +  OUT UINT8      *MacAddress
> +  );
> +
> +BOOLEAN
> +Ax88179GetLinkStatus (
> +  IN NIC_DEVICE *NicDevice
> +);
> +
> +EFI_STATUS
> +Ax88179BulkIn(
> +  IN NIC_DEVICE *NicDevice
> +);
> +
> +
> +#endif  //  AX88179_H_
> diff --git a/Drivers/ASIX/Bus/Usb/UsbNetworking/Ax88179/Ax88179.c
> b/Drivers/ASIX/Bus/Usb/UsbNetworking/Ax88179/Ax88179.c
> new file mode 100644
> index 000000000000..a2af3c5618d1
> --- /dev/null
> +++ b/Drivers/ASIX/Bus/Usb/UsbNetworking/Ax88179/Ax88179.c
> @@ -0,0 +1,1042 @@
> + /** @file
> +  Implement the interface to the AX88179 Ethernet controller.
> +
> +  This module implements the interface to the ASIX AX88179
> +  USB to Ethernet MAC with integrated 10/100 PHY.  Note that this implementation
> +  only supports the integrated PHY since no other test cases were available.
> +
> +  Copyright (c) 2011, Intel Corporation
> +  Copyright (c) 2020, ARM Limited. All rights reserved.
> +
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include "Ax88179.h"
> +
> +
> +/**
> +  Compute the CRC
> +
> +  @param [in] MacAddress      Address of a six byte buffer to containing the MAC address.
> +
> +  @returns The CRC-32 value associated with this MAC address
> +
> +**/
> +UINT32
> +Ax88179Crc (
> +  IN UINT8 *MacAddress
> +  )
> +{
> +  UINT32 BitNumber;
> +  INT32  Carry;
> +  INT32  Crc;
> +  UINT32 Data;
> +  UINT8  *End;
> +
> +  //
> +  //  Walk the MAC address
> +  //
> +  Crc = -1;
> +  End = &MacAddress[PXE_HWADDR_LEN_ETHER];
> +  while (End > MacAddress) {
> +    Data = *MacAddress++;
> +
> +
> +    //
> +    //  CRC32: x32 + x26 + x23 + x22 + x16 + x12 + x11 + x10 + x8 + x7 + x5 + x4 + x2 + x + 1
> +    //
> +    //          1 0000 0100 1100 0001 0001 1101 1011 0111
> +    //
> +    for (BitNumber = 0; 8 > BitNumber; BitNumber++) {
> +      Carry = ((Crc >> 31) & 1) ^ (Data & 1);
> +      Crc <<= 1;
> +      if (Carry != 0) {
> +        Crc ^= 0x04c11db7;
> +      }
> +      Data >>= 1;
> +    }
> +  }
> +
> +  //
> +  //  Return the CRC value
> +  //
> +  return (UINT32) Crc;
> +}
> +
> +/**
> +  Get the MAC address
> +
> +  This routine calls ::Ax88179UsbCommand to request the MAC
> +  address from the network adapter.
> +
> +  @param [in] NicDevice       Pointer to the NIC_DEVICE structure
> +  @param [out] MacAddress      Address of a six byte buffer to receive the MAC address.
> +
> +  @retval EFI_SUCCESS          The MAC address is available.
> +  @retval other                The MAC address is not valid.
> +
> +**/
> +EFI_STATUS
> +Ax88179MacAddressGet (
> +  IN  NIC_DEVICE *NicDevice,
> +  OUT UINT8      *MacAddress
> +  )
> +{
> +  EFI_STATUS Status;
> +
> +  Status  = Ax88179MacRead (NODE_ID,
> +                            PXE_HWADDR_LEN_ETHER,
> +                            NicDevice,
> +                            MacAddress);
> +
> +  return Status;
> +}
> +
> +/**
> +  Set the MAC address
> +
> +  This routine calls ::Ax88179UsbCommand to set the MAC address
> +  in the network adapter.
> +
> +  @param [in] NicDevice       Pointer to the NIC_DEVICE structure
> +  @param [in] MacAddress      Address of a six byte buffer to containing the new MAC address.
> +
> +  @retval EFI_SUCCESS          The MAC address was set.
> +  @retval other                The MAC address was not set.
> +
> +**/
> +EFI_STATUS
> +Ax88179MacAddressSet (
> +  IN  NIC_DEVICE *NicDevice,
> +  OUT UINT8      *MacAddress
> +  )
> +{
> +  EFI_STATUS Status;
> +
> +  Status  = Ax88179MacWrite (NODE_ID,
> +                             PXE_HWADDR_LEN_ETHER,
> +                             NicDevice,
> +                             MacAddress);
> +
> +  return Status;
> +}
> +
> +/**
> +  Clear the multicast hash table
> +
> +  @param [in] NicDevice       Pointer to the NIC_DEVICE structure
> +
> +**/
> +VOID
> +Ax88179MulticastClear (
> +  IN NIC_DEVICE *NicDevice
> +  )
> +{
> +  int Index = 0;
> +  //
> +  // Clear the multicast hash table
> +  //
> +  for (Index = 0 ; Index < 8 ; Index ++)
> +    NicDevice->MulticastHash[Index] = 0;
> +}
> +
> +/**
> +  Enable a multicast address in the multicast hash table
> +
> +  This routine calls ::Ax88179Crc to compute the hash bit for
> +  this MAC address.
> +
> +  @param [in] NicDevice       Pointer to the NIC_DEVICE structure
> +  @param [in] MacAddress      Address of a six byte buffer to containing the MAC address.
> +
> +**/
> +VOID
> +Ax88179MulticastSet (
> +  IN NIC_DEVICE *NicDevice,
> +  IN UINT8      *MacAddress
> +  )
> +{
> +  UINT32 Crc;
> +
> +  //
> +  // Compute the CRC on the destination address
> +  //
> +  Crc = Ax88179Crc (MacAddress) >> 26;
> +
> +  //
> +  //  Set the bit corresponding to the destination address
> +  //
> +  NicDevice->MulticastHash [Crc >> 3] |= (1 << (Crc & 7));
> +
> +}
> +
> +/**
> +  Start the link negotiation
> +
> +  This routine calls ::Ax88179PhyWrite to start the PHY's link
> +  negotiation.
> +
> +  @param [in] NicDevice       Pointer to the NIC_DEVICE structure
> +
> +  @retval EFI_SUCCESS          The link negotiation was started.
> +  @retval other                Failed to start the link negotiation.
> +
> +**/
> +EFI_STATUS
> +Ax88179NegotiateLinkStart (
> +  IN NIC_DEVICE *NicDevice
> +  )
> +{
> +  UINT16     Control = 0;
> +  EFI_STATUS Status;
> +
> +#if FORCE_100Mbps
> +  Ax88179PhyRead (NicDevice,
> +                   0x09,
> +                   &Control);
> +  Control &= 0xFCFF;
> +  Ax88179PhyWrite (NicDevice, 0x09, Control);
> +#endif
> +
> +  //
> +  // Set the link speed and duplex
> +  //
> +  Control = BMCR_AUTONEGOTIATION_ENABLE
> +          | BMCR_RESTART_AUTONEGOTIATION;
> +  if (NicDevice->LinkSpeed1000Mbps) {
> +    Control |= BMCR_1000MBPS;
> +  } else if (NicDevice->LinkSpeed100Mbps) {
> +    Control |= BMCR_100MBPS;
> +  }
> +
> +  if (NicDevice->FullDuplex) {
> +    Control |= BMCR_FULL_DUPLEX;
> +  }
> +  Status = Ax88179PhyWrite (NicDevice, PHY_BMCR, Control);
> +  if (!EFI_ERROR(Status))
> +    gBS->Stall(3000000);
> +  //
> +  // Return the operation status
> +  //
> +  return Status;
> +}
> +
> +
> +
> +/**
> +  Complete the negotiation of the PHY link
> +
> +  This routine calls ::Ax88179PhyRead to determine if the
> +  link negotiation is complete.
> +
> +  @param [in] NicDevice       Pointer to the NIC_DEVICE structure
> +  @param [in, out] PollCount  Address of number of times this routine was polled
> +  @param [out] Complete      Address of boolean to receive complate status.
> +  @param [out] LinkUp        Address of boolean to receive link status, TRUE=up.
> +  @param [out] HiSpeed       Address of boolean to receive link speed, TRUE=100Mbps.
> +  @param [out] FullDuplex    Address of boolean to receive link duplex, TRUE=full.
> +
> +  @retval EFI_SUCCESS          The MAC address is available.
> +  @retval other                The MAC address is not valid.
> +
> +**/
> +EFI_STATUS
> +Ax88179NegotiateLinkComplete (
> +  IN     NIC_DEVICE *NicDevice,
> +  IN OUT UINTN      *PollCount,
> +  OUT    BOOLEAN    *Complete,
> +  OUT    BOOLEAN    *LinkUp,
> +  OUT    BOOLEAN    *HiSpeed,
> +  OUT    BOOLEAN    *GigaSpeed,
> +  OUT    BOOLEAN    *FullDuplex
> +  )
> +{
> +  UINT16      PhyData;
> +  EFI_STATUS  Status;
> +
> +  //
> +  //  Determine if the link is up.
> +  //
> +  *Complete = FALSE;
> +
> +  //
> +  //  Get the link status
> +  //
> +  Status = Ax88179PhyRead (NicDevice,
> +                            PHY_PHYSR,
> +                            &PhyData);
> +  if (EFI_ERROR (Status)) {
> +    return Status;
> +  }
> +
> +  *LinkUp = ((PhyData & PHYSR_LINK) != 0);
> +  if (*LinkUp) {
> +    //
> +    //  Determine if the autonegotiation is complete.
> +    //
> +    Status = Ax88179PhyRead (NicDevice,
> +                          PHY_BMSR,
> +                          &PhyData);
> +    if (EFI_ERROR(Status)) {
> +      return Status;
> +    }
> +
> +    *Complete = ((PhyData & BMSR_AUTONEG_CMPLT) != 0);
> +
> +    if (*Complete != 0) {
> +      //
> +      //  Get the partners capabilities.
> +      //
> +      Status = Ax88179PhyRead (NicDevice,
> +                                PHY_PHYSR,
> +                                &PhyData);
> +      if (EFI_ERROR (Status)) {
> +        return Status;
> +      }
> +
> +      //
> +      //  Autonegotiation is complete
> +      //  Determine the link speed.
> +      //
> +      *GigaSpeed = ((PhyData & PHYSR_SPEED_MASK) == PHYSR_1000);
> +      *HiSpeed = ((PhyData & PHYSR_SPEED_MASK) == PHYSR_100);
> +
> +      //
> +      //  Determine the link duplex.
> +      //
> +      *FullDuplex = ((PhyData & PHYSR_FULLDUP) == PHYSR_FULLDUP);
> +    }
> +  }
> +
> +
> +  //
> +  // Return the operation status
> +  //
> +  return Status;
> +}
> +
> +
> +/**
> +  Read a register from the PHY
> +
> +  This routine calls ::Ax88179UsbCommand to read a PHY register.
> +
> +  @param [in] NicDevice       Pointer to the NIC_DEVICE structure
> +  @param [in] RegisterAddress  Number of the register to read.
> +  @param [in, out] PhyData    Address of a buffer to receive the PHY register value
> +
> +  @retval EFI_SUCCESS          The PHY data is available.
> +  @retval other                The PHY data is not valid.
> +
> +**/
> +EFI_STATUS
> +Ax88179PhyRead (
> +  IN     NIC_DEVICE *NicDevice,
> +  IN     UINT8      RegisterAddress,
> +  IN OUT UINT16     *PhyData
> +  )
> +{
> +  USB_DEVICE_REQUEST SetupMsg;
> +  EFI_STATUS         Status;
> +
> +  //
> +  //  Read the PHY register address.
> +  //
> +  SetupMsg.RequestType = USB_ENDPOINT_DIR_IN
> +                       | USB_REQ_TYPE_VENDOR
> +                       | USB_TARGET_DEVICE;
> +  SetupMsg.Request = ACCESS_PHY;
> +  SetupMsg.Value = NicDevice->PhyId;
> +  SetupMsg.Index = RegisterAddress;
> +  SetupMsg.Length = sizeof (*PhyData);
> +  Status = Ax88179UsbCommand (NicDevice,
> +                               &SetupMsg,
> +                               PhyData);
> +
> +  //
> +  //  Return the operation status.
> +  //
> +  return Status;
> +}
> +
> +
> +/**
> +  Write to a PHY register
> +
> +  This routine calls ::Ax88179UsbCommand to write a PHY register.
> +
> +  @param [in] NicDevice       Pointer to the NIC_DEVICE structure
> +  @param [in] RegisterAddress  Number of the register to read.
> +  @param [in] PhyData          Address of a buffer to receive the PHY register value
> +
> +  @retval EFI_SUCCESS          The PHY data was written.
> +  @retval other                Failed to wwrite the PHY register.
> +
> +**/
> +EFI_STATUS
> +Ax88179PhyWrite (
> +  IN NIC_DEVICE *NicDevice,
> +  IN UINT8      RegisterAddress,
> +  IN UINT16     PhyData
> +  )
> +{
> +  USB_DEVICE_REQUEST SetupMsg;
> +  EFI_STATUS         Status;
> +
> +  //
> +  //  Write the PHY register
> +  //
> +  SetupMsg.RequestType = USB_REQ_TYPE_VENDOR
> +                       | USB_TARGET_DEVICE;
> +  SetupMsg.Request = ACCESS_PHY;
> +  SetupMsg.Value = NicDevice->PhyId;
> +  SetupMsg.Index = RegisterAddress;
> +  SetupMsg.Length = sizeof (PhyData);
> +  Status = Ax88179UsbCommand (NicDevice,
> +                               &SetupMsg,
> +                               &PhyData);
> +  //
> +  //  Return the operation status.
> +  //
> +  return Status;
> +}
> +
> +
> +/**
> +  Reset the AX88179
> +
> +  This routine uses ::Ax88179UsbCommand to reset the network
> +  adapter.  This routine also uses ::Ax88179PhyWrite to reset
> +  the PHY.
> +
> +  @param [in] NicDevice       Pointer to the NIC_DEVICE structure
> +
> +  @retval EFI_SUCCESS          The MAC address is available.
> +  @retval other                The MAC address is not valid.
> +
> +**/
> +EFI_STATUS
> +Ax88179Reset (
> +  IN NIC_DEVICE *NicDevice
> +  )
> +{
> +  EFI_STATUS Status;
> +  UINT16     Val;
> +  UINT8      Val8;
> +
> +  Status = Ax88179SetIInInterval(NicDevice, 0xff);
> +
> +  if (EFI_ERROR(Status)) goto err;
> +
> +  Val8 = 0;
> +  Status  = Ax88179MacRead (PLSR,
> +                            sizeof(Val8),
> +                            NicDevice,
> +                            &Val8);
> +
> +  if (EFI_ERROR(Status)) goto err;
> +
> +  if (Val8 & PLSR_USB_SS)
> +    NicDevice->UsbMaxPktSize = 1024;
> +  else
> +    NicDevice->UsbMaxPktSize = 512;
> +
> +  Val = 0;
> +  Status = Ax88179MacWrite (PHYPWRRSTCTL,
> +                             sizeof (Val),
> +                             NicDevice,
> +                             &Val);
> +
> +  if (EFI_ERROR(Status)) goto err;
> +
> +  gBS->Stall (10000);
> +
> +  Val =  PHYPWRRSTCTL_IPRL;
> +  Status = Ax88179MacWrite (PHYPWRRSTCTL,
> +                             sizeof (Val),
> +                             NicDevice,
> +                             &Val);
> +
> +  if (EFI_ERROR(Status)){
> +    goto err;
> +  }
> +
> +  gBS->Stall (200000);
> +
> +  Val = CLKSELECT_BCS | CLKSELECT_ACS;
> +  Status = Ax88179MacWrite (CLKSELECT,
> +                             1,
> +                             NicDevice,
> +                             &Val);
> +
> +  if (EFI_ERROR(Status)) goto err;
> +
> +  gBS->Stall (100000);
> +
> +  Val = 0x52;
> +  Status = Ax88179MacWrite (PAUSE_WATERLVL_HIGH,
> +                             1,
> +                             NicDevice,
> +                             &Val);
> +
> +  if (EFI_ERROR(Status)) goto err;
> +
> +  Val = 0x34;
> +  Status = Ax88179MacWrite (PAUSE_WATERLVL_LOW,
> +                             1,
> +                             NicDevice,
> +                             &Val);
> +
> +  if (EFI_ERROR(Status)) goto err;
> +
> +  Val = RXBINQCTRL_TIMEN | RXBINQCTRL_IFGEN | RXBINQCTRL_SIZEN;
> +
> +  Status =  Ax88179MacWrite (RXBINQCTRL,
> +                              0x01,
> +                              NicDevice,
> +                              &Val);
> +
> +  if (EFI_ERROR(Status)) goto err;
> +
> +  Val = 0;
> +  Status =  Ax88179MacWrite (RXBINQTIMERL,
> +                              0x01,
> +                              NicDevice,
> +                              &Val);
> +
> +  if (EFI_ERROR(Status)) goto err;
> +
> +  Val = 0;
> +  Status =  Ax88179MacWrite (RXBINQTIMERH,
> +                              0x01,
> +                              NicDevice,
> +                              &Val);
> +
> +  if (EFI_ERROR(Status)) goto err;
> +
> +  Val = 12; //AX88179_BULKIN_SIZE_INK - 1;
> +  Status =  Ax88179MacWrite (RXBINQSIZE,
> +                              0x01,
> +                              NicDevice,
> +                              &Val);
> +
> +  if (EFI_ERROR(Status)) goto err;
> +
> +  Val = 0x0F;
> +  Status =  Ax88179MacWrite (RXBINQIFG,
> +                              0x01,
> +                              NicDevice,
> +                              &Val);
> +
> +err:
> +  return Status;
> +}
> +
> +EFI_STATUS
> +Ax88179RxControl (
> +  IN NIC_DEVICE *NicDevice,
> +  IN UINT32     RxFilter
> +  )
> +{
> +  UINT16     MediumStatus;
> +  UINT16     RxControl = 0;
> +  EFI_STATUS Status = EFI_SUCCESS;
> +
> +  //
> +  // Enable the receiver if something is to be received
> +  //
> +  if (RxFilter != 0) {
> +    //
> +    //  Enable the receiver
> +    //
> +    Status  = Ax88179MacRead (MEDIUMSTSMOD,
> +                              sizeof (MediumStatus),
> +                              NicDevice,
> +                              &MediumStatus);
> +
> +    if (!EFI_ERROR (Status) && NicDevice->CurMediumStatus != MediumStatus) {
> +        MediumStatus = MEDIUMSTSMOD_RE | MEDIUMSTSMOD_ONE;
> +        if (NicDevice->FullDuplex) {
> +          MediumStatus |= MEDIUMSTSMOD_TFC | MEDIUMSTSMOD_RFC | MEDIUMSTSMOD_FD;
> +        } else {
> +          MediumStatus &= ~(MEDIUMSTSMOD_TFC | MEDIUMSTSMOD_RFC | MEDIUMSTSMOD_FD);
> +        }
> +        if (NicDevice->LinkSpeed1000Mbps) {
> +          MediumStatus |= MEDIUMSTSMOD_GM;
> +          MediumStatus |= MEDIUMSTSMOD_ENCK;
> +          MediumStatus &= ~MEDIUMSTSMOD_PS;
> +        } else {
> +          MediumStatus &= ~MEDIUMSTSMOD_GM;
> +          MediumStatus &= ~MEDIUMSTSMOD_ENCK;
> +          if (NicDevice->LinkSpeed100Mbps) {
> +            MediumStatus |= MEDIUMSTSMOD_PS;
> +          }  else {
> +            MediumStatus &= ~MEDIUMSTSMOD_PS;
> +          }
> +        }
> +        Status  = Ax88179MacWrite (MEDIUMSTSMOD,
> +                                   sizeof (MediumStatus),
> +                                   NicDevice,
> +                                   &MediumStatus);
> +        if (!EFI_ERROR (Status)) {
> +          NicDevice->CurMediumStatus = MediumStatus;
> +        }
> +    }
> +  }
> +
> +  RxControl = RXCTL_SO | RXCTL_IPE;
> +
> +  //
> +  //  Enable multicast if requested
> +  //
> +  if ((RxFilter & EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST) != 0) {
> +    RxControl |= RXCTL_AM;
> +    //
> +    //  Update the multicast hash table
> +    //
> +    Status  = Ax88179MacWrite (MULCATFLTARRY,
> +                               8,
> +                               NicDevice,
> +                               &NicDevice->MulticastHash);
> +  }
> +
> +  //
> +  //  Enable all multicast if requested
> +  //
> +  if ((RxFilter & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST) != 0) {
> +    RxControl |= RXCTL_AMALL;
> +  }
> +  //
> +  //  Enable broadcast if requested
> +  //
> +  if ((RxFilter & EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST) != 0) {
> +    RxControl |= RXCTL_AB;
> +  }
> +
> +  //
> +  //  Enable promiscuous mode if requested
> +  //
> +  if ((RxFilter & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS) != 0) {
> +    RxControl |= RXCTL_PRO;
> +  }
> +
> +  //
> +  //  Update the receiver control
> +  //
> +  if (NicDevice->CurRxControl != RxControl) {
> +    Status  = Ax88179MacWrite (RXCTL,
> +                               0x02,
> +                               NicDevice,
> +                               &RxControl);
> +    if (!EFI_ERROR (Status))
> +      NicDevice->CurRxControl = RxControl;
> +  }
> +
> +  //
> +  // Return the operation status
> +  //
> +  return Status;
> +}
> +
> +EFI_STATUS
> +Ax88179ReloadSrom  (
> +  IN NIC_DEVICE *NicDevice
> + )
> +{
> +  EFI_STATUS Status;
> +
> +  Status = EFI_UNSUPPORTED;
> +  return Status;
> +
> +}
> +
> +/**
> +  Read an SROM location
> +
> +  This routine calls ::Ax88179UsbCommand to read data from the
> +  SROM.
> +
> +  @param [in] NicDevice       Pointer to the NIC_DEVICE structure
> +  @param [in] Address          SROM address
> +  @param [out] Data           Buffer to receive the data
> +
> +  @retval EFI_SUCCESS          The read was successful
> +  @retval other                The read failed
> +
> +**/
> +EFI_STATUS
> +Ax88179SromRead (
> +  IN  NIC_DEVICE *NicDevice,
> +  IN  UINT32     Address,
> +  OUT UINT16     *Data
> +  )
> +{
> +  EFI_STATUS Status;
> +
> +  Status = EFI_UNSUPPORTED;
> +  return Status;
> +}
> +
> +EFI_STATUS
> +Ax88179EnableSromWrite  (
> +  IN NIC_DEVICE *NicDevice
> +  )
> +{
> +  EFI_STATUS Status;
> +
> +  Status = EFI_UNSUPPORTED;
> +  return Status;
> +}
> +
> +
> +EFI_STATUS
> +Ax88179DisableSromWrite  (
> +  IN NIC_DEVICE *NicDevice
> +  )
> +{
> +  EFI_STATUS Status;
> +
> +  Status = EFI_UNSUPPORTED;
> +  return Status;
> +}
> +
> +/**
> +  Write an SROM location
> +
> +  This routine calls ::Ax88179UsbCommand to write data from the
> +  SROM.
> +
> +  @param [in] NicDevice       Pointer to the NIC_DEVICE structure
> +  @param [in] Address          SROM address
> +  @param [out] Data           Buffer of data to write
> +
> +  @retval EFI_SUCCESS          The write was successful
> +  @retval other                The write failed
> +
> +**/
> +EFI_STATUS
> +Ax88179SromWrite (
> +  IN NIC_DEVICE *NicDevice,
> +  IN UINT32     Address,
> +  IN UINT16     *Data
> +  )
> +{
> +  EFI_STATUS Status;
> +
> +  Status = EFI_UNSUPPORTED;
> +  return Status;
> +}
> +
> +/**
> +  Send a command to the USB device.
> +
> +  @param [in] NicDevice       Pointer to the NIC_DEVICE structure
> +  @param [in] Request         Pointer to the request structure
> +  @param [in, out] Buffer     Data buffer address
> +
> +  @retval EFI_SUCCESS          The USB transfer was successful
> +  @retval other                The USB transfer failed
> +
> +**/
> +EFI_STATUS
> +Ax88179UsbCommand (
> +  IN     NIC_DEVICE         *NicDevice,
> +  IN     USB_DEVICE_REQUEST *Request,
> +  IN OUT VOID               *Buffer
> +  )
> +{
> +  EFI_USB_DATA_DIRECTION Direction;
> +  EFI_USB_IO_PROTOCOL    *UsbIo;
> +  EFI_STATUS             Status = EFI_TIMEOUT;
> +  UINT32                 CmdStatus = EFI_USB_NOERROR;
> +  int                    i;
> +  //
> +  // Determine the transfer direction
> +  //
> +  Direction = EfiUsbNoData;
> +  if (Request->Length != 0) {
> +    Direction = ((Request->RequestType & USB_ENDPOINT_DIR_IN) != 0)
> +                        ? EfiUsbDataIn : EfiUsbDataOut;
> +  }
> +
> +  //
> +  // Issue the command
> +  //
> +  UsbIo = NicDevice->UsbIo;
> +
> +  for (i = 0 ; i < 3 && EFI_TIMEOUT == Status; i++) {
> +    Status = UsbIo->UsbControlTransfer (UsbIo,
> +                                        Request,
> +                                        Direction,
> +                                        USB_BUS_TIMEOUT,
> +                                        Buffer,
> +                                        Request->Length,
> +                                        &CmdStatus);
> +  }
> +  //
> +  // Determine the operation status
> +  //
> +  if (EFI_ERROR(Status) || EFI_ERROR(CmdStatus))
> +    Status = EFI_DEVICE_ERROR;
> +  //
> +  // Return the operation status
> +  //
> +  return Status;
> +}
> +
> +EFI_STATUS
> +Ax88179MacRead (
> +  IN       UINT8      Offset,
> +  IN       UINT8      Length,
> +  IN       NIC_DEVICE *NicDevice,
> +  IN  OUT  VOID       *Data
> +  )
> +{
> +
> +  EFI_STATUS         Status;
> +  USB_DEVICE_REQUEST SetupMsg;
> +
> +  SetupMsg.RequestType = USB_REQ_TYPE_VENDOR
> +                       | USB_TARGET_DEVICE
> +                       | USB_ENDPOINT_DIR_IN;
> +
> +  SetupMsg.Request = ACCESS_MAC;
> +  SetupMsg.Value  = Offset;
> +  SetupMsg.Index  = Length;
> +  SetupMsg.Length = SetupMsg.Index;
> +
> +  Status = Ax88179UsbCommand (NicDevice,
> +                               &SetupMsg,
> +                               Data);
> +
> +  return Status;
> +
> +}
> +
> +EFI_STATUS
> +Ax88179MacWrite (
> +  IN       UINT8      Offset,
> +  IN       UINT8      Length,
> +  IN       NIC_DEVICE *NicDevice,
> +  IN  OUT  VOID       *Data
> + )
> +{
> +
> +  EFI_STATUS         Status;
> +  USB_DEVICE_REQUEST SetupMsg;
> +
> +  SetupMsg.RequestType = USB_REQ_TYPE_VENDOR
> +                       | USB_TARGET_DEVICE;
> +
> +  SetupMsg.Request = ACCESS_MAC;
> +  SetupMsg.Value  = Offset;
> +  SetupMsg.Index  = Length;
> +  SetupMsg.Length = SetupMsg.Index;
> +
> +  Status = Ax88179UsbCommand (NicDevice,
> +                               &SetupMsg,
> +                               Data);
> +
> +  return Status;
> +
> +}
> +
> +EFI_STATUS
> +Ax88179SetIInInterval (
> +  IN  NIC_DEVICE *NicDevice,
> +  IN  UINT8      Interval
> + )
> +{
> +
> +  EFI_STATUS         Status;
> +  USB_DEVICE_REQUEST SetupMsg;
> +
> +  SetupMsg.RequestType = USB_REQ_TYPE_VENDOR
> +                       | USB_TARGET_DEVICE;
> +
> +  SetupMsg.Request = 0x91;
> +  SetupMsg.Value  = Interval;
> +  SetupMsg.Index  = 0;
> +  SetupMsg.Length = 0;
> +
> +  Status = Ax88179UsbCommand (NicDevice,
> +                               &SetupMsg,
> +                               NULL);
> +
> +  return Status;
> +
> +}
> +
> +EFI_STATUS
> +Ax88179SetMedium (
> +  IN NIC_DEVICE *NicDevice
> + )
> +{
> +  UINT16     MediumStatus;
> +  EFI_STATUS Status;
> +
> +  MediumStatus = MEDIUMSTSMOD_RE | MEDIUMSTSMOD_ONE;
> +  if (NicDevice->FullDuplex) {
> +    MediumStatus |= MEDIUMSTSMOD_TFC | MEDIUMSTSMOD_RFC | MEDIUMSTSMOD_FD;
> +  } else {
> +    MediumStatus &= ~(MEDIUMSTSMOD_TFC | MEDIUMSTSMOD_RFC | MEDIUMSTSMOD_FD);
> +  }
> +  if (NicDevice->LinkSpeed1000Mbps) {
> +    MediumStatus |= MEDIUMSTSMOD_GM;
> +    MediumStatus &= ~MEDIUMSTSMOD_PS;
> +  } else {
> +    MediumStatus &= ~MEDIUMSTSMOD_GM;
> +    if (NicDevice->LinkSpeed100Mbps) {
> +      MediumStatus |= MEDIUMSTSMOD_PS;
> +    } else {
> +      MediumStatus &= ~MEDIUMSTSMOD_PS;
> +    }
> +  }
> +  Status  = Ax88179MacWrite (MEDIUMSTSMOD,
> +                             sizeof (MediumStatus),
> +                             NicDevice,
> +                             &MediumStatus);
> +  if (!EFI_ERROR (Status)) {
> +    NicDevice->CurMediumStatus = MediumStatus;
> +  }
> +
> +  return Status;
> +}
> +
> +
> +BOOLEAN
> +Ax88179GetLinkStatus (
> +  IN NIC_DEVICE *NicDevice
> +)
> +{
> +  UINT32              CmdStatus;
> +  EFI_USB_IO_PROTOCOL *UsbIo;
> +  UINT64              IntData = 0;
> +  UINTN               IntDataLeng = 8;
> +  EFI_STATUS          Status;
> +
> +  //
> +  // Issue the command
> +  //
> +  UsbIo = NicDevice->UsbIo;
> +  Status = UsbIo->UsbSyncInterruptTransfer(UsbIo,
> +                                        USB_ENDPOINT_DIR_IN | INTERRUPT_ENDPOINT,
> +                                        &IntData,
> +                                        &IntDataLeng,
> +                                        USB_BUS_TIMEOUT,
> +                                        &CmdStatus);
> +
> +  if (EFI_ERROR(Status) || EFI_ERROR(CmdStatus) || 0 == IntDataLeng)
> +    return FALSE;
> +
> +  return (IntData & 0x10000)? TRUE : FALSE;
> +
> +}
> +
> +EFI_STATUS
> +Ax88179BulkIn(
> +  IN NIC_DEVICE *NicDevice
> +)
> +{
> +  int i;
> +  UINT16  Val;
> +  UINTN               LengthInBytes = 0;
> +  UINTN               TmpLen = AX88179_MAX_BULKIN_SIZE;
> +  UINTN               CURBufSize = AX88179_MAX_BULKIN_SIZE;
> +  UINTN               PREBufSize = 0;
> +  EFI_STATUS          Status = EFI_NOT_READY;
> +  EFI_USB_IO_PROTOCOL *UsbIo;
> +  UINT32 TransferStatus;
> +
> +  NicDevice->SkipRXCnt = 0;
> +
> +  UsbIo = NicDevice->UsbIo;
> +  for (i = 0 ; i < (AX88179_MAX_BULKIN_SIZE / 512) && UsbIo != NULL; i++) {
> +    VOID* TmpAddr = 0;
> +
> +    if (NicDevice->SetZeroLen) {
> +      Val =  PHYPWRRSTCTL_IPRL | PHYPWRRSTCTL_BZ;
> +      Status = Ax88179MacWrite (PHYPWRRSTCTL,
> +                                 sizeof (Val),
> +                                 NicDevice,
> +                                 &Val);
> +      if (EFI_ERROR(Status)) {
> +        LengthInBytes = 0;
> +        Status = EFI_NOT_READY;
> +        goto no_pkt;
> +      }
> +      NicDevice->SetZeroLen = FALSE;
> +    }
> +    TmpAddr = (VOID*) &NicDevice->BulkInbuf[LengthInBytes];
> +
> +    Status =  EFI_NOT_READY;
> +    Status = UsbIo->UsbBulkTransfer (UsbIo,
> +                          USB_ENDPOINT_DIR_IN | BULK_IN_ENDPOINT,
> +                          TmpAddr,
> +                          &TmpLen,
> +                          BULKIN_TIMEOUT,
> +                          &TransferStatus);
> +
> +    if ((!EFI_ERROR (Status)) && (!EFI_ERROR (TransferStatus)) && TmpLen != 0) {
> +      LengthInBytes += TmpLen;
> +      if ((TmpLen % NicDevice->UsbMaxPktSize) != 0) {
> +        goto done;
> +      }
> +      CURBufSize = CURBufSize - TmpLen;
> +      TmpLen = CURBufSize;
> +      NicDevice->SetZeroLen = TRUE;
> +    } else if ((!EFI_ERROR (Status)) &&
> +               (!EFI_ERROR (TransferStatus)) &&
> +               (TmpLen == 0) &&
> +               LengthInBytes) {
> +      if (PREBufSize == CURBufSize) {
> +        goto done;
> +      }
> +      TmpLen = CURBufSize;
> +      PREBufSize = CURBufSize;
> +      NicDevice->SetZeroLen = TRUE;
> +    } else if ((!EFI_ERROR (Status)) &&
> +               (!EFI_ERROR (TransferStatus)) &&
> +               (TmpLen == 0)) {
> +      NicDevice->SetZeroLen = TRUE;
> +      LengthInBytes = 0;
> +      Status = EFI_NOT_READY;
> +      goto done;
> +    } else if (EFI_TIMEOUT == Status && EFI_USB_ERR_TIMEOUT == TransferStatus) {
> +      NicDevice->SetZeroLen = TRUE;
> +      LengthInBytes = 0;
> +      Status = EFI_NOT_READY;
> +      goto done;
> +    } else {
> +      NicDevice->SetZeroLen = TRUE;
> +      LengthInBytes = 0;
> +      Status = EFI_NOT_READY;
> +      goto done;
> +    }
> +  }
> +
> +done:
> +  if (LengthInBytes != 0) {
> +    UINT16 tmplen = 0;
> +    UINT16 TmpPktCnt = 0;
> +
> +    TmpPktCnt = *((UINT16 *) (NicDevice->BulkInbuf + LengthInBytes - 4));
> +    tmplen =  *((UINT16*) (NicDevice->BulkInbuf + LengthInBytes - 2));
> +
> +    if (((UINTN)(((TmpPktCnt * 4 + 4 + 7) & 0xfff8) + tmplen)) == LengthInBytes) {
> +      NicDevice->PktCnt = TmpPktCnt;
> +      NicDevice->CurPktHdrOff = NicDevice->BulkInbuf + tmplen;
> +      NicDevice->CurPktOff = NicDevice->BulkInbuf;
> +      *((UINT16 *) (NicDevice->BulkInbuf + LengthInBytes - 4)) = 0;
> +      *((UINT16*) (NicDevice->BulkInbuf + LengthInBytes - 2)) = 0;
> +      Status = EFI_SUCCESS;
> +    } else {
> +      Status = EFI_NOT_READY;
> +    }
> +  } else {
> +    Status = EFI_NOT_READY;
> +  }
> +no_pkt:
> +   return Status;
> +}
> diff --git a/Drivers/ASIX/Bus/Usb/UsbNetworking/Ax88179/ComponentName.c
> b/Drivers/ASIX/Bus/Usb/UsbNetworking/Ax88179/ComponentName.c
> new file mode 100644
> index 000000000000..daf917ce5b7d
> --- /dev/null
> +++ b/Drivers/ASIX/Bus/Usb/UsbNetworking/Ax88179/ComponentName.c
> @@ -0,0 +1,223 @@
> +/** @file
> +  UEFI Component Name(2) protocol implementation.
> +
> +  Copyright (c) 2011, Intel Corporation. All rights reserved.
> +  Copyright (c) 2020, ARM Limited. All rights reserved
> +
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include "Ax88179.h"
> +
> +/**
> +  EFI Component Name Protocol declaration
> +**/
> +GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL  gComponentName = {
> +  GetDriverName,
> +  GetControllerName,
> +  "eng"
> +};
> +
> +/**
> +  EFI Component Name 2 Protocol declaration
> +**/
> +GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gComponentName2 = {
> +  (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) GetDriverName,
> +  (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) GetControllerName,
> +  "en"
> +};
> +
> +
> +/**
> +  Driver name table declaration
> +**/
> +GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE
> +mDriverNameTable[] = {
> +  {"eng;en", L"ASIX AX88179 Ethernet Driver 2.9.0"},
> +  {NULL,  NULL}
> +};
> +
> +/**
> +  Controller name table declaration
> +**/
> +GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE
> +mControllerNameTable[] = {
> +  {"eng;en", L"AX88179 USB3.0 Gigabit Ethernet Controller"},
> +  {NULL,  NULL}
> +};
> +
> +/**
> +  Retrieves a Unicode string that is the user readable name of the driver.
> +
> +  This function retrieves the user readable name of a driver in the form of a
> +  Unicode string. If the driver specified by This has a user readable name in
> +  the language specified by Language, then a pointer to the driver name is
> +  returned in DriverName, and EFI_SUCCESS is returned. If the driver specified
> +  by This does not support the language specified by Language,
> +  then EFI_UNSUPPORTED is returned.
> +
> +  @param [in] This             A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
> +                                EFI_COMPONENT_NAME_PROTOCOL instance.
> +  @param [in] Language         A pointer to a Null-terminated ASCII string
> +                                array indicating the language. This is the
> +                                language of the driver name that the caller is
> +                                requesting, and it must match one of the
> +                                languages specified in SupportedLanguages. The
> +                                number of languages supported by a driver is up
> +                                to the driver writer. Language is specified
> +                                in RFC 3066 or ISO 639-2 language code format.
> +  @param [out] DriverName     A pointer to the Unicode string to return.
> +                                This Unicode string is the name of the
> +                                driver specified by This in the language
> +                                specified by Language.
> +
> +  @retval EFI_SUCCESS           The Unicode string for the Driver specified by
> +                                This and the language specified by Language was
> +                                returned in DriverName.
> +  @retval EFI_INVALID_PARAMETER Language is NULL.
> +  @retval EFI_INVALID_PARAMETER DriverName is NULL.
> +  @retval EFI_UNSUPPORTED       The driver specified by This does not support
> +                                the language specified by Language.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +GetDriverName (
> +  IN  EFI_COMPONENT_NAME_PROTOCOL *This,
> +  IN  CHAR8                       *Language,
> +  OUT CHAR16                      **DriverName
> +  )
> +{
> +  EFI_STATUS Status;
> +
> +
> +  Status = LookupUnicodeString2 (
> +             Language,
> +             This->SupportedLanguages,
> +             mDriverNameTable,
> +             DriverName,
> +             (BOOLEAN)(This == &gComponentName)
> +             );
> +
> +  return Status;
> +}
> +
> +/**
> +  Retrieves a Unicode string that is the user readable name of the controller
> +  that is being managed by a driver.
> +
> +  This function retrieves the user readable name of the controller specified by
> +  ControllerHandle and ChildHandle in the form of a Unicode string. If the
> +  driver specified by This has a user readable name in the language specified by
> +  Language, then a pointer to the controller name is returned in ControllerName,
> +  and EFI_SUCCESS is returned.  If the driver specified by This is not currently
> +  managing the controller specified by ControllerHandle and ChildHandle,
> +  then EFI_UNSUPPORTED is returned.  If the driver specified by This does not
> +  support the language specified by Language, then EFI_UNSUPPORTED is returned.
> +
> +  @param [in] This             A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
> +                                EFI_COMPONENT_NAME_PROTOCOL instance.
> +  @param [in] ControllerHandle  The handle of a controller that the driver
> +                                specified by This is managing.  This handle
> +                                specifies the controller whose name is to be
> +                                returned.
> +  @param [in] ChildHandle       The handle of the child controller to retrieve
> +                                the name of.  This is an optional parameter that
> +                                may be NULL.  It will be NULL for device
> +                                drivers.  It will also be NULL for a bus drivers
> +                                that wish to retrieve the name of the bus
> +                                controller.  It will not be NULL for a bus
> +                                driver that wishes to retrieve the name of a
> +                                child controller.
> +  @param [in] Language         A pointer to a Null-terminated ASCII string
> +                                array indicating the language.  This is the
> +                                language of the driver name that the caller is
> +                                requesting, and it must match one of the
> +                                languages specified in SupportedLanguages. The
> +                                number of languages supported by a driver is up
> +                                to the driver writer. Language is specified in
> +                                RFC 3066 or ISO 639-2 language code format.
> +  @param [out] ControllerName A pointer to the Unicode string to return.
> +                                This Unicode string is the name of the
> +                                controller specified by ControllerHandle and
> +                                ChildHandle in the language specified by
> +                                Language from the point of view of the driver
> +                                specified by This.
> +
> +  @retval EFI_SUCCESS           The Unicode string for the user readable name in
> +                                the language specified by Language for the
> +                                driver specified by This was returned in
> +                                DriverName.
> +  @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE.
> +  @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid
> +                                EFI_HANDLE.
> +  @retval EFI_INVALID_PARAMETER Language is NULL.
> +  @retval EFI_INVALID_PARAMETER ControllerName is NULL.
> +  @retval EFI_UNSUPPORTED       The driver specified by This is not currently
> +                                managing the controller specified by
> +                                ControllerHandle and ChildHandle.
> +  @retval EFI_UNSUPPORTED       The driver specified by This does not support
> +                                the language specified by Language.
> +
> +**/
> +
> +
> +
> +EFI_STATUS
> +EFIAPI
> +GetControllerName (
> +  IN          EFI_COMPONENT_NAME_PROTOCOL *This,
> +  IN          EFI_HANDLE                  ControllerHandle,
> +  IN OPTIONAL EFI_HANDLE                  ChildHandle,
> +  IN          CHAR8                       *Language,
> +  OUT         CHAR16                      **ControllerName
> +  )
> +{
> +
> +  EFI_STATUS                  Status;
> +  EFI_USB_IO_PROTOCOL         *UsbIoProtocol;
> +
> +  //
> +  // This is a device driver, so ChildHandle must be NULL.
> +  //
> +  if (ChildHandle != NULL) {
> +    return EFI_UNSUPPORTED;
> +  }
> +
> +  //
> +  // Check Controller's handle
> +  //
> +  Status = gBS->OpenProtocol (
> +                  ControllerHandle,
> +                  &gEfiUsbIoProtocolGuid,
> +                  (VOID **) &UsbIoProtocol,
> +                  gDriverBinding.DriverBindingHandle,
> +                  ControllerHandle,
> +                  EFI_OPEN_PROTOCOL_BY_DRIVER
> +                  );
> +  if (!EFI_ERROR (Status)) {
> +    gBS->CloseProtocol (
> +           ControllerHandle,
> +           &gEfiUsbIoProtocolGuid,
> +           gDriverBinding.DriverBindingHandle,
> +           ControllerHandle
> +           );
> +    return EFI_UNSUPPORTED;
> +  }
> +
> +  if (Status != EFI_ALREADY_STARTED) {
> +    return EFI_UNSUPPORTED;
> +  }
> +
> +  Status =  LookupUnicodeString2 (
> +           Language,
> +            This->SupportedLanguages,
> +           mControllerNameTable,
> +           ControllerName,
> +           (BOOLEAN)(This == &gComponentName)
> +           );
> +
> +  return  Status;
> +}
> +
> diff --git a/Drivers/ASIX/Bus/Usb/UsbNetworking/Ax88179/DriverBinding.c
> b/Drivers/ASIX/Bus/Usb/UsbNetworking/Ax88179/DriverBinding.c
> new file mode 100644
> index 000000000000..7a287cfbfb5d
> --- /dev/null
> +++ b/Drivers/ASIX/Bus/Usb/UsbNetworking/Ax88179/DriverBinding.c
> @@ -0,0 +1,639 @@
> +/** @file
> +  Implement the driver binding protocol for Asix AX88179 Ethernet driver.
> +
> +  Copyright (c) 2011, Intel Corporation
> +  Copyright (c) 2020, ARM Limited. All rights reserved.
> +
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include "Ax88179.h"
> +
> +/**
> +  Verify the controller type
> +
> +  @param [in] This                Protocol instance pointer.
> +  @param [in] Controller           Handle of device to test.
> +  @param [in] pRemainingDevicePath Not used.
> +
> +  @retval EFI_SUCCESS          This driver supports this device.
> +  @retval other                This driver does not support this device.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +DriverSupported (
> +  IN EFI_DRIVER_BINDING_PROTOCOL *This,
> +  IN EFI_HANDLE                  Controller,
> +  IN EFI_DEVICE_PATH_PROTOCOL    *RemainingDevicePath
> +  )
> +{
> +  EFI_USB_DEVICE_DESCRIPTOR Device;
> +  EFI_USB_IO_PROTOCOL       *UsbIo;
> +  EFI_STATUS                Status;
> +
> +  //
> +  //  Connect to the USB stack
> +  //
> +  Status = gBS->OpenProtocol (
> +                  Controller,
> +                  &gEfiUsbIoProtocolGuid,
> +                  (VOID **) &UsbIo,
> +                  This->DriverBindingHandle,
> +                  Controller,
> +                  EFI_OPEN_PROTOCOL_BY_DRIVER
> +                  );
> +  if (!EFI_ERROR (Status)) {
> +
> +    //
> +    //  Get the interface descriptor to check the USB class and find a transport
> +    //  protocol handler.
> +    //
> +    Status = UsbIo->UsbGetDeviceDescriptor (UsbIo, &Device);
> +    if (EFI_ERROR(Status)) {
> +      Status = EFI_UNSUPPORTED;
> +    } else {
> +      //
> +      //  Validate the adapter
> +      //
> +      if ((VENDOR_ID == Device.IdVendor) &&
> +          (PRODUCT_ID == Device.IdProduct)) {
> +        Status = EFI_SUCCESS;
> +      } else if ((VENDOR_ID == Device.IdVendor) &&
> +                 (PRODUCT_ID_178A == Device.IdProduct)) {
> +        Status = EFI_SUCCESS;
> +      } else {
> +        Status = EFI_UNSUPPORTED;
> +      }
> +    }
> +
> +    //
> +    //  Done with the USB stack
> +    //
> +    gBS->CloseProtocol (
> +           Controller,
> +           &gEfiUsbIoProtocolGuid,
> +           This->DriverBindingHandle,
> +           Controller
> +           );
> +  }
> +
> +  //
> +  //  Return the device supported status
> +  //
> +  return Status;
> +}
> +
> +
> +/**
> +  Start this driver on Controller by opening UsbIo and DevicePath protocols.
> +  Initialize PXE structures, create a copy of the Controller Device Path with the
> +  NIC's MAC address apEnded to it, install the NetworkInterfaceIdentifier protocol
> +  on the newly created Device Path.
> +
> +  @param [in] This                Protocol instance pointer.
> +  @param [in] Controller           Handle of device to work with.
> +  @param [in] pRemainingDevicePath Not used, always produce all possible children.
> +
> +  @retval EFI_SUCCESS          This driver is added to Controller.
> +  @retval other                This driver does not support this device.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +DriverStart (
> +  IN EFI_DRIVER_BINDING_PROTOCOL *This,
> +  IN EFI_HANDLE                  Controller,
> +  IN EFI_DEVICE_PATH_PROTOCOL    *RemainingDevicePath
> +  )
> +{
> +  EFI_STATUS                Status;
> +  NIC_DEVICE                *NicDevice;
> +  UINTN                     LengthInBytes;
> +  EFI_DEVICE_PATH_PROTOCOL  *ParentDevicePath = NULL;
> +  MAC_ADDR_DEVICE_PATH      MacDeviceNode;
> +
> +  //
> +  //  Allocate the device structure
> +  //
> +  LengthInBytes = sizeof (*NicDevice);
> +  Status = gBS->AllocatePool (
> +                  EfiBootServicesData,
> +                  LengthInBytes,
> +                  (VOID **) &NicDevice
> +                  );
> +
> +  if (EFI_ERROR (Status)) {
> +    goto ERR;
> +  }
> +
> +  //
> +  //  Set the structure signature
> +  //
> +  ZeroMem (NicDevice, LengthInBytes);
> +  NicDevice->Signature = DEV_SIGNATURE;
> +
> +  Status = gBS->OpenProtocol (
> +                    Controller,
> +                    &gEfiUsbIoProtocolGuid,
> +                    (VOID **) &NicDevice->UsbIo,
> +                    This->DriverBindingHandle,
> +                    Controller,
> +                    EFI_OPEN_PROTOCOL_BY_DRIVER
> +                    );
> +
> +  if (EFI_ERROR (Status)) {
> +    goto ERR;
> +  }
> +
> +  //
> +  //  Initialize the simple network protocol
> +  //
> +  Status = SN_Setup (NicDevice);
> +
> +  if (EFI_ERROR(Status)){
> +    gBS->CloseProtocol (
> +              Controller,
> +              &gEfiUsbIoProtocolGuid,
> +              This->DriverBindingHandle,
> +              Controller
> +              );
> +    goto ERR;
> +  }
> +
> +  //
> +  // Set Device Path
> +  //
> +  Status = gBS->OpenProtocol (
> +                  Controller,
> +                  &gEfiDevicePathProtocolGuid,
> +                  (VOID **) &ParentDevicePath,
> +                  This->DriverBindingHandle,
> +                  Controller,
> +                  EFI_OPEN_PROTOCOL_BY_DRIVER
> +                  );
> +  if (EFI_ERROR(Status)) {
> +    gBS->CloseProtocol (
> +              Controller,
> +              &gEfiUsbIoProtocolGuid,
> +              This->DriverBindingHandle,
> +              Controller
> +              );
> +    goto ERR;
> +  }
> +
> +  ZeroMem (&MacDeviceNode, sizeof (MAC_ADDR_DEVICE_PATH));
> +  MacDeviceNode.Header.Type = MESSAGING_DEVICE_PATH;
> +  MacDeviceNode.Header.SubType = MSG_MAC_ADDR_DP;
> +
> +  SetDevicePathNodeLength (&MacDeviceNode.Header, sizeof (MAC_ADDR_DEVICE_PATH));
> +
> +  CopyMem (&MacDeviceNode.MacAddress,
> +           &NicDevice->SimpleNetworkData.CurrentAddress,
> +           PXE_HWADDR_LEN_ETHER);
> +
> +  MacDeviceNode.IfType = NicDevice->SimpleNetworkData.IfType;
> +
> +  NicDevice->MyDevPath = AppendDevicePathNode (
> +                                          ParentDevicePath,
> +                                          (EFI_DEVICE_PATH_PROTOCOL *) &MacDeviceNode
> +                                          );
> +
> +  NicDevice->Controller = NULL;
> +
> +  //
> +  //  Install both the simple network and device path protocols.
> +  //
> +  Status = gBS->InstallMultipleProtocolInterfaces (
> +                          &NicDevice->Controller,
> +                          &gEfiCallerIdGuid,
> +                          NicDevice,
> +                          &gEfiSimpleNetworkProtocolGuid,
> +                          &NicDevice->SimpleNetwork,
> +                          &gEfiDevicePathProtocolGuid,
> +                          NicDevice->MyDevPath,
> +                          NULL
> +                          );
> +
> +  if (EFI_ERROR(Status)){
> +    gBS->CloseProtocol (
> +              Controller,
> +              &gEfiDevicePathProtocolGuid,
> +              This->DriverBindingHandle,
> +              Controller);
> +    gBS->CloseProtocol (
> +              Controller,
> +              &gEfiUsbIoProtocolGuid,
> +              This->DriverBindingHandle,
> +              Controller
> +              );
> +    goto ERR;
> +  }
> +
> +  //
> +  // Open For Child Device
> +  //
> +  Status = gBS->OpenProtocol (
> +                  Controller,
> +                  &gEfiUsbIoProtocolGuid,
> +                  (VOID **) &NicDevice->UsbIo,
> +                  This->DriverBindingHandle,
> +                  NicDevice->Controller,
> +                  EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
> +                  );
> +
> +  if (EFI_ERROR(Status)){
> +    gBS->UninstallMultipleProtocolInterfaces (
> +                          &NicDevice->Controller,
> +                          &gEfiCallerIdGuid,
> +                          NicDevice,
> +                          &gEfiSimpleNetworkProtocolGuid,
> +                          &NicDevice->SimpleNetwork,
> +                          &gEfiDevicePathProtocolGuid,
> +                          NicDevice->MyDevPath,
> +                          NULL
> +                          );
> +    gBS->CloseProtocol (
> +              Controller,
> +              &gEfiDevicePathProtocolGuid,
> +              This->DriverBindingHandle,
> +              Controller);
> +    gBS->CloseProtocol (
> +              Controller,
> +              &gEfiUsbIoProtocolGuid,
> +              This->DriverBindingHandle,
> +              Controller
> +              );
> +    goto ERR;
> +  }
> +
> +  return Status;
> +
> +
> +ERR:
> +
> +  if (NicDevice->BulkInbuf != NULL) {
> +    gBS->FreePool (NicDevice->BulkInbuf);
> +  }
> +
> +  if (NicDevice->TxTest != NULL) {
> +    gBS->FreePool (NicDevice->TxTest);
> +  }
> +
> +  if (NicDevice->MyDevPath != NULL) {
> +    gBS->FreePool (NicDevice->MyDevPath);
> +  }
> +
> +  if (NicDevice != NULL) {
> +    gBS->FreePool (NicDevice);
> +  }
> +
> +  return Status;
> +}
> +
> +/**
> +  Stop this driver on Controller by removing NetworkInterfaceIdentifier protocol and
> +  closing the DevicePath and PciIo protocols on Controller.
> +
> +  @param [in] This                Protocol instance pointer.
> +  @param [in] Controller           Handle of device to stop driver on.
> +  @param [in] NumberOfChildren     How many children need to be stopped.
> +  @param [in] pChildHandleBuffer   Not used.
> +
> +  @retval EFI_SUCCESS          This driver is removed Controller.
> +  @retval EFI_DEVICE_ERROR     The device could not be stopped due to a device error.
> +  @retval other                This driver was not removed from this device.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +DriverStop (
> +  IN  EFI_DRIVER_BINDING_PROTOCOL * This,
> +  IN  EFI_HANDLE Controller,
> +  IN  UINTN NumberOfChildren,
> +  IN  EFI_HANDLE * ChildHandleBuffer
> +  )
> +{
> +  BOOLEAN                     AllChildrenStopped;
> +  EFI_SIMPLE_NETWORK_PROTOCOL *SimpleNetwork;
> +  EFI_STATUS                  Status = EFI_SUCCESS;
> +  NIC_DEVICE                  *NicDevice;
> +  UINTN                       Index;
> +
> +  //
> +  // Complete all outstanding transactions to Controller.
> +  // Don't allow any new transaction to Controller to be started.
> +  //
> +  if (NumberOfChildren == 0) {
> +    Status = gBS->OpenProtocol (
> +                      Controller,
> +                      &gEfiSimpleNetworkProtocolGuid,
> +                      (VOID **) &SimpleNetwork,
> +                      This->DriverBindingHandle,
> +                      Controller,
> +                      EFI_OPEN_PROTOCOL_GET_PROTOCOL
> +                      );
> +
> +    if (EFI_ERROR(Status)) {
> +      //
> +      // This is a 2nd type handle(multi-lun root), it needs to close devicepath
> +      // and usbio protocol.
> +      //
> +      gBS->CloseProtocol (
> +                Controller,
> +                &gEfiDevicePathProtocolGuid,
> +                This->DriverBindingHandle,
> +                Controller
> +                );
> +      gBS->CloseProtocol (
> +                Controller,
> +                &gEfiUsbIoProtocolGuid,
> +                This->DriverBindingHandle,
> +                Controller
> +                );
> +      return EFI_SUCCESS;
> +    }
> +
> +    NicDevice = DEV_FROM_SIMPLE_NETWORK (SimpleNetwork);
> +
> +    Status = gBS->UninstallMultipleProtocolInterfaces (
> +                          Controller,
> +                          &gEfiCallerIdGuid,
> +                          NicDevice,
> +                          &gEfiSimpleNetworkProtocolGuid,
> +                          &NicDevice->SimpleNetwork,
> +                          &gEfiDevicePathProtocolGuid,
> +                          NicDevice->MyDevPath,
> +                          NULL
> +                          );
> +
> +    if (EFI_ERROR (Status)) {
> +      return Status;
> +    }
> +    //
> +    // Close the bus driver
> +    //
> +    Status = gBS->CloseProtocol (
> +                        Controller,
> +                        &gEfiDevicePathProtocolGuid,
> +                        This->DriverBindingHandle,
> +                        Controller
> +                        );
> +
> +    Status = gBS->CloseProtocol (
> +                        Controller,
> +                        &gEfiUsbIoProtocolGuid,
> +                        This->DriverBindingHandle,
> +                        Controller
> +                        );
> +    return EFI_SUCCESS;
> +  }
> +
> +  AllChildrenStopped = TRUE;
> +
> +  for (Index = 0; Index < NumberOfChildren; Index++) {
> +    Status = gBS->OpenProtocol (
> +                      ChildHandleBuffer[Index],
> +                      &gEfiSimpleNetworkProtocolGuid,
> +                      (VOID **) &SimpleNetwork,
> +                      This->DriverBindingHandle,
> +                      Controller,
> +                      EFI_OPEN_PROTOCOL_GET_PROTOCOL
> +                      );
> +
> +    if (EFI_ERROR (Status)) {
> +      AllChildrenStopped = FALSE;
> +      continue;
> +    }
> +
> +    NicDevice = DEV_FROM_SIMPLE_NETWORK (SimpleNetwork);
> +
> +    gBS->CloseProtocol (
> +              Controller,
> +              &gEfiUsbIoProtocolGuid,
> +              This->DriverBindingHandle,
> +              ChildHandleBuffer[Index]
> +              );
> +
> +    Status = gBS->UninstallMultipleProtocolInterfaces (
> +                          ChildHandleBuffer[Index],
> +                          &gEfiCallerIdGuid,
> +                          NicDevice,
> +                          &gEfiSimpleNetworkProtocolGuid,
> +                          &NicDevice->SimpleNetwork,
> +                          &gEfiDevicePathProtocolGuid,
> +                          NicDevice->MyDevPath,
> +                          NULL
> +                          );
> +
> +    if (EFI_ERROR (Status)) {
> +      Status = gBS->OpenProtocol (
> +                        Controller,
> +                        &gEfiUsbIoProtocolGuid,
> +                        (VOID **) &NicDevice->UsbIo,
> +                        This->DriverBindingHandle,
> +                        ChildHandleBuffer[Index],
> +                        EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
> +                        );
> +    } else {
> +      if (NicDevice->BulkInbuf != NULL) {
> +        gBS->FreePool (NicDevice->BulkInbuf);
> +      }
> +
> +      if (NicDevice->TxTest != NULL) {
> +        gBS->FreePool (NicDevice->TxTest);
> +      }
> +
> +      if (NicDevice->MyDevPath != NULL) {
> +        gBS->FreePool (NicDevice->MyDevPath);
> +      }
> +
> +      if (NicDevice != NULL) {
> +        gBS->FreePool (NicDevice);
> +      }
> +    }
> +  }
> +
> +  if (!AllChildrenStopped) {
> +    return EFI_DEVICE_ERROR;
> +  }
> +
> +  return EFI_SUCCESS;
> +}
> +
> +
> +/**
> +  Driver binding protocol declaration
> +**/
> +EFI_DRIVER_BINDING_PROTOCOL  gDriverBinding = {
> +  DriverSupported,
> +  DriverStart,
> +  DriverStop,
> +  0xa,
> +  NULL,
> +  NULL
> +};
> +
> +
> +/**
> +  Ax88179 driver unload routine.
> +
> +  @param [in] ImageHandle       Handle for the image.
> +
> +  @retval EFI_SUCCESS           Image may be unloaded
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +DriverUnload (
> +  IN EFI_HANDLE ImageHandle
> +  )
> +{
> +  UINTN       BufferSize;
> +  UINTN       Index;
> +  UINTN       Max;
> +  EFI_HANDLE  *Handle;
> +  EFI_STATUS  Status;
> +
> +  //
> +  //  Determine which devices are using this driver
> +  //
> +  BufferSize = 0;
> +  Handle = NULL;
> +  Status = gBS->LocateHandle (
> +                  ByProtocol,
> +                  &gEfiCallerIdGuid,
> +                  NULL,
> +                  &BufferSize,
> +                  NULL);
> +  if (EFI_BUFFER_TOO_SMALL == Status) {
> +    for (; ;) {
> +      //
> +      //  One or more block IO devices are present
> +      //
> +      Status = gBS->AllocatePool (
> +                      EfiBootServicesData,
> +                      BufferSize,
> +                      (VOID **) &Handle
> +                      );
> +      if (EFI_ERROR (Status)) {
> +        break;
> +      }
> +
> +      //
> +      //  Locate the block IO devices
> +      //
> +      Status = gBS->LocateHandle (
> +                      ByProtocol,
> +                      &gEfiCallerIdGuid,
> +                      NULL,
> +                      &BufferSize,
> +                      Handle);
> +      if (EFI_ERROR (Status)) {
> +        //
> +        //  Error getting handles
> +        //
> +
> +        break;
> +      }
> +
> +      //
> +      //  Remove any use of the driver
> +      //
> +      Max = BufferSize / sizeof (Handle[0]);
> +      for (Index = 0; Max > Index; Index++) {
> +        Status = DriverStop (&gDriverBinding,
> +                              Handle[Index],
> +                              0,
> +                              NULL);
> +        if (EFI_ERROR (Status)) {
> +          break;
> +        }
> +      }
> +      break;
> +    }
> +  } else {
> +    if (EFI_NOT_FOUND == Status) {
> +      //
> +      //  No devices were found
> +      //
> +      Status = EFI_SUCCESS;
> +    }
> +  }
> +
> +  //
> +  //  Free the handle array
> +  //
> +  if (Handle != NULL) {
> +    gBS->FreePool (Handle);
> +  }
> +
> +  //
> +  //  Remove the protocols installed by the EntryPoint routine.
> +  //
> +  if (!EFI_ERROR (Status)) {
> +    gBS->UninstallMultipleProtocolInterfaces (
> +            ImageHandle,
> +            &gEfiDriverBindingProtocolGuid,
> +            &gDriverBinding,
> +            &gEfiComponentNameProtocolGuid,
> +            &gComponentName,
> +            &gEfiComponentName2ProtocolGuid,
> +            &gComponentName2,
> +            NULL
> +            );
> +  }
> +
> +  //
> +  //  Return the unload status
> +  //
> +  return Status;
> +}
> +
> +
> +/**
> +Ax88179 driver entry point.
> +
> + at param [in] ImageHandle       Handle for the image.
> + at param [in] SystemTable       Address of the system table.
> +
> + at retval EFI_SUCCESS           Image successfully loaded.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +EntryPoint (
> +  IN EFI_HANDLE       ImageHandle,
> +  IN EFI_SYSTEM_TABLE *SystemTable
> +  )
> +{
> +  EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
> +  EFI_STATUS                Status;
> +
> +  //
> +  //  Enable unload support
> +  //
> +  Status = gBS->HandleProtocol (
> +                  gImageHandle,
> +                  &gEfiLoadedImageProtocolGuid,
> +                  (VOID **)&LoadedImage
> +                  );
> +  if (!EFI_ERROR (Status)) {
> +    LoadedImage->Unload = DriverUnload;
> +  }
> +
> +  //
> +  //  Add the driver to the list of drivers
> +  //
> +  Status = EfiLibInstallDriverBindingComponentName2 (
> +             ImageHandle,
> +             SystemTable,
> +             &gDriverBinding,
> +             ImageHandle,
> +             &gComponentName,
> +             &gComponentName2
> +             );
> +
> +  return Status;
> +}
> diff --git a/Drivers/ASIX/Bus/Usb/UsbNetworking/Ax88179/SimpleNetwork.c
> b/Drivers/ASIX/Bus/Usb/UsbNetworking/Ax88179/SimpleNetwork.c
> new file mode 100644
> index 000000000000..948b73031463
> --- /dev/null
> +++ b/Drivers/ASIX/Bus/Usb/UsbNetworking/Ax88179/SimpleNetwork.c
> @@ -0,0 +1,1548 @@
> +/** @file
> +  Provides the Simple Network functions.
> +
> +  Copyright (c) 2011, Intel Corporation
> +  Copyright (c) 2020, ARM Limited. All rights reserved.
> +
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include "Ax88179.h"
> +
> +/**
> +  This function updates the filtering on the receiver.
> +
> +  This support routine calls ::Ax88179MacAddressSet to update
> +  the MAC address.  This routine then rebuilds the multicast
> +  hash by calling ::Ax88179MulticastClear and ::Ax88179MulticastSet.
> +  Finally this routine enables the receiver by calling
> +  ::Ax88179RxControl.
> +
> +  @param [in] SimpleNetwork    Simple network mode pointer
> +
> +  @retval EFI_SUCCESS           This operation was successful.
> +  @retval EFI_NOT_STARTED       The network interface was not started.
> +  @retval EFI_INVALID_PARAMETER SimpleNetwork parameter was NULL or did not point to a valid
> +                                EFI_SIMPLE_NETWORK_PROTOCOL structure.
> +  @retval EFI_DEVICE_ERROR      The command could not be sent to the network interface.
> +  @retval EFI_UNSUPPORTED       The increased buffer size feature is not supported.
> +
> +**/
> +EFI_STATUS
> +ReceiveFilterUpdate (
> +  IN EFI_SIMPLE_NETWORK_PROTOCOL *SimpleNetwork
> +  )
> +{
> +  EFI_SIMPLE_NETWORK_MODE *Mode;
> +  NIC_DEVICE              *NicDevice;
> +  EFI_STATUS              Status;
> +  UINT32                  Index;
> +
> +  //
> +  // Set the MAC address
> +  //
> +  NicDevice = DEV_FROM_SIMPLE_NETWORK (SimpleNetwork);
> +  Mode = SimpleNetwork->Mode;
> +  //
> +  // Clear the multicast hash table
> +  //
> +  Ax88179MulticastClear (NicDevice);
> +
> +  //
> +  // Load the multicast hash table
> +  //
> +  if ((Mode->ReceiveFilterSetting & EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST) != 0) {
> +    for (Index = 0; Index < Mode->MCastFilterCount; Index++) {
> +      //
> +      // Enable the next multicast address
> +      //
> +      Ax88179MulticastSet (NicDevice,
> +                            &Mode->MCastFilter[Index].Addr[0]);
> +    }
> +  }
> +
> +  //
> +  // Enable the receiver
> +  //
> +  Status = Ax88179RxControl (NicDevice, Mode->ReceiveFilterSetting);
> +
> +  return Status;
> +}
> +
> +
> +/**
> +  This function updates the SNP driver status.
> +
> +  This function gets the current interrupt and recycled transmit
> +  buffer status from the network interface.  The interrupt status
> +  and the media status are returned as a bit mask in InterruptStatus.
> +  If InterruptStatus is NULL, the interrupt status will not be read.
> +  Upon successful return of the media status, the MediaPresent field
> +  of EFI_SIMPLE_NETWORK_MODE will be updated to reflect any change
> +  of media status.  If TxBuf is not NULL, a recycled transmit buffer
> +  address will be retrived.  If a recycled transmit buffer address
> +  is returned in TxBuf, then the buffer has been successfully
> +  transmitted, and the status for that buffer is cleared.
> +
> +  This function calls ::Ax88179Rx to update the media status and
> +  queue any receive packets.
> +
> +  @param [in] SimpleNetwork    Protocol instance pointer
> +  @param [in] InterruptStatus  A pointer to the bit mask of the current active interrupts.
> +                                If this is NULL, the interrupt status will not be read from
> +                                the device.  If this is not NULL, the interrupt status will
> +                                be read from teh device.  When the interrupt status is read,
> +                                it will also be cleared.  Clearing the transmit interrupt
> +                                does not empty the recycled transmit buffer array.
> +  @param [out] TxBuf          Recycled transmit buffer address.  The network interface will
> +                                not transmit if its internal recycled transmit buffer array is
> +                                full.  Reading the transmit buffer does not clear the transmit
> +                                interrupt.  If this is NULL, then the transmit buffer status
> +                                will not be read.  If there are not transmit buffers to recycle
> +                                and TxBuf is not NULL, *TxBuf will be set to NULL.
> +
> +  @retval EFI_SUCCESS           This operation was successful.
> +  @retval EFI_NOT_STARTED       The network interface was not started.
> +  @retval EFI_INVALID_PARAMETER SimpleNetwork parameter was NULL or did not point to a valid
> +                                EFI_SIMPLE_NETWORK_PROTOCOL structure.
> +  @retval EFI_DEVICE_ERROR      The command could not be sent to the network interface.
> +
> +**/
> +
> +EFI_STATUS
> +EFIAPI
> +SN_GetStatus (
> +  IN  EFI_SIMPLE_NETWORK_PROTOCOL *SimpleNetwork,
> +  OUT UINT32                      *InterruptStatus,
> +  OUT VOID                        **TxBuf
> +  )
> +{
> +  EFI_SIMPLE_NETWORK_MODE *Mode;
> +  NIC_DEVICE              *NicDevice;
> +  EFI_STATUS              Status = EFI_SUCCESS;
> +  EFI_TPL                 TplPrevious;
> +
> +  TplPrevious = gBS->RaiseTPL(TPL_CALLBACK);
> +  //
> +  // Verify the parameters
> +  //
> +  if ((SimpleNetwork != NULL) && (SimpleNetwork->Mode != NULL)) {
> +    //
> +    // Return the transmit buffer
> +    //
> +    NicDevice = DEV_FROM_SIMPLE_NETWORK (SimpleNetwork);
> +
> +    if ((TxBuf != NULL) && (NicDevice->TxBuffer != NULL)) {
> +      *TxBuf = NicDevice->TxBuffer;
> +      NicDevice->TxBuffer = NULL;
> +    }
> +
> +    Mode = SimpleNetwork->Mode;
> +    if (EfiSimpleNetworkInitialized == Mode->State) {
> +      if ((TxBuf == NULL) && (InterruptStatus == NULL)) {
> +        Status = EFI_INVALID_PARAMETER;
> +        goto EXIT;
> +      }
> +
> +#if REPORTLINK
> +#else
> +      if (!NicDevice->LinkUp || !NicDevice->Complete) {
> +#endif
> +        Status = Ax88179NegotiateLinkComplete (NicDevice,
> +                                                &NicDevice->PollCount,
> +                                                &NicDevice->Complete,
> +                                                &NicDevice->LinkUp,
> +                                                &NicDevice->LinkSpeed100Mbps,
> +                                                &NicDevice->LinkSpeed1000Mbps,
> +                                                &NicDevice->FullDuplex);
> +
> +        if (EFI_ERROR(Status))
> +          goto EXIT;
> +#if REPORTLINK
> +        if (NicDevice->LinkUp && NicDevice->Complete) {
> +          Mode->MediaPresent = TRUE;
> +          Status = Ax88179SetMedium (NicDevice);
> +        } else {
> +          Mode->MediaPresent = FALSE;
> +        }
> +#else
> +        if (NicDevice->LinkUp && NicDevice->Complete) {
> +          Mode->MediaPresent = TRUE;
> +          Mode->MediaPresentSupported = FALSE;
> +          Status = Ax88179SetMedium (NicDevice);
> +
> +        }
> +      }
> +#endif
> +    } else {
> +      if (EfiSimpleNetworkStarted == Mode->State) {
> +        Status = EFI_DEVICE_ERROR;
> +      } else {
> +        Status = EFI_NOT_STARTED ;
> +      }
> +    }
> +  } else {
> +    Status = EFI_INVALID_PARAMETER;
> +  }
> +  if (InterruptStatus != NULL) {
> +    *InterruptStatus = 0;
> +  }
> +
> +EXIT:
> +  gBS->RestoreTPL(TplPrevious) ;
> +
> +  return Status;
> +}
> +
> +/**
> +  This function performs read and write operations on the NVRAM device
> +  attached to a network interface.
> +
> +  @param [in] SimpleNetwork    Protocol instance pointer
> +  @param [in] ReadWrite         TRUE for read operations, FALSE for write operations.
> +  @param [in] Offset            Byte offset in the NVRAM device at which to start the
> +                                read or write operation.  This must be a multiple of
> +                                NvRamAccessSize and less than NvRamSize.
> +  @param [in] BufferSize        The number of bytes to read or write from the NVRAM device.
> +                                This must also be a multiple of NvramAccessSize.
> +  @param [in, out] Buffer      A pointer to the data buffer.
> +
> +  @retval EFI_SUCCESS           This operation was successful.
> +  @retval EFI_NOT_STARTED       The network interface was not started.
> +  @retval EFI_INVALID_PARAMETER SimpleNetwork parameter was NULL or did not point to a valid
> +                                EFI_SIMPLE_NETWORK_PROTOCOL structure.
> +  @retval EFI_DEVICE_ERROR      The command could not be sent to the network interface.
> +  @retval EFI_UNSUPPORTED       The increased buffer size feature is not supported.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +SN_NvData (
> +  IN     EFI_SIMPLE_NETWORK_PROTOCOL *SimpleNetwork,
> +  IN     BOOLEAN                     ReadWrite,
> +  IN     UINTN                       Offset,
> +  IN     UINTN                       BufferSize,
> +  IN OUT VOID                        *Buffer
> +  )
> +{
> +  EFI_STATUS              Status = EFI_INVALID_PARAMETER;
> +  EFI_TPL                 TplPrevious;
> +  EFI_SIMPLE_NETWORK_MODE *Mode;
> +  NIC_DEVICE              *NicDevice;
> +  UINTN                   Index;
> +
> +  TplPrevious = gBS->RaiseTPL(TPL_CALLBACK);
> +  if ((SimpleNetwork == NULL) || (SimpleNetwork->Mode == NULL)) {
> +    Status = EFI_INVALID_PARAMETER;
> +    goto  EXIT;
> +  }
> +
> +  NicDevice = DEV_FROM_SIMPLE_NETWORK (SimpleNetwork);
> +  Mode = SimpleNetwork->Mode;
> +
> +  if (EfiSimpleNetworkInitialized != Mode->State) {
> +    Status = EFI_NOT_STARTED;
> +    goto  EXIT;
> +  }
> +
> +  if (Offset != 0) {
> +    if (((Offset % Mode->NvRamAccessSize) != 0) || (Offset >= Mode->NvRamSize)) {
> +      Status = EFI_INVALID_PARAMETER;
> +      goto  EXIT;
> +    }
> +  }
> +  //
> +  // Offset must be a multiple of NvRamAccessSize and less than NvRamSize.
> +  //
> +  if ((BufferSize % Mode->NvRamAccessSize) != 0) {
> +    Status = EFI_INVALID_PARAMETER;
> +    goto  EXIT;
> +  }
> +
> +  if (BufferSize + Offset > Mode->NvRamSize) {
> +    Status = EFI_INVALID_PARAMETER;
> +    goto  EXIT;
> +  }
> +
> +  if (Buffer == NULL) {
> +    Status = EFI_INVALID_PARAMETER;
> +    goto  EXIT;
> +  }
> +
> +  //
> +  // ReadWrite: TRUE FOR READ FALSE FOR WRITE
> +  //
> +  if (ReadWrite) {
> +    for (Index = 0; Index < BufferSize / 2; Index++) {
> +      Status = Ax88179SromRead (NicDevice,
> +                                 (UINT32)(Offset/2 + Index),
> +                                 (((UINT16*)Buffer) + Index));
> +    }
> +  } else {
> +    Status = Ax88179EnableSromWrite(NicDevice);
> +    if (EFI_ERROR(Status))
> +      goto EXIT;
> +
> +    for (Index = 0; Index < BufferSize / 2; Index++) {
> +      Status = Ax88179SromWrite (NicDevice,
> +                                  (UINT32)(Offset/2 + Index),
> +                                  (((UINT16*)Buffer) + Index));
> +    }
> +
> +    Status = Ax88179DisableSromWrite(NicDevice);
> +
> +    if (BufferSize == 272)
> +      Status = Ax88179ReloadSrom(NicDevice);
> +  }
> +
> +  //
> +  // Return the operation status
> +  //
> +EXIT:
> +  gBS->RestoreTPL (TplPrevious);
> +  return Status;
> +}
> +
> +/**
> +  Resets the network adapter and allocates the transmit and receive buffers
> +  required by the network interface; optionally, also requests allocation of
> +  additional transmit and receive buffers.  This routine must be called before
> +  any other routine in the Simple Network protocol is called.
> +
> +  @param [in] SimpleNetwork    Protocol instance pointer
> +  @param [in] ExtraRxBufferSize Size in bytes to add to the receive buffer allocation
> +  @param [in] ExtraTxBufferSize Size in bytes to add to the transmit buffer allocation
> +
> +  @retval EFI_SUCCESS           This operation was successful.
> +  @retval EFI_NOT_STARTED       The network interface was not started.
> +  @retval EFI_OUT_OF_RESOURCES  There was not enough memory for the transmit and receive buffers
> +  @retval EFI_INVALID_PARAMETER SimpleNetwork parameter was NULL or did not point to a valid
> +                                EFI_SIMPLE_NETWORK_PROTOCOL structure.
> +  @retval EFI_DEVICE_ERROR      The command could not be sent to the network interface.
> +  @retval EFI_UNSUPPORTED       The increased buffer size feature is not supported.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +SN_Initialize (
> +  IN EFI_SIMPLE_NETWORK_PROTOCOL * SimpleNetwork,
> +  IN UINTN ExtraRxBufferSize,
> +  IN UINTN ExtraTxBufferSize
> +  )
> +{
> +  EFI_SIMPLE_NETWORK_MODE *Mode;
> +  EFI_STATUS              Status;
> +  UINT32                  TmpState;
> +  EFI_TPL                 TplPrevious;
> +  NIC_DEVICE              *NicDevice;
> +
> +  TplPrevious = gBS->RaiseTPL (TPL_CALLBACK);
> +
> +  //
> +  // Verify the parameters
> +  //
> +  if ((SimpleNetwork != NULL) && (SimpleNetwork->Mode != NULL)) {
> +    //
> +    // Determine if the interface is already started
> +    //
> +    Mode = SimpleNetwork->Mode;
> +    if (EfiSimpleNetworkStarted == Mode->State) {
> +      if ((0 == ExtraRxBufferSize) && (0 == ExtraTxBufferSize)) {
> +        //
> +        // Start the adapter
> +        //
> +        TmpState = Mode->State;
> +        Mode->State = EfiSimpleNetworkInitialized;
> +        Status = SN_Reset (SimpleNetwork, FALSE);
> +        if (EFI_ERROR (Status)) {
> +          //
> +          // Update the network state
> +          //
> +          Mode->State = TmpState;
> +        } else {
> +          Mode->MediaPresentSupported = TRUE;
> +          NicDevice = DEV_FROM_SIMPLE_NETWORK (SimpleNetwork);
> +          Mode->MediaPresent = Ax88179GetLinkStatus (NicDevice);
> +        }
> +      } else {
> +        Status = EFI_UNSUPPORTED;
> +      }
> +    } else {
> +      Status = EFI_NOT_STARTED;
> +    }
> +  } else {
> +    Status = EFI_INVALID_PARAMETER;
> +  }
> +
> +  //
> +  // Return the operation status
> +  //
> +  gBS->RestoreTPL (TplPrevious);
> +  return Status;
> +}
> +
> +
> +/**
> +  This function converts a multicast IP address to a multicast HW MAC address
> +  for all packet transactions.
> +
> +  @param [in] SimpleNetwork    Protocol instance pointer
> +  @param [in] IPv6             Set to TRUE if the multicast IP address is IPv6 [RFC2460].
> +                                Set to FALSE if the multicast IP address is IPv4 [RFC 791].
> +  @param [in] IP               The multicast IP address that is to be converted to a
> +                                multicast HW MAC address.
> +  @param [in] MAC              The multicast HW MAC address that is to be generated from IP.
> +
> +  @retval EFI_SUCCESS           This operation was successful.
> +  @retval EFI_NOT_STARTED       The network interface was not started.
> +  @retval EFI_INVALID_PARAMETER SimpleNetwork parameter was NULL or did not point to a valid
> +                                EFI_SIMPLE_NETWORK_PROTOCOL structure.
> +  @retval EFI_DEVICE_ERROR      The command could not be sent to the network interface.
> +  @retval EFI_UNSUPPORTED       The increased buffer size feature is not supported.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +SN_MCastIPtoMAC (
> +  IN EFI_SIMPLE_NETWORK_PROTOCOL *SimpleNetwork,
> +  IN BOOLEAN                     IPv6,
> +  IN EFI_IP_ADDRESS              *IP,
> +  IN EFI_MAC_ADDRESS             *MAC
> +  )
> +{
> +  EFI_STATUS              Status;
> +  EFI_TPL                 TplPrevious;
> +  EFI_SIMPLE_NETWORK_MODE *Mode;
> +
> +  TplPrevious = gBS->RaiseTPL(TPL_CALLBACK);
> +  if ((SimpleNetwork != NULL) && (SimpleNetwork->Mode != NULL)) {
> +    //
> +    // The interface must be running
> +    //
> +    Mode = SimpleNetwork->Mode;
> +    if (EfiSimpleNetworkInitialized == Mode->State) {
> +      if (IP == NULL || MAC == NULL) {
> +        Status = EFI_INVALID_PARAMETER;
> +        goto EXIT;
> +      }
> +      if (IPv6) {
> +        Status = EFI_UNSUPPORTED;
> +        goto EXIT;
> +      } else {
> +        //
> +        // check if the ip given is a mcast IP
> +        //
> +        if ((IP->v4.Addr[0] & 0xF0) != 0xE0) {
> +          Status = EFI_INVALID_PARAMETER;
> +          goto EXIT;
> +        } else {
> +          MAC->Addr[0] = 0x01;
> +          MAC->Addr[1] = 0x00;
> +          MAC->Addr[2] = 0x5e;
> +          MAC->Addr[3] = (UINT8) (IP->v4.Addr[1] & 0x7f);
> +          MAC->Addr[4] = (UINT8) IP->v4.Addr[2];
> +          MAC->Addr[5] = (UINT8) IP->v4.Addr[3];
> +          Status = EFI_SUCCESS;
> +        }
> +      }
> +    } else {
> +      if (EfiSimpleNetworkStarted == Mode->State) {
> +        Status = EFI_DEVICE_ERROR;
> +      } else {
> +        Status = EFI_NOT_STARTED ;
> +      }
> +    }
> +  } else {
> +    Status = EFI_INVALID_PARAMETER;
> +  }
> +
> +EXIT:
> +  gBS->RestoreTPL(TplPrevious);
> +  return Status;
> +}
> +
> +/**
> +  Attempt to receive a packet from the network adapter.
> +
> +  This function retrieves one packet from the receive queue of the network
> +  interface.  If there are no packets on the receive queue, then EFI_NOT_READY
> +  will be returned.  If there is a packet on the receive queue, and the size
> +  of the packet is smaller than BufferSize, then the contents of the packet
> +  will be placed in Buffer, and BufferSize will be udpated with the actual
> +  size of the packet.  In addition, if SrcAddr, DestAddr, and Protocol are
> +  not NULL, then these values will be extracted from the media header and
> +  returned.  If BufferSize is smaller than the received packet, then the
> +  size of the receive packet will be placed in BufferSize and
> +  EFI_BUFFER_TOO_SMALL will be returned.
> +
> +  This routine calls ::Ax88179Rx to update the media status and
> +  empty the network adapter of receive packets.
> +
> +  @param [in] SimpleNetwork    Protocol instance pointer
> +  @param [out] HeaderSize      The size, in bytes, of the media header to be filled in by
> +                                the Transmit() function.  If HeaderSize is non-zero, then
> +                                it must be equal to SimpleNetwork->Mode->MediaHeaderSize
> +                                and DestAddr and Protocol parameters must not be NULL.
> +  @param [out] BufferSize      The size, in bytes, of the entire packet (media header and
> +                                data) to be transmitted through the network interface.
> +  @param [out] Buffer          A pointer to the packet (media header followed by data) to
> +                                to be transmitted.  This parameter can not be NULL.  If
> +                                HeaderSize is zero, then the media header is Buffer must
> +                                already be filled in by the caller.  If HeaderSize is nonzero,
> +                                then the media header will be filled in by the Transmit()
> +                                function.
> +  @param [out] SrcAddr         The source HW MAC address.  If HeaderSize is zero, then
> +                                this parameter is ignored.  If HeaderSize is nonzero and
> +                                SrcAddr is NULL, then SimpleNetwork->Mode->CurrentAddress
> +                                is used for the source HW MAC address.
> +  @param [out] DestAddr        The destination HW MAC address.  If HeaderSize is zero, then
> +                                this parameter is ignored.
> +  @param [out] Protocol        The type of header to build.  If HeaderSize is zero, then
> +                                this parameter is ignored.
> +
> +  @retval EFI_SUCCESS           This operation was successful.
> +  @retval EFI_NOT_STARTED       The network interface was not started.
> +  @retval EFI_NOT_READY         No packets have been received on the network interface.
> +  @retval EFI_BUFFER_TOO_SMALL  The packet is larger than BufferSize bytes.
> +  @retval EFI_INVALID_PARAMETER SimpleNetwork parameter was NULL or did not point to a valid
> +                                EFI_SIMPLE_NETWORK_PROTOCOL structure.
> +  @retval EFI_DEVICE_ERROR      The command could not be sent to the network interface.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +SN_Receive (
> +  IN  EFI_SIMPLE_NETWORK_PROTOCOL *SimpleNetwork,
> +  OUT UINTN                       *HeaderSize,
> +  OUT UINTN                       *BufferSize,
> +  OUT VOID                        *Buffer,
> +  OUT EFI_MAC_ADDRESS             *SrcAddr,
> +  OUT EFI_MAC_ADDRESS             *DestAddr,
> +  OUT UINT16                      *Protocol
> +  )
> +{
> +  ETHERNET_HEADER         *Header;
> +  EFI_SIMPLE_NETWORK_MODE *Mode;
> +  NIC_DEVICE              *NicDevice;
> +  EFI_STATUS              Status;
> +  UINT16                  Type = 0;
> +  UINT16                  CurrentPktLen;
> +  BOOLEAN                 Valid = TRUE;
> +  EFI_TPL                 TplPrevious;
> +
> +  TplPrevious = gBS->RaiseTPL (TPL_CALLBACK);
> +  //
> +  // Verify the parameters
> +  //
> +  if ((SimpleNetwork != NULL) && (SimpleNetwork->Mode != NULL)) {
> +    //
> +    // The interface must be running
> +    //
> +    Mode = SimpleNetwork->Mode;
> +    if (EfiSimpleNetworkInitialized == Mode->State) {
> +      if ((BufferSize == NULL) || (Buffer == NULL)) {
> +        Status = EFI_INVALID_PARAMETER;
> +        gBS->RestoreTPL (TplPrevious);
> +        return Status;
> +      }
> +
> +      //
> +      // Update the link status
> +      //
> +      NicDevice = DEV_FROM_SIMPLE_NETWORK (SimpleNetwork);
> +
> +      if (NicDevice->LinkUp && NicDevice->Complete) {
> +        if ((HeaderSize != NULL) && (*HeaderSize == 7720)) {
> +          NicDevice->Grub_f = TRUE;
> +        }
> +
> +        if ((NicDevice->Grub_f) && (*HeaderSize != 7720)) {
> +          gBS->RestoreTPL (TplPrevious);
> +          return EFI_NOT_READY;
> +        }
> +
> +        //
> +        //  Attempt to do bulk in
> +        //
> +        if (NicDevice->PktCnt == 0) {
> +          Status = Ax88179BulkIn(NicDevice);
> +          if (EFI_ERROR(Status))
> +            goto  no_pkt;
> +        }
> +        CurrentPktLen = *((UINT16*) (NicDevice->CurPktHdrOff + 2));
> +        if (CurrentPktLen & (RXHDR_DROP | RXHDR_CRCERR))
> +          Valid = FALSE;
> +        CurrentPktLen &=  0x1fff;
> +        CurrentPktLen -= 2; /*EEEE*/
> +
> +        if (Valid && (60 <= CurrentPktLen) &&
> +        ((CurrentPktLen - 14) <= MAX_ETHERNET_PKT_SIZE) &&
> +            (*((UINT16*)NicDevice->CurPktOff)) == 0xEEEE) {
> +          if (*BufferSize < (UINTN)CurrentPktLen) {
> +            gBS->RestoreTPL (TplPrevious);
> +            return EFI_BUFFER_TOO_SMALL;
> +          }
> +          *BufferSize = CurrentPktLen;
> +          CopyMem (Buffer, NicDevice->CurPktOff + 2, CurrentPktLen);
> +
> +          Header = (ETHERNET_HEADER *) NicDevice->CurPktOff + 2;
> +
> +          if ((HeaderSize != NULL)  && ((*HeaderSize != 7720))) {
> +            *HeaderSize = sizeof (*Header);
> +          }
> +
> +          if (DestAddr != NULL) {
> +            CopyMem (DestAddr, &Header->DestAddr, PXE_HWADDR_LEN_ETHER);
> +          }
> +          if (SrcAddr != NULL) {
> +            CopyMem (SrcAddr, &Header->SrcAddr, PXE_HWADDR_LEN_ETHER);
> +          }
> +          if (Protocol != NULL) {
> +            Type = Header->Type;
> +            Type = (UINT16)((Type >> 8) | (Type << 8));
> +            *Protocol = Type;
> +          }
> +          NicDevice->PktCnt--;
> +          NicDevice->CurPktHdrOff += 4;
> +          NicDevice->CurPktOff += (CurrentPktLen + 2 + 7) & 0xfff8;
> +          Status = EFI_SUCCESS;
> +        } else {
> +          NicDevice->PktCnt = 0;
> +          Status = EFI_NOT_READY;
> +        }
> +      } else {
> +        Status = EFI_NOT_READY;
> +      }
> +    } else {
> +      if (EfiSimpleNetworkStarted == Mode->State) {
> +        Status = EFI_DEVICE_ERROR;
> +      } else {
> +        Status = EFI_NOT_STARTED;
> +      }
> +    }
> +  } else {
> +    Status = EFI_INVALID_PARAMETER;
> +  }
> +
> +  //
> +  // Return the operation status
> +  //
> +no_pkt:
> +  gBS->RestoreTPL (TplPrevious);
> +  return Status;
> +}
> +
> +/**
> +  This function is used to enable and disable the hardware and software receive
> +  filters for the underlying network device.
> +
> +  The receive filter change is broken down into three steps:
> +
> +    1.  The filter mask bits that are set (ON) in the Enable parameter
> +        are added to the current receive filter settings.
> +
> +    2.  The filter mask bits that are set (ON) in the Disable parameter
> +        are subtracted from the updated receive filter settins.
> +
> +    3.  If the resulting filter settigns is not supported by the hardware
> +        a more liberal setting is selected.
> +
> +  If the same bits are set in the Enable and Disable parameters, then the bits
> +  in the Disable parameter takes precedence.
> +
> +  If the ResetMCastFilter parameter is TRUE, then the multicast address list
> +  filter is disabled (irregardless of what other multicast bits are set in
> +  the enable and Disable parameters).  The SNP->Mode->MCastFilterCount field
> +  is set to zero.  The SNP->Mode->MCastFilter contents are undefined.
> +
> +  After enableing or disabling receive filter settings, software should
> +  verify the new settings by checking the SNP->Mode->ReceeiveFilterSettings,
> +  SNP->Mode->MCastFilterCount and SNP->Mode->MCastFilter fields.
> +
> +  Note: Some network drivers and/or devices will automatically promote
> +  receive filter settings if the requested setting can not be honored.
> +  For example, if a request for four multicast addresses is made and
> +  the underlying hardware only supports two multicast addresses the
> +  driver might set the promiscuous or promiscuous multicast receive filters
> +  instead.  The receiving software is responsible for discarding any extra
> +  packets that get through the hardware receive filters.
> +
> +  If ResetMCastFilter is TRUE, then the multicast receive filter list
> +  on the network interface will be reset to the default multicast receive
> +  filter list.  If ResetMCastFilter is FALSE, and this network interface
> +  allows the multicast receive filter list to be modified, then the
> +  MCastFilterCnt and MCastFilter are used to update the current multicast
> +  receive filter list.  The modified receive filter list settings can be
> +  found in the MCastFilter field of EFI_SIMPLE_NETWORK_MODE.
> +
> +  This routine calls ::ReceiveFilterUpdate to update the receive
> +  state in the network adapter.
> +
> +  @param [in] SimpleNetwork    Protocol instance pointer
> +  @param [in] Enable            A bit mask of receive filters to enable on the network interface.
> +  @param [in] Disable           A bit mask of receive filters to disable on the network interface.
> +                                For backward compatibility with EFI 1.1 platforms, the
> +                                EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST bit must be set
> +                                when the ResetMCastFilter parameter is TRUE.
> +  @param [in] ResetMCastFilter Set to TRUE to reset the contents of the multicast receive
> +                                filters on the network interface to their default values.
> +  @param [in] MCastFilterCnt    Number of multicast HW MAC address in the new MCastFilter list.
> +                                This value must be less than or equal to the MaxMCastFilterCnt
> +                                field of EFI_SIMPLE_NETWORK_MODE.  This field is optional if
> +                                ResetMCastFilter is TRUE.
> +  @param [in] MCastFilter      A pointer to a list of new multicast receive filter HW MAC
> +                                addresses.  This list will replace any existing multicast
> +                                HW MAC address list.  This field is optional if ResetMCastFilter
> +                                is TRUE.
> +
> +  @retval EFI_SUCCESS           This operation was successful.
> +  @retval EFI_NOT_STARTED       The network interface was not started.
> +  @retval EFI_INVALID_PARAMETER SimpleNetwork parameter was NULL or did not point to a valid
> +                                EFI_SIMPLE_NETWORK_PROTOCOL structure.
> +  @retval EFI_DEVICE_ERROR      The command could not be sent to the network interface.
> +  @retval EFI_UNSUPPORTED       The increased buffer size feature is not supported.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +SN_ReceiveFilters (
> +  IN EFI_SIMPLE_NETWORK_PROTOCOL *SimpleNetwork,
> +  IN UINT32                      Enable,
> +  IN UINT32                      Disable,
> +  IN BOOLEAN                     ResetMCastFilter,
> +  IN UINTN                       MCastFilterCnt,
> +  IN EFI_MAC_ADDRESS             *MCastFilter
> +  )
> +{
> +  EFI_SIMPLE_NETWORK_MODE *Mode;
> +  EFI_STATUS              Status = EFI_SUCCESS;
> +  EFI_TPL                 TplPrevious;
> +  UINTN                   Index;
> +  UINT8                   Temp;
> +
> +  TplPrevious = gBS->RaiseTPL(TPL_CALLBACK);
> +  Mode = SimpleNetwork->Mode;
> +
> +  if (SimpleNetwork == NULL) {
> +    gBS->RestoreTPL(TplPrevious);
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  switch (Mode->State) {
> +  case EfiSimpleNetworkInitialized:
> +    break;
> +
> +  case EfiSimpleNetworkStopped:
> +    Status = EFI_NOT_STARTED;
> +    gBS->RestoreTPL(TplPrevious);
> +    return Status;
> +
> +  default:
> +    Status = EFI_DEVICE_ERROR;
> +    gBS->RestoreTPL(TplPrevious);
> +    return Status;
> +  }
> +
> +  //
> +  // check if we are asked to enable or disable something that the SNP
> +  // does not even support!
> +  //
> +  if (((Enable &~Mode->ReceiveFilterMask) != 0) ||
> +      ((Disable &~Mode->ReceiveFilterMask) != 0)) {
> +    Status = EFI_INVALID_PARAMETER;
> +    gBS->RestoreTPL(TplPrevious);
> +    return Status;
> +  }
> +
> +  if (ResetMCastFilter) {
> +    Disable |= (EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST & Mode->ReceiveFilterMask);
> +    MCastFilterCnt = 0;
> +    Mode->MCastFilterCount = 0;
> +    if ((0 == (Mode->ReceiveFilterSetting & EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST)) &&
> +   Enable == 0 && Disable == 2) {
> +      gBS->RestoreTPL(TplPrevious);
> +      return EFI_SUCCESS;
> +    }
> +  } else {
> +    if (MCastFilterCnt != 0) {
> +      EFI_MAC_ADDRESS * MulticastAddress;
> +      MulticastAddress =  MCastFilter;
> +
> +      if ((MCastFilterCnt > Mode->MaxMCastFilterCount) ||
> +          (MCastFilter == NULL)) {
> +        Status = EFI_INVALID_PARAMETER;
> +        gBS->RestoreTPL(TplPrevious);
> +        return Status;
> +      }
> +
> +      for (Index = 0 ; Index < MCastFilterCnt ; Index++) {
> +          Temp = MulticastAddress->Addr[0];
> +          if ((Temp & 0x01) != 0x01) {
> +            gBS->RestoreTPL(TplPrevious);
> +            return EFI_INVALID_PARAMETER;
> +          }
> +          MulticastAddress++;
> +      }
> +
> +      Mode->MCastFilterCount = (UINT32)MCastFilterCnt;
> +      CopyMem (&Mode->MCastFilter[0],
> +               MCastFilter,
> +               MCastFilterCnt * sizeof (EFI_MAC_ADDRESS/**MCastFilter*/));
> +    }
> +  }
> +
> +  if (Enable == 0 && Disable == 0 && !ResetMCastFilter && MCastFilterCnt == 0) {
> +    Status = EFI_SUCCESS;
> +    gBS->RestoreTPL(TplPrevious);
> +    return Status;
> +  }
> +
> +  if ((Enable & EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST) != 0 && MCastFilterCnt == 0) {
> +    Status = EFI_INVALID_PARAMETER;
> +    gBS->RestoreTPL(TplPrevious);
> +    return Status;
> +  }
> +
> +  Mode->ReceiveFilterSetting |= Enable;
> +  Mode->ReceiveFilterSetting &= ~Disable;
> +
> +  Status = ReceiveFilterUpdate (SimpleNetwork);
> +
> +  gBS->RestoreTPL(TplPrevious);
> +
> +  return Status;
> +}
> +
> +/**
> +  Reset the network adapter.
> +
> +  Resets a network adapter and reinitializes it with the parameters that
> +  were provided in the previous call to Initialize ().  The transmit and
> +  receive queues are cleared.  Receive filters, the station address, the
> +  statistics, and the multicast-IP-to-HW MAC addresses are not reset by
> +  this call.
> +
> +  This routine calls ::Ax88179Reset to perform the adapter specific
> +  reset operation.  This routine also starts the link negotiation
> +  by calling ::Ax88179NegotiateLinkStart.
> +
> +  @param [in] SimpleNetwork    Protocol instance pointer
> +  @param [in] ExtendedVerification  Indicates that the driver may perform a more
> +                                exhaustive verification operation of the device
> +                                during reset.
> +
> +  @retval EFI_SUCCESS           This operation was successful.
> +  @retval EFI_NOT_STARTED       The network interface was not started.
> +  @retval EFI_INVALID_PARAMETER SimpleNetwork parameter was NULL or did not point to a valid
> +                                EFI_SIMPLE_NETWORK_PROTOCOL structure.
> +  @retval EFI_DEVICE_ERROR      The command could not be sent to the network interface.
> +  @retval EFI_UNSUPPORTED       The increased buffer size feature is not supported.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +SN_Reset (
> +  IN EFI_SIMPLE_NETWORK_PROTOCOL *SimpleNetwork,
> +  IN BOOLEAN                     ExtendedVerification
> +  )
> +{
> +  EFI_SIMPLE_NETWORK_MODE *Mode;
> +  NIC_DEVICE              *NicDevice;
> +  EFI_STATUS              Status;
> +  EFI_TPL                 TplPrevious;
> +
> +  TplPrevious = gBS->RaiseTPL(TPL_CALLBACK);
> +  //
> +  //  Verify the parameters
> +  //
> +  if ((SimpleNetwork != NULL) && (SimpleNetwork->Mode != NULL)) {
> +    Mode = SimpleNetwork->Mode;
> +    if (EfiSimpleNetworkInitialized == Mode->State) {
> +      //
> +      //  Update the device state
> +      //
> +      NicDevice = DEV_FROM_SIMPLE_NETWORK (SimpleNetwork);
> +
> +      //
> +      //  Reset the device
> +      //
> +      if (!NicDevice->FirstRst) {
> +        Status = EFI_SUCCESS;
> +      } else {
> +        Status = Ax88179Reset (NicDevice);
> +        if (!EFI_ERROR (Status)) {
> +          Status = ReceiveFilterUpdate (SimpleNetwork);
> +          if (!EFI_ERROR (Status) && !NicDevice->LinkUp && NicDevice->FirstRst) {
> +            Status = Ax88179NegotiateLinkStart (NicDevice);
> +            NicDevice->FirstRst = FALSE;
> +          }
> +        }
> +      }
> +    } else {
> +      Status = EFI_NOT_STARTED;
> +    }
> +  } else {
> +    Status = EFI_INVALID_PARAMETER;
> +  }
> +  //
> +  // Return the operation status
> +  //
> +  gBS->RestoreTPL(TplPrevious);
> +  return Status;
> +}
> +
> +/**
> +  Initialize the simple network protocol.
> +
> +  This routine calls ::Ax88179MacAddressGet to obtain the
> +  MAC address.
> +
> +  @param [in] NicDevice       NIC_DEVICE_INSTANCE pointer
> +
> +  @retval EFI_SUCCESS     Setup was successful
> +
> +**/
> +EFI_STATUS
> +SN_Setup (
> +  IN NIC_DEVICE *NicDevice
> +  )
> +{
> +  EFI_SIMPLE_NETWORK_MODE     *Mode;
> +  EFI_SIMPLE_NETWORK_PROTOCOL *SimpleNetwork;
> +  EFI_STATUS                  Status;
> +
> +  //
> +  // Initialize the simple network protocol
> +  //
> +  SimpleNetwork = &NicDevice->SimpleNetwork;
> +  SimpleNetwork->Revision = EFI_SIMPLE_NETWORK_PROTOCOL_REVISION;
> +  SimpleNetwork->Start = SN_Start;
> +  SimpleNetwork->Stop = SN_Stop;
> +  SimpleNetwork->Initialize = SN_Initialize;
> +  SimpleNetwork->Reset = SN_Reset;
> +  SimpleNetwork->Shutdown = SN_Shutdown;
> +  SimpleNetwork->ReceiveFilters = SN_ReceiveFilters;
> +  SimpleNetwork->StationAddress = SN_StationAddress;
> +  SimpleNetwork->Statistics = SN_Statistics;
> +  SimpleNetwork->MCastIpToMac = SN_MCastIPtoMAC;
> +  SimpleNetwork->NvData = SN_NvData;
> +  SimpleNetwork->GetStatus = SN_GetStatus;
> +  SimpleNetwork->Transmit = SN_Transmit;
> +  SimpleNetwork->Receive = SN_Receive;
> +  SimpleNetwork->WaitForPacket = NULL;
> +  Mode = &NicDevice->SimpleNetworkData;
> +  SimpleNetwork->Mode = Mode;
> +  Mode->State = EfiSimpleNetworkStopped;
> +  Mode->HwAddressSize = PXE_HWADDR_LEN_ETHER;
> +  Mode->MediaHeaderSize = sizeof (ETHERNET_HEADER);
> +  Mode->MaxPacketSize = MAX_ETHERNET_PKT_SIZE;
> +  Mode->ReceiveFilterMask = EFI_SIMPLE_NETWORK_RECEIVE_UNICAST
> +                           | EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST
> +                           | EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST
> +                           | EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS
> +                           | EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST;
> +  Mode->ReceiveFilterSetting = EFI_SIMPLE_NETWORK_RECEIVE_UNICAST
> +                              | EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST;
> +  Mode->MaxMCastFilterCount = MAX_MCAST_FILTER_CNT;
> +  Mode->MCastFilterCount = 0;
> +  Mode->NvRamSize = 512;
> +  Mode->NvRamAccessSize = 2;
> +  SetMem (&Mode->BroadcastAddress,
> +           PXE_HWADDR_LEN_ETHER,
> +           0xff);
> +  Mode->IfType = NET_IFTYPE_ETHERNET;
> +  Mode->MacAddressChangeable = TRUE;
> +  Mode->MultipleTxSupported = FALSE;
> +  Mode->MediaPresentSupported = TRUE;
> +  Mode->MediaPresent = FALSE;
> +  //
> +  //  Read the MAC address
> +  //
> +  NicDevice->PhyId = PHY_ID_INTERNAL;
> +  NicDevice->LinkSpeed100Mbps = FALSE;
> +  NicDevice->LinkSpeed1000Mbps = TRUE;
> +  NicDevice->FullDuplex = TRUE;
> +  NicDevice->Complete = FALSE;
> +  NicDevice->LinkUp = FALSE;
> +  NicDevice->Grub_f = FALSE;
> +  NicDevice->FirstRst = TRUE;
> +  NicDevice->PktCnt = 0;
> +  NicDevice->SkipRXCnt = 0;
> +  NicDevice->UsbMaxPktSize = 512;
> +  NicDevice->SetZeroLen = TRUE;
> +
> +  Status = Ax88179MacAddressGet (NicDevice,
> +                                  &Mode->PermanentAddress.Addr[0]);
> +  if (EFI_ERROR (Status)) {
> +    return Status;
> +  }
> +
> +  //
> +  //  Use the hardware address as the current address
> +  //
> +  CopyMem (&Mode->CurrentAddress,
> +            &Mode->PermanentAddress,
> +            PXE_HWADDR_LEN_ETHER);
> +
> +  CopyMem (&NicDevice->MAC,
> +            &Mode->PermanentAddress,
> +            PXE_HWADDR_LEN_ETHER);
> +
> +  Status = gBS->AllocatePool (EfiBootServicesData,
> +                               AX88179_MAX_BULKIN_SIZE,
> +                               (VOID **) &NicDevice->BulkInbuf);
> +
> +  if (EFI_ERROR (Status)) {
> +    return Status;
> +  }
> +
> +  Status = gBS->AllocatePool (EfiBootServicesData,
> +                               sizeof (TX_PACKET),
> +                               (VOID **) &NicDevice->TxTest);
> +  if (EFI_ERROR (Status)) {
> +    gBS->FreePool (NicDevice->BulkInbuf);
> +  }
> +
> +  //
> +  //  Return the setup status
> +  //
> +  return Status;
> +}
> +
> +
> +/**
> +  This routine starts the network interface.
> +
> +  @param [in] SimpleNetwork    Protocol instance pointer
> +
> +  @retval EFI_SUCCESS           This operation was successful.
> +  @retval EFI_ALREADY_STARTED   The network interface was already started.
> +  @retval EFI_INVALID_PARAMETER SimpleNetwork parameter was NULL or did not point to a valid
> +                                EFI_SIMPLE_NETWORK_PROTOCOL structure.
> +  @retval EFI_DEVICE_ERROR      The command could not be sent to the network interface.
> +  @retval EFI_UNSUPPORTED       The increased buffer size feature is not supported.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +SN_Start (
> +  IN EFI_SIMPLE_NETWORK_PROTOCOL *SimpleNetwork
> +  )
> +{
> +  NIC_DEVICE              *NicDevice;
> +  EFI_SIMPLE_NETWORK_MODE *Mode;
> +  EFI_STATUS              Status;
> +  EFI_TPL                 TplPrevious;
> +
> +  TplPrevious = gBS->RaiseTPL(TPL_CALLBACK);
> +  //
> +  // Verify the parameters
> +  //
> +  Status = EFI_INVALID_PARAMETER;
> +  if ((SimpleNetwork != NULL) && (SimpleNetwork->Mode != NULL)) {
> +    Mode = SimpleNetwork->Mode;
> +    if (EfiSimpleNetworkStopped == Mode->State) {
> +      //
> +      // Initialize the mode structure
> +      // NVRAM access is not supported
> +      //
> +      ZeroMem (Mode, sizeof (*Mode));
> +
> +      Mode->State = EfiSimpleNetworkStarted;
> +      Mode->HwAddressSize = PXE_HWADDR_LEN_ETHER;
> +      Mode->MediaHeaderSize = sizeof (ETHERNET_HEADER);
> +      Mode->MaxPacketSize = MAX_ETHERNET_PKT_SIZE;
> +      Mode->ReceiveFilterMask = EFI_SIMPLE_NETWORK_RECEIVE_UNICAST
> +                               | EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST
> +                               | EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST
> +                               | EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS
> +                               | EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST;
> +      Mode->ReceiveFilterSetting = EFI_SIMPLE_NETWORK_RECEIVE_UNICAST;
> +      Mode->MaxMCastFilterCount = MAX_MCAST_FILTER_CNT;
> +      Mode->MCastFilterCount = 0;
> +      Mode->NvRamSize = 512;
> +      Mode->NvRamAccessSize = 2;
> +      NicDevice = DEV_FROM_SIMPLE_NETWORK (SimpleNetwork);
> +      Status = Ax88179MacAddressGet (NicDevice, &Mode->PermanentAddress.Addr[0]);
> +      CopyMem (&Mode->CurrentAddress,
> +                &Mode->PermanentAddress,
> +                sizeof (Mode->CurrentAddress));
> +      SetMem(&Mode->BroadcastAddress, PXE_HWADDR_LEN_ETHER, 0xff);
> +      Mode->IfType = NET_IFTYPE_ETHERNET;
> +      Mode->MacAddressChangeable = TRUE;
> +      Mode->MultipleTxSupported = FALSE;
> +      Mode->MediaPresentSupported = TRUE;
> +      Mode->MediaPresent = FALSE;
> +
> +    } else {
> +      Status = EFI_ALREADY_STARTED;
> +    }
> +  }
> +
> +  //
> +  // Return the operation status
> +  //
> +  gBS->RestoreTPL(TplPrevious);
> +  return Status;
> +}
> +
> +
> +/**
> +  Set the MAC address.
> +
> +  This function modifies or resets the current station address of a
> +  network interface.  If Reset is TRUE, then the current station address
> +  is set ot the network interface's permanent address.  If Reset if FALSE
> +  then the current station address is changed to the address specified by
> +  New.
> +
> +  This routine calls ::Ax88179MacAddressSet to update the MAC address
> +  in the network adapter.
> +
> +  @param [in] SimpleNetwork    Protocol instance pointer
> +  @param [in] Reset            Flag used to reset the station address to the
> +                                network interface's permanent address.
> +  @param [in] New              New station address to be used for the network
> +                                interface.
> +
> +  @retval EFI_SUCCESS           This operation was successful.
> +  @retval EFI_NOT_STARTED       The network interface was not started.
> +  @retval EFI_INVALID_PARAMETER SimpleNetwork parameter was NULL or did not point to a valid
> +                                EFI_SIMPLE_NETWORK_PROTOCOL structure.
> +  @retval EFI_DEVICE_ERROR      The command could not be sent to the network interface.
> +  @retval EFI_UNSUPPORTED       The increased buffer size feature is not supported.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +SN_StationAddress (
> +  IN EFI_SIMPLE_NETWORK_PROTOCOL *SimpleNetwork,
> +  IN BOOLEAN                     Reset,
> +  IN EFI_MAC_ADDRESS             *New
> +  )
> +{
> +  NIC_DEVICE              *NicDevice;
> +  EFI_SIMPLE_NETWORK_MODE *Mode;
> +  EFI_STATUS              Status;
> +
> +  EFI_TPL TplPrevious;
> +
> +  TplPrevious = gBS->RaiseTPL(TPL_CALLBACK);
> +  //
> +  // Verify the parameters
> +  //
> +  if ((SimpleNetwork != NULL) &&
> +      (SimpleNetwork->Mode != NULL) &&
> +      ((!Reset) || (Reset && (New != NULL)))) {
> +    //
> +    // Verify that the adapter is already started
> +    //
> +    NicDevice = DEV_FROM_SIMPLE_NETWORK (SimpleNetwork);
> +    Mode = SimpleNetwork->Mode;
> +    if (EfiSimpleNetworkInitialized == Mode->State) {
> +      //
> +      // Determine the adapter MAC address
> +      //
> +      if (Reset) {
> +        //
> +        // Use the permanent address
> +        //
> +        CopyMem (&Mode->CurrentAddress,
> +                  &Mode->PermanentAddress,
> +                  sizeof (Mode->CurrentAddress));
> +      } else {
> +        //
> +        // Use the specified address
> +        //
> +        CopyMem (&Mode->CurrentAddress,
> +                  New,
> +                  sizeof (Mode->CurrentAddress));
> +      }
> +
> +      //
> +      // Update the address on the adapter
> +      //
> +      Status = Ax88179MacAddressSet (NicDevice, &Mode->CurrentAddress.Addr[0]);
> +    } else {
> +      if (EfiSimpleNetworkStarted == Mode->State) {
> +        Status = EFI_DEVICE_ERROR; ;
> +      } else {
> +        Status = EFI_NOT_STARTED ;
> +      }
> +    }
> +  } else {
> +    Status = EFI_INVALID_PARAMETER;
> +  }
> +
> +  //
> +  // Return the operation status
> +  //
> +  gBS->RestoreTPL(TplPrevious);
> +  return Status;
> +}
> +
> +
> +/**
> +  This function resets or collects the statistics on a network interface.
> +  If the size of the statistics table specified by StatisticsSize is not
> +  big enough for all of the statistics that are collected by the network
> +  interface, then a partial buffer of statistics is returned in
> +  StatisticsTable.
> +
> +  @param [in] SimpleNetwork    Protocol instance pointer
> +  @param [in] Reset            Set to TRUE to reset the statistics for the network interface.
> +  @param [in, out] StatisticsSize  On input the size, in bytes, of StatisticsTable.  On output
> +                                the size, in bytes, of the resulting table of statistics.
> +  @param [out] StatisticsTable A pointer to the EFI_NETWORK_STATISTICS structure that
> +                                conains the statistics.
> +
> +  @retval EFI_SUCCESS           This operation was successful.
> +  @retval EFI_NOT_STARTED       The network interface was not started.
> +  @retval EFI_BUFFER_TOO_SMALL  The StatisticsTable is NULL or the buffer is too small.
> +  @retval EFI_INVALID_PARAMETER SimpleNetwork parameter was NULL or did not point to a valid
> +                                EFI_SIMPLE_NETWORK_PROTOCOL structure.
> +  @retval EFI_DEVICE_ERROR      The command could not be sent to the network interface.
> +  @retval EFI_UNSUPPORTED       The increased buffer size feature is not supported.
> +**/
> +EFI_STATUS
> +EFIAPI
> +SN_Statistics (
> +  IN     EFI_SIMPLE_NETWORK_PROTOCOL *SimpleNetwork,
> +  IN     BOOLEAN                     Reset,
> +  IN OUT UINTN                       *StatisticsSize,
> +  OUT    EFI_NETWORK_STATISTICS      *StatisticsTable
> +  )
> +{
> +  EFI_STATUS              Status;
> +  EFI_TPL                 TplPrevious;
> +  EFI_SIMPLE_NETWORK_MODE *Mode;
> +
> +  TplPrevious = gBS->RaiseTPL(TPL_CALLBACK);
> +  Mode = SimpleNetwork->Mode;
> +
> +  if (EfiSimpleNetworkInitialized == Mode->State) {
> +    if ((StatisticsSize != NULL) && (*StatisticsSize == 0)) {
> +      Status = EFI_BUFFER_TOO_SMALL;
> +      goto EXIT;
> +    }
> +
> +    if(Reset) {
> +      Status = EFI_SUCCESS;
> +    } else {
> +      Status = EFI_SUCCESS;
> +    }
> +  } else {
> +    if (EfiSimpleNetworkStarted == Mode->State) {
> +      Status = EFI_DEVICE_ERROR; ;
> +    } else {
> +      Status = EFI_NOT_STARTED ;
> +    }
> +  }
> +
> +  Status = EFI_UNSUPPORTED;
> +EXIT:
> +  gBS->RestoreTPL(TplPrevious);
> +  return Status;
> +}
> +
> +
> +/**
> +  This function stops a network interface.  This call is only valid
> +  if the network interface is in the started state.
> +
> +  @param [in] SimpleNetwork    Protocol instance pointer
> +
> +  @retval EFI_SUCCESS           This operation was successful.
> +  @retval EFI_NOT_STARTED       The network interface was not started.
> +  @retval EFI_INVALID_PARAMETER SimpleNetwork parameter was NULL or did not point to a valid
> +                                EFI_SIMPLE_NETWORK_PROTOCOL structure.
> +  @retval EFI_DEVICE_ERROR      The command could not be sent to the network interface.
> +  @retval EFI_UNSUPPORTED       The increased buffer size feature is not supported.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +SN_Stop (
> +  IN EFI_SIMPLE_NETWORK_PROTOCOL *SimpleNetwork
> +  )
> +{
> +  EFI_SIMPLE_NETWORK_MODE *Mode;
> +  EFI_STATUS              Status;
> +  EFI_TPL                 TplPrevious;
> +
> +  TplPrevious = gBS->RaiseTPL(TPL_CALLBACK);
> +  //
> +  // Verify the parameters
> +  //
> +  if ((SimpleNetwork != NULL) && (SimpleNetwork->Mode != NULL)) {
> +    //
> +    // Determine if the interface is started
> +    //
> +    Mode = SimpleNetwork->Mode;
> +
> +    if (EfiSimpleNetworkStarted == Mode->State) {
> +        Mode->State = EfiSimpleNetworkStopped;
> +        Status = EFI_SUCCESS;
> +    } else {
> +        Status = EFI_NOT_STARTED;
> +    }
> +  } else {
> +    Status = EFI_INVALID_PARAMETER;
> +  }
> +
> +  //
> +  // Return the operation status
> +  //
> +  gBS->RestoreTPL(TplPrevious);
> +  return Status;
> +}
> +
> +
> +/**
> +  This function releases the memory buffers assigned in the Initialize() call.
> +  Ending transmits and receives are lost, and interrupts are cleared and disabled.
> +  After this call, only Initialize() and Stop() calls may be used.
> +
> +  @param [in] SimpleNetwork    Protocol instance pointer
> +
> +  @retval EFI_SUCCESS           This operation was successful.
> +  @retval EFI_NOT_STARTED       The network interface was not started.
> +  @retval EFI_INVALID_PARAMETER SimpleNetwork parameter was NULL or did not point to a valid
> +                                EFI_SIMPLE_NETWORK_PROTOCOL structure.
> +  @retval EFI_DEVICE_ERROR      The command could not be sent to the network interface.
> +  @retval EFI_UNSUPPORTED       The increased buffer size feature is not supported.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +SN_Shutdown (
> +  IN EFI_SIMPLE_NETWORK_PROTOCOL *SimpleNetwork
> +  )
> +{
> +  EFI_SIMPLE_NETWORK_MODE *Mode;
> +  EFI_STATUS              Status;
> +  NIC_DEVICE              *NicDevice;
> +  EFI_TPL                 TplPrevious;
> +
> +  TplPrevious = gBS->RaiseTPL(TPL_CALLBACK);
> +  //
> +  // Verify the parameters
> +  //
> +  if ((SimpleNetwork != NULL) && (SimpleNetwork->Mode != NULL)) {
> +    //
> +    // Determine if the interface is already started
> +    //
> +    Mode = SimpleNetwork->Mode;
> +    if (EfiSimpleNetworkInitialized == Mode->State) {
> +      //
> +      // Stop the adapter
> +      //
> +      NicDevice = DEV_FROM_SIMPLE_NETWORK (SimpleNetwork);
> +
> +      Status = Ax88179MacAddressGet (NicDevice, &Mode->PermanentAddress.Addr[0]);
> +      if (!EFI_ERROR (Status)) {
> +        //
> +        // Update the network state
> +        //
> +        Mode->State = EfiSimpleNetworkStarted;
> +      } else if (EFI_DEVICE_ERROR == Status) {
> +        Mode->State = EfiSimpleNetworkStopped;
> +      }
> +
> +    } else {
> +      Status = EFI_NOT_STARTED;
> +    }
> +  } else {
> +    Status = EFI_INVALID_PARAMETER;
> +  }
> +
> +  //
> +  // Return the operation status
> +  //
> +  gBS->RestoreTPL(TplPrevious);
> +  return Status;
> +}
> +
> +
> +/**
> +  Send a packet over the network.
> +
> +  This function places the packet specified by Header and Buffer on
> +  the transmit queue.  This function performs a non-blocking transmit
> +  operation.  When the transmit is complete, the buffer is returned
> +  via the GetStatus() call.
> +
> +  This routine calls ::Ax88179Rx to empty the network adapter of
> +  receive packets.  The routine then passes the transmit packet
> +  to the network adapter.
> +
> +  @param [in] SimpleNetwork    Protocol instance pointer
> +  @param [in] HeaderSize        The size, in bytes, of the media header to be filled in by
> +                                the Transmit() function.  If HeaderSize is non-zero, then
> +                                it must be equal to SimpleNetwork->Mode->MediaHeaderSize
> +                                and DestAddr and Protocol parameters must not be NULL.
> +  @param [in] BufferSize        The size, in bytes, of the entire packet (media header and
> +                                data) to be transmitted through the network interface.
> +  @param [in] Buffer           A pointer to the packet (media header followed by data) to
> +                                to be transmitted.  This parameter can not be NULL.  If
> +                                HeaderSize is zero, then the media header is Buffer must
> +                                already be filled in by the caller.  If HeaderSize is nonzero,
> +                                then the media header will be filled in by the Transmit()
> +                                function.
> +  @param [in] SrcAddr          The source HW MAC address.  If HeaderSize is zero, then
> +                                this parameter is ignored.  If HeaderSize is nonzero and
> +                                SrcAddr is NULL, then SimpleNetwork->Mode->CurrentAddress
> +                                is used for the source HW MAC address.
> +  @param [in] DestAddr         The destination HW MAC address.  If HeaderSize is zero, then
> +                                this parameter is ignored.
> +  @param [in] Protocol         The type of header to build.  If HeaderSize is zero, then
> +                                this parameter is ignored.
> +
> +  @retval EFI_SUCCESS           This operation was successful.
> +  @retval EFI_NOT_STARTED       The network interface was not started.
> +  @retval EFI_NOT_READY         The network interface is too busy to accept this transmit request.
> +  @retval EFI_BUFFER_TOO_SMALL  The BufferSize parameter is too small.
> +  @retval EFI_INVALID_PARAMETER SimpleNetwork parameter was NULL or did not point to a valid
> +                                EFI_SIMPLE_NETWORK_PROTOCOL structure.
> +  @retval EFI_DEVICE_ERROR      The command could not be sent to the network interface.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +SN_Transmit (
> +  IN EFI_SIMPLE_NETWORK_PROTOCOL *SimpleNetwork,
> +  IN UINTN                       HeaderSize,
> +  IN UINTN                       BufferSize,
> +  IN VOID                        *Buffer,
> +  IN EFI_MAC_ADDRESS             *SrcAddr,
> +  IN EFI_MAC_ADDRESS             *DestAddr,
> +  IN UINT16                      *Protocol
> +  )
> +{
> +  ETHERNET_HEADER         *Header;
> +  EFI_SIMPLE_NETWORK_MODE *Mode;
> +  NIC_DEVICE              *NicDevice;
> +  EFI_USB_IO_PROTOCOL     *UsbIo;
> +  EFI_STATUS              Status;
> +  UINTN                   TransferLength;
> +  UINT32                  TransferStatus;
> +  UINT16                  Type = 0;
> +  EFI_TPL                 TplPrevious;
> +
> +  TplPrevious = gBS->RaiseTPL(TPL_CALLBACK);
> +  //
> +  // Verify the parameters
> +  //
> +  if ((SimpleNetwork != NULL) && (SimpleNetwork->Mode != NULL)) {
> +    //
> +    // The interface must be running
> +    //
> +    Mode = SimpleNetwork->Mode;
> +    if (EfiSimpleNetworkInitialized == Mode->State) {
> +      //
> +      // Update the link status
> +      //
> +      NicDevice = DEV_FROM_SIMPLE_NETWORK (SimpleNetwork);
> +
> +      if (NicDevice->LinkUp && NicDevice->Complete) {
> +        if ((HeaderSize != 0) && (Mode->MediaHeaderSize != HeaderSize))  {
> +          Status = EFI_INVALID_PARAMETER;
> +          goto EXIT;
> +        }
> +        if (BufferSize <  Mode->MediaHeaderSize) {
> +          Status = EFI_INVALID_PARAMETER;
> +          goto EXIT;
> +        }
> +        if (Buffer == NULL) {
> +          Status = EFI_INVALID_PARAMETER;
> +          goto EXIT;
> +        }
> +        if ((HeaderSize != 0) && (DestAddr == NULL)) {
> +          Status = EFI_INVALID_PARAMETER;
> +          goto EXIT;
> +        }
> +        if ((HeaderSize != 0) && (Protocol == NULL)) {
> +          Status = EFI_INVALID_PARAMETER;
> +          goto EXIT;
> +        }
> +        //
> +        //  Copy the packet into the USB buffer
> +        //
> +        // Buffer starting with 14 bytes 0
> +        CopyMem (&NicDevice->TxTest->Data[0], Buffer, BufferSize);
> +        NicDevice->TxTest->TxHdr1 = (UINT32) BufferSize;
> +        NicDevice->TxTest->TxHdr2 = 0;
> +        //
> +        //  Transmit the packet
> +        //
> +        Header = (ETHERNET_HEADER *) &NicDevice->TxTest->Data[0];
> +        if (HeaderSize != 0) {
> +          if (DestAddr != NULL) {
> +            CopyMem (&Header->DestAddr, DestAddr, PXE_HWADDR_LEN_ETHER);
> +          }
> +          if (SrcAddr != NULL) {
> +            CopyMem (&Header->SrcAddr, SrcAddr, PXE_HWADDR_LEN_ETHER);
> +          } else {
> +            CopyMem (&Header->SrcAddr, &Mode->CurrentAddress.Addr[0], PXE_HWADDR_LEN_ETHER);
> +          }
> +          if (Protocol != NULL) {
> +            Type = *Protocol;
> +          } else {
> +              Type = (UINT16) BufferSize;
> +          }
> +          Type = (UINT16)((Type >> 8) | (Type << 8));
> +          Header->Type = Type;
> +        }
> +
> +        if (NicDevice->TxTest->TxHdr1 < MIN_ETHERNET_PKT_SIZE) {
> +          NicDevice->TxTest->TxHdr1 = MIN_ETHERNET_PKT_SIZE;
> +          ZeroMem (&NicDevice->TxTest->Data[BufferSize],
> +                    MIN_ETHERNET_PKT_SIZE - BufferSize);
> +        }
> +
> +        TransferLength = sizeof (NicDevice->TxTest->TxHdr1)
> +                       + sizeof (NicDevice->TxTest->TxHdr2)
> +                       + NicDevice->TxTest->TxHdr1;
> +        //
> +        //  Work around USB bus driver bug where a timeout set by receive
> +        //  succeeds but the timeout expires immediately after, causing the
> +        //  transmit operation to timeout.
> +        //
> +        UsbIo = NicDevice->UsbIo;
> +        Status = UsbIo->UsbBulkTransfer (UsbIo,
> +                                           BULK_OUT_ENDPOINT,
> +                                           &NicDevice->TxTest->TxHdr1,
> +                                           &TransferLength,
> +                                           0xfffffffe,
> +                                           &TransferStatus);
> +
> +        if (!EFI_ERROR(Status) && !EFI_ERROR(Status)) {
> +          NicDevice->TxBuffer = Buffer;
> +          Status = EFI_SUCCESS;
> +        } else if (EFI_TIMEOUT == Status && EFI_USB_ERR_TIMEOUT == TransferStatus) {
> +          Status = EFI_NOT_READY;
> +        } else {
> +          Status = EFI_DEVICE_ERROR;
> +        }
> +      } else {
> +        //
> +        // No packets available.
> +        //
> +        Status = EFI_NOT_READY;
> +      }
> +    } else {
> +      if (EfiSimpleNetworkStarted == Mode->State) {
> +        Status = EFI_DEVICE_ERROR;
> +      } else {
> +        Status = EFI_NOT_STARTED;
> +      }
> +    }
> +  } else {
> +    Status = EFI_INVALID_PARAMETER;
> +  }
> +
> +EXIT:
> +  gBS->RestoreTPL (TplPrevious);
> +  return Status;
> +}
> --
> 2.17.1


-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.

View/Reply Online (#60924): https://edk2.groups.io/g/devel/message/60924
Mute This Topic: https://groups.io/mt/74751638/1813853
Group Owner: devel+owner at edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub  [edk2-devel-archive at redhat.com]
-=-=-=-=-=-=-=-=-=-=-=-





More information about the edk2-devel-archive mailing list