public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
From: "Samer El-Haj-Mahmoud" <samer.el-haj-mahmoud@arm.com>
To: devel@edk2.groups.io
Cc: Ray Ni <ray.ni@intel.com>, Leif Lindholm <leif@nuviainc.com>,
	Ard Biesheuvel <ard.biesheuvel@arm.com>
Subject: [edk2-platform][PATCH v1 2/2] Drivers/OptionRomPkg: UsbNetworking: ASIX Ax88772c driver v2.8.0
Date: Wed,  6 May 2020 23:37:20 -0400	[thread overview]
Message-ID: <20200507033720.31152-3-Samer.El-Haj-Mahmoud@arm.com> (raw)
In-Reply-To: <20200507033720.31152-1-Samer.El-Haj-Mahmoud@arm.com>

This is the initial revision of ASIX USB networking UEFI driver
version 2.8.0 for Ax88772c / Ax88772b / Ax88772a
https://www.asix.com.tw/download.php?sub=driverdetail&PItemID=136

Source code contributed by ASIX.

Cc: Ray Ni <ray.ni@intel.com>
Cc: Leif Lindholm <leif@nuviainc.com>
Cc: Ard Biesheuvel <ard.biesheuvel@arm.com>

Signed-off-by: Samer El-Haj-Mahmoud <samer.el-haj-mahmoud@arm.com>
---
 Drivers/OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772c/Ax88772c.inf    |   65 +
 Drivers/OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772c/Ax88772.h       | 1097 +++++++++++++
 Drivers/OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772c/Ax88772.c       | 1296 ++++++++++++++++
 Drivers/OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772c/ComponentName.c |  246 +++
 Drivers/OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772c/DriverBinding.c |  637 ++++++++
 Drivers/OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772c/SimpleNetwork.c | 1612 ++++++++++++++++++++
 6 files changed, 4953 insertions(+)

diff --git a/Drivers/OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772c/Ax88772c.inf b/Drivers/OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772c/Ax88772c.inf
new file mode 100644
index 000000000000..1d37a5dae34b
--- /dev/null
+++ b/Drivers/OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772c/Ax88772c.inf
@@ -0,0 +1,65 @@
+## @file
+# Component description file for ASIX AX88772 USB/Ethernet driver.
+#
+# This module provides support for the ASIX AX88772 USB/Ethernet adapter.
+# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+#  SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x00010018
+  BASE_NAME                      = Ax88772c
+  FILE_GUID                      = B15239D6-6A01-4808-A0F7-B7F20F073555
+  MODULE_TYPE                    = DXE_DRIVER
+  VERSION_STRING                 = 1.0
+
+  ENTRY_POINT                    = EntryPoint
+
+#
+#  VALID_ARCHITECTURES           = IA32 X64 EBC
+#
+
+[Sources.common]
+  Ax88772.h
+  Ax88772.c
+  ComponentName.c
+  DriverBinding.c
+  SimpleNetwork.c
+
+
+[Packages]
+  MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+  UefiLib
+  UefiBootServicesTableLib
+  BaseMemoryLib
+  DebugLib
+  UefiDriverEntryPoint
+
+[Protocols]
+  gEfiDevicePathProtocolGuid           ## BY_START
+  gEfiSimpleNetworkProtocolGuid        ## BY_START
+  gEfiUsbIoProtocolGuid                ## TO_START
+
+#[Guids]
+#  gEfiEventExitBootServicesGuid        ## PRODUCES ## Event
+#  gEfiEventVirtualAddressChangeGuid    ## PRODUCES ## Event
+#  gEfiNicIp4ConfigVariableGuid
+
+[Depex]
+  gEfiBdsArchProtocolGuid AND
+  gEfiCpuArchProtocolGuid AND
+  gEfiMetronomeArchProtocolGuid AND
+  gEfiMonotonicCounterArchProtocolGuid AND
+  gEfiRealTimeClockArchProtocolGuid AND
+  gEfiResetArchProtocolGuid AND
+  gEfiRuntimeArchProtocolGuid AND
+  gEfiSecurityArchProtocolGuid AND
+  gEfiTimerArchProtocolGuid AND
+  gEfiVariableWriteArchProtocolGuid AND
+  gEfiVariableArchProtocolGuid AND
+  gEfiWatchdogTimerArchProtocolGuid
diff --git a/Drivers/OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772c/Ax88772.h b/Drivers/OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772c/Ax88772.h
new file mode 100644
index 000000000000..18317fd5c4f7
--- /dev/null
+++ b/Drivers/OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772c/Ax88772.h
@@ -0,0 +1,1097 @@
+/** @file
+  Definitions for ASIX AX88772 Ethernet adapter.
+
+  Copyright (c) 2011 - 2015, Intel Corporation. All rights reserved.
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _AX88772_H_
+#define _AX88772_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/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 MAX_QUEUE_SIZE 50
+#define MAX_BULKIN_SIZE 16384
+#define HW_HDR_LENGTH 8
+#define PASS_SCT      0
+#define REPORTLINK    1
+
+#define ARM  0
+
+#if ARM
+#define MAX_LINKIDLE_THRESHOLD  100
+#else
+#define MAX_LINKIDLE_THRESHOLD  30
+#endif
+
+#define AMI    1
+#define ASIX_MCAST_FILTER_CNT 8
+#define RXTHOU 0
+
+#if 0
+//------------------------------------------------------------------------------
+//  Macros
+//------------------------------------------------------------------------------
+
+#if defined(_MSC_VER)           /* Handle Microsoft VC++ compiler specifics. */
+#define DBG_ENTER()             DEBUG (( 0xffffffff, "Entering " __FUNCTION__ "\n" )) ///<  Display routine entry
+#define DBG_EXIT()              DEBUG (( 0xffffffff, "Exiting " __FUNCTION__ "\n" ))  ///<  Display routine exit
+#define DBG_EXIT_DEC(Status)    DEBUG (( 0xffffffff, "Exiting " __FUNCTION__ ", Status: %d\n", Status ))      ///<  Display routine exit with decimal value
+#define DBG_EXIT_HEX(Status)    DEBUG (( 0xffffffff, "Exiting " __FUNCTION__ ", Status: 0x%08x\n", Status ))  ///<  Display routine exit with hex value
+#define DBG_EXIT_STATUS(Status) DEBUG (( 0xffffffff, "Exiting " __FUNCTION__ ", Status: %r\n", Status ))      ///<  Display routine exit with status value
+#define DBG_EXIT_TF(Status)     DEBUG (( 0xffffffff, "Exiting " __FUNCTION__ ", returning %s\n", (FALSE == Status) ? L"FALSE" : L"TRUE" ))  ///<  Display routine with TRUE/FALSE value
+#else   //  _MSC_VER
+#define DBG_ENTER()               ///<  Display routine entry
+#define DBG_EXIT()                ///<  Display routine exit
+#define DBG_EXIT_DEC(Status)      ///<  Display routine exit with decimal value
+#define DBG_EXIT_HEX(Status)      ///<  Display routine exit with hex value
+#define DBG_EXIT_STATUS(Status)   ///<  Display routine exit with status value
+#define DBG_EXIT_TF(Status)       ///<  Display routine with TRUE/FALSE value
+#endif  //  _MSC_VER
+
+#endif
+
+#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
+
+
+#define PRINT(_L_STR) (gST->ConOut->OutputString(gST->ConOut,(_L_STR)))
+//------------------------------------------------------------------------------
+//  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
+
+#if RXTHOU
+#define AX88772_MAX_BULKIN_SIZE    1024 * 17 //32
+#else
+#define AX88772_MAX_BULKIN_SIZE    1024 * 3
+#endif
+
+#define AX88772_MAX_PKT_SIZE  2048  ///< Maximum packet size
+
+#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  ///<  Ethernet spec 3.1.1: Minimum packet size
+
+#define USB_NETWORK_CLASS   0x09    ///<  USB Network class code
+#define USB_BUS_TIMEOUT     1000    ///<  USB timeout in milliseconds
+
+#define TIMER_MSEC          20              ///<  Polling interval for the NIC
+//#define TPL_AX88772         TPL_CALLBACK    ///<  TPL for routine synchronization
+
+#define HC_DEBUG  0
+
+#if RXTHOU
+#define BULKIN_TIMEOUT  3 //10 //100 //1000
+#else
+#define BULKIN_TIMEOUT  3000
+#endif
+
+#define AUTONEG_DELAY   2000000
+#define AUTONEG_POLL_CNT    5
+
+/**
+  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 FreeQueueSize     10
+
+#define DEV_SIGNATURE     SIGNATURE_32 ('A','X','8','8')  ///<  Signature of data structures in memory
+
+#define VENDOR_ID         0x0B95  ///<  Vendor ID for Asix
+#define VENDOR_AX88772B_LENOVO_ID  0x17EF
+
+
+/* Freddy */
+#define PRODUCT_ID        0x7720  ///<  Product ID for the AX88772 USB 10/100 Ethernet controller
+#define PRODUCT_AX88772A_ID   0x772A
+#define PRODUCT_AX88772B_ID   0x772b
+#define PRODUCT_AX88772B_ASUS_ID 0x7e2b
+#define PRODUCT_AX88772B_LENOVO_ID 0x7203
+/* Freddy */
+
+
+#define RESET_MSEC        1000    ///<  Reset duration
+#define PHY_RESET_MSEC     500    ///<  PHY reset duration
+
+//
+//  RX Control register
+//
+
+#define RXC_PRO           0x0001  ///<  Receive all packets
+#define RXC_AMALL         0x0002  ///<  Receive all multicast packets
+#define RXC_SEP           0x0004  ///<  Save error packets
+#define RXC_AB            0x0008  ///<  Receive broadcast packets
+#define RXC_AM            0x0010  ///<  Use multicast destination address hash table
+#define RXC_AP            0x0020  ///<  Accept physical address from Multicast Filter
+#define RXC_SO            0x0080  ///<  Start operation
+#define RXC_MFB           0x0300  ///<  Maximum frame burst
+#define RXC_MFB_2048      0       ///<  Maximum frame size:  2048 bytes
+#define RXC_MFB_4096      0x0100  ///<  Maximum frame size:  4096 bytes
+#define RXC_MFB_8192      0x0200  ///<  Maximum frame size:  8192 bytes
+#define RXC_MFB_16384     0x0300  ///<  Maximum frame size: 16384 bytes
+
+/*Freddy*/
+#define RXC_RH1M          0x0100  ///<  Rx header 1
+#define RXC_RH2M          0x0200  ///<  Rx header 2
+#define RXC_RH3M          0x0400  ///<  Rx header 3
+/*Freddy*/
+
+//
+//  Medium Status register
+//
+
+#define MS_FD             0x0002  ///<  Full duplex
+#define MS_ONE            0x0004  ///<  Must be one
+#define MS_RFC            0x0010  ///<  RX flow control enable
+#define MS_TFC            0x0020  ///<  TX flow control enable
+#define MS_PF             0x0080  ///<  Pause frame enable
+#define MS_RE             0x0100  ///<  Receive enable
+#define MS_PS             0x0200  ///<  Port speed 1=100, 0=10 Mbps
+#define MS_SBP            0x0800  ///<  Stop back pressure
+#define MS_SM             0x1000  ///<  Super MAC support
+
+//
+//  Software PHY Select register
+//
+
+#define SPHY_PSEL         (1 << 0)    ///<  Select internal PHY
+#define SPHY_SSMII        (1 << 2)
+#define SPHY_SSEN         (1 << 4)
+#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_BZTYPE        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   0x0010  ///<  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_SROM_WRITE            0x0c  ///<  Read SROM register: Value: Address, Data: Value
+#define CMD_SROM_WRITE_EN         0x0d
+#define CMD_SROM_WRITE_DIS        0x0e
+#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      0x13  ///<  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_MULTICAST_HASH_READ   0x15  ///<  Read the multicast hash table
+#define CMD_MULTICAST_HASH_WRITE  0x16  ///<  Write the multicast hash table, Data: New 8 byte value
+#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_WRITE_GPIOS           0x1f
+#define CMD_RESET                 0x20  ///<  Reset register, Value: New value
+#define CMD_PHY_SELECT            0x22  ///<  PHY select register, Value: New value
+
+/*Freddy*/
+#define CMD_RXQTC                 0x2a  ///<  RX Queue Cascade Threshold Control Register
+/*Freddy*/
+
+//------------------------------
+//  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_BMCR                        0       ///<  Control register
+#define PHY_BMSR                        1       ///<  Status register
+#define PHY_ANAR                        4       ///<  Autonegotiation advertisement register
+#define PHY_ANLPAR                      5       ///<  Autonegotiation link parter ability register
+#define PHY_ANER                        6       ///<  Autonegotiation expansion register
+
+//  BMCR - Register 0
+
+#define BMCR_RESET                      0x8000  ///<  1 = Reset the PHY, bit clears after reset
+#define BMCR_LOOPBACK                   0x4000  ///<  1 = Loopback enabled
+#define BMCR_100MBPS                    0x2000  ///<  100 Mbits/Sec
+#define BMCR_10MBPS                     0       ///<  10 Mbits/Sec
+#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_HALF_DUPLEX                0       ///<  Half duplex operation
+#define BMCR_COLLISION_TEST             0x0080  ///<  1 = Collision test enabled
+
+//  BSMR - Register 1
+
+#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
+
+//  ANAR and ANLPAR Registers 4, 5
+
+#define AN_NP                           0x8000  ///<  1 = Next page available
+#define AN_ACK                          0x4000  ///<  1 = Link partner acknowledged
+#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
+
+
+
+//------------------------------------------------------------------------------
+//  Data Types
+//------------------------------------------------------------------------------
+
+/**
+  Ethernet header layout
+
+  IEEE 802.3-2002 Part 3 specification, section 3.1.1.
+**/
+#pragma pack(1)
+typedef struct {
+  UINT8 dest_addr[PXE_HWADDR_LEN_ETHER];  ///<  Destination LAN address
+  UINT8 src_addr[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 _RX_TX_PACKET {
+  struct _RX_TX_PACKET * pNext;       ///<  Next receive packet
+  UINT16 Length;                      ///<  Packet length
+  UINT16 LengthBar;                   ///<  Complement of the length
+  UINT8 Data[ AX88772_MAX_PKT_SIZE ]; ///<  Received packet data
+} RX_TX_PACKET;
+#pragma pack()
+
+/**
+  AX88772 control structure
+
+  The driver uses this structure to manage the Asix AX88772 10/100
+  Ethernet controller.
+**/
+typedef struct {
+  UINTN Signature;          ///<  Structure identification
+
+  //
+  //  USB data
+  //
+  EFI_HANDLE Controller;        ///<  Controller handle
+  EFI_USB_IO_PROTOCOL * pUsbIo;  ///<  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 bInitialized;     ///<  Controller initialized
+  UINT16 PhyId;             ///<  PHY ID
+
+  //
+  //  Link state
+  //
+  BOOLEAN b100Mbps;         ///<  Current link speed, FALSE = 10 Mbps
+  BOOLEAN bComplete;        ///<  Current state of auto-negotiation
+  BOOLEAN bFullDuplex;      ///<  Current duplex
+  BOOLEAN bLinkUp;          ///<  Current link state
+  UINTN PollCount;          ///<  Number of times the autonegotiation status was polled
+  UINT16 CurRxControl;
+  VOID * pTxBuffer;
+  //
+  //  Receive buffer list
+  //
+  UINT8     *pBulkInbuf;
+  UINT8    * pCurPktHdrOff;
+  UINT8     *pCurPktOff;
+  UINT16    PktCnt;
+
+  RX_TX_PACKET * pTxTest;
+
+  UINT8 MulticastHash[8];
+  EFI_MAC_ADDRESS MAC;
+
+  EFI_DEVICE_PATH_PROTOCOL                  *MyDevPath;
+  BOOLEAN   Grub_f;
+  BOOLEAN   bFirstRst;
+  BOOLEAN   Flag772A;
+#if RXTHOU
+  UINT8 rxburst;
+#endif
+
+} NIC_DEVICE;
+
+
+//
+// Global Variables
+//
+extern EFI_DRIVER_BINDING_PROTOCOL   gDriverBinding;
+extern EFI_COMPONENT_NAME_PROTOCOL   gComponentName;
+extern EFI_COMPONENT_NAME2_PROTOCOL  gComponentName2;
+
+#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 ::Ax88772Reset to perform the adapter specific
+  reset operation.  This routine also starts the link negotiation
+  by calling ::Ax88772NegotiateLinkStart.
+
+  @param [in] pSimpleNetwork    Protocol instance pointer
+  @param [in] bExtendedVerification  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 pSimpleNetwork 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 * pSimpleNetwork,
+  IN BOOLEAN bExtendedVerification
+  );
+
+/**
+  Initialize the simple network protocol.
+
+  This routine calls ::Ax88772MacAddressGet to obtain the
+  MAC address.
+
+  @param [in] pNicDevice       NIC_DEVICE_INSTANCE pointer
+
+  @retval EFI_SUCCESS     Setup was successful
+
+**/
+EFI_STATUS
+SN_Setup (
+  IN NIC_DEVICE * pNicDevice
+  );
+
+/**
+  This routine starts the network interface.
+
+  @param [in] pSimpleNetwork    Protocol instance pointer
+
+  @retval EFI_SUCCESS           This operation was successful.
+  @retval EFI_ALREADY_STARTED   The network interface was already started.
+  @retval EFI_INVALID_PARAMETER pSimpleNetwork 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 * pSimpleNetwork
+  );
+
+/**
+  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
+  pNew.
+
+  This routine calls ::Ax88772MacAddressSet to update the MAC address
+  in the network adapter.
+
+  @param [in] pSimpleNetwork    Protocol instance pointer
+  @param [in] bReset            Flag used to reset the station address to the
+                                network interface's permanent address.
+  @param [in] pNew              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 pSimpleNetwork 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 * pSimpleNetwork,
+  IN BOOLEAN bReset,
+  IN EFI_MAC_ADDRESS * pNew
+  );
+
+/**
+  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] pSimpleNetwork    Protocol instance pointer
+  @param [in] bReset            Set to TRUE to reset the statistics for the network interface.
+  @param [in, out] pStatisticsSize  On input the size, in bytes, of StatisticsTable.  On output
+                                the size, in bytes, of the resulting table of statistics.
+  @param [out] pStatisticsTable 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 pStatisticsTable is NULL or the buffer is too small.
+  @retval EFI_INVALID_PARAMETER pSimpleNetwork 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 * pSimpleNetwork,
+  IN BOOLEAN bReset,
+  IN OUT UINTN * pStatisticsSize,
+  OUT EFI_NETWORK_STATISTICS * pStatisticsTable
+  );
+
+/**
+  This function stops a network interface.  This call is only valid
+  if the network interface is in the started state.
+
+  @param [in] pSimpleNetwork    Protocol instance pointer
+
+  @retval EFI_SUCCESS           This operation was successful.
+  @retval EFI_NOT_STARTED       The network interface was not started.
+  @retval EFI_INVALID_PARAMETER pSimpleNetwork 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 * pSimpleNetwork
+  );
+
+/**
+  This function releases the memory buffers assigned in the Initialize() call.
+  Pending transmits and receives are lost, and interrupts are cleared and disabled.
+  After this call, only Initialize() and Stop() calls may be used.
+
+  @param [in] pSimpleNetwork    Protocol instance pointer
+
+  @retval EFI_SUCCESS           This operation was successful.
+  @retval EFI_NOT_STARTED       The network interface was not started.
+  @retval EFI_INVALID_PARAMETER pSimpleNetwork 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 * pSimpleNetwork
+  );
+
+/**
+  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 ::Ax88772Rx to empty the network adapter of
+  receive packets.  The routine then passes the transmit packet
+  to the network adapter.
+
+  @param [in] pSimpleNetwork    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] pBuffer           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] pSrcAddr          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] pDestAddr         The destination HW MAC address.  If HeaderSize is zero, then
+                                this parameter is ignored.
+  @param [in] pProtocol         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 pSimpleNetwork 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 * pSimpleNetwork,
+  IN UINTN HeaderSize,
+  IN UINTN BufferSize,
+  IN VOID * pBuffer,
+  IN EFI_MAC_ADDRESS * pSrcAddr,
+  IN EFI_MAC_ADDRESS * pDestAddr,
+  IN UINT16 * pProtocol
+  );
+
+//------------------------------------------------------------------------------
+// Support Routines
+//------------------------------------------------------------------------------
+
+/**
+  Get the MAC address
+
+  This routine calls ::Ax88772UsbCommand to request the MAC
+  address from the network adapter.
+
+  @param [in] pNicDevice       Pointer to the NIC_DEVICE structure
+  @param [out] pMacAddress      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
+Ax88772MacAddressGet (
+  IN NIC_DEVICE * pNicDevice,
+  OUT UINT8 * pMacAddress
+  );
+
+/**
+  Set the MAC address
+
+  This routine calls ::Ax88772UsbCommand to set the MAC address
+  in the network adapter.
+
+  @param [in] pNicDevice       Pointer to the NIC_DEVICE structure
+  @param [in] pMacAddress      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
+Ax88772MacAddressSet (
+  IN NIC_DEVICE * pNicDevice,
+  IN UINT8 * pMacAddress
+  );
+
+/**
+  Clear the multicast hash table
+
+  @param [in] pNicDevice       Pointer to the NIC_DEVICE structure
+
+**/
+VOID
+Ax88772MulticastClear (
+  IN NIC_DEVICE * pNicDevice
+  );
+
+/**
+  Enable a multicast address in the multicast hash table
+
+  This routine calls ::Ax88772Crc to compute the hash bit for
+  this MAC address.
+
+  @param [in] pNicDevice       Pointer to the NIC_DEVICE structure
+  @param [in] pMacAddress      Address of a six byte buffer to containing the MAC address.
+
+**/
+VOID
+Ax88772MulticastSet (
+  IN NIC_DEVICE * pNicDevice,
+  IN UINT8 * pMacAddress
+  );
+
+/**
+  Start the link negotiation
+
+  This routine calls ::Ax88772PhyWrite to start the PHY's link
+  negotiation.
+
+  @param [in] pNicDevice       Pointer to the NIC_DEVICE structure
+
+  @retval EFI_SUCCESS          The link negotiation was started.
+  @retval other                Failed to start the link negotiation.
+
+**/
+EFI_STATUS
+Ax88772NegotiateLinkStart (
+  IN NIC_DEVICE * pNicDevice
+  );
+
+/**
+  Complete the negotiation of the PHY link
+
+  This routine calls ::Ax88772PhyRead to determine if the
+  link negotiation is complete.
+
+  @param [in] pNicDevice       Pointer to the NIC_DEVICE structure
+  @param [in, out] pPollCount  Address of number of times this routine was polled
+  @param [out] pbComplete      Address of boolean to receive complate status.
+  @param [out] pbLinkUp        Address of boolean to receive link status, TRUE=up.
+  @param [out] pbHiSpeed       Address of boolean to receive link speed, TRUE=100Mbps.
+  @param [out] pbFullDuplex    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
+Ax88772NegotiateLinkComplete (
+  IN NIC_DEVICE * pNicDevice,
+  IN OUT UINTN * pPollCount,
+  OUT BOOLEAN * pbComplete,
+  OUT BOOLEAN * pbLinkUp,
+  OUT BOOLEAN * pbHiSpeed,
+  OUT BOOLEAN * pbFullDuplex
+  );
+
+/**
+  Read a register from the PHY
+
+  This routine calls ::Ax88772UsbCommand to read a PHY register.
+
+  @param [in] pNicDevice       Pointer to the NIC_DEVICE structure
+  @param [in] RegisterAddress  Number of the register to read.
+  @param [in, out] pPhyData    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
+Ax88772PhyRead (
+  IN NIC_DEVICE * pNicDevice,
+  IN UINT8 RegisterAddress,
+  IN OUT UINT16 * pPhyData
+  );
+
+/**
+  Write to a PHY register
+
+  This routine calls ::Ax88772UsbCommand to write a PHY register.
+
+  @param [in] pNicDevice       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
+Ax88772PhyWrite (
+  IN NIC_DEVICE * pNicDevice,
+  IN UINT8 RegisterAddress,
+  IN UINT16 PhyData
+  );
+
+/**
+  Reset the AX88772
+
+  This routine uses ::Ax88772UsbCommand to reset the network
+  adapter.  This routine also uses ::Ax88772PhyWrite to reset
+  the PHY.
+
+  @param [in] pNicDevice       Pointer to the NIC_DEVICE structure
+
+  @retval EFI_SUCCESS          The MAC address is available.
+  @retval other                The MAC address is not valid.
+
+**/
+EFI_STATUS
+Ax88772Reset (
+  IN NIC_DEVICE * pNicDevice
+  );
+
+VOID
+Ax88772ChkLink (
+  IN NIC_DEVICE * pNicDevice,
+  IN BOOLEAN bUpdateLink
+  );
+
+/**
+  Receive a frame from the network.
+
+  This routine polls the USB receive interface for a packet.  If a packet
+  is available, this routine adds the receive packet to the list of
+  pending receive packets.
+
+  This routine calls ::Ax88772NegotiateLinkComplete to verify
+  that the link is up.  This routine also calls ::SN_Reset to
+  reset the network adapter when necessary.  Finally this
+  routine attempts to receive one or more packets from the
+  network adapter.
+
+  @param [in] pNicDevice  Pointer to the NIC_DEVICE structure
+  @param [in] bUpdateLink TRUE = Update link status
+
+**/
+VOID
+Ax88772Rx (
+  IN NIC_DEVICE * pNicDevice,
+  IN BOOLEAN bUpdateLink
+  );
+
+/**
+  Enable or disable the receiver
+
+  This routine calls ::Ax88772UsbCommand to update the
+  receiver state.  This routine also calls ::Ax88772MacAddressSet
+  to establish the MAC address for the network adapter.
+
+  @param [in] pNicDevice       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
+Ax88772RxControl (
+  IN NIC_DEVICE * pNicDevice,
+  IN UINT32 RxFilter
+  );
+
+EFI_STATUS
+Ax88772ReloadSrom  (
+  IN NIC_DEVICE * pNicDevice
+  );
+
+/**
+  Read an SROM location
+
+  This routine calls ::Ax88772UsbCommand to read data from the
+  SROM.
+
+  @param [in] pNicDevice       Pointer to the NIC_DEVICE structure
+  @param [in] Address          SROM address
+  @param [out] pData           Buffer to receive the data
+
+  @retval EFI_SUCCESS          The read was successful
+  @retval other                The read failed
+
+**/
+EFI_STATUS
+Ax88772SromRead (
+  IN NIC_DEVICE * pNicDevice,
+  IN UINT32 Address,
+  OUT UINT16 * pData
+  );
+
+
+EFI_STATUS
+Ax88772EnableSromWrite  (
+  IN NIC_DEVICE * pNicDevice
+  );
+
+
+EFI_STATUS
+Ax88772DisableSromWrite  (
+  IN NIC_DEVICE * pNicDevice
+  );
+
+EFI_STATUS
+Ax88772SromWrite (
+  IN NIC_DEVICE * pNicDevice,
+  IN UINT32 Address,
+  OUT UINT16 * pData
+  );
+#if 0
+/**
+  This routine is called at a regular interval to poll for
+  receive packets.
+
+  This routine polls the link state and gets any receive packets
+  by calling ::Ax88772Rx.
+
+  @param [in] Event            Timer event
+  @param [in] pNicDevice       Pointer to the NIC_DEVICE structure
+
+**/
+VOID
+Ax88772Timer (
+  IN EFI_EVENT Event,
+  IN NIC_DEVICE * pNicDevice
+  );
+#endif
+/**
+  Send a command to the USB device.
+
+  @param [in] pNicDevice       Pointer to the NIC_DEVICE structure
+  @param [in] pRequest         Pointer to the request structure
+  @param [in, out] pBuffer     Data buffer address
+
+  @retval EFI_SUCCESS          The USB transfer was successful
+  @retval other                The USB transfer failed
+
+**/
+EFI_STATUS
+Ax88772UsbCommand (
+  IN NIC_DEVICE * pNicDevice,
+  IN USB_DEVICE_REQUEST * pRequest,
+  IN OUT VOID * pBuffer
+  );
+
+BOOLEAN
+Ax88772GetLinkStatus (
+  IN NIC_DEVICE * pNicDevice
+) ;
+
+//------------------------------------------------------------------------------
+// EFI Component Name Protocol Support
+//------------------------------------------------------------------------------
+
+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] pThis             A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+                                EFI_COMPONENT_NAME_PROTOCOL instance.
+  @param [in] pLanguage         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] ppDriverName     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 * pThis,
+  IN  CHAR8 * pLanguage,
+  OUT CHAR16 ** ppDriverName
+  );
+
+
+/**
+  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] pThis             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] pLanguage         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] ppControllerName 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 * pThis,
+  IN  EFI_HANDLE ControllerHandle,
+  IN OPTIONAL EFI_HANDLE ChildHandle,
+  IN  CHAR8 * pLanguage,
+  OUT CHAR16 ** ppControllerName
+  );
+
+
+EFI_STATUS
+Ax88772BulkIn(
+  IN NIC_DEVICE * pNicDevice
+);
+
+//------------------------------------------------------------------------------
+
+#endif  //  _AX88772_H_
diff --git a/Drivers/OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772c/Ax88772.c b/Drivers/OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772c/Ax88772.c
new file mode 100644
index 000000000000..a905dc548197
--- /dev/null
+++ b/Drivers/OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772c/Ax88772.c
@@ -0,0 +1,1296 @@
+/** @file
+  Implement the interface to the AX88772 Ethernet controller.
+
+  This module implements the interface to the ASIX AX88772
+  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. All rights reserved.
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "Ax88772.h"
+
+
+/**
+  Compute the CRC
+
+  @param [in] pMacAddress      Address of a six byte buffer to containing the MAC address.
+
+  @returns The CRC-32 value associated with this MAC address
+
+**/
+UINT32
+Ax88772Crc (
+  IN UINT8 * pMacAddress
+  )
+{
+  UINT32 BitNumber;
+  INT32 Carry;
+  INT32 Crc;
+  UINT32 Data;
+  UINT8 * pEnd;
+
+  //
+  //  Walk the MAC address
+  //
+  Crc = -1;
+  pEnd = &pMacAddress[ PXE_HWADDR_LEN_ETHER ];
+  while ( pEnd > pMacAddress ) {
+    Data = *pMacAddress++;
+
+
+    //
+    //  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 ( 0 != Carry ) {
+        Crc ^= 0x04c11db7;
+      }
+      Data >>= 1;
+    }
+  }
+
+  //
+  //  Return the CRC value
+  //
+
+  return (UINT32) Crc;
+}
+
+
+/**
+  Get the MAC address
+
+  This routine calls ::Ax88772UsbCommand to request the MAC
+  address from the network adapter.
+
+  @param [in] pNicDevice       Pointer to the NIC_DEVICE structure
+  @param [out] pMacAddress      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
+Ax88772MacAddressGet (
+  IN NIC_DEVICE * pNicDevice,
+  OUT UINT8 * pMacAddress
+  )
+{
+  USB_DEVICE_REQUEST SetupMsg;
+  EFI_STATUS Status;
+
+  //
+  //  Set the register address.
+  //
+  SetupMsg.RequestType = USB_ENDPOINT_DIR_IN
+                       | USB_REQ_TYPE_VENDOR
+                       | USB_TARGET_DEVICE;
+  SetupMsg.Request = CMD_MAC_ADDRESS_READ;
+  SetupMsg.Value = 0;
+  SetupMsg.Index = 0;
+  SetupMsg.Length = PXE_HWADDR_LEN_ETHER;
+
+  //
+  //  Read the PHY register
+  //
+  Status = Ax88772UsbCommand ( pNicDevice,
+                               &SetupMsg,
+                               pMacAddress );
+
+  //
+  // Return the operation status
+  //
+  return Status;
+}
+
+
+/**
+  Set the MAC address
+
+  This routine calls ::Ax88772UsbCommand to set the MAC address
+  in the network adapter.
+
+  @param [in] pNicDevice       Pointer to the NIC_DEVICE structure
+  @param [in] pMacAddress      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
+Ax88772MacAddressSet (
+  IN NIC_DEVICE * pNicDevice,
+  IN UINT8 * pMacAddress
+  )
+{
+  USB_DEVICE_REQUEST SetupMsg;
+  EFI_STATUS Status;
+
+  //
+  //  Set the register address.
+  //
+  SetupMsg.RequestType = USB_REQ_TYPE_VENDOR
+                       | USB_TARGET_DEVICE;
+  SetupMsg.Request = CMD_MAC_ADDRESS_WRITE;
+  SetupMsg.Value = 0;
+  SetupMsg.Index = 0;
+  SetupMsg.Length = PXE_HWADDR_LEN_ETHER;
+
+  //
+  //  Read the PHY register
+  //
+  Status = Ax88772UsbCommand ( pNicDevice,
+                               &SetupMsg,
+                               pMacAddress );
+
+  //
+  // Return the operation status
+  //
+  return Status;
+}
+
+/**
+  Clear the multicast hash table
+
+  @param [in] pNicDevice       Pointer to the NIC_DEVICE structure
+
+**/
+VOID
+Ax88772MulticastClear (
+  IN NIC_DEVICE * pNicDevice
+  )
+{
+  int i = 0;
+  //
+  // Clear the multicast hash table
+  //
+  for ( i = 0 ; i < 8 ; i ++ )
+     pNicDevice->MulticastHash[i] = 0;
+}
+
+
+/**
+  Enable a multicast address in the multicast hash table
+
+  This routine calls ::Ax88772Crc to compute the hash bit for
+  this MAC address.
+
+  @param [in] pNicDevice       Pointer to the NIC_DEVICE structure
+  @param [in] pMacAddress      Address of a six byte buffer to containing the MAC address.
+
+**/
+VOID
+Ax88772MulticastSet (
+  IN NIC_DEVICE * pNicDevice,
+  IN UINT8 * pMacAddress
+  )
+{
+  UINT32 Crc;
+
+  //
+  //  Compute the CRC on the destination address
+  //
+  Crc = Ax88772Crc ( pMacAddress ) >> 26;
+
+  //
+  //  Set the bit corresponding to the destination address
+  //
+  pNicDevice->MulticastHash [ Crc >> 3 ] |= ( 1<< (Crc& 7));
+
+}
+
+/**
+  Start the link negotiation
+
+  This routine calls ::Ax88772PhyWrite to start the PHY's link
+  negotiation.
+
+  @param [in] pNicDevice       Pointer to the NIC_DEVICE structure
+
+  @retval EFI_SUCCESS          The link negotiation was started.
+  @retval other                Failed to start the link negotiation.
+
+**/
+EFI_STATUS
+Ax88772NegotiateLinkStart (
+  IN NIC_DEVICE * pNicDevice
+  )
+{
+  UINT16 Control;
+  EFI_STATUS Status;
+
+  //
+  // Set the supported capabilities.
+  //
+  Status = Ax88772PhyWrite ( pNicDevice,
+                             PHY_ANAR,
+                             AN_CSMA_CD
+                             | AN_TX_FDX | AN_TX_HDX
+                             | AN_10_FDX | AN_10_HDX | AN_FCS );
+  if ( !EFI_ERROR ( Status )) {
+    //
+    // Set the link speed and duplex
+    //
+    Control = BMCR_AUTONEGOTIATION_ENABLE
+            | BMCR_RESTART_AUTONEGOTIATION;
+    if ( pNicDevice->b100Mbps ) {
+      Control |= BMCR_100MBPS;
+    }
+    if ( pNicDevice->bFullDuplex ) {
+      Control |= BMCR_FULL_DUPLEX;
+    }
+    Status = Ax88772PhyWrite ( pNicDevice, PHY_BMCR, Control );
+
+    if (!EFI_ERROR(Status))
+        gBS->Stall(3000000);
+  }
+  return Status;
+}
+
+
+
+/**
+  Complete the negotiation of the PHY link
+
+  This routine calls ::Ax88772PhyRead to determine if the
+  link negotiation is complete.
+
+  @param [in] pNicDevice       Pointer to the NIC_DEVICE structure
+  @param [in, out] pPollCount  Address of number of times this routine was polled
+  @param [out] pbComplete      Address of boolean to receive complate status.
+  @param [out] pbLinkUp        Address of boolean to receive link status, TRUE=up.
+  @param [out] pbHiSpeed       Address of boolean to receive link speed, TRUE=100Mbps.
+  @param [out] pbFullDuplex    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
+Ax88772NegotiateLinkComplete (
+  IN NIC_DEVICE * pNicDevice,
+  IN OUT UINTN * pPollCount,
+  OUT BOOLEAN * pbComplete,
+  OUT BOOLEAN * pbLinkUp,
+  OUT BOOLEAN * pbHiSpeed,
+  OUT BOOLEAN * pbFullDuplex
+  )
+{
+  UINT16 Mask;
+  UINT16 PhyData;
+  EFI_STATUS  Status;
+
+  //
+  //  Determine if the link is up.
+  //
+  *pbComplete = FALSE;
+
+  //
+  //  Get the link status
+  //
+  Status = Ax88772PhyRead ( pNicDevice,
+                            PHY_BMSR,
+                            &PhyData );
+
+  if ( !EFI_ERROR ( Status )) {
+    *pbLinkUp = (BOOLEAN)( 0 != ( PhyData & BMSR_LINKST ));
+    if ( 0 == *pbLinkUp ) {
+    } else {
+      *pbComplete = (BOOLEAN)( 0 != ( PhyData & 0x20 ));
+      if ( 0 == *pbComplete ) {
+      } else {
+        Status = Ax88772PhyRead ( pNicDevice,
+                                  PHY_ANLPAR,
+                                  &PhyData );
+        if ( !EFI_ERROR ( Status )) {
+          //
+          //  Autonegotiation is complete
+          //  Determine the link speed.
+          //
+          *pbHiSpeed = (BOOLEAN)( 0 != ( PhyData & ( AN_TX_FDX | AN_TX_HDX )));
+
+          //
+          //  Determine the link duplex.
+          //
+          Mask = ( *pbHiSpeed ) ? AN_TX_FDX : AN_10_FDX;
+          *pbFullDuplex = (BOOLEAN)( 0 != ( PhyData & Mask ));
+        }
+      }
+    }
+  } else {
+  }
+  return Status;
+}
+
+
+/**
+  Read a register from the PHY
+
+  This routine calls ::Ax88772UsbCommand to read a PHY register.
+
+  @param [in] pNicDevice       Pointer to the NIC_DEVICE structure
+  @param [in] RegisterAddress  Number of the register to read.
+  @param [in, out] pPhyData    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
+Ax88772PhyRead (
+  IN NIC_DEVICE * pNicDevice,
+  IN UINT8 RegisterAddress,
+  IN OUT UINT16 * pPhyData
+  )
+{
+  USB_DEVICE_REQUEST SetupMsg;
+  EFI_STATUS Status;
+
+  //
+  //  Request access to the PHY
+  //
+  SetupMsg.RequestType = USB_REQ_TYPE_VENDOR
+                       | USB_TARGET_DEVICE;
+  SetupMsg.Request = CMD_PHY_ACCESS_SOFTWARE;
+  SetupMsg.Value = 0;
+  SetupMsg.Index = 0;
+  SetupMsg.Length = 0;
+  Status = Ax88772UsbCommand ( pNicDevice,
+                               &SetupMsg,
+                               NULL );
+  if ( !EFI_ERROR ( Status )) {
+    //
+    //  Read the PHY register address.
+    //
+    SetupMsg.RequestType = USB_ENDPOINT_DIR_IN
+                         | USB_REQ_TYPE_VENDOR
+                         | USB_TARGET_DEVICE;
+    SetupMsg.Request = CMD_PHY_REG_READ;
+    SetupMsg.Value = pNicDevice->PhyId;
+    SetupMsg.Index = RegisterAddress;
+    SetupMsg.Length = sizeof ( *pPhyData );
+    Status = Ax88772UsbCommand ( pNicDevice,
+                                 &SetupMsg,
+                                 pPhyData );
+    if ( !EFI_ERROR ( Status )) {
+
+      //
+      //  Release the PHY to the hardware
+      //
+      SetupMsg.RequestType = USB_REQ_TYPE_VENDOR
+                           | USB_TARGET_DEVICE;
+      SetupMsg.Request = CMD_PHY_ACCESS_HARDWARE;
+      SetupMsg.Value = 0;
+      SetupMsg.Index = 0;
+      SetupMsg.Length = 0;
+      Status = Ax88772UsbCommand ( pNicDevice,
+                                   &SetupMsg,
+                                   NULL );
+    }
+  }
+
+  //
+  //  Return the operation status.
+  //
+  return Status;
+}
+
+
+/**
+  Write to a PHY register
+
+  This routine calls ::Ax88772UsbCommand to write a PHY register.
+
+  @param [in] pNicDevice       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
+Ax88772PhyWrite (
+  IN NIC_DEVICE * pNicDevice,
+  IN UINT8 RegisterAddress,
+  IN UINT16 PhyData
+  )
+{
+  USB_DEVICE_REQUEST SetupMsg;
+  EFI_STATUS Status;
+
+  //
+  //  Request access to the PHY
+  //
+  SetupMsg.RequestType = USB_REQ_TYPE_VENDOR
+                       | USB_TARGET_DEVICE;
+  SetupMsg.Request = CMD_PHY_ACCESS_SOFTWARE;
+  SetupMsg.Value = 0;
+  SetupMsg.Index = 0;
+  SetupMsg.Length = 0;
+  Status = Ax88772UsbCommand ( pNicDevice,
+                               &SetupMsg,
+                               NULL );
+  if ( !EFI_ERROR ( Status )) {
+    //
+    //  Write the PHY register
+    //
+    SetupMsg.RequestType = USB_REQ_TYPE_VENDOR
+                         | USB_TARGET_DEVICE;
+    SetupMsg.Request = CMD_PHY_REG_WRITE;
+    SetupMsg.Value = pNicDevice->PhyId;
+    SetupMsg.Index = RegisterAddress;
+    SetupMsg.Length = sizeof ( PhyData );
+    Status = Ax88772UsbCommand ( pNicDevice,
+                                 &SetupMsg,
+                                 &PhyData );
+    if ( !EFI_ERROR ( Status )) {
+
+      //
+      //  Release the PHY to the hardware
+      //
+      SetupMsg.RequestType = USB_REQ_TYPE_VENDOR
+                           | USB_TARGET_DEVICE;
+      SetupMsg.Request = CMD_PHY_ACCESS_HARDWARE;
+      SetupMsg.Value = 0;
+      SetupMsg.Index = 0;
+      SetupMsg.Length = 0;
+      Status = Ax88772UsbCommand ( pNicDevice,
+                                   &SetupMsg,
+                                   NULL );
+    }
+  }
+
+  //
+  //  Return the operation status.
+  //
+  return Status;
+}
+
+
+/**
+  Reset the AX88772
+
+  This routine uses ::Ax88772UsbCommand to reset the network
+  adapter.  This routine also uses ::Ax88772PhyWrite to reset
+  the PHY.
+
+  @param [in] pNicDevice       Pointer to the NIC_DEVICE structure
+
+  @retval EFI_SUCCESS          The MAC address is available.
+  @retval other                The MAC address is not valid.
+
+**/
+EFI_STATUS
+Ax88772Reset (
+  IN NIC_DEVICE * pNicDevice
+  )
+{
+  USB_DEVICE_REQUEST SetupMsg;
+  EFI_STATUS Status;
+  EFI_USB_IO_PROTOCOL *pUsbIo;
+
+  pUsbIo = pNicDevice->pUsbIo;
+
+  SetupMsg.RequestType = USB_REQ_TYPE_VENDOR
+                           | USB_TARGET_DEVICE;
+  SetupMsg.Request = CMD_PHY_ACCESS_HARDWARE;
+  SetupMsg.Value = 0;
+  SetupMsg.Index = 0;
+  SetupMsg.Length = 0;
+  Status = Ax88772UsbCommand ( pNicDevice,
+                               &SetupMsg,
+                               NULL );
+
+  if (EFI_ERROR(Status)) goto err;
+
+  SetupMsg.RequestType = USB_REQ_TYPE_VENDOR
+                          | USB_TARGET_DEVICE;
+  SetupMsg.Request = CMD_PHY_SELECT;
+  SetupMsg.Value = SPHY_PSEL;
+  SetupMsg.Index = 0;
+  SetupMsg.Length = 0;
+  Status = Ax88772UsbCommand ( pNicDevice,
+                               &SetupMsg,
+                               NULL );
+
+  if (EFI_ERROR(Status)) goto err;
+
+  SetupMsg.RequestType = USB_REQ_TYPE_VENDOR
+                       | USB_TARGET_DEVICE;
+  SetupMsg.Request = CMD_RESET;
+  SetupMsg.Value = SRR_IPRL ;
+  SetupMsg.Index = 0;
+  SetupMsg.Length = 0;
+  Status = Ax88772UsbCommand ( pNicDevice,
+                               &SetupMsg,
+                               NULL );
+
+  if (EFI_ERROR(Status)) goto err;
+
+  SetupMsg.RequestType = USB_REQ_TYPE_VENDOR
+                       | USB_TARGET_DEVICE;
+  SetupMsg.Request = CMD_RESET;
+  SetupMsg.Value = SRR_IPPD | SRR_IPRL ;
+  SetupMsg.Index = 0;
+  SetupMsg.Length = 0;
+  Status = Ax88772UsbCommand ( pNicDevice,
+                               &SetupMsg,
+                               NULL );
+
+  gBS->Stall ( 200000 );
+
+  if (EFI_ERROR(Status)) goto err;
+
+  SetupMsg.RequestType = USB_REQ_TYPE_VENDOR
+                       | USB_TARGET_DEVICE;
+  SetupMsg.Request = CMD_RESET;
+  SetupMsg.Value =  SRR_IPRL  ;
+  SetupMsg.Index = 0;
+  SetupMsg.Length = 0;
+  Status = Ax88772UsbCommand ( pNicDevice,
+                               &SetupMsg,
+                               NULL );
+
+  gBS->Stall ( 200000 );
+
+  if (EFI_ERROR(Status)) goto err;
+
+  SetupMsg.RequestType = USB_REQ_TYPE_VENDOR
+                       | USB_TARGET_DEVICE;
+  SetupMsg.Request = CMD_RESET;
+  SetupMsg.Value = 0;
+  SetupMsg.Index = 0;
+  SetupMsg.Length = 0;
+  Status = Ax88772UsbCommand ( pNicDevice,
+                               &SetupMsg,
+                               NULL );
+
+  if (EFI_ERROR(Status)) goto err;
+
+  SetupMsg.RequestType = USB_REQ_TYPE_VENDOR
+                       | USB_TARGET_DEVICE;
+  SetupMsg.Request = CMD_PHY_SELECT;
+  SetupMsg.Value = SPHY_PSEL;
+  SetupMsg.Index = 0;
+  SetupMsg.Length = 0;
+  Status = Ax88772UsbCommand ( pNicDevice,
+                               &SetupMsg,
+                               NULL );
+
+  if (EFI_ERROR(Status)) goto err;
+
+  SetupMsg.RequestType = USB_REQ_TYPE_VENDOR
+                       | USB_TARGET_DEVICE;
+  SetupMsg.Request = CMD_RESET;
+  SetupMsg.Value =  SRR_IPRL | SRR_BZ | SRR_BZTYPE;
+  SetupMsg.Index = 0;
+  SetupMsg.Length = 0;
+  Status = Ax88772UsbCommand ( pNicDevice,
+                               &SetupMsg,
+                               NULL );
+
+  if (EFI_ERROR(Status)) goto err;
+
+  SetupMsg.RequestType = USB_REQ_TYPE_VENDOR
+                       | USB_TARGET_DEVICE;
+  SetupMsg.Request = CMD_RX_CONTROL_WRITE;
+  SetupMsg.Value = 0;
+  SetupMsg.Index = 0;
+  SetupMsg.Length = 0;
+  Status = Ax88772UsbCommand ( pNicDevice,
+                               &SetupMsg,
+                               NULL );
+
+  if (EFI_ERROR(Status)) goto err;
+
+  if (!pNicDevice->Flag772A) {
+    SetupMsg.RequestType = USB_REQ_TYPE_VENDOR
+                         | USB_TARGET_DEVICE;
+    SetupMsg.Request = CMD_RXQTC;
+#if RXTHOU
+    /*size cannot exceed 3K*/
+    //SetupMsg.Value = 0x0;
+    //SetupMsg.Index = 0x8001;
+    /*size cannot exceed 16K*/
+    SetupMsg.Value = 0x8300;
+    SetupMsg.Index = 0x8500;
+    /*size cannot exceed 32K*/
+    //SetupMsg.Value = 0x8784;
+    //SetupMsg.Index = 0x8A00;
+    SetupMsg.Length = 0;
+#else
+    SetupMsg.Value = 0x8000;
+    SetupMsg.Index = 0x8001;
+#endif
+    Status = Ax88772UsbCommand ( pNicDevice,
+                                 &SetupMsg,
+                                 NULL );
+  }
+err:
+  return Status;
+}
+
+/**
+  Enable or disable the receiver
+
+  This routine calls ::Ax88772UsbCommand to update the
+  receiver state.  This routine also calls ::Ax88772MacAddressSet
+  to establish the MAC address for the network adapter.
+
+  @param [in] pNicDevice       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
+Ax88772RxControl (
+  IN NIC_DEVICE * pNicDevice,
+  IN UINT32 RxFilter
+  )
+{
+  UINT16 MediumStatus;
+  UINT16 RxControl;
+  USB_DEVICE_REQUEST SetupMsg;
+  EFI_STATUS Status = EFI_SUCCESS;
+
+  //
+  // Enable the receiver if something is to be received
+  //
+  if ( 0 != RxFilter ) {
+    //
+    //  Enable the receiver
+    //
+    SetupMsg.RequestType = USB_ENDPOINT_DIR_IN
+                         | USB_REQ_TYPE_VENDOR
+                         | USB_TARGET_DEVICE;
+    SetupMsg.Request = CMD_MEDIUM_STATUS_READ;
+    SetupMsg.Value = 0;
+    SetupMsg.Index = 0;
+    SetupMsg.Length = sizeof ( MediumStatus );
+    Status = Ax88772UsbCommand ( pNicDevice,
+                                 &SetupMsg,
+                                 &MediumStatus );
+    if ( !EFI_ERROR ( Status )) {
+      if ( 0 == ( MediumStatus & MS_RE )) {
+        MediumStatus |= MS_RE | MS_ONE;
+
+        if ( pNicDevice->bFullDuplex )
+          MediumStatus |= MS_TFC | MS_RFC | MS_FD;
+        else
+          MediumStatus &= ~(MS_TFC | MS_RFC | MS_FD);
+
+        if ( pNicDevice->b100Mbps )
+          MediumStatus |= MS_PS;
+        else
+          MediumStatus &= ~MS_PS;
+
+        SetupMsg.RequestType = USB_REQ_TYPE_VENDOR
+                             | USB_TARGET_DEVICE;
+        SetupMsg.Request = CMD_MEDIUM_STATUS_WRITE;
+        SetupMsg.Value = MediumStatus;
+        SetupMsg.Index = 0;
+        SetupMsg.Length = 0;
+        Status = Ax88772UsbCommand ( pNicDevice,
+                                     &SetupMsg,
+                                     NULL );
+
+        if (EFI_ERROR(Status))
+              goto EXIT;
+      }
+    } else {
+        goto EXIT;
+    }
+  }
+  RxControl = RXC_SO;
+  if (!pNicDevice->Flag772A)
+    RxControl |= RXC_RH1M;
+
+  //
+  //  Enable multicast if requested
+  //
+  if ( 0 != ( RxFilter & EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST )) {
+      RxControl |= RXC_AM;
+      //
+      //  Update the multicast hash table
+      //
+      SetupMsg.RequestType = USB_REQ_TYPE_VENDOR
+                           | USB_TARGET_DEVICE;
+      SetupMsg.Request = CMD_MULTICAST_HASH_WRITE;
+      SetupMsg.Value = 0;
+      SetupMsg.Index = 0;
+      SetupMsg.Length = sizeof ( pNicDevice ->MulticastHash );
+      Status = Ax88772UsbCommand ( pNicDevice,
+                                   &SetupMsg,
+                                   &pNicDevice->MulticastHash );
+
+      if (EFI_ERROR(Status))
+              goto EXIT;
+  }
+
+  //
+  //  Enable all multicast if requested
+  //
+  if ( 0 != ( RxFilter & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST )) {
+      RxControl |= RXC_AMALL;
+  }
+
+  //
+  //  Enable broadcast if requested
+  //
+  if ( 0 != ( RxFilter & EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST )) {
+      RxControl |= RXC_AB;
+  }
+
+  //
+  //  Enable promiscuous mode if requested
+  //
+  if ( 0 != ( RxFilter & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS )) {
+      RxControl |= RXC_PRO;
+  }
+
+  //
+  //  Update the receiver control
+  //
+  if (pNicDevice->CurRxControl != RxControl) {
+    SetupMsg.RequestType = USB_REQ_TYPE_VENDOR
+                         | USB_TARGET_DEVICE;
+    SetupMsg.Request = CMD_RX_CONTROL_WRITE;
+#if RXTHOU
+    if (pNicDevice->Flag772A)
+      RxControl |= 0x0300;
+#endif
+    if (pNicDevice->Flag772A)
+      RxControl &= ~(RXC_MFB);
+    SetupMsg.Value = RxControl;
+    SetupMsg.Index = 0;
+    SetupMsg.Length = 0;
+    Status = Ax88772UsbCommand ( pNicDevice,
+                                 &SetupMsg,
+                                 NULL );
+    if ( !EFI_ERROR ( Status ))
+      pNicDevice->CurRxControl = RxControl;
+  }
+
+  //
+  // Return the operation status
+  //
+EXIT:
+  return Status;
+}
+
+
+
+EFI_STATUS
+Ax88772ReloadSrom  (
+  IN NIC_DEVICE * pNicDevice
+  )
+{
+  USB_DEVICE_REQUEST SetupMsg;
+  EFI_STATUS Status;
+
+  //
+  //  Read a value from the SROM
+  //
+  SetupMsg.RequestType = USB_REQ_TYPE_VENDOR
+                       | USB_TARGET_DEVICE;
+
+  SetupMsg.Request = CMD_WRITE_GPIOS;
+  SetupMsg.Value = 0x80;
+  SetupMsg.Index = 0;
+  SetupMsg.Length = 0 ;
+  Status = Ax88772UsbCommand ( pNicDevice,
+                               &SetupMsg,
+                               NULL );
+
+  if (EFI_SUCCESS == Status)
+          gBS->Stall(500000);
+
+  return Status;
+
+}
+
+
+/**
+  Read an SROM location
+
+  This routine calls ::Ax88772UsbCommand to read data from the
+  SROM.
+
+  @param [in] pNicDevice       Pointer to the NIC_DEVICE structure
+  @param [in] Address          SROM address
+  @param [out] pData           Buffer to receive the data
+
+  @retval EFI_SUCCESS          The read was successful
+  @retval other                The read failed
+
+**/
+EFI_STATUS
+Ax88772SromRead (
+  IN NIC_DEVICE * pNicDevice,
+  IN UINT32 Address,
+  OUT UINT16 * pData
+  )
+{
+
+  USB_DEVICE_REQUEST SetupMsg;
+  EFI_STATUS Status;
+
+  //
+  //  Read a value from the SROM
+  //
+  SetupMsg.RequestType = USB_ENDPOINT_DIR_IN
+                       | USB_REQ_TYPE_VENDOR
+                       | USB_TARGET_DEVICE;
+  SetupMsg.Request = CMD_SROM_READ;
+  SetupMsg.Value = (UINT16) Address;
+  SetupMsg.Index = 0;
+  SetupMsg.Length = sizeof ( *pData );
+  Status = Ax88772UsbCommand ( pNicDevice,
+                               &SetupMsg,
+                               pData );
+
+  //
+  // Return the operation status
+  //
+  return Status;
+}
+
+EFI_STATUS
+Ax88772EnableSromWrite  (
+  IN NIC_DEVICE * pNicDevice
+  )
+{
+  USB_DEVICE_REQUEST SetupMsg;
+  EFI_STATUS Status;
+
+  //
+  //  Read a value from the SROM
+  //
+  SetupMsg.RequestType = USB_REQ_TYPE_VENDOR
+                       | USB_TARGET_DEVICE;
+
+  SetupMsg.Request = CMD_SROM_WRITE_EN;
+  SetupMsg.Value = 0;
+  SetupMsg.Index = 0;
+  SetupMsg.Length = 0 ;
+  Status = Ax88772UsbCommand ( pNicDevice,
+                               &SetupMsg,
+                               NULL );
+
+  if (EFI_SUCCESS == Status)
+          gBS->Stall(500000);
+
+  return Status;
+
+}
+
+
+EFI_STATUS
+Ax88772DisableSromWrite  (
+  IN NIC_DEVICE * pNicDevice
+  )
+{
+  USB_DEVICE_REQUEST SetupMsg;
+  EFI_STATUS Status;
+
+  //
+  //  Read a value from the SROM
+  //
+  SetupMsg.RequestType = USB_REQ_TYPE_VENDOR
+                       | USB_TARGET_DEVICE;
+
+  SetupMsg.Request = CMD_SROM_WRITE_DIS;
+  SetupMsg.Value = 0;
+  SetupMsg.Index = 0;
+  SetupMsg.Length = 0;
+  Status = Ax88772UsbCommand ( pNicDevice,
+                      &SetupMsg,
+                      NULL );
+
+  if (EFI_SUCCESS == Status)
+          gBS->Stall(500000);
+
+  return Status;
+
+}
+
+/**
+  Write an SROM location
+
+  This routine calls ::Ax88772UsbCommand to write data from the
+  SROM.
+
+  @param [in] pNicDevice       Pointer to the NIC_DEVICE structure
+  @param [in] Address          SROM address
+  @param [out] pData           Buffer of data to write
+
+  @retval EFI_SUCCESS          The write was successful
+  @retval other                The write failed
+
+**/
+EFI_STATUS
+Ax88772SromWrite (
+  IN NIC_DEVICE * pNicDevice,
+  IN UINT32 Address,
+  IN UINT16 * pData
+  )
+{
+
+  USB_DEVICE_REQUEST SetupMsg;
+  EFI_STATUS Status;
+
+  SetupMsg.RequestType = USB_REQ_TYPE_VENDOR
+                       | USB_TARGET_DEVICE;
+
+  SetupMsg.Request = CMD_SROM_WRITE;
+  SetupMsg.Value = (UINT16) Address;
+  SetupMsg.Index = (UINT16) (*pData);
+  SetupMsg.Length = 0;
+
+  Status = Ax88772UsbCommand ( pNicDevice,
+                               &SetupMsg,
+                               NULL );
+
+  //
+  // Return the operation status
+  //
+  return Status;
+}
+
+/**
+  Send a command to the USB device.
+
+  @param [in] pNicDevice       Pointer to the NIC_DEVICE structure
+  @param [in] pRequest         Pointer to the request structure
+  @param [in, out] pBuffer     Data buffer address
+
+  @retval EFI_SUCCESS          The USB transfer was successful
+  @retval other                The USB transfer failed
+
+**/
+EFI_STATUS
+Ax88772UsbCommand (
+  IN NIC_DEVICE * pNicDevice,
+  IN USB_DEVICE_REQUEST * pRequest,
+  IN OUT VOID * pBuffer
+  )
+{
+  UINT32 CmdStatus;
+  EFI_USB_DATA_DIRECTION Direction;
+  EFI_USB_IO_PROTOCOL * pUsbIo;
+  EFI_STATUS Status;
+
+  //
+  // Determine the transfer direction
+  //
+  Direction = EfiUsbNoData;
+  if ( 0 != pRequest->Length ) {
+    Direction = ( 0 != ( pRequest->RequestType & USB_ENDPOINT_DIR_IN ))
+              ? EfiUsbDataIn : EfiUsbDataOut;
+  }
+
+  //
+  // Issue the command
+  //
+  pUsbIo = pNicDevice->pUsbIo;
+  Status = pUsbIo->UsbControlTransfer ( pUsbIo,
+                                        pRequest,
+                                        Direction,
+                                        USB_BUS_TIMEOUT,
+                                        pBuffer,
+                                        pRequest->Length,
+                                        &CmdStatus );
+
+  //
+  // Determine the operation status
+  //
+  if ( !EFI_ERROR ( Status )) {
+    Status = CmdStatus;
+  } else {
+    //
+    // Only use status values associated with the Simple Network protocol
+    //
+    if ( EFI_TIMEOUT == Status ) {
+      Status = EFI_DEVICE_ERROR;
+    }
+  }
+
+  //
+  // Return the operation status
+  //
+  return Status;
+}
+
+BOOLEAN
+Ax88772GetLinkStatus (
+  IN NIC_DEVICE * pNicDevice
+)
+{
+  UINT32 CmdStatus;
+  EFI_USB_IO_PROTOCOL * pUsbIo;
+  UINT64    IntData = 0;
+  UINTN     IntDataLeng = 8;
+  EFI_STATUS Status;
+
+  //
+  // Issue the command
+  //
+  pUsbIo = pNicDevice->pUsbIo;
+  Status = pUsbIo->UsbSyncInterruptTransfer( pUsbIo,
+                                        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 & 0x800000)? FALSE : TRUE;
+
+}
+
+#if RXTHOU
+EFI_STATUS
+Ax88772BulkIn(
+  IN NIC_DEVICE * pNicDevice
+)
+{
+  int i;
+  UINTN LengthInBytes = 0;
+  UINTN TMP_LENG = AX88772_MAX_BULKIN_SIZE;
+  UINTN ORI_TMP_LENG = 0;
+  EFI_STATUS Status = EFI_DEVICE_ERROR;
+  EFI_USB_IO_PROTOCOL *pUsbIo;
+  UINT32 TransferStatus = 0;
+  UINT16 tmpPktCnt = 0;
+  UINT16 * tmpHdr = (UINT16 *)pNicDevice->pBulkInbuf;
+  USB_DEVICE_REQUEST SetupMsg;
+
+  pUsbIo = pNicDevice->pUsbIo;
+  for ( i = 0 ; i < (AX88772_MAX_BULKIN_SIZE / 512) && pUsbIo != NULL; i++) {
+    VOID* tmpAddr = 0;
+
+    tmpPktCnt = 0;
+    tmpAddr = (VOID*) &pNicDevice->pBulkInbuf[LengthInBytes];
+    ORI_TMP_LENG = TMP_LENG;
+    Status = pUsbIo->UsbBulkTransfer ( pUsbIo,
+                          USB_ENDPOINT_DIR_IN | BULK_IN_ENDPOINT,
+                          tmpAddr,
+                          &TMP_LENG,
+                          BULKIN_TIMEOUT,
+                          &TransferStatus );
+
+    if (ORI_TMP_LENG == TMP_LENG) {
+      Status = EFI_NOT_READY;
+      goto no_pkt;
+    }
+
+    if (( !EFI_ERROR ( Status )) &&
+        ( !EFI_ERROR ( TransferStatus )) &&
+        TMP_LENG != 0) {
+      LengthInBytes += TMP_LENG;
+      if ((TMP_LENG % 512) != 0) {
+        goto done;
+      }
+    } else if (( !EFI_ERROR ( Status )) &&
+               ( !EFI_ERROR ( TransferStatus )) &&
+               (TMP_LENG == 0)) {
+      Status = EFI_NOT_READY;
+      goto done;
+    } else if (EFI_TIMEOUT == Status && EFI_USB_ERR_TIMEOUT == TransferStatus) {
+      SetupMsg.RequestType = USB_REQ_TYPE_STANDARD | 0x02;
+      SetupMsg.Request = 0x01;
+      SetupMsg.Value =  0;
+      SetupMsg.Index = 0x82;
+      SetupMsg.Length = 0;
+      Status = Ax88772UsbCommand ( pNicDevice,
+                                   &SetupMsg,
+                                   NULL );
+      Status = EFI_NOT_READY;
+      goto done;
+    } else {
+      Status = EFI_DEVICE_ERROR;
+      goto done;
+    }
+  }
+done:
+  if (LengthInBytes != 0) {
+    UINT16 tmpLen;
+    UINT16 tmpLenBar;
+    UINT16 tmpTotalLen = 0;
+    UINTN TotalLen = LengthInBytes;
+
+    do {
+      tmpLen = (*tmpHdr) & 0x7FF;
+      tmpLenBar = *(tmpHdr + 1);
+      tmpTotalLen = ((tmpLen + 4 + 1) & 0xfffe);
+
+      if ((tmpLen & 0x7FF) + (tmpLenBar & 0x7FF) == 0x7FF) {
+        tmpPktCnt++;
+      } else {
+        if ( tmpPktCnt != 0) {
+          break;
+        }
+        Status = EFI_NOT_READY;
+        goto no_pkt;
+      }
+      tmpHdr += (tmpTotalLen / 2);
+      TotalLen -= tmpTotalLen;
+    } while (TotalLen > 0);
+
+  if (LengthInBytes >= 1000 && tmpPktCnt != 0) {
+    if ((pNicDevice->rxburst) == 1) {
+      SetupMsg.RequestType = USB_REQ_TYPE_VENDOR
+                           | USB_TARGET_DEVICE;
+      SetupMsg.Request = CMD_RESET;
+      SetupMsg.Value =  SRR_IPRL;
+      SetupMsg.Index = 0;
+      SetupMsg.Length = 0;
+      Ax88772UsbCommand ( pNicDevice,
+                          &SetupMsg,
+                          NULL );
+    }
+
+    if (pNicDevice->rxburst < 2)
+    pNicDevice->rxburst++;
+
+  } else {
+    if (pNicDevice->rxburst >= 2) {
+      SetupMsg.RequestType = USB_REQ_TYPE_VENDOR
+                           | USB_TARGET_DEVICE;
+      SetupMsg.Request = CMD_RESET;
+      SetupMsg.Value =  SRR_IPRL| SRR_BZ | SRR_BZTYPE;
+      SetupMsg.Index = 0;
+      SetupMsg.Length = 0;
+      Ax88772UsbCommand ( pNicDevice,
+                          &SetupMsg,
+                          NULL );
+      }
+      pNicDevice->rxburst = 0;
+    }
+  }
+
+  if (tmpPktCnt != 0) {
+    pNicDevice->PktCnt = tmpPktCnt;
+    pNicDevice->pCurPktHdrOff = pNicDevice->pBulkInbuf;
+    pNicDevice->pCurPktOff = pNicDevice->pBulkInbuf + 4;
+    Status = EFI_SUCCESS;
+  }
+
+no_pkt:
+  return Status;
+}
+#else
+EFI_STATUS
+Ax88772BulkIn(
+  IN NIC_DEVICE * pNicDevice
+)
+{
+  int i;
+  UINTN LengthInBytes = 0;
+  UINTN TMP_LENG = AX88772_MAX_BULKIN_SIZE;
+  UINTN ORI_TMP_LENG = 0;
+  UINTN CURBufSize = AX88772_MAX_BULKIN_SIZE;
+  EFI_STATUS Status = EFI_DEVICE_ERROR;
+  EFI_USB_IO_PROTOCOL *pUsbIo;
+  UINT32 TransferStatus = 0;
+  UINT16 tmpPktCnt = 0;
+  UINT16 * tmpHdr = (UINT16 *)pNicDevice->pBulkInbuf;
+
+  pUsbIo = pNicDevice->pUsbIo;
+  for ( i = 0 ; i < (AX88772_MAX_BULKIN_SIZE / 512) && pUsbIo != NULL; i++) {
+    VOID* tmpAddr = 0;
+
+    tmpPktCnt = 0;
+    tmpAddr = (VOID*) &pNicDevice->pBulkInbuf[LengthInBytes];
+    ORI_TMP_LENG = TMP_LENG;
+    Status = pUsbIo->UsbBulkTransfer ( pUsbIo,
+                          USB_ENDPOINT_DIR_IN | BULK_IN_ENDPOINT,
+                          tmpAddr,
+                          &TMP_LENG,
+                          BULKIN_TIMEOUT,
+                          &TransferStatus );
+
+    if (ORI_TMP_LENG == TMP_LENG) {
+      Status = EFI_NOT_READY;
+      goto no_pkt;
+    }
+
+    if (( !EFI_ERROR ( Status )) &&
+        ( !EFI_ERROR ( TransferStatus )) &&
+        TMP_LENG != 0) {
+      UINT16 tmpLen;
+      UINT16 tmpLenBar;
+      UINT16 tmpTotalLen = 0;
+
+      LengthInBytes += TMP_LENG;
+      CURBufSize = CURBufSize - TMP_LENG;
+      TMP_LENG = CURBufSize;
+      do {
+        tmpLen = *tmpHdr;
+        tmpLenBar = *(tmpHdr + 1);
+        tmpTotalLen += ((tmpLen + 4 + 1) & 0xfffe);
+
+        if (((tmpLen ^ tmpLenBar) == 0xffff))  {
+          if (tmpTotalLen == LengthInBytes) {
+            tmpPktCnt++;
+            Status = EFI_SUCCESS;
+            goto done;
+          } else if (tmpTotalLen > LengthInBytes) {
+            break;
+          }
+        } else if (((tmpLen ^ tmpLenBar) != 0xffff)) {
+          if ( tmpPktCnt != 0) {
+            Status = EFI_SUCCESS;
+            goto done;
+          }
+          Status = EFI_NOT_READY;
+          goto no_pkt;
+        }
+        tmpHdr += (tmpTotalLen / 2);
+        tmpPktCnt++;
+      }while (tmpTotalLen < LengthInBytes);
+    } else if (( !EFI_ERROR ( Status )) &&
+               ( !EFI_ERROR ( TransferStatus )) &&
+               (TMP_LENG == 0)) {
+      if ( tmpPktCnt != 0) {
+        Status = EFI_SUCCESS;
+        goto done;
+      }
+      Status = EFI_NOT_READY;
+      goto no_pkt;
+    } else if (EFI_TIMEOUT == Status && EFI_USB_ERR_TIMEOUT == TransferStatus) {
+      if ( tmpPktCnt != 0) {
+        Status = EFI_SUCCESS;
+        goto done;
+      }
+      Status = EFI_NOT_READY;
+      goto no_pkt;
+    } else {
+      if ( tmpPktCnt != 0) {
+        Status = EFI_SUCCESS;
+        goto done;
+      }
+      Status = EFI_DEVICE_ERROR;
+      goto no_pkt;
+    }
+  }
+done:
+  pNicDevice->PktCnt = tmpPktCnt;
+  pNicDevice->pCurPktHdrOff = pNicDevice->pBulkInbuf;
+  pNicDevice->pCurPktOff = pNicDevice->pBulkInbuf + 4;
+no_pkt:
+  return Status;
+}
+#endif
diff --git a/Drivers/OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772c/ComponentName.c b/Drivers/OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772c/ComponentName.c
new file mode 100644
index 000000000000..8e2ba86f945e
--- /dev/null
+++ b/Drivers/OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772c/ComponentName.c
@@ -0,0 +1,246 @@
+/** @file
+  UEFI Component Name(2) protocol implementation.
+
+  Copyright (c) 2011, Intel Corporation. All rights reserved.
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "Ax88772.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 AX88772B Ethernet Driver 2.8.0"},
+  {NULL,  NULL}
+};
+
+
+/**
+  Controller name table declaration
+**/
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE
+mControllerNameTable[] = {
+  {"eng;en", L"ASIX AX88772B USB Fast 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] pThis             A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+                                EFI_COMPONENT_NAME_PROTOCOL instance.
+  @param [in] pLanguage         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] ppDriverName     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 * pThis,
+  IN  CHAR8 * pLanguage,
+  OUT CHAR16 ** ppDriverName
+  )
+{
+  EFI_STATUS Status;
+
+  Status = LookupUnicodeString2 (
+             pLanguage,
+             pThis->SupportedLanguages,
+             mDriverNameTable,
+             ppDriverName,
+             (BOOLEAN)(pThis == &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] pThis             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] pLanguage         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] ppControllerName 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.
+
+**/
+
+
+#if PASS_SCT
+EFI_STATUS
+EFIAPI
+GetControllerName (
+  IN  EFI_COMPONENT_NAME_PROTOCOL * pThis,
+  IN  EFI_HANDLE ControllerHandle,
+  IN OPTIONAL EFI_HANDLE ChildHandle,
+  IN  CHAR8 * pLanguage,
+  OUT CHAR16 ** ppControllerName
+  )
+{
+
+  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 (
+                    pLanguage,
+            pThis->SupportedLanguages,
+           mControllerNameTable,
+           ppControllerName,
+           (BOOLEAN)(pThis == &gComponentName)
+           );
+
+  return  Status;
+}
+#else
+EFI_STATUS
+EFIAPI
+GetControllerName (
+  IN  EFI_COMPONENT_NAME_PROTOCOL * pThis,
+  IN  EFI_HANDLE ControllerHandle,
+  IN OPTIONAL EFI_HANDLE ChildHandle,
+  IN  CHAR8 * pLanguage,
+  OUT CHAR16 ** ppControllerName
+  )
+{
+  EFI_STATUS Status;
+
+  //
+  // Set the controller name
+  //
+  *ppControllerName = L"ASIX AX88772B USB Fast Ethernet Controller";
+  Status = EFI_SUCCESS;
+
+  //
+  // Return the operation status
+  //
+
+  return Status;
+}
+
+#endif
diff --git a/Drivers/OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772c/DriverBinding.c b/Drivers/OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772c/DriverBinding.c
new file mode 100644
index 000000000000..5edb7cbb2630
--- /dev/null
+++ b/Drivers/OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772c/DriverBinding.c
@@ -0,0 +1,637 @@
+/** @file
+  Implement the driver binding protocol for Asix AX88772 Ethernet driver.
+
+  Copyright (c) 2011-2013, Intel Corporation. All rights reserved.
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "Ax88772.h"
+#include <Library/MemoryAllocationLib.h>
+/**
+  Verify the controller type
+
+  @param [in] pThis                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 * pThis,
+  IN EFI_HANDLE Controller,
+  IN EFI_DEVICE_PATH_PROTOCOL * pRemainingDevicePath
+  )
+{
+  EFI_USB_DEVICE_DESCRIPTOR Device;
+  EFI_USB_IO_PROTOCOL * pUsbIo;
+  EFI_STATUS Status;
+
+  //
+  //  Connect to the USB stack
+  //
+  Status = gBS->OpenProtocol (
+                  Controller,
+                  &gEfiUsbIoProtocolGuid,
+                  (VOID **) &pUsbIo,
+                  pThis->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 = pUsbIo->UsbGetDeviceDescriptor ( pUsbIo, &Device );
+    if (EFI_ERROR ( Status )) {
+      Status = EFI_UNSUPPORTED;
+    } else {
+      //
+      //  Validate the adapter
+      //
+      if ( VENDOR_ID == Device.IdVendor ) {
+        if (PRODUCT_AX88772B_ID != Device.IdProduct) {
+        } else if (PRODUCT_AX88772B_ASUS_ID == Device.IdProduct) {
+        } else if (PRODUCT_AX88772A_ID == Device.IdProduct) {
+        } else if (PRODUCT_ID == Device.IdProduct) {
+        } else {
+          Status = EFI_UNSUPPORTED;
+        }
+      } else if ( VENDOR_AX88772B_LENOVO_ID == Device.IdVendor ) {
+        if (PRODUCT_AX88772B_LENOVO_ID != Device.IdProduct) {
+          Status = EFI_UNSUPPORTED;
+        }
+      } else {
+        Status = EFI_UNSUPPORTED;
+      }
+    }
+
+    //
+    //  Done with the USB stack
+    //
+    gBS->CloseProtocol (
+           Controller,
+           &gEfiUsbIoProtocolGuid,
+           pThis->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 appended to it, install the NetworkInterfaceIdentifier protocol
+  on the newly created Device Path.
+
+  @param [in] pThis                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 * pThis,
+  IN EFI_HANDLE Controller,
+  IN EFI_DEVICE_PATH_PROTOCOL * pRemainingDevicePath
+  )
+{
+  EFI_STATUS Status;
+  NIC_DEVICE *pNicDevice;
+  UINTN LengthInBytes;
+  EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath = NULL;
+  MAC_ADDR_DEVICE_PATH MacDeviceNode;
+  EFI_USB_DEVICE_DESCRIPTOR Device;
+
+  //
+  //  Allocate the device structure
+  //
+  LengthInBytes = sizeof ( *pNicDevice );
+  Status = gBS->AllocatePool (
+                  EfiRuntimeServicesData,
+                  LengthInBytes,
+                  (VOID **) &pNicDevice
+                  );
+
+  if (EFI_ERROR (Status)) {
+    goto ERR;
+  }
+
+  //
+  //  Set the structure signature
+  //
+  ZeroMem ( pNicDevice, LengthInBytes );
+  pNicDevice->Signature = DEV_SIGNATURE;
+
+  Status = gBS->OpenProtocol (
+                    Controller,
+                    &gEfiUsbIoProtocolGuid,
+                    (VOID **) &pNicDevice->pUsbIo,
+                    pThis->DriverBindingHandle,
+                    Controller,
+                    EFI_OPEN_PROTOCOL_BY_DRIVER
+                    );
+
+  if (EFI_ERROR (Status)) {
+    goto ERR;
+  }
+
+  pNicDevice->Flag772A = FALSE;
+  pNicDevice->pUsbIo->UsbGetDeviceDescriptor ( pNicDevice->pUsbIo, &Device );
+  if ((PRODUCT_AX88772A_ID == Device.IdProduct) ||
+      (PRODUCT_ID == Device.IdProduct))
+    pNicDevice->Flag772A = TRUE;
+  //
+  //  Initialize the simple network protocol
+  //
+  Status = SN_Setup ( pNicDevice );
+
+  if (EFI_ERROR(Status)){
+    gBS->CloseProtocol (
+             Controller,
+             &gEfiUsbIoProtocolGuid,
+             pThis->DriverBindingHandle,
+             Controller
+             );
+    goto ERR;
+  }
+
+  //
+  // Set Device Path
+  //
+
+  Status = gBS->OpenProtocol (
+                    Controller,
+                    &gEfiDevicePathProtocolGuid,
+                    (VOID **) &ParentDevicePath,
+                    pThis->DriverBindingHandle,
+                    Controller,
+                    EFI_OPEN_PROTOCOL_BY_DRIVER
+                    );
+  if (EFI_ERROR(Status)) {
+    gBS->CloseProtocol (
+              Controller,
+              &gEfiUsbIoProtocolGuid,
+              pThis->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,
+           &pNicDevice->SimpleNetworkData.CurrentAddress,
+           PXE_HWADDR_LEN_ETHER);
+
+  MacDeviceNode.IfType = pNicDevice->SimpleNetworkData.IfType;
+
+  pNicDevice->MyDevPath = AppendDevicePathNode (
+                                          ParentDevicePath,
+                                          (EFI_DEVICE_PATH_PROTOCOL *) &MacDeviceNode
+                                          );
+
+  pNicDevice->Controller = NULL;
+
+  //
+  //  Install both the simple network and device path protocols.
+  //
+  Status = gBS->InstallMultipleProtocolInterfaces (
+                          &pNicDevice->Controller,
+                          &gEfiCallerIdGuid,
+                          pNicDevice,
+                          &gEfiSimpleNetworkProtocolGuid,
+                          &pNicDevice->SimpleNetwork,
+                          &gEfiDevicePathProtocolGuid,
+                          pNicDevice->MyDevPath,
+                          NULL
+                          );
+
+  if (EFI_ERROR(Status)){
+    gBS->CloseProtocol (
+              Controller,
+              &gEfiDevicePathProtocolGuid,
+              pThis->DriverBindingHandle,
+              Controller);
+    gBS->CloseProtocol (
+              Controller,
+              &gEfiUsbIoProtocolGuid,
+              pThis->DriverBindingHandle,
+              Controller
+              );
+    goto ERR;
+  }
+
+  //
+  // Open For Child Device
+  //
+  Status = gBS->OpenProtocol (
+                  Controller,
+                  &gEfiUsbIoProtocolGuid,
+                  (VOID **) &pNicDevice->pUsbIo,
+                  pThis->DriverBindingHandle,
+                  pNicDevice->Controller,
+                  EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
+                  );
+
+  if (EFI_ERROR(Status)){
+    gBS->UninstallMultipleProtocolInterfaces (
+                          &pNicDevice->Controller,
+                          &gEfiCallerIdGuid,
+                          pNicDevice,
+                          &gEfiSimpleNetworkProtocolGuid,
+                          &pNicDevice->SimpleNetwork,
+                          &gEfiDevicePathProtocolGuid,
+                          pNicDevice->MyDevPath,
+                          NULL
+                          );
+    gBS->CloseProtocol (
+              Controller,
+              &gEfiDevicePathProtocolGuid,
+              pThis->DriverBindingHandle,
+              Controller);
+    gBS->CloseProtocol (
+              Controller,
+              &gEfiUsbIoProtocolGuid,
+              pThis->DriverBindingHandle,
+              Controller
+              );
+    goto ERR;
+  }
+
+  return Status;
+ERR:
+  if ( NULL != pNicDevice->pBulkInbuf)
+    gBS->FreePool (pNicDevice->pBulkInbuf);
+  if ( NULL != pNicDevice->pTxTest)
+    gBS->FreePool (pNicDevice->pTxTest);
+  if ( NULL != pNicDevice->MyDevPath)
+    gBS->FreePool (pNicDevice->MyDevPath);
+  if (NULL != pNicDevice)
+    gBS->FreePool ( pNicDevice );
+  return Status;
+}
+
+/**
+  Stop this driver on Controller by removing NetworkInterfaceIdentifier protocol and
+  closing the DevicePath and PciIo protocols on Controller.
+
+  @param [in] pThis                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 * pThis,
+  IN  EFI_HANDLE Controller,
+  IN  UINTN NumberOfChildren,
+  IN  EFI_HANDLE * ChildHandleBuffer
+  )
+{
+  BOOLEAN AllChildrenStopped;
+  UINTN Index;
+  EFI_SIMPLE_NETWORK_PROTOCOL *SimpleNetwork;
+  EFI_STATUS Status = EFI_SUCCESS;
+  NIC_DEVICE *pNicDevice;
+
+  //
+  // 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,
+                      pThis->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,
+                pThis->DriverBindingHandle,
+                Controller
+                );
+      gBS->CloseProtocol (
+                Controller,
+                &gEfiUsbIoProtocolGuid,
+                pThis->DriverBindingHandle,
+                Controller
+                );
+      return EFI_SUCCESS;
+    }
+
+    pNicDevice = DEV_FROM_SIMPLE_NETWORK ( SimpleNetwork );
+
+    Status = gBS->UninstallMultipleProtocolInterfaces (
+                          Controller,
+                          &gEfiCallerIdGuid,
+                          pNicDevice,
+                          &gEfiSimpleNetworkProtocolGuid,
+                          &pNicDevice->SimpleNetwork,
+                          &gEfiDevicePathProtocolGuid,
+                          pNicDevice->MyDevPath,
+                          NULL
+                          );
+
+    if (EFI_ERROR (Status)) {
+      return Status;
+    }
+    //
+    // Close the bus driver
+    //
+    Status = gBS->CloseProtocol (
+                       Controller,
+                       &gEfiDevicePathProtocolGuid,
+                       pThis->DriverBindingHandle,
+                       Controller
+                       );
+
+    if (EFI_ERROR(Status)){ }
+
+    Status = gBS->CloseProtocol (
+                       Controller,
+                       &gEfiUsbIoProtocolGuid,
+                       pThis->DriverBindingHandle,
+                       Controller
+                       );
+
+    if (EFI_ERROR(Status)){ }
+
+    return EFI_SUCCESS;
+  }
+
+  AllChildrenStopped = TRUE;
+
+  for (Index = 0; Index < NumberOfChildren; Index++) {
+    Status = gBS->OpenProtocol (
+                      ChildHandleBuffer[Index],
+                      &gEfiSimpleNetworkProtocolGuid,
+                      (VOID **) &SimpleNetwork,
+                      pThis->DriverBindingHandle,
+                      Controller,
+                      EFI_OPEN_PROTOCOL_GET_PROTOCOL
+                      );
+
+    if (EFI_ERROR (Status)) {
+      AllChildrenStopped = FALSE;
+      continue;
+    }
+
+    pNicDevice = DEV_FROM_SIMPLE_NETWORK ( SimpleNetwork );
+
+    gBS->CloseProtocol (
+              Controller,
+              &gEfiUsbIoProtocolGuid,
+              pThis->DriverBindingHandle,
+              ChildHandleBuffer[Index]
+              );
+
+    Status = gBS->UninstallMultipleProtocolInterfaces (
+                          ChildHandleBuffer[Index],
+                          &gEfiCallerIdGuid,
+                          pNicDevice,
+                          &gEfiSimpleNetworkProtocolGuid,
+                          &pNicDevice->SimpleNetwork,
+                          &gEfiDevicePathProtocolGuid,
+                          pNicDevice->MyDevPath,
+                          NULL
+                          );
+
+    if (EFI_ERROR (Status)) {
+      Status = gBS->OpenProtocol (
+                  Controller,
+                  &gEfiUsbIoProtocolGuid,
+                  (VOID **) &pNicDevice->pUsbIo,
+                  pThis->DriverBindingHandle,
+                  ChildHandleBuffer[Index],
+                  EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
+                  );
+    } else {
+      if ( NULL != pNicDevice->pBulkInbuf)
+        gBS->FreePool (pNicDevice->pBulkInbuf);
+      if ( NULL != pNicDevice->pTxTest)
+        gBS->FreePool (pNicDevice->pTxTest);
+      if ( NULL != pNicDevice->MyDevPath)
+        gBS->FreePool (pNicDevice->MyDevPath);
+      if ( NULL != pNicDevice)
+        gBS->FreePool (pNicDevice);
+    }
+  }
+
+  if (!AllChildrenStopped) {
+    return EFI_DEVICE_ERROR;
+  }
+
+  return EFI_SUCCESS;
+}
+
+
+/**
+  Driver binding protocol declaration
+**/
+EFI_DRIVER_BINDING_PROTOCOL  gDriverBinding = {
+  DriverSupported,
+  DriverStart,
+  DriverStop,
+  0xa,
+  NULL,
+  NULL
+};
+
+
+/**
+  Ax88772 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 * pHandle;
+  EFI_STATUS Status;
+
+
+  //
+  //  Determine which devices are using this driver
+  //
+  BufferSize = 0;
+  pHandle = 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 (
+                      EfiRuntimeServicesData,
+                      BufferSize,
+                      (VOID **) &pHandle
+                      );
+      if ( EFI_ERROR ( Status )) {
+
+        break;
+      }
+
+      //
+      //  Locate the block IO devices
+      //
+      Status = gBS->LocateHandle (
+                      ByProtocol,
+                      &gEfiCallerIdGuid,
+                      NULL,
+                      &BufferSize,
+                      pHandle );
+      if ( EFI_ERROR ( Status )) {
+        //
+        //  Error getting handles
+        //
+        break;
+      }
+
+      //
+      //  Remove any use of the driver
+      //
+      Max = BufferSize / sizeof ( pHandle[ 0 ]);
+      for ( Index = 0; Max > Index; Index++ ) {
+        Status = DriverStop ( &gDriverBinding,
+                              pHandle[ 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 ( NULL != pHandle ) {
+    gBS->FreePool ( pHandle );
+  }
+
+  //
+  //  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;
+}
+
+
+/**
+Ax88772 driver entry point.
+
+@param [in] ImageHandle       Handle for the image.
+@param [in] pSystemTable      Address of the system table.
+
+@retval EFI_SUCCESS           Image successfully loaded.
+
+**/
+EFI_STATUS
+EFIAPI
+EntryPoint (
+  IN EFI_HANDLE ImageHandle,
+  IN EFI_SYSTEM_TABLE * pSystemTable
+  )
+{
+  EFI_LOADED_IMAGE_PROTOCOL * pLoadedImage;
+  EFI_STATUS    Status;
+
+  //
+  //  Enable unload support
+  //
+  Status = gBS->HandleProtocol (
+                  gImageHandle,
+                  &gEfiLoadedImageProtocolGuid,
+                  (VOID **)&pLoadedImage
+                  );
+  if (!EFI_ERROR (Status)) {
+    pLoadedImage->Unload = DriverUnload;
+  }
+
+  //
+  //  Add the driver to the list of drivers
+  //
+  Status = EfiLibInstallDriverBindingComponentName2 (
+             ImageHandle,
+             pSystemTable,
+             &gDriverBinding,
+             ImageHandle,
+             &gComponentName,
+             &gComponentName2
+             );
+  if ( !EFI_ERROR ( Status )) { }
+  return Status;
+}
diff --git a/Drivers/OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772c/SimpleNetwork.c b/Drivers/OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772c/SimpleNetwork.c
new file mode 100644
index 000000000000..b4627092a676
--- /dev/null
+++ b/Drivers/OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772c/SimpleNetwork.c
@@ -0,0 +1,1612 @@
+/** @file
+  Provides the Simple Network functions.
+
+  Copyright (c) 2011 - 2016, Intel Corporation. All rights reserved.
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "Ax88772.h"
+#include <Library/MemoryAllocationLib.h>
+/**
+  This function updates the filtering on the receiver.
+
+  This support routine calls ::Ax88772MacAddressSet to update
+  the MAC address.  This routine then rebuilds the multicast
+  hash by calling ::Ax88772MulticastClear and ::Ax88772MulticastSet.
+  Finally this routine enables the receiver by calling
+  ::Ax88772RxControl.
+
+  @param [in] pSimpleNetwork    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 pSimpleNetwork 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 * pSimpleNetwork
+  )
+{
+  EFI_SIMPLE_NETWORK_MODE * pMode;
+  NIC_DEVICE * pNicDevice;
+  EFI_STATUS Status;
+  UINT32 Index;
+
+  //
+  // Set the MAC address
+  //
+  pNicDevice = DEV_FROM_SIMPLE_NETWORK ( pSimpleNetwork );
+  pMode = pSimpleNetwork->Mode;
+
+    //
+    // Clear the multicast hash table
+    //
+    Ax88772MulticastClear ( pNicDevice );
+
+    //
+    // Load the multicast hash table
+    //
+    if ( 0 != ( pMode->ReceiveFilterSetting & EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST )) {
+      for ( Index = 0; Index < pMode->MCastFilterCount; Index++ ) {
+        //
+        // Enable the next multicast address
+        //
+        Ax88772MulticastSet ( pNicDevice,
+                              &pMode->MCastFilter[ Index ].Addr[0]);
+      }
+    }
+
+    Status = Ax88772RxControl ( pNicDevice, pMode->ReceiveFilterSetting );
+
+  //
+  // Return the operation status
+  //
+  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 ::Ax88772Rx to update the media status and
+  queue any receive packets.
+
+  @param [in] pSimpleNetwork    Protocol instance pointer
+  @param [in] pInterruptStatus  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] ppTxBuf          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 pSimpleNetwork 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 * pSimpleNetwork,
+  OUT UINT32 * pInterruptStatus,
+  OUT VOID ** ppTxBuf
+  )
+{
+  EFI_SIMPLE_NETWORK_MODE * pMode;
+  NIC_DEVICE * pNicDevice = NULL;
+  EFI_STATUS Status = EFI_SUCCESS;
+  EFI_TPL TplPrevious;
+
+  TplPrevious = gBS->RaiseTPL(TPL_CALLBACK);
+
+  //
+  // Verify the parameters
+  //
+  if (( NULL != pSimpleNetwork ) && ( NULL != pSimpleNetwork->Mode )) {
+    //
+    // Return the transmit buffer
+    //
+    pNicDevice = DEV_FROM_SIMPLE_NETWORK ( pSimpleNetwork );
+
+    if (( NULL != ppTxBuf ) &&
+        ( NULL != pNicDevice->pTxBuffer )) {
+      *ppTxBuf = pNicDevice->pTxBuffer;
+      pNicDevice->pTxBuffer = NULL;
+    }
+
+    pMode = pSimpleNetwork->Mode;
+    if (EfiSimpleNetworkInitialized == pMode->State) {
+      if (NULL == ppTxBuf && NULL == pInterruptStatus) {
+        Status = EFI_INVALID_PARAMETER;
+        goto EXIT;
+      }
+
+#if REPORTLINK
+#else
+      if (!pNicDevice->bLinkUp || !pNicDevice->bComplete) {
+#endif
+        Status = Ax88772NegotiateLinkComplete ( pNicDevice,
+                                                &pNicDevice->PollCount,
+                                                &pNicDevice->bComplete,
+                                                &pNicDevice->bLinkUp,
+                                                &pNicDevice->b100Mbps,
+                                                &pNicDevice->bFullDuplex );
+        if (EFI_ERROR(Status))
+          goto EXIT;
+#if REPORTLINK
+        if (pNicDevice->bLinkUp && pNicDevice->bComplete) {
+          pMode->MediaPresent = TRUE;
+          Status = ReceiveFilterUpdate ( pSimpleNetwork );
+        } else {
+          pMode->MediaPresent = FALSE;
+        }
+#else
+        if (pNicDevice->bLinkUp && pNicDevice->bComplete)  {
+          pMode->MediaPresent = TRUE;
+          pMode->MediaPresentSupported = FALSE;
+          Status = ReceiveFilterUpdate ( pSimpleNetwork );
+        }
+      }
+#endif
+    } else {
+      if (EfiSimpleNetworkStarted == pMode->State) {
+        Status = EFI_DEVICE_ERROR;
+      } else {
+        Status = EFI_NOT_STARTED ;
+      }
+    }
+  } else {
+    Status = EFI_INVALID_PARAMETER;
+  }
+  if ( NULL != pInterruptStatus ) {
+    *pInterruptStatus = 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] pSimpleNetwork    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] pBuffer      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 pSimpleNetwork 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 * pSimpleNetwork,
+  IN BOOLEAN ReadWrite,
+  IN UINTN Offset,
+  IN UINTN BufferSize,
+  IN OUT VOID * pBuffer
+  )
+{
+  EFI_STATUS Status = EFI_INVALID_PARAMETER;
+  EFI_TPL TplPrevious;
+  EFI_SIMPLE_NETWORK_MODE * pMode;
+  NIC_DEVICE * pNicDevice;
+
+
+  TplPrevious = gBS->RaiseTPL(TPL_CALLBACK);
+
+  if (( NULL == pSimpleNetwork ) || ( NULL == pSimpleNetwork->Mode )) {
+        Status = EFI_INVALID_PARAMETER;
+        goto  EXIT;
+  }
+
+  pNicDevice = DEV_FROM_SIMPLE_NETWORK ( pSimpleNetwork );
+  pMode = pSimpleNetwork->Mode;
+
+#if PASS_SCT
+  if (EfiSimpleNetworkInitialized != pMode->State) {
+    Status = EFI_NOT_STARTED;
+    goto  EXIT;
+  }
+#endif
+
+  if ( 0 != Offset ) {
+    if ((0 != (Offset % pMode->NvRamAccessSize) ) ||
+        (Offset >= pMode->NvRamSize)) {
+      Status = EFI_INVALID_PARAMETER;
+      goto  EXIT;
+    }
+  }
+  //
+  // Offset must be a multiple of NvRamAccessSize and less than NvRamSize.
+  //
+  if (0 != (BufferSize % pMode->NvRamAccessSize)) {
+    Status = EFI_INVALID_PARAMETER;
+    goto  EXIT;
+  }
+
+  if (BufferSize + Offset > pMode->NvRamSize) {
+    Status = EFI_INVALID_PARAMETER;
+    goto  EXIT;
+  }
+
+  if (NULL == pBuffer) {
+    Status = EFI_INVALID_PARAMETER;
+    goto  EXIT;
+  }
+
+  //
+  // ReadWrite: TRUE FOR READ FALSE FOR WRITE
+  //
+  if (ReadWrite){
+    UINTN i;
+
+    for (i = 0; i < BufferSize / 2; i++) {
+      Status = Ax88772SromRead ( pNicDevice,
+                                 (UINT32)(Offset/2 + i),
+                                 (((UINT16*)pBuffer) + i));
+    }
+  } else {
+    UINTN i;
+
+    Status = Ax88772EnableSromWrite(pNicDevice);
+    if (EFI_ERROR(Status))
+      goto EXIT;
+
+    for (i = 0; i < BufferSize / 2; i++){
+      Status = Ax88772SromWrite ( pNicDevice,
+                                  (UINT32)(Offset/2 + i),
+                                  (((UINT16*)pBuffer) + i));
+      }
+
+      Status = Ax88772DisableSromWrite(pNicDevice);
+
+      if (BufferSize == 272)
+        Status = Ax88772ReloadSrom(pNicDevice);
+  }
+
+  //
+  // 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] pSimpleNetwork    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 pSimpleNetwork 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 * pSimpleNetwork,
+  IN UINTN ExtraRxBufferSize,
+  IN UINTN ExtraTxBufferSize
+  )
+{
+  EFI_SIMPLE_NETWORK_MODE * pMode;
+  EFI_STATUS Status;
+  UINT32  TmpState;
+   EFI_TPL TplPrevious;
+   NIC_DEVICE * pNicDevice;
+
+   TplPrevious = gBS->RaiseTPL (TPL_CALLBACK);
+
+  //
+  // Verify the parameters
+  //
+  if (( NULL != pSimpleNetwork ) && ( NULL != pSimpleNetwork->Mode )) {
+    //
+    // Determine if the interface is already started
+    //
+    pMode = pSimpleNetwork->Mode;
+    if ( EfiSimpleNetworkStarted == pMode->State ) {
+      if (( 0 == ExtraRxBufferSize ) && ( 0 == ExtraTxBufferSize )) {
+        //
+        // Start the adapter
+        //
+        TmpState = pMode->State;
+        pMode->State = EfiSimpleNetworkInitialized;
+        Status = SN_Reset ( pSimpleNetwork, FALSE );
+        if ( EFI_ERROR ( Status )) {
+          //
+          // Update the network state
+          //
+          pMode->State = TmpState ; // EfiSimpleNetworkInitialized;
+        } else {
+          pMode->MediaPresentSupported = TRUE;
+          pNicDevice = DEV_FROM_SIMPLE_NETWORK ( pSimpleNetwork );
+          pMode->MediaPresent = Ax88772GetLinkStatus (pNicDevice);
+        }
+      } 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] pSimpleNetwork    Protocol instance pointer
+  @param [in] bIPv6             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] pIP               The multicast IP address that is to be converted to a
+                                multicast HW MAC address.
+  @param [in] pMAC              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 pSimpleNetwork 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 * pSimpleNetwork,
+  IN BOOLEAN bIPv6,
+  IN EFI_IP_ADDRESS * pIP,
+  IN EFI_MAC_ADDRESS * pMAC
+  )
+{
+  EFI_STATUS Status;
+  EFI_TPL TplPrevious;
+  EFI_SIMPLE_NETWORK_MODE * pMode;
+
+  TplPrevious = gBS->RaiseTPL(TPL_CALLBACK);
+
+  if (( NULL != pSimpleNetwork ) && ( NULL != pSimpleNetwork->Mode )) {
+    //
+    // The interface must be running
+    //
+    pMode = pSimpleNetwork->Mode;
+    if ( EfiSimpleNetworkInitialized == pMode->State ) {
+      if (pIP == NULL || pMAC == NULL) {
+        Status = EFI_INVALID_PARAMETER;
+        goto EXIT;
+      }
+
+      if (bIPv6) {
+        Status = EFI_UNSUPPORTED;
+        goto EXIT;
+      } else {
+        //
+        // check if the ip given is a mcast IP
+        //
+        if ((pIP->v4.Addr[0] & 0xF0) != 0xE0) {
+          Status = EFI_INVALID_PARAMETER;
+          goto EXIT;
+        } else {
+          pMAC->Addr[0] = 0x01;
+          pMAC->Addr[1] = 0x00;
+          pMAC->Addr[2] = 0x5e;
+          pMAC->Addr[3] = (UINT8) (pIP->v4.Addr[1] & 0x7f);
+          pMAC->Addr[4] = (UINT8) pIP->v4.Addr[2];
+          pMAC->Addr[5] = (UINT8) pIP->v4.Addr[3];
+          Status = EFI_SUCCESS;
+        }
+      }
+    } else {
+      if (EfiSimpleNetworkStarted == pMode->State) {
+        Status = EFI_DEVICE_ERROR;
+      } else {
+        Status = EFI_NOT_STARTED ;
+      }
+    }
+  } else {
+    Status = EFI_INVALID_PARAMETER;
+  }
+
+EXIT:
+  gBS->RestoreTPL(TplPrevious);
+  return Status;
+}
+
+EFI_STATUS
+EFIAPI
+SN_Receive (
+  IN EFI_SIMPLE_NETWORK_PROTOCOL * pSimpleNetwork,
+  OUT UINTN                      * pHeaderSize,
+  OUT UINTN                      * pBufferSize,
+  OUT VOID                       * pBuffer,
+  OUT EFI_MAC_ADDRESS            * pSrcAddr,
+  OUT EFI_MAC_ADDRESS            * pDestAddr,
+  OUT UINT16                     * pProtocol
+  )
+{
+  ETHERNET_HEADER * pHeader;
+  EFI_SIMPLE_NETWORK_MODE * pMode;
+  NIC_DEVICE * pNicDevice = NULL;
+  EFI_STATUS Status;
+  EFI_TPL TplPrevious;
+  UINT16 Type;
+  UINT16 CurrentPktLen;
+
+
+  TplPrevious = gBS->RaiseTPL (TPL_CALLBACK);
+
+  //
+  // Verify the parameters
+  //
+  if (( NULL != pSimpleNetwork ) && ( NULL != pSimpleNetwork->Mode )) {
+    //
+    // The interface must be running
+    //
+    pMode = pSimpleNetwork->Mode;
+    if ( EfiSimpleNetworkInitialized == pMode->State ) {
+
+      if ((pBufferSize == NULL) || (pBuffer == NULL)) {
+        Status = EFI_INVALID_PARAMETER;
+        gBS->RestoreTPL (TplPrevious);
+        return Status;
+      }
+
+      //
+      // Update the link status
+      //
+      pNicDevice = DEV_FROM_SIMPLE_NETWORK ( pSimpleNetwork );
+
+      if ( pNicDevice->bLinkUp && pNicDevice->bComplete) {
+        if ((NULL != pHeaderSize) && (7720 == *pHeaderSize)) {
+          pNicDevice->Grub_f = TRUE;
+        }
+
+        if ((pNicDevice->Grub_f) && (7720 != *pHeaderSize)) {
+          gBS->RestoreTPL (TplPrevious);
+          return EFI_NOT_READY;
+        }
+
+        //
+        //  Attempt to receive a packet
+        //
+        if (0 == pNicDevice->PktCnt) {
+          Status = Ax88772BulkIn(pNicDevice);
+          if (EFI_ERROR(Status)) {
+            goto  no_pkt;
+          }
+        }
+
+        CurrentPktLen = *((UINT16*) (pNicDevice->pCurPktHdrOff));
+        CurrentPktLen &=  0x7ff;
+
+        if (( 60 <= CurrentPktLen ) &&
+            ( CurrentPktLen - 14 <= MAX_ETHERNET_PKT_SIZE)) {
+            if (*pBufferSize < (UINTN)CurrentPktLen) {
+              gBS->RestoreTPL (TplPrevious);
+              return EFI_BUFFER_TOO_SMALL;
+            }
+
+            *pBufferSize = CurrentPktLen;
+            CopyMem ( pBuffer, pNicDevice->pCurPktOff, CurrentPktLen );
+            pHeader = (ETHERNET_HEADER *) pNicDevice->pCurPktOff;
+
+            if ( NULL != pHeaderSize  && (7720 != *pHeaderSize)) {
+              *pHeaderSize = sizeof ( *pHeader );
+            }
+            if ( NULL != pDestAddr ) {
+              CopyMem ( pDestAddr, &pHeader->dest_addr, PXE_HWADDR_LEN_ETHER );
+            }
+            if ( NULL != pSrcAddr ) {
+              CopyMem ( pSrcAddr, &pHeader->src_addr, PXE_HWADDR_LEN_ETHER );
+            }
+            if ( NULL != pProtocol ) {
+              Type = pHeader->type;
+              Type = (UINT16)(( Type >> 8 ) | ( Type << 8 ));
+              *pProtocol = Type;
+            }
+            pNicDevice->PktCnt--;
+            pNicDevice->pCurPktHdrOff += (CurrentPktLen + 4 + 1) & 0xfffe;
+            pNicDevice->pCurPktOff = pNicDevice->pCurPktHdrOff + 4;
+            Status = EFI_SUCCESS;
+        } else {
+          pNicDevice->PktCnt = 0;
+          Status = EFI_DEVICE_ERROR;
+        }
+      } else {
+        //
+        //  Link no up
+        //
+        Status = EFI_NOT_READY;
+      }
+    } else {
+      if (EfiSimpleNetworkStarted == pMode->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] pSimpleNetwork    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] bResetMCastFilter 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] pMCastFilter      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 pSimpleNetwork 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 * pSimpleNetwork,
+  IN UINT32 Enable,
+  IN UINT32 Disable,
+/*
+#define EFI_SIMPLE_NETWORK_RECEIVE_UNICAST               0x01
+#define EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST             0x02
+#define EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST             0x04
+#define EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS           0x08
+#define EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST 0x10
+*/
+  IN BOOLEAN bResetMCastFilter,
+  IN UINTN MCastFilterCnt,
+  IN EFI_MAC_ADDRESS * pMCastFilter
+  )
+{
+  EFI_SIMPLE_NETWORK_MODE * pMode;
+
+  EFI_STATUS Status = EFI_SUCCESS;
+  EFI_TPL TplPrevious;
+
+
+  NIC_DEVICE * pNicDevice;
+  TplPrevious = gBS->RaiseTPL(TPL_CALLBACK);
+
+  pNicDevice = DEV_FROM_SIMPLE_NETWORK ( pSimpleNetwork );
+   pMode = pSimpleNetwork->Mode;
+
+
+  if (pSimpleNetwork == NULL) {
+    gBS->RestoreTPL(TplPrevious);
+    return EFI_INVALID_PARAMETER;
+  }
+
+
+  switch (pMode->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 UNDI
+  // does not even support!
+  //
+  if (((Enable &~pMode->ReceiveFilterMask) != 0) ||
+      ((Disable &~pMode->ReceiveFilterMask) != 0)) {
+    Status = EFI_INVALID_PARAMETER;
+    gBS->RestoreTPL(TplPrevious);
+    return Status;
+  }
+
+  if (bResetMCastFilter) {
+    if ( (0 == (pMode->ReceiveFilterSetting & EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST)) &&
+          Enable == 0 &&
+          Disable == 2) {
+      gBS->RestoreTPL(TplPrevious);
+      return EFI_SUCCESS;
+    }
+    pMode->MCastFilterCount = 0;
+    SetMem ( &pMode->MCastFilter[0],
+             sizeof(EFI_MAC_ADDRESS) * MAX_MCAST_FILTER_CNT,
+             0);
+  } else {
+    if (MCastFilterCnt != 0) {
+      UINTN i;
+      EFI_MAC_ADDRESS * pMulticastAddress;
+      pMulticastAddress =  pMCastFilter;
+
+      if ((MCastFilterCnt > pMode->MaxMCastFilterCount) ||
+          (pMCastFilter == NULL)) {
+        Status = EFI_INVALID_PARAMETER;
+        gBS->RestoreTPL(TplPrevious);
+        return Status;
+      }
+
+      for ( i = 0 ; i < MCastFilterCnt ; i++ ) {
+          UINT8  tmp;
+          tmp = pMulticastAddress->Addr[0];
+          if ( (tmp & 0x01) != 0x01 ) {
+            gBS->RestoreTPL(TplPrevious);
+            return EFI_INVALID_PARAMETER;
+          }
+          pMulticastAddress++;
+      }
+
+      pMode->MCastFilterCount = (UINT32)MCastFilterCnt;
+      CopyMem (&pMode->MCastFilter[0],
+               pMCastFilter,
+               MCastFilterCnt * sizeof ( EFI_MAC_ADDRESS ));
+    }
+  }
+
+  if (Enable == 0 && Disable == 0 && !bResetMCastFilter && 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;
+  }
+
+  pMode->ReceiveFilterSetting |= Enable;
+  pMode->ReceiveFilterSetting &= ~Disable;
+
+  Status = ReceiveFilterUpdate (pSimpleNetwork);
+
+  if (EFI_DEVICE_ERROR == Status || EFI_INVALID_PARAMETER == Status)
+    Status = EFI_SUCCESS;
+
+
+  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 ::Ax88772Reset to perform the adapter specific
+  reset operation.  This routine also starts the link negotiation
+  by calling ::Ax88772NegotiateLinkStart.
+
+  @param [in] pSimpleNetwork    Protocol instance pointer
+  @param [in] bExtendedVerification  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 pSimpleNetwork 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 * pSimpleNetwork,
+  IN BOOLEAN bExtendedVerification
+  )
+{
+  EFI_SIMPLE_NETWORK_MODE * pMode;
+  NIC_DEVICE * pNicDevice;
+  EFI_STATUS Status;
+
+  EFI_TPL TplPrevious;
+
+  TplPrevious = gBS->RaiseTPL(TPL_CALLBACK);
+
+  //
+  //  Verify the parameters
+  //
+  if (( NULL != pSimpleNetwork ) && ( NULL != pSimpleNetwork->Mode )) {
+    pMode = pSimpleNetwork->Mode;
+    if ( EfiSimpleNetworkInitialized == pMode->State ) {
+      //
+      //  Update the device state
+      //
+      pNicDevice = DEV_FROM_SIMPLE_NETWORK ( pSimpleNetwork );
+
+      //
+      //  Reset the device
+      //
+      if (!pNicDevice->bFirstRst) {
+        Status = EFI_SUCCESS;
+      } else {
+        Status = Ax88772Reset ( pNicDevice );
+        if ( !EFI_ERROR ( Status )) {
+          Status = ReceiveFilterUpdate ( pSimpleNetwork );
+          if ( !EFI_ERROR ( Status ) && !pNicDevice->bLinkUp && pNicDevice->bFirstRst) {
+            Status = Ax88772NegotiateLinkStart ( pNicDevice );
+            pNicDevice->bFirstRst = 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 ::Ax88772MacAddressGet to obtain the
+  MAC address.
+
+  @param [in] pNicDevice       NIC_DEVICE_INSTANCE pointer
+
+  @retval EFI_SUCCESS     Setup was successful
+
+**/
+EFI_STATUS
+SN_Setup (
+  IN NIC_DEVICE * pNicDevice
+  )
+{
+
+
+  EFI_SIMPLE_NETWORK_MODE * pMode;
+  EFI_SIMPLE_NETWORK_PROTOCOL * pSimpleNetwork;
+  EFI_STATUS Status;
+
+  //
+  // Initialize the simple network protocol
+  //
+  pSimpleNetwork = &pNicDevice->SimpleNetwork;
+  pSimpleNetwork->Revision = EFI_SIMPLE_NETWORK_PROTOCOL_REVISION;
+  pSimpleNetwork->Start = (EFI_SIMPLE_NETWORK_START)SN_Start;
+  pSimpleNetwork->Stop = (EFI_SIMPLE_NETWORK_STOP)SN_Stop;
+  pSimpleNetwork->Initialize = (EFI_SIMPLE_NETWORK_INITIALIZE)SN_Initialize;
+  pSimpleNetwork->Reset = (EFI_SIMPLE_NETWORK_RESET)SN_Reset;
+  pSimpleNetwork->Shutdown = (EFI_SIMPLE_NETWORK_SHUTDOWN)SN_Shutdown;
+  pSimpleNetwork->ReceiveFilters = (EFI_SIMPLE_NETWORK_RECEIVE_FILTERS)SN_ReceiveFilters;
+  pSimpleNetwork->StationAddress = (EFI_SIMPLE_NETWORK_STATION_ADDRESS)SN_StationAddress;
+  pSimpleNetwork->Statistics = (EFI_SIMPLE_NETWORK_STATISTICS)SN_Statistics;
+  pSimpleNetwork->MCastIpToMac = (EFI_SIMPLE_NETWORK_MCAST_IP_TO_MAC)SN_MCastIPtoMAC;
+  pSimpleNetwork->NvData = (EFI_SIMPLE_NETWORK_NVDATA)SN_NvData;
+  pSimpleNetwork->GetStatus = (EFI_SIMPLE_NETWORK_GET_STATUS)SN_GetStatus;
+  pSimpleNetwork->Transmit = (EFI_SIMPLE_NETWORK_TRANSMIT)SN_Transmit;
+  pSimpleNetwork->Receive = (EFI_SIMPLE_NETWORK_RECEIVE)SN_Receive;
+  pSimpleNetwork->WaitForPacket = NULL;
+  pMode = &pNicDevice->SimpleNetworkData;
+  pSimpleNetwork->Mode = pMode;
+  pMode->State = EfiSimpleNetworkStopped;
+  pMode->HwAddressSize = PXE_HWADDR_LEN_ETHER;
+  pMode->MediaHeaderSize = sizeof ( ETHERNET_HEADER );
+  pMode->MaxPacketSize = MAX_ETHERNET_PKT_SIZE;
+  pMode->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;
+  pMode->ReceiveFilterSetting = EFI_SIMPLE_NETWORK_RECEIVE_UNICAST
+                              | EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST;
+  pMode->MaxMCastFilterCount = ASIX_MCAST_FILTER_CNT;
+  pMode->MCastFilterCount = 0;
+  pMode->NvRamSize = 512;
+  pMode->NvRamAccessSize = 2;
+  SetMem ( &pMode->BroadcastAddress,
+           PXE_HWADDR_LEN_ETHER,
+           0xff );
+
+  SetMem ( &pMode->MCastFilter[0],
+           sizeof(EFI_MAC_ADDRESS) * MAX_MCAST_FILTER_CNT,
+           0);
+
+  pMode->IfType = EfiNetworkInterfaceUndi;
+  pMode->MacAddressChangeable = TRUE;
+  pMode->MultipleTxSupported = FALSE;
+  pMode->MediaPresentSupported = TRUE;
+  pMode->MediaPresent = FALSE;
+
+  //
+  //  Read the MAC address
+  //
+  pNicDevice->PhyId = PHY_ID_INTERNAL;
+  pNicDevice->b100Mbps = TRUE;
+  pNicDevice->bFullDuplex = TRUE;
+  pNicDevice->bComplete = FALSE;
+  pNicDevice->bLinkUp = FALSE;
+  pNicDevice->Grub_f = FALSE;
+  pNicDevice->bFirstRst = TRUE;
+  pNicDevice->PktCnt = 0;
+
+  Status = Ax88772MacAddressGet (
+                pNicDevice,
+                &pMode->PermanentAddress.Addr[0]);
+
+  if ( !EFI_ERROR ( Status )) {
+
+    //
+    //  Use the hardware address as the current address
+    //
+
+    CopyMem ( &pMode->CurrentAddress,
+              &pMode->PermanentAddress,
+              PXE_HWADDR_LEN_ETHER );
+
+    CopyMem ( &pNicDevice->MAC,
+              &pMode->PermanentAddress,
+              PXE_HWADDR_LEN_ETHER );
+
+
+    if (EFI_ERROR(Status)) {
+        return Status;
+    }
+  } else {
+    return Status;
+  }
+
+  Status = gBS->AllocatePool ( EfiRuntimeServicesData,
+                                   AX88772_MAX_BULKIN_SIZE,
+                                   (VOID **) &pNicDevice->pBulkInbuf );
+
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  Status = gBS->AllocatePool ( EfiRuntimeServicesData,
+                                   sizeof ( RX_TX_PACKET ),
+                                   (VOID **) &pNicDevice->pTxTest );
+
+  if (EFI_ERROR (Status)) {
+    gBS->FreePool (pNicDevice->pBulkInbuf);
+    return Status;
+  }
+
+  //
+  //  Return the setup status
+  //
+  return Status;
+}
+
+
+/**
+  This routine starts the network interface.
+
+  @param [in] pSimpleNetwork    Protocol instance pointer
+
+  @retval EFI_SUCCESS           This operation was successful.
+  @retval EFI_ALREADY_STARTED   The network interface was already started.
+  @retval EFI_INVALID_PARAMETER pSimpleNetwork 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 * pSimpleNetwork
+  )
+{
+  NIC_DEVICE * pNicDevice;
+  EFI_SIMPLE_NETWORK_MODE * pMode;
+  EFI_STATUS Status;
+
+  EFI_TPL TplPrevious;
+
+
+  TplPrevious = gBS->RaiseTPL(TPL_CALLBACK);
+
+  //
+  // Verify the parameters
+  //
+  Status = EFI_INVALID_PARAMETER;
+  if (( NULL != pSimpleNetwork ) && ( NULL != pSimpleNetwork->Mode )) {
+    pMode = pSimpleNetwork->Mode;
+    if ( EfiSimpleNetworkStopped == pMode->State ) {
+      //
+      // Initialize the mode structure
+      // NVRAM access is not supported
+      //
+      ZeroMem ( pMode, sizeof ( *pMode ));
+
+      pMode->State = EfiSimpleNetworkStarted;
+      pMode->HwAddressSize = PXE_HWADDR_LEN_ETHER;
+      pMode->MediaHeaderSize = sizeof ( ETHERNET_HEADER );
+      pMode->MaxPacketSize = MAX_ETHERNET_PKT_SIZE;
+      pMode->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;
+      pMode->ReceiveFilterSetting = EFI_SIMPLE_NETWORK_RECEIVE_UNICAST;
+      pMode->MaxMCastFilterCount = ASIX_MCAST_FILTER_CNT;
+      pMode->MCastFilterCount = 0;
+
+      SetMem ( &pMode->MCastFilter[0],
+               sizeof(EFI_MAC_ADDRESS) * MAX_MCAST_FILTER_CNT,
+               0);
+
+      pMode->NvRamSize = 512;
+      pMode->NvRamAccessSize = 2;
+      pNicDevice = DEV_FROM_SIMPLE_NETWORK ( pSimpleNetwork );
+      Status = Ax88772MacAddressGet ( pNicDevice, &pMode->PermanentAddress.Addr[0]);
+      CopyMem ( &pMode->CurrentAddress,
+                &pMode->PermanentAddress,
+                sizeof ( pMode->CurrentAddress ));
+      SetMem(&pMode->BroadcastAddress, PXE_HWADDR_LEN_ETHER, 0xff);
+      pMode->IfType = EfiNetworkInterfaceUndi;
+      pMode->MacAddressChangeable = TRUE;
+      pMode->MultipleTxSupported = FALSE;
+
+      pMode->MediaPresentSupported = TRUE;
+      pMode->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
+  pNew.
+
+  This routine calls ::Ax88772MacAddressSet to update the MAC address
+  in the network adapter.
+
+  @param [in] pSimpleNetwork    Protocol instance pointer
+  @param [in] bReset            Flag used to reset the station address to the
+                                network interface's permanent address.
+  @param [in] pNew              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 pSimpleNetwork 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 * pSimpleNetwork,
+  IN BOOLEAN bReset,
+  IN EFI_MAC_ADDRESS * pNew
+  )
+{
+  NIC_DEVICE * pNicDevice;
+  EFI_SIMPLE_NETWORK_MODE * pMode;
+  EFI_STATUS Status;
+
+  EFI_TPL TplPrevious;
+
+
+  TplPrevious = gBS->RaiseTPL(TPL_CALLBACK);
+
+  //
+  // Verify the parameters
+  //
+  if (( NULL != pSimpleNetwork ) &&
+      ( NULL != pSimpleNetwork->Mode ) &&
+      (( !bReset ) || ( bReset && ( NULL != pNew )))) {
+    //
+    // Verify that the adapter is already started
+    //
+    pNicDevice = DEV_FROM_SIMPLE_NETWORK ( pSimpleNetwork );
+    pMode = pSimpleNetwork->Mode;
+    if ( EfiSimpleNetworkInitialized == pMode->State ) {
+      //
+      // Determine the adapter MAC address
+      //
+      if ( bReset ) {
+        //
+        // Use the permanent address
+        //
+        CopyMem ( &pMode->CurrentAddress,
+                  &pMode->PermanentAddress,
+                  sizeof ( pMode->CurrentAddress ));
+      } else {
+        //
+        // Use the specified address
+        //
+        CopyMem ( &pMode->CurrentAddress,
+                  pNew,
+                  sizeof ( pMode->CurrentAddress ));
+      }
+
+      //
+      // Update the address on the adapter
+      //
+      Status = Ax88772MacAddressSet ( pNicDevice, &pMode->CurrentAddress.Addr[0]);
+    } else {
+      if (EfiSimpleNetworkStarted == pMode->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] pSimpleNetwork    Protocol instance pointer
+  @param [in] bReset            Set to TRUE to reset the statistics for the network interface.
+  @param [in, out] pStatisticsSize  On input the size, in bytes, of StatisticsTable.  On output
+                                the size, in bytes, of the resulting table of statistics.
+  @param [out] pStatisticsTable 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 pStatisticsTable is NULL or the buffer is too small.
+  @retval EFI_INVALID_PARAMETER pSimpleNetwork 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.
+
+  typedef struct {
+  UINT64 RxTotalFrames;
+  UINT64 RxGoodFrames;
+  UINT64 RxUndersizeFrames;
+  UINT64 RxOversizeFrames;
+  UINT64 RxDroppedFrames;
+  UINT64 RxUnicastFrames;
+  UINT64 RxBroadcastFrames;
+  UINT64 RxMulticastFrames;
+  UINT64 RxCrcErrorFrames;
+  UINT64 RxTotalBytes;
+  UINT64 TxTotalFrames;
+  UINT64 TxGoodFrames;
+  UINT64 TxUndersizeFrames;
+  UINT64 TxOversizeFrames;
+  UINT64 TxDroppedFrames;
+  UINT64 TxUnicastFrames;
+  UINT64 TxBroadcastFrames;
+  UINT64 TxMulticastFrames;
+  UINT64 TxCrcErrorFrames;
+  UINT64 TxTotalBytes;
+  UINT64 Collisions;
+  UINT64 UnsupportedProtocol;
+  } EFI_NETWORK_STATISTICS;
+**/
+EFI_STATUS
+EFIAPI
+SN_Statistics (
+  IN EFI_SIMPLE_NETWORK_PROTOCOL * pSimpleNetwork,
+  IN BOOLEAN bReset,
+  IN OUT UINTN * pStatisticsSize,
+  OUT EFI_NETWORK_STATISTICS * pStatisticsTable
+  )
+{
+  EFI_STATUS Status;
+  EFI_TPL TplPrevious;
+  EFI_SIMPLE_NETWORK_MODE * pMode;
+
+
+
+  TplPrevious = gBS->RaiseTPL(TPL_CALLBACK);
+
+  pMode = pSimpleNetwork->Mode;
+
+  if ( EfiSimpleNetworkInitialized == pMode->State ) {
+    if (NULL != pStatisticsSize && 0 == *pStatisticsSize) {
+      Status = EFI_BUFFER_TOO_SMALL;
+      goto EXIT;
+    }
+    if(bReset) {
+      Status = EFI_SUCCESS;
+    } else {
+      Status = EFI_SUCCESS;
+    }
+  } else {
+    if (EfiSimpleNetworkStarted == pMode->State) {
+      Status = EFI_DEVICE_ERROR; ;
+    } else {
+      Status = EFI_NOT_STARTED ;
+    }
+  }
+  //
+  // This is not currently supported
+  //
+
+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] pSimpleNetwork    Protocol instance pointer
+
+  @retval EFI_SUCCESS           This operation was successful.
+  @retval EFI_NOT_STARTED       The network interface was not started.
+  @retval EFI_INVALID_PARAMETER pSimpleNetwork 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 * pSimpleNetwork
+  )
+{
+  EFI_SIMPLE_NETWORK_MODE * pMode;
+  EFI_STATUS Status;
+
+  EFI_TPL TplPrevious;
+
+  TplPrevious = gBS->RaiseTPL(TPL_CALLBACK);
+
+  //
+  // Verify the parameters
+  //
+  if (( NULL != pSimpleNetwork ) && ( NULL != pSimpleNetwork->Mode )) {
+    //
+    // Determine if the interface is started
+    //
+    pMode = pSimpleNetwork->Mode;
+
+    if ( EfiSimpleNetworkStarted == pMode->State ) {
+        pMode->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.
+  Pending transmits and receives are lost, and interrupts are cleared and disabled.
+  After this call, only Initialize() and Stop() calls may be used.
+
+  @param [in] pSimpleNetwork    Protocol instance pointer
+
+  @retval EFI_SUCCESS           This operation was successful.
+  @retval EFI_NOT_STARTED       The network interface was not started.
+  @retval EFI_INVALID_PARAMETER pSimpleNetwork 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 * pSimpleNetwork
+  )
+{
+  EFI_SIMPLE_NETWORK_MODE * pMode;
+  UINT32 RxFilter;
+  EFI_STATUS Status;
+
+  EFI_TPL TplPrevious;
+
+  TplPrevious = gBS->RaiseTPL(TPL_CALLBACK);
+
+  //
+  // Verify the parameters
+  //
+  if (( NULL != pSimpleNetwork ) && ( NULL != pSimpleNetwork->Mode )) {
+    //
+    // Determine if the interface is already started
+    //
+    pMode = pSimpleNetwork->Mode;
+    if ( EfiSimpleNetworkInitialized == pMode->State ) {
+      //
+      // Stop the adapter
+      //
+      RxFilter = pMode->ReceiveFilterSetting;
+      pMode->ReceiveFilterSetting = 0;
+      Status = SN_Reset ( pSimpleNetwork, FALSE );
+      pMode->ReceiveFilterSetting = RxFilter;
+      if ( !EFI_ERROR ( Status )) {
+        //
+        // Update the network state
+        //
+        pMode->State = EfiSimpleNetworkStarted;
+      } else if ( EFI_DEVICE_ERROR == Status ) {
+        pMode->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 ::Ax88772Rx to empty the network adapter of
+  receive packets.  The routine then passes the transmit packet
+  to the network adapter.
+
+  @param [in] pSimpleNetwork    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] pBuffer           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] pSrcAddr          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] pDestAddr         The destination HW MAC address.  If HeaderSize is zero, then
+                                this parameter is ignored.
+  @param [in] pProtocol         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 pSimpleNetwork 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 * pSimpleNetwork,
+  IN UINTN HeaderSize,
+  IN UINTN BufferSize,
+  IN VOID * pBuffer,
+  IN EFI_MAC_ADDRESS * pSrcAddr,
+  IN EFI_MAC_ADDRESS * pDestAddr,
+  IN UINT16 * pProtocol
+  )
+{
+  ETHERNET_HEADER * pHeader;
+  EFI_SIMPLE_NETWORK_MODE * pMode;
+  NIC_DEVICE * pNicDevice;
+  EFI_USB_IO_PROTOCOL * pUsbIo;
+  EFI_STATUS Status;
+  UINTN TransferLength;
+  UINT32 TransferStatus;
+  UINT16 Type;
+  EFI_TPL TplPrevious;
+  TplPrevious = gBS->RaiseTPL(TPL_CALLBACK);
+
+  // Verify the parameters
+  //
+  if (( NULL != pSimpleNetwork ) && ( NULL != pSimpleNetwork->Mode )) {
+    //
+    // The interface must be running
+    //
+    pMode = pSimpleNetwork->Mode;
+    if ( EfiSimpleNetworkInitialized == pMode->State ) {
+      //
+      // Update the link status
+      //
+      pNicDevice = DEV_FROM_SIMPLE_NETWORK ( pSimpleNetwork );
+
+      //
+      //  Release the synchronization with Ax88772Timer
+      //
+      if ( pNicDevice->bLinkUp && pNicDevice->bComplete) {
+        //
+        //  Copy the packet into the USB buffer
+        //
+
+        if (0 != HeaderSize && pMode->MediaHeaderSize != HeaderSize)  {
+          Status = EFI_INVALID_PARAMETER;
+          goto EXIT;
+        }
+        if (BufferSize <  pMode->MediaHeaderSize) {
+          Status = EFI_INVALID_PARAMETER;
+          goto EXIT;
+        }
+        if (NULL == pBuffer) {
+          Status = EFI_INVALID_PARAMETER;
+          goto EXIT;
+        }
+        if (0 != HeaderSize && NULL == pDestAddr) {
+          Status = EFI_INVALID_PARAMETER;
+          goto EXIT;
+        }
+        if (0 != HeaderSize && NULL == pProtocol) {
+          Status = EFI_INVALID_PARAMETER;
+          goto EXIT;
+        }
+
+        CopyMem ( &pNicDevice->pTxTest->Data[0], pBuffer, BufferSize );
+        pNicDevice->pTxTest->Length = (UINT16) BufferSize;
+
+        //
+        //  Transmit the packet
+        //
+        pHeader = (ETHERNET_HEADER *) &pNicDevice->pTxTest->Data[0];
+        if ( 0 != HeaderSize ) {
+          if ( NULL != pDestAddr ) {
+            CopyMem ( &pHeader->dest_addr, pDestAddr, PXE_HWADDR_LEN_ETHER );
+          }
+          if ( NULL != pSrcAddr ) {
+            CopyMem ( &pHeader->src_addr, pSrcAddr, PXE_HWADDR_LEN_ETHER );
+          }
+          else {
+            CopyMem ( &pHeader->src_addr, &pMode->CurrentAddress.Addr[0], PXE_HWADDR_LEN_ETHER );
+          }
+          if ( NULL != pProtocol ) {
+            Type = *pProtocol;
+          } else {
+            Type = pNicDevice->pTxTest->Length;
+          }
+          Type = (UINT16)(( Type >> 8 ) | ( Type << 8 ));
+          pHeader->type = Type;
+        }
+
+
+        if ( pNicDevice->pTxTest->Length < MIN_ETHERNET_PKT_SIZE ) {
+          pNicDevice->pTxTest->Length = MIN_ETHERNET_PKT_SIZE;
+          ZeroMem ( &pNicDevice->pTxTest->Data[ BufferSize],
+                    pNicDevice->pTxTest->Length - BufferSize );
+        }
+
+        pNicDevice->pTxTest->LengthBar = ~(pNicDevice->pTxTest->Length);
+        TransferLength = sizeof ( pNicDevice->pTxTest->Length )
+                       + sizeof ( pNicDevice->pTxTest->LengthBar )
+                       + pNicDevice->pTxTest->Length;
+
+        if (TransferLength % 512 == 0 || TransferLength % 1024 == 0)
+          TransferLength +=4;
+#if RXTHOU
+        if (pNicDevice->rxburst == 1)
+          pNicDevice->rxburst--;
+#endif
+        //
+        //  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.
+        //
+        pUsbIo = pNicDevice->pUsbIo;
+        Status = pUsbIo->UsbBulkTransfer ( pUsbIo,
+                                           BULK_OUT_ENDPOINT,
+                                           &pNicDevice->pTxTest->Length,
+                                           &TransferLength,
+                                           0xfffffffe,
+                                           &TransferStatus );
+        if ( EFI_SUCCESS == Status) {
+          Status = TransferStatus;
+        }
+        if ( EFI_SUCCESS == Status && EFI_SUCCESS == TransferStatus) {
+          pNicDevice->pTxBuffer = pBuffer;
+        } else {
+          if ( EFI_DEVICE_ERROR == Status ) {
+                SN_Reset ( pSimpleNetwork, FALSE );
+          }
+          Status = EFI_NOT_READY;
+        }
+      } else {
+        //
+        // No packets available.
+        //
+
+        Status = EFI_NOT_READY;
+      }
+    } else {
+      if (EfiSimpleNetworkStarted == pMode->State) {
+        Status = EFI_DEVICE_ERROR; ;
+      } else {
+        Status = EFI_NOT_STARTED ;
+      }
+    }
+  } else {
+    Status = EFI_INVALID_PARAMETER;
+  }
+
+EXIT:
+  gBS->RestoreTPL (TplPrevious);
+
+  return Status;
+}
-- 
2.17.1


      parent reply	other threads:[~2020-05-07  3:37 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-05-07  3:37 [edk2-platform][PATCH v1 0/2] Update ASIX USB Networking drivers Samer El-Haj-Mahmoud
2020-05-07  3:37 ` [edk2-platform][PATCH v1 1/2] OptionRomPkg: UsbNetworking: ASIX Ax88179 driver Samer El-Haj-Mahmoud
2020-05-07  5:22   ` Ni, Ray
2020-05-07 16:20     ` Samer El-Haj-Mahmoud
2020-05-08  0:53       ` [edk2-devel] " Ni, Ray
2020-05-07  3:37 ` Samer El-Haj-Mahmoud [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-list from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20200507033720.31152-3-Samer.El-Haj-Mahmoud@arm.com \
    --to=devel@edk2.groups.io \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox