]> git.proxmox.com Git - mirror_edk2.git/commitdiff
SNP driver for ASIX Electronics AX88772 found in SMC Networks SMC2209 USB/Ethernet...
authorlpleahy <lpleahy@6f19259b-4bc3-4df7-8a09-765794883524>
Tue, 22 May 2012 17:08:33 +0000 (17:08 +0000)
committerlpleahy <lpleahy@6f19259b-4bc3-4df7-8a09-765794883524>
Tue, 22 May 2012 17:08:33 +0000 (17:08 +0000)
Signed-off-by: lpleahy
Contributed-by: Intel
git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@13348 6f19259b-4bc3-4df7-8a09-765794883524

OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772/Ax88772.c [new file with mode: 0644]
OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772/Ax88772.h [new file with mode: 0644]
OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772/Ax88772.inf [new file with mode: 0644]
OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772/ComponentName.c [new file with mode: 0644]
OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772/DriverBinding.c [new file with mode: 0644]
OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772/SimpleNetwork.c [new file with mode: 0644]

diff --git a/OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772/Ax88772.c b/OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772/Ax88772.c
new file mode 100644 (file)
index 0000000..6a74f1c
--- /dev/null
@@ -0,0 +1,1264 @@
+/** @file\r
+  Implement the interface to the AX88772 Ethernet controller.\r
+\r
+  This module implements the interface to the ASIX AX88772\r
+  USB to Ethernet MAC with integrated 10/100 PHY.  Note that this implementation\r
+  only supports the integrated PHY since no other test cases were available.\r
+\r
+  Copyright (c) 2011, Intel Corporation\r
+  All rights reserved. This program and the accompanying materials\r
+  are licensed and made available under the terms and conditions of the BSD License\r
+  which accompanies this distribution.  The full text of the license may be found at\r
+  http://opensource.org/licenses/bsd-license.php\r
+\r
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "Ax88772.h"\r
+\r
+\r
+/**\r
+  Compute the CRC\r
+\r
+  @param [in] pMacAddress      Address of a six byte buffer to containing the MAC address.\r
+\r
+  @returns The CRC-32 value associated with this MAC address\r
+\r
+**/\r
+UINT32\r
+Ax88772Crc (\r
+  IN UINT8 * pMacAddress\r
+  )\r
+{\r
+  UINT32 BitNumber;\r
+  INT32 Carry;\r
+  INT32 Crc;\r
+  UINT32 Data;\r
+  UINT8 * pEnd;\r
+\r
+  DBG_ENTER ( );\r
+\r
+  //\r
+  //  Walk the MAC address\r
+  //\r
+  Crc = -1;\r
+  pEnd = &pMacAddress[ PXE_HWADDR_LEN_ETHER ];\r
+  while ( pEnd > pMacAddress ) {\r
+    Data = *pMacAddress++;\r
+    \r
+    \r
+    //\r
+    //  CRC32: x32 + x26 + x23 + x22 + x16 + x12 + x11 + x10 + x8 + x7 + x5 + x4 + x2 + x + 1\r
+    //\r
+    //          1 0000 0100 1100 0001 0001 1101 1011 0111\r
+    //\r
+    for ( BitNumber = 0; 8 > BitNumber; BitNumber++ ) {\r
+      Carry = (( Crc >> 31 ) & 1 ) ^ ( Data & 1 );\r
+      Crc <<= 1;\r
+      if ( 0 != Carry ) {\r
+        Crc ^= 0x04c11db7;\r
+      }\r
+      Data >>= 1;\r
+    }\r
+  }\r
+\r
+  //\r
+  //  Return the CRC value\r
+  //\r
+  DBG_EXIT_HEX ( Crc );\r
+  return (UINT32) Crc;\r
+}\r
+\r
+\r
+/**\r
+  Get the MAC address\r
+\r
+  This routine calls ::Ax88772UsbCommand to request the MAC\r
+  address from the network adapter.\r
+\r
+  @param [in] pNicDevice       Pointer to the NIC_DEVICE structure\r
+  @param [out] pMacAddress      Address of a six byte buffer to receive the MAC address.\r
+\r
+  @retval EFI_SUCCESS          The MAC address is available.\r
+  @retval other                The MAC address is not valid.\r
+\r
+**/\r
+EFI_STATUS\r
+Ax88772MacAddressGet (\r
+  IN NIC_DEVICE * pNicDevice,\r
+  OUT UINT8 * pMacAddress\r
+  )\r
+{\r
+  USB_DEVICE_REQUEST SetupMsg;\r
+  EFI_STATUS Status;\r
+  \r
+  DBG_ENTER ( );\r
+  \r
+  //\r
+  //  Set the register address.\r
+  //\r
+  SetupMsg.RequestType = USB_ENDPOINT_DIR_IN\r
+                       | USB_REQ_TYPE_VENDOR\r
+                       | USB_TARGET_DEVICE;\r
+  SetupMsg.Request = CMD_MAC_ADDRESS_READ;\r
+  SetupMsg.Value = 0;\r
+  SetupMsg.Index = 0;\r
+  SetupMsg.Length = PXE_HWADDR_LEN_ETHER;\r
+\r
+  //\r
+  //  Read the PHY register\r
+  //\r
+  Status = Ax88772UsbCommand ( pNicDevice,\r
+                               &SetupMsg,\r
+                               pMacAddress );\r
+\r
+  //\r
+  // Return the operation status\r
+  //\r
+  DBG_EXIT_STATUS ( Status );\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Set the MAC address\r
+\r
+  This routine calls ::Ax88772UsbCommand to set the MAC address\r
+  in the network adapter.\r
+\r
+  @param [in] pNicDevice       Pointer to the NIC_DEVICE structure\r
+  @param [in] pMacAddress      Address of a six byte buffer to containing the new MAC address.\r
+\r
+  @retval EFI_SUCCESS          The MAC address was set.\r
+  @retval other                The MAC address was not set.\r
+\r
+**/\r
+EFI_STATUS\r
+Ax88772MacAddressSet (\r
+  IN NIC_DEVICE * pNicDevice,\r
+  IN UINT8 * pMacAddress\r
+  )\r
+{\r
+  USB_DEVICE_REQUEST SetupMsg;\r
+  EFI_STATUS Status;\r
+  \r
+  DBG_ENTER ( );\r
+  \r
+  //\r
+  //  Set the register address.\r
+  //\r
+  SetupMsg.RequestType = USB_REQ_TYPE_VENDOR\r
+                       | USB_TARGET_DEVICE;\r
+  SetupMsg.Request = CMD_MAC_ADDRESS_WRITE;\r
+  SetupMsg.Value = 0;\r
+  SetupMsg.Index = 0;\r
+  SetupMsg.Length = PXE_HWADDR_LEN_ETHER;\r
+  \r
+  //\r
+  //  Read the PHY register\r
+  //\r
+  Status = Ax88772UsbCommand ( pNicDevice,\r
+                               &SetupMsg,\r
+                               pMacAddress );\r
+  \r
+  //\r
+  // Return the operation status\r
+  //\r
+  DBG_EXIT_STATUS ( Status );\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Clear the multicast hash table\r
+\r
+  @param [in] pNicDevice       Pointer to the NIC_DEVICE structure\r
+\r
+**/\r
+VOID\r
+Ax88772MulticastClear (\r
+  IN NIC_DEVICE * pNicDevice\r
+  )\r
+{\r
+  DBG_ENTER ( );\r
+\r
+  //\r
+  // Clear the multicast hash table\r
+  //\r
+  pNicDevice->MulticastHash[0] = 0;\r
+  pNicDevice->MulticastHash[1] = 0;\r
+\r
+  DBG_EXIT ( );\r
+}\r
+\r
+\r
+/**\r
+  Enable a multicast address in the multicast hash table\r
+\r
+  This routine calls ::Ax88772Crc to compute the hash bit for\r
+  this MAC address.\r
+\r
+  @param [in] pNicDevice       Pointer to the NIC_DEVICE structure\r
+  @param [in] pMacAddress      Address of a six byte buffer to containing the MAC address.\r
+\r
+**/\r
+VOID\r
+Ax88772MulticastSet (\r
+  IN NIC_DEVICE * pNicDevice,\r
+  IN UINT8 * pMacAddress\r
+  )\r
+{\r
+  UINT32 BitNumber;\r
+  UINT32 Crc;\r
+  UINT32 Mask;\r
+\r
+  DBG_ENTER ( );\r
+\r
+  //\r
+  //  Compute the CRC on the destination address\r
+  //\r
+  Crc = Ax88772Crc ( pMacAddress );\r
+\r
+  //\r
+  //  Set the bit corresponding to the destination address\r
+  //\r
+  BitNumber = Crc >> 26;\r
+  if ( 32 > BitNumber ) {\r
+    Mask = 1 << BitNumber;\r
+    pNicDevice->MulticastHash[0] |= Mask;\r
+  }\r
+  else {\r
+    Mask = 1 << ( BitNumber - 32 );\r
+    pNicDevice->MulticastHash[1] |= Mask;\r
+  }\r
+\r
+  //\r
+  //  Display the multicast address\r
+  //\r
+  DEBUG (( DEBUG_RX_MULTICAST | DEBUG_INFO,\r
+            "Enable multicast: 0x%02x-%02x-%02x-%02x-%02x-%02x, CRC: 0x%08x, Bit number: 0x%02x\r\n",\r
+            pMacAddress[0],\r
+            pMacAddress[1],\r
+            pMacAddress[2],\r
+            pMacAddress[3],\r
+            pMacAddress[4],\r
+            pMacAddress[5],\r
+            Crc,\r
+            BitNumber ));\r
+\r
+  DBG_EXIT ( );\r
+}\r
+\r
+\r
+/**\r
+  Start the link negotiation\r
+\r
+  This routine calls ::Ax88772PhyWrite to start the PHY's link\r
+  negotiation.\r
+\r
+  @param [in] pNicDevice       Pointer to the NIC_DEVICE structure\r
+\r
+  @retval EFI_SUCCESS          The link negotiation was started.\r
+  @retval other                Failed to start the link negotiation.\r
+\r
+**/\r
+EFI_STATUS\r
+Ax88772NegotiateLinkStart (\r
+  IN NIC_DEVICE * pNicDevice\r
+  )\r
+{\r
+  UINT16 Control;\r
+  EFI_STATUS Status;\r
+\r
+  DBG_ENTER ( );\r
+\r
+  //\r
+  // Set the supported capabilities.\r
+  //\r
+  Status = Ax88772PhyWrite ( pNicDevice,\r
+                             PHY_ANAR,\r
+                             AN_CSMA_CD\r
+                             | AN_TX_FDX | AN_TX_HDX\r
+                             | AN_10_FDX | AN_10_HDX );\r
+  if ( !EFI_ERROR ( Status )) {\r
+    //\r
+    // Set the link speed and duplex\r
+    //\r
+    Control = BMCR_AUTONEGOTIATION_ENABLE\r
+            | BMCR_RESTART_AUTONEGOTIATION;\r
+    if ( pNicDevice->b100Mbps ) {\r
+      Control |= BMCR_100MBPS;\r
+    }\r
+    if ( pNicDevice->bFullDuplex ) {\r
+      Control |= BMCR_FULL_DUPLEX;\r
+    }\r
+    Status = Ax88772PhyWrite ( pNicDevice, PHY_BMCR, Control );\r
+  }\r
+\r
+  //\r
+  // Return the operation status\r
+  //\r
+  DBG_EXIT_STATUS ( Status );\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Complete the negotiation of the PHY link\r
+\r
+  This routine calls ::Ax88772PhyRead to determine if the\r
+  link negotiation is complete.\r
+\r
+  @param [in] pNicDevice       Pointer to the NIC_DEVICE structure\r
+  @param [in, out] pPollCount  Address of number of times this routine was polled\r
+  @param [out] pbComplete      Address of boolean to receive complate status.\r
+  @param [out] pbLinkUp        Address of boolean to receive link status, TRUE=up.\r
+  @param [out] pbHiSpeed       Address of boolean to receive link speed, TRUE=100Mbps.\r
+  @param [out] pbFullDuplex    Address of boolean to receive link duplex, TRUE=full.\r
+\r
+  @retval EFI_SUCCESS          The MAC address is available.\r
+  @retval other                The MAC address is not valid.\r
+\r
+**/\r
+EFI_STATUS\r
+Ax88772NegotiateLinkComplete (\r
+  IN NIC_DEVICE * pNicDevice,\r
+  IN OUT UINTN * pPollCount,\r
+  OUT BOOLEAN * pbComplete,\r
+  OUT BOOLEAN * pbLinkUp,\r
+  OUT BOOLEAN * pbHiSpeed,\r
+  OUT BOOLEAN * pbFullDuplex\r
+  )\r
+{\r
+  UINT16 Mask;\r
+  UINT16 PhyData;\r
+  EFI_STATUS  Status;\r
+\r
+  DBG_ENTER ( );\r
+  \r
+  //\r
+  //  Determine if the link is up.\r
+  //\r
+  *pbComplete = FALSE;\r
+\r
+  //\r
+  //  Get the link status\r
+  //\r
+  Status = Ax88772PhyRead ( pNicDevice,\r
+                            PHY_BMSR,\r
+                            &PhyData );\r
+  if ( !EFI_ERROR ( Status )) {\r
+    //\r
+    //  Determine if the autonegotiation is complete.\r
+    //\r
+    *pbLinkUp = (BOOLEAN)( 0 != ( PhyData & BMSR_LINKST ));\r
+    *pbComplete = *pbLinkUp;\r
+    if ( 0 != *pbComplete ) {\r
+      //\r
+      //  Get the partners capabilities.\r
+      //\r
+      Status = Ax88772PhyRead ( pNicDevice,\r
+                                PHY_ANLPAR,\r
+                                &PhyData );\r
+      if ( !EFI_ERROR ( Status )) {\r
+        //\r
+        //  Autonegotiation is complete\r
+        //  Determine the link speed.\r
+        //\r
+        *pbHiSpeed = (BOOLEAN)( 0 != ( PhyData & ( AN_TX_FDX | AN_TX_HDX )));\r
+\r
+        //\r
+        //  Determine the link duplex.\r
+        //\r
+        Mask = ( *pbHiSpeed ) ? AN_TX_FDX : AN_10_FDX;\r
+        *pbFullDuplex = (BOOLEAN)( 0 != ( PhyData & Mask ));\r
+      }\r
+    }\r
+  }\r
+\r
+  //\r
+  // Return the operation status\r
+  //\r
+  DBG_EXIT_STATUS ( Status );\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Read a register from the PHY\r
+\r
+  This routine calls ::Ax88772UsbCommand to read a PHY register.\r
+\r
+  @param [in] pNicDevice       Pointer to the NIC_DEVICE structure\r
+  @param [in] RegisterAddress  Number of the register to read.\r
+  @param [in, out] pPhyData    Address of a buffer to receive the PHY register value\r
+\r
+  @retval EFI_SUCCESS          The PHY data is available.\r
+  @retval other                The PHY data is not valid.\r
+\r
+**/\r
+EFI_STATUS\r
+Ax88772PhyRead (\r
+  IN NIC_DEVICE * pNicDevice,\r
+  IN UINT8 RegisterAddress,\r
+  IN OUT UINT16 * pPhyData\r
+  )\r
+{\r
+  USB_DEVICE_REQUEST SetupMsg;\r
+  EFI_STATUS Status;\r
+\r
+  DBG_ENTER ( );\r
+\r
+  //\r
+  //  Request access to the PHY\r
+  //\r
+  SetupMsg.RequestType = USB_REQ_TYPE_VENDOR\r
+                       | USB_TARGET_DEVICE;\r
+  SetupMsg.Request = CMD_PHY_ACCESS_SOFTWARE;\r
+  SetupMsg.Value = 0;\r
+  SetupMsg.Index = 0;\r
+  SetupMsg.Length = 0;\r
+  Status = Ax88772UsbCommand ( pNicDevice,\r
+                               &SetupMsg,\r
+                               NULL );\r
+  if ( !EFI_ERROR ( Status )) {\r
+    //\r
+    //  Read the PHY register address.\r
+    //\r
+    SetupMsg.RequestType = USB_ENDPOINT_DIR_IN\r
+                         | USB_REQ_TYPE_VENDOR\r
+                         | USB_TARGET_DEVICE;\r
+    SetupMsg.Request = CMD_PHY_REG_READ;\r
+    SetupMsg.Value = pNicDevice->PhyId;\r
+    SetupMsg.Index = RegisterAddress;\r
+    SetupMsg.Length = sizeof ( *pPhyData );\r
+    Status = Ax88772UsbCommand ( pNicDevice,\r
+                                 &SetupMsg,\r
+                                 pPhyData );\r
+    if ( !EFI_ERROR ( Status )) {\r
+      DEBUG (( DEBUG_PHY | DEBUG_INFO,\r
+                "PHY %d: 0x%02x --> 0x%04x\r\n",\r
+                pNicDevice->PhyId,\r
+                RegisterAddress,\r
+                *pPhyData ));\r
+\r
+      //\r
+      //  Release the PHY to the hardware\r
+      //\r
+      SetupMsg.RequestType = USB_REQ_TYPE_VENDOR\r
+                           | USB_TARGET_DEVICE;\r
+      SetupMsg.Request = CMD_PHY_ACCESS_HARDWARE;\r
+      SetupMsg.Value = 0;\r
+      SetupMsg.Index = 0;\r
+      SetupMsg.Length = 0;\r
+      Status = Ax88772UsbCommand ( pNicDevice,\r
+                                   &SetupMsg,\r
+                                   NULL );\r
+    }\r
+  }\r
+\r
+  //\r
+  //  Return the operation status.\r
+  //\r
+  DBG_EXIT_STATUS ( Status );\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Write to a PHY register\r
+\r
+  This routine calls ::Ax88772UsbCommand to write a PHY register.\r
+\r
+  @param [in] pNicDevice       Pointer to the NIC_DEVICE structure\r
+  @param [in] RegisterAddress  Number of the register to read.\r
+  @param [in] PhyData          Address of a buffer to receive the PHY register value\r
+\r
+  @retval EFI_SUCCESS          The PHY data was written.\r
+  @retval other                Failed to wwrite the PHY register.\r
+\r
+**/\r
+EFI_STATUS\r
+Ax88772PhyWrite (\r
+  IN NIC_DEVICE * pNicDevice,\r
+  IN UINT8 RegisterAddress,\r
+  IN UINT16 PhyData\r
+  )\r
+{\r
+  USB_DEVICE_REQUEST SetupMsg;\r
+  EFI_STATUS Status;\r
+  \r
+  DBG_ENTER ( );\r
+  \r
+  //\r
+  //  Request access to the PHY\r
+  //\r
+  SetupMsg.RequestType = USB_REQ_TYPE_VENDOR\r
+                       | USB_TARGET_DEVICE;\r
+  SetupMsg.Request = CMD_PHY_ACCESS_SOFTWARE;\r
+  SetupMsg.Value = 0;\r
+  SetupMsg.Index = 0;\r
+  SetupMsg.Length = 0;\r
+  Status = Ax88772UsbCommand ( pNicDevice,\r
+                               &SetupMsg,\r
+                               NULL );\r
+  if ( !EFI_ERROR ( Status )) {\r
+    //\r
+    //  Write the PHY register\r
+    //\r
+    SetupMsg.RequestType = USB_REQ_TYPE_VENDOR\r
+                         | USB_TARGET_DEVICE;\r
+    SetupMsg.Request = CMD_PHY_REG_WRITE;\r
+    SetupMsg.Value = pNicDevice->PhyId;\r
+    SetupMsg.Index = RegisterAddress;\r
+    SetupMsg.Length = sizeof ( PhyData );\r
+    Status = Ax88772UsbCommand ( pNicDevice,\r
+                                 &SetupMsg,\r
+                                 &PhyData );\r
+    if ( !EFI_ERROR ( Status )) {\r
+      DEBUG (( DEBUG_PHY | DEBUG_INFO,\r
+                "PHY %d: 0x%02x <-- 0x%04x\r\n",\r
+                pNicDevice->PhyId,\r
+                RegisterAddress,\r
+                PhyData ));\r
+\r
+      //\r
+      //  Release the PHY to the hardware\r
+      //\r
+      SetupMsg.RequestType = USB_REQ_TYPE_VENDOR\r
+                           | USB_TARGET_DEVICE;\r
+      SetupMsg.Request = CMD_PHY_ACCESS_HARDWARE;\r
+      SetupMsg.Value = 0;\r
+      SetupMsg.Index = 0;\r
+      SetupMsg.Length = 0;\r
+      Status = Ax88772UsbCommand ( pNicDevice,\r
+                                   &SetupMsg,\r
+                                   NULL );\r
+    }\r
+  }\r
+\r
+  //\r
+  //  Return the operation status.\r
+  //\r
+  DBG_EXIT_STATUS ( Status );\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Reset the AX88772\r
+\r
+  This routine uses ::Ax88772UsbCommand to reset the network\r
+  adapter.  This routine also uses ::Ax88772PhyWrite to reset\r
+  the PHY.\r
+\r
+  @param [in] pNicDevice       Pointer to the NIC_DEVICE structure\r
+\r
+  @retval EFI_SUCCESS          The MAC address is available.\r
+  @retval other                The MAC address is not valid.\r
+\r
+**/\r
+EFI_STATUS\r
+Ax88772Reset (\r
+  IN NIC_DEVICE * pNicDevice\r
+  )\r
+{\r
+  USB_DEVICE_REQUEST SetupMsg;\r
+  EFI_STATUS Status;\r
+  \r
+  DBG_ENTER ( );\r
+\r
+  //\r
+  //  Turn off the MAC\r
+  //\r
+  SetupMsg.RequestType = USB_REQ_TYPE_VENDOR\r
+                       | USB_TARGET_DEVICE;\r
+  SetupMsg.Request = CMD_RX_CONTROL_WRITE;\r
+  SetupMsg.Value = 0;\r
+  SetupMsg.Index = 0;\r
+  SetupMsg.Length = 0;\r
+  Status = Ax88772UsbCommand ( pNicDevice,\r
+                               &SetupMsg,\r
+                               NULL );\r
+  if ( !EFI_ERROR ( Status )) {\r
+    DEBUG (( DEBUG_PHY | DEBUG_RX_BROADCAST | DEBUG_RX_MULTICAST\r
+              | DEBUG_RX_UNICAST | DEBUG_TX | DEBUG_INFO,\r
+              "MAC reset\r\n" ));\r
+\r
+    //\r
+    //  The link is now idle\r
+    //\r
+    pNicDevice->bLinkIdle = TRUE;\r
+\r
+    //\r
+    //  Delay for a bit\r
+    //\r
+    gBS->Stall ( RESET_MSEC );\r
+\r
+    //\r
+    //  Select the internal PHY\r
+    //\r
+    SetupMsg.RequestType = USB_REQ_TYPE_VENDOR\r
+                         | USB_TARGET_DEVICE;\r
+    SetupMsg.Request = CMD_PHY_SELECT;\r
+    SetupMsg.Value = SPHY_PSEL;\r
+    SetupMsg.Index = 0;\r
+    SetupMsg.Length = 0;\r
+    Status = Ax88772UsbCommand ( pNicDevice,\r
+                                 &SetupMsg,\r
+                                 NULL );\r
+    if ( !EFI_ERROR ( Status )) {\r
+      //\r
+      //  Delay for a bit\r
+      //\r
+      gBS->Stall ( PHY_RESET_MSEC );\r
+\r
+      //\r
+      //  Clear the internal PHY reset\r
+      //\r
+      SetupMsg.Request = CMD_RESET;\r
+      SetupMsg.Value = SRR_IPRL | SRR_PRL;\r
+      Status = Ax88772UsbCommand ( pNicDevice,\r
+                                   &SetupMsg,\r
+                                   NULL );\r
+      if ( !EFI_ERROR ( Status )) {\r
+        //\r
+        //  Reset the PHY\r
+        //\r
+        Status = Ax88772PhyWrite ( pNicDevice,\r
+                                   PHY_BMCR,\r
+                                   BMCR_RESET );\r
+        if ( !EFI_ERROR ( Status )) {\r
+          //\r
+          //  Set the gaps\r
+          //\r
+          SetupMsg.RequestType = USB_REQ_TYPE_VENDOR\r
+                               | USB_TARGET_DEVICE;\r
+          SetupMsg.Request = CMD_GAPS_WRITE;\r
+          SetupMsg.Value = 0x0c15;\r
+          SetupMsg.Index = 0x0e;\r
+          SetupMsg.Length = 0;\r
+          Status = Ax88772UsbCommand ( pNicDevice,\r
+                                       &SetupMsg,\r
+                                       NULL );\r
+        }\r
+      }\r
+    }\r
+  }\r
+\r
+  //\r
+  //  Return the operation status.\r
+  //\r
+  DBG_EXIT_STATUS ( Status );\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Receive a frame from the network.\r
+\r
+  This routine polls the USB receive interface for a packet.  If a packet\r
+  is available, this routine adds the receive packet to the list of\r
+  pending receive packets.\r
+\r
+  This routine calls ::Ax88772NegotiateLinkComplete to verify\r
+  that the link is up.  This routine also calls ::SN_Reset to\r
+  reset the network adapter when necessary.  Finally this\r
+  routine attempts to receive one or more packets from the\r
+  network adapter.\r
+\r
+  @param [in] pNicDevice  Pointer to the NIC_DEVICE structure\r
+  @param [in] bUpdateLink TRUE = Update link status\r
+\r
+**/\r
+VOID\r
+Ax88772Rx (\r
+  IN NIC_DEVICE * pNicDevice,\r
+  IN BOOLEAN bUpdateLink\r
+  )\r
+{\r
+  BOOLEAN bFullDuplex;\r
+  BOOLEAN bLinkUp;\r
+  BOOLEAN bRxPacket;\r
+  BOOLEAN bSpeed100;\r
+  UINTN LengthInBytes;\r
+  RX_TX_PACKET Packet;\r
+  RX_TX_PACKET * pRxPacket;\r
+  EFI_USB_IO_PROTOCOL *pUsbIo;\r
+  EFI_STATUS Status;\r
+  EFI_TPL TplPrevious;\r
+  UINT32 TransferStatus;\r
+\r
+  //\r
+  //  Synchronize with Ax88772Timer\r
+  //\r
+  VERIFY_TPL ( TPL_AX88772 );\r
+  TplPrevious = gBS->RaiseTPL ( TPL_AX88772 );\r
+  DEBUG (( DEBUG_TPL | DEBUG_INFO,\r
+            "%d: TPL\r\n",\r
+            TPL_AX88772 ));\r
+\r
+  //\r
+  //  Get the link status\r
+  //\r
+  if ( bUpdateLink ) {\r
+    bLinkUp = pNicDevice->bLinkUp;\r
+    bSpeed100 = pNicDevice->b100Mbps;\r
+    bFullDuplex = pNicDevice->bFullDuplex;\r
+    Status = Ax88772NegotiateLinkComplete ( pNicDevice,\r
+                                            &pNicDevice->PollCount,\r
+                                            &pNicDevice->bComplete,\r
+                                            &pNicDevice->bLinkUp,\r
+                                            &pNicDevice->b100Mbps,\r
+                                            &pNicDevice->bFullDuplex );\r
+\r
+    //\r
+    // Determine if the autonegotiation is complete\r
+    //\r
+    if ( pNicDevice->bComplete ) {\r
+      if ( pNicDevice->bLinkUp ) {\r
+        if (( bSpeed100 && ( !pNicDevice->b100Mbps ))\r
+          || (( !bSpeed100 ) && pNicDevice->b100Mbps )\r
+          || ( bFullDuplex && ( !pNicDevice->bFullDuplex ))\r
+          || (( !bFullDuplex ) && pNicDevice->bFullDuplex )) {\r
+          pNicDevice->PollCount = 0;\r
+          DEBUG (( DEBUG_LINK | DEBUG_INFO,\r
+                    "Reset to establish proper link setup: %d Mbps, %s duplex\r\n",\r
+                    pNicDevice->b100Mbps ? 100 : 10,\r
+                    pNicDevice->bFullDuplex ? L"Full" : L"Half" ));\r
+          Status = SN_Reset ( &pNicDevice->SimpleNetwork, FALSE );\r
+        }\r
+        if (( !bLinkUp ) && pNicDevice->bLinkUp ) {\r
+          //\r
+          // Display the autonegotiation status\r
+          //\r
+          DEBUG (( DEBUG_LINK | DEBUG_INFO,\r
+                    "Link: Up, %d Mbps, %s duplex\r\n",\r
+                    pNicDevice->b100Mbps ? 100 : 10,\r
+                    pNicDevice->bFullDuplex ? L"Full" : L"Half" ));\r
+        }\r
+      }\r
+    }\r
+\r
+    //\r
+    //  Update the link status\r
+    //\r
+    if ( bLinkUp && ( !pNicDevice->bLinkUp )) {\r
+      DEBUG (( DEBUG_LINK | DEBUG_INFO, "Link: Down\r\n" ));\r
+    }\r
+  }\r
+\r
+  //\r
+  //  Loop until all the packets are emptied from the receiver\r
+  //\r
+  do {\r
+    bRxPacket = FALSE;\r
+\r
+    //\r
+    //  Locate a packet for use\r
+    //\r
+    pRxPacket = pNicDevice->pRxFree;\r
+    LengthInBytes = sizeof ( *pRxPacket ) - sizeof ( pRxPacket->pNext );\r
+    if ( NULL == pRxPacket ) {\r
+      Status = gBS->AllocatePool ( EfiRuntimeServicesData,\r
+                                   LengthInBytes,\r
+                                   (VOID **) &pRxPacket );\r
+      if ( !EFI_ERROR ( Status )) {\r
+        //\r
+        //  Add this packet to the free packet list\r
+        //\r
+        pNicDevice->pRxFree = pRxPacket;\r
+        pRxPacket->pNext = NULL;\r
+      }\r
+      else {\r
+        //\r
+        //  Use the discard packet buffer\r
+        //\r
+        pRxPacket = &Packet;\r
+      }\r
+    }\r
+\r
+    //\r
+    //  Attempt to receive a packet\r
+    //\r
+    pUsbIo = pNicDevice->pUsbIo;\r
+    Status = pUsbIo->UsbBulkTransfer ( pUsbIo,\r
+                                       USB_ENDPOINT_DIR_IN | BULK_IN_ENDPOINT,\r
+                                       &pRxPacket->Length,\r
+                                       &LengthInBytes,\r
+                                       2,\r
+                                       &TransferStatus );\r
+    if (( !EFI_ERROR ( Status ))\r
+      && ( 0 < pRxPacket->Length )\r
+      && ( pRxPacket->Length <= sizeof ( pRxPacket->Data ))) {\r
+\r
+      //\r
+      //  Determine if the packet should be received\r
+      //\r
+      bRxPacket = TRUE;\r
+      LengthInBytes = pRxPacket->Length;\r
+      pNicDevice->bLinkIdle = FALSE;\r
+      if ( pNicDevice->pRxFree == pRxPacket ) {\r
+        //\r
+        //  Display the received packet\r
+        //\r
+        if ( 0 != ( pRxPacket->Data[0] & 1 )) {\r
+          if (( 0xff == pRxPacket->Data[0])\r
+            && ( 0xff == pRxPacket->Data[1])\r
+            && ( 0xff == pRxPacket->Data[2])\r
+            && ( 0xff == pRxPacket->Data[3])\r
+            && ( 0xff == pRxPacket->Data[4])\r
+            && ( 0xff == pRxPacket->Data[5])) {\r
+            DEBUG (( DEBUG_RX_BROADCAST | DEBUG_INFO,\r
+                      "RX: %02x-%02x-%02x-%02x-%02x-%02x  %02x-%02x-%02x-%02x-%02x-%02x  %02x-%02x  %d bytes\r\n",\r
+                      pRxPacket->Data[0],\r
+                      pRxPacket->Data[1],\r
+                      pRxPacket->Data[2],\r
+                      pRxPacket->Data[3],\r
+                      pRxPacket->Data[4],\r
+                      pRxPacket->Data[5],\r
+                      pRxPacket->Data[6],\r
+                      pRxPacket->Data[7],\r
+                      pRxPacket->Data[8],\r
+                      pRxPacket->Data[9],\r
+                      pRxPacket->Data[10],\r
+                      pRxPacket->Data[11],\r
+                      pRxPacket->Data[12],\r
+                      pRxPacket->Data[13],\r
+                      LengthInBytes ));\r
+          }\r
+          else {\r
+            DEBUG (( DEBUG_RX_MULTICAST | DEBUG_INFO,\r
+                      "RX: %02x-%02x-%02x-%02x-%02x-%02x  %02x-%02x-%02x-%02x-%02x-%02x  %02x-%02x  %d bytes\r\n",\r
+                      pRxPacket->Data[0],\r
+                      pRxPacket->Data[1],\r
+                      pRxPacket->Data[2],\r
+                      pRxPacket->Data[3],\r
+                      pRxPacket->Data[4],\r
+                      pRxPacket->Data[5],\r
+                      pRxPacket->Data[6],\r
+                      pRxPacket->Data[7],\r
+                      pRxPacket->Data[8],\r
+                      pRxPacket->Data[9],\r
+                      pRxPacket->Data[10],\r
+                      pRxPacket->Data[11],\r
+                      pRxPacket->Data[12],\r
+                      pRxPacket->Data[13],\r
+                      LengthInBytes ));\r
+          }\r
+        }\r
+        else {\r
+          DEBUG (( DEBUG_RX_UNICAST | DEBUG_INFO,\r
+                    "RX: %02x-%02x-%02x-%02x-%02x-%02x  %02x-%02x-%02x-%02x-%02x-%02x  %02x-%02x  %d bytes\r\n",\r
+                    pRxPacket->Data[0],\r
+                    pRxPacket->Data[1],\r
+                    pRxPacket->Data[2],\r
+                    pRxPacket->Data[3],\r
+                    pRxPacket->Data[4],\r
+                    pRxPacket->Data[5],\r
+                    pRxPacket->Data[6],\r
+                    pRxPacket->Data[7],\r
+                    pRxPacket->Data[8],\r
+                    pRxPacket->Data[9],\r
+                    pRxPacket->Data[10],\r
+                    pRxPacket->Data[11],\r
+                    pRxPacket->Data[12],\r
+                    pRxPacket->Data[13],\r
+                    LengthInBytes ));\r
+        }\r
+        \r
+        //\r
+        //  Remove this packet from the free packet list\r
+        //\r
+        pNicDevice->pRxFree = pRxPacket->pNext;\r
+        pRxPacket->pNext = NULL;\r
+\r
+        //\r
+        //  Append this packet to the receive list\r
+        //\r
+        if ( NULL == pNicDevice->pRxTail ) {\r
+          pNicDevice->pRxHead = pRxPacket;\r
+        }\r
+        else {\r
+          pNicDevice->pRxTail->pNext = pRxPacket;\r
+        }\r
+        pNicDevice->pRxTail = pRxPacket;\r
+      }\r
+      else {\r
+        //\r
+        //  Error, not enough buffers for this packet, discard packet\r
+        //\r
+        DEBUG (( DEBUG_WARN | DEBUG_INFO,\r
+                  "WARNING - No buffer, discarding RX packet: %02x-%02x-%02x-%02x-%02x-%02x  %02x-%02x-%02x-%02x-%02x-%02x  %02x-%02x  %d bytes\r\n",\r
+                  pRxPacket->Data[0],\r
+                  pRxPacket->Data[1],\r
+                  pRxPacket->Data[2],\r
+                  pRxPacket->Data[3],\r
+                  pRxPacket->Data[4],\r
+                  pRxPacket->Data[5],\r
+                  pRxPacket->Data[6],\r
+                  pRxPacket->Data[7],\r
+                  pRxPacket->Data[8],\r
+                  pRxPacket->Data[9],\r
+                  pRxPacket->Data[10],\r
+                  pRxPacket->Data[11],\r
+                  pRxPacket->Data[12],\r
+                  pRxPacket->Data[13],\r
+                  LengthInBytes ));\r
+      }\r
+    }\r
+  }while ( bRxPacket );\r
+\r
+  //\r
+  //  Release the synchronization withhe Ax88772Timer\r
+  //\r
+  gBS->RestoreTPL ( TplPrevious );\r
+  DEBUG (( DEBUG_TPL | DEBUG_INFO,\r
+            "%d: TPL\r\n",\r
+            TplPrevious ));\r
+}\r
+\r
+\r
+/**\r
+  Enable or disable the receiver\r
+\r
+  This routine calls ::Ax88772UsbCommand to update the\r
+  receiver state.  This routine also calls ::Ax88772MacAddressSet\r
+  to establish the MAC address for the network adapter.\r
+\r
+  @param [in] pNicDevice       Pointer to the NIC_DEVICE structure\r
+  @param [in] RxFilter         Simple network RX filter mask value\r
+\r
+  @retval EFI_SUCCESS          The MAC address was set.\r
+  @retval other                The MAC address was not set.\r
+\r
+**/\r
+EFI_STATUS\r
+Ax88772RxControl (\r
+  IN NIC_DEVICE * pNicDevice,\r
+  IN UINT32 RxFilter\r
+  )\r
+{\r
+  UINT16 MediumStatus;\r
+  INT32 MulticastHash[2];\r
+  UINT16 RxControl;\r
+  USB_DEVICE_REQUEST SetupMsg;\r
+  EFI_STATUS Status;\r
+\r
+  DBG_ENTER ( );\r
+\r
+  //\r
+  //  Disable all multicast\r
+  //\r
+  MulticastHash[0] = 0;\r
+  MulticastHash[1] = 0;\r
+\r
+  //\r
+  // Enable the receiver if something is to be received\r
+  //\r
+  Status = EFI_SUCCESS;\r
+  RxControl = RXC_SO | RXC_MFB_16384;\r
+  if ( 0 != RxFilter ) {\r
+    //\r
+    //  Enable the receiver\r
+    //\r
+    SetupMsg.RequestType = USB_ENDPOINT_DIR_IN\r
+                         | USB_REQ_TYPE_VENDOR\r
+                         | USB_TARGET_DEVICE;\r
+    SetupMsg.Request = CMD_MEDIUM_STATUS_READ;\r
+    SetupMsg.Value = 0;\r
+    SetupMsg.Index = 0;\r
+    SetupMsg.Length = sizeof ( MediumStatus );\r
+    Status = Ax88772UsbCommand ( pNicDevice,\r
+                                 &SetupMsg,\r
+                                 &MediumStatus );\r
+    if ( !EFI_ERROR ( Status )) {\r
+      if ( 0 == ( MediumStatus & MS_RE )) {\r
+        MediumStatus |= MS_RE | MS_ONE;\r
+        if ( pNicDevice->bFullDuplex ) {\r
+          MediumStatus |= MS_TFC | MS_RFC;\r
+        }\r
+        SetupMsg.RequestType = USB_REQ_TYPE_VENDOR\r
+                             | USB_TARGET_DEVICE;\r
+        SetupMsg.Request = CMD_MEDIUM_STATUS_WRITE;\r
+        SetupMsg.Value = MediumStatus;\r
+        SetupMsg.Index = 0;\r
+        SetupMsg.Length = 0;\r
+        Status = Ax88772UsbCommand ( pNicDevice,\r
+                                     &SetupMsg,\r
+                                     NULL );\r
+        if ( EFI_ERROR ( Status )) {\r
+          DEBUG (( DEBUG_ERROR | DEBUG_INFO,\r
+                    "ERROR - Failed to enable receiver, Status: %r\r\n",\r
+                    Status ));\r
+        }\r
+      }\r
+    }\r
+    else {\r
+      DEBUG (( DEBUG_ERROR | DEBUG_INFO,\r
+                "ERROR - Failed to read receiver status, Status: %r\r\n",\r
+                Status ));\r
+    }\r
+\r
+    //\r
+    //  Enable multicast if requested\r
+    //\r
+    if ( 0 != ( RxFilter & EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST )) {\r
+      RxControl |= RXC_AM;\r
+      MulticastHash[0] = pNicDevice->MulticastHash[0];\r
+      MulticastHash[1] = pNicDevice->MulticastHash[1];\r
+    }\r
+\r
+    //\r
+    //  Enable all multicast if requested\r
+    //\r
+    if ( 0 != ( RxFilter & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST )) {\r
+      RxControl |= RXC_AMALL;\r
+      MulticastHash[0] = -1;\r
+      MulticastHash[1] = -1;\r
+    }\r
+\r
+    //\r
+    //  Enable broadcast if requested\r
+    //\r
+    if ( 0 != ( RxFilter & EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST )) {\r
+      RxControl |= RXC_AB;\r
+    }\r
+\r
+    //\r
+    //  Enable promiscuous mode if requested\r
+    //\r
+    if ( 0 != ( RxFilter & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS )) {\r
+      RxControl |= RXC_PRO;\r
+      MulticastHash[0] = -1;\r
+      MulticastHash[1] = -1;\r
+    }\r
+  }\r
+\r
+  //\r
+  //  Update the MAC address\r
+  //\r
+  if ( !EFI_ERROR ( Status )) {\r
+    Status = Ax88772MacAddressSet ( pNicDevice, &pNicDevice->SimpleNetworkData.CurrentAddress.Addr[0]);\r
+  }\r
+\r
+  //\r
+  //  Update the receiver control\r
+  //\r
+  if ( !EFI_ERROR ( Status )) {\r
+    SetupMsg.RequestType = USB_REQ_TYPE_VENDOR\r
+                         | USB_TARGET_DEVICE;\r
+    SetupMsg.Request = CMD_RX_CONTROL_WRITE;\r
+    SetupMsg.Value = RxControl;\r
+    SetupMsg.Index = 0;\r
+    SetupMsg.Length = 0;\r
+    Status = Ax88772UsbCommand ( pNicDevice,\r
+                                 &SetupMsg,\r
+                                 NULL );\r
+    if ( !EFI_ERROR ( Status )) {\r
+      DEBUG (( DEBUG_RX_BROADCAST | DEBUG_RX_MULTICAST | DEBUG_RX_UNICAST | DEBUG_INFO,\r
+                "RxControl: 0x%04x\r\n",\r
+                RxControl ));\r
+\r
+      //\r
+      //  Update the multicast hash table\r
+      //\r
+      SetupMsg.RequestType = USB_REQ_TYPE_VENDOR\r
+                           | USB_TARGET_DEVICE;\r
+      SetupMsg.Request = CMD_MULTICAST_HASH_WRITE;\r
+      SetupMsg.Value = 0;\r
+      SetupMsg.Index = 0;\r
+      SetupMsg.Length = sizeof ( pNicDevice ->MulticastHash );\r
+      Status = Ax88772UsbCommand ( pNicDevice,\r
+                                   &SetupMsg,\r
+                                   &pNicDevice->MulticastHash );\r
+      if ( !EFI_ERROR ( Status )) {\r
+        DEBUG (( DEBUG_RX_MULTICAST | DEBUG_INFO,\r
+                  "Multicast Hash: 0x%02x %02x %02x %02x %02x %02x %02x %02x\r\n",\r
+                  (UINT8) MulticastHash[0],\r
+                  (UINT8)( MulticastHash[0] >> 8 ),\r
+                  (UINT8)( MulticastHash[0] >> 16 ),\r
+                  (UINT8)( MulticastHash[0] >> 24 ),\r
+                  (UINT8) MulticastHash[1],\r
+                  (UINT8)( MulticastHash[1] >> 8 ),\r
+                  (UINT8)( MulticastHash[1] >> 16 ),\r
+                  (UINT8)( MulticastHash[1] >> 24 )));\r
+      }\r
+      else {\r
+        DEBUG (( DEBUG_ERROR | DEBUG_INFO,\r
+                  "ERROR - Failed to update multicast hash table, Status: %r\r\n",\r
+                  Status ));\r
+      }\r
+    }\r
+    else {\r
+      DEBUG (( DEBUG_ERROR | DEBUG_INFO,\r
+                "ERROR - Failed to set receiver control, Status: %r\r\n",\r
+                Status ));\r
+    }\r
+  }\r
+\r
+  //\r
+  // Return the operation status\r
+  //\r
+  DBG_EXIT_STATUS ( Status );\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Read an SROM location\r
+\r
+  This routine calls ::Ax88772UsbCommand to read data from the\r
+  SROM.\r
+\r
+  @param [in] pNicDevice       Pointer to the NIC_DEVICE structure\r
+  @param [in] Address          SROM address\r
+  @param [out] pData           Buffer to receive the data\r
+\r
+  @retval EFI_SUCCESS          The read was successful\r
+  @retval other                The read failed\r
+\r
+**/\r
+EFI_STATUS\r
+Ax88772SromRead (\r
+  IN NIC_DEVICE * pNicDevice,\r
+  IN UINT32 Address,\r
+  OUT UINT16 * pData\r
+  )\r
+{\r
+  USB_DEVICE_REQUEST SetupMsg;\r
+  EFI_STATUS Status;\r
+\r
+  DBG_ENTER ( );\r
+\r
+  //\r
+  //  Read a value from the SROM\r
+  //\r
+  SetupMsg.RequestType = USB_ENDPOINT_DIR_IN\r
+                       | USB_REQ_TYPE_VENDOR\r
+                       | USB_TARGET_DEVICE;\r
+  SetupMsg.Request = CMD_SROM_READ;\r
+  SetupMsg.Value = (UINT16) Address;\r
+  SetupMsg.Index = 0;\r
+  SetupMsg.Length = sizeof ( *pData );\r
+  Status = Ax88772UsbCommand ( pNicDevice,\r
+                               &SetupMsg,\r
+                               pData );\r
+\r
+  //\r
+  // Return the operation status\r
+  //\r
+  DBG_EXIT_STATUS ( Status );\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  This routine is called at a regular interval to poll for\r
+  receive packets.\r
+\r
+  This routine polls the link state and gets any receive packets\r
+  by calling ::Ax88772Rx.\r
+\r
+  @param [in] Event            Timer event\r
+  @param [in] pNicDevice       Pointer to the NIC_DEVICE structure\r
+\r
+**/\r
+VOID\r
+Ax88772Timer (\r
+  IN EFI_EVENT Event,\r
+  IN NIC_DEVICE * pNicDevice\r
+  )\r
+{\r
+  //\r
+  //  Use explicit DEBUG messages since the output frequency is too\r
+  //  high for DEBUG_INFO to keep up and have spare cycles for the\r
+  //  shell\r
+  //\r
+  DEBUG (( DEBUG_TIMER, "Entering Ax88772Timer\r\n" ));\r
+\r
+  //\r
+  //  Poll the link state and get any receive packets\r
+  //\r
+  Ax88772Rx ( pNicDevice, FALSE );\r
+\r
+  DEBUG (( DEBUG_TIMER, "Exiting Ax88772Timer\r\n" ));\r
+}\r
+\r
+\r
+/**\r
+  Send a command to the USB device.\r
+\r
+  @param [in] pNicDevice       Pointer to the NIC_DEVICE structure\r
+  @param [in] pRequest         Pointer to the request structure\r
+  @param [in, out] pBuffer     Data buffer address\r
+\r
+  @retval EFI_SUCCESS          The USB transfer was successful\r
+  @retval other                The USB transfer failed\r
+\r
+**/\r
+EFI_STATUS\r
+Ax88772UsbCommand (\r
+  IN NIC_DEVICE * pNicDevice,\r
+  IN USB_DEVICE_REQUEST * pRequest,\r
+  IN OUT VOID * pBuffer\r
+  )\r
+{\r
+  UINT32 CmdStatus;\r
+  EFI_USB_DATA_DIRECTION Direction;\r
+  EFI_USB_IO_PROTOCOL * pUsbIo;\r
+  EFI_STATUS Status;\r
+\r
+  DBG_ENTER ( );\r
+\r
+  //\r
+  // Determine the transfer direction\r
+  //\r
+  Direction = EfiUsbNoData;\r
+  if ( 0 != pRequest->Length ) {\r
+    Direction = ( 0 != ( pRequest->RequestType & USB_ENDPOINT_DIR_IN ))\r
+              ? EfiUsbDataIn : EfiUsbDataOut;\r
+  }\r
+\r
+  //\r
+  // Issue the command\r
+  //\r
+  pUsbIo = pNicDevice->pUsbIo;\r
+  Status = pUsbIo->UsbControlTransfer ( pUsbIo,\r
+                                        pRequest,\r
+                                        Direction,\r
+                                        USB_BUS_TIMEOUT,\r
+                                        pBuffer,\r
+                                        pRequest->Length,\r
+                                        &CmdStatus );\r
+\r
+  //\r
+  // Determine the operation status\r
+  //\r
+  if ( !EFI_ERROR ( Status )) {\r
+    Status = CmdStatus;\r
+  }\r
+  else {\r
+    //\r
+    // Display any errors\r
+    //\r
+    DEBUG (( DEBUG_INFO,\r
+              "Ax88772UsbCommand - Status: %r\n",\r
+              Status ));\r
+\r
+    //\r
+    // Only use status values associated with the Simple Network protocol\r
+    //\r
+    if ( EFI_TIMEOUT == Status ) {\r
+      Status = EFI_DEVICE_ERROR;\r
+    }\r
+  }\r
+\r
+  //\r
+  // Return the operation status\r
+  //\r
+  DBG_EXIT_STATUS ( Status );\r
+  return Status;\r
+}\r
diff --git a/OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772/Ax88772.h b/OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772/Ax88772.h
new file mode 100644 (file)
index 0000000..667214a
--- /dev/null
@@ -0,0 +1,971 @@
+/** @file\r
+  Definitions for ASIX AX88772 Ethernet adapter.\r
+\r
+  Copyright (c) 2011, Intel Corporation\r
+  All rights reserved. This program and the accompanying materials\r
+  are licensed and made available under the terms and conditions of the BSD License\r
+  which accompanies this distribution.  The full text of the license may be found at\r
+  http://opensource.org/licenses/bsd-license.php\r
+\r
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _AX88772_H_\r
+#define _AX88772_H_\r
+\r
+#include <Uefi.h>\r
+\r
+#include <Guid/EventGroup.h>\r
+#include <Guid/NicIp4ConfigNvData.h>\r
+\r
+#include <IndustryStandard/Pci.h>\r
+\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/DevicePathLib.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/UefiDriverEntryPoint.h>\r
+#include <Library/UefiLib.h>\r
+#include <Library/UefiRuntimeLib.h>\r
+\r
+#include <Protocol/DevicePath.h>\r
+#include <Protocol/LoadedImage.h>\r
+#include <Protocol/NetworkInterfaceIdentifier.h>\r
+#include <Protocol/SimpleNetwork.h>\r
+#include <Protocol/UsbIo.h>\r
+\r
+//------------------------------------------------------------------------------\r
+//  Macros\r
+//------------------------------------------------------------------------------\r
+\r
+#if defined(_MSC_VER)           /* Handle Microsoft VC++ compiler specifics. */\r
+#define DBG_ENTER()             DEBUG (( DEBUG_INFO, "Entering " __FUNCTION__ "\n" )) ///<  Display routine entry\r
+#define DBG_EXIT()              DEBUG (( DEBUG_INFO, "Exiting " __FUNCTION__ "\n" ))  ///<  Display routine exit\r
+#define DBG_EXIT_DEC(Status)    DEBUG (( DEBUG_INFO, "Exiting " __FUNCTION__ ", Status: %d\n", Status ))      ///<  Display routine exit with decimal value\r
+#define DBG_EXIT_HEX(Status)    DEBUG (( DEBUG_INFO, "Exiting " __FUNCTION__ ", Status: 0x%08x\n", Status ))  ///<  Display routine exit with hex value\r
+#define DBG_EXIT_STATUS(Status) DEBUG (( DEBUG_INFO, "Exiting " __FUNCTION__ ", Status: %r\n", Status ))      ///<  Display routine exit with status value\r
+#define DBG_EXIT_TF(Status)     DEBUG (( DEBUG_INFO, "Exiting " __FUNCTION__ ", returning %s\n", (FALSE == Status) ? L"FALSE" : L"TRUE" ))  ///<  Display routine with TRUE/FALSE value\r
+#else   //  _MSC_VER\r
+#define DBG_ENTER()               ///<  Display routine entry\r
+#define DBG_EXIT()                ///<  Display routine exit\r
+#define DBG_EXIT_DEC(Status)      ///<  Display routine exit with decimal value\r
+#define DBG_EXIT_HEX(Status)      ///<  Display routine exit with hex value\r
+#define DBG_EXIT_STATUS(Status)   ///<  Display routine exit with status value\r
+#define DBG_EXIT_TF(Status)       ///<  Display routine with TRUE/FALSE value\r
+#endif  //  _MSC_VER\r
+\r
+#define USB_IS_IN_ENDPOINT(EndPointAddr)      (((EndPointAddr) & BIT7) != 0)  ///<  Return TRUE/FALSE for IN direction\r
+#define USB_IS_OUT_ENDPOINT(EndPointAddr)     (((EndPointAddr) & BIT7) == 0)  ///<  Return TRUE/FALSE for OUT direction\r
+#define USB_IS_BULK_ENDPOINT(Attribute)       (((Attribute) & (BIT0 | BIT1)) == USB_ENDPOINT_BULK)      ///<  Return TRUE/FALSE for BULK type\r
+#define USB_IS_INTERRUPT_ENDPOINT(Attribute)  (((Attribute) & (BIT0 | BIT1)) == USB_ENDPOINT_INTERRUPT) ///<  Return TRUE/FALSE for INTERRUPT type\r
+\r
+//------------------------------------------------------------------------------\r
+//  Constants\r
+//------------------------------------------------------------------------------\r
+\r
+#define DEBUG_RX_BROADCAST  0x40000000  ///<  Display RX broadcast messages\r
+#define DEBUG_RX_MULTICAST  0x20000000  ///<  Display RX multicast messages\r
+#define DEBUG_RX_UNICAST    0x10000000  ///<  Display RX unicast messages\r
+#define DEBUG_MAC_ADDRESS   0x08000000  ///<  Display the MAC address\r
+#define DEBUG_LINK          0x04000000  ///<  Display the link status\r
+#define DEBUG_TX            0x02000000  ///<  Display the TX messages\r
+#define DEBUG_PHY           0x01000000  ///<  Display the PHY register values\r
+#define DEBUG_SROM          0x00800000  ///<  Display the SROM contents\r
+#define DEBUG_TIMER         0x00400000  ///<  Display the timer routine entry/exit\r
+#define DEBUG_TPL           0x00200000  ///<  Display the timer routine entry/exit\r
+\r
+#define AX88772_MAX_PKT_SIZE  ( 2048 - 4 )  ///< Maximum packet size\r
+#define ETHERNET_HEADER_SIZE  sizeof ( ETHERNET_HEADER )  ///<  Size in bytes of the Ethernet header\r
+#define MIN_ETHERNET_PKT_SIZE 60    ///<  Minimum packet size including Ethernet header\r
+#define MAX_ETHERNET_PKT_SIZE 1500  ///<  Ethernet spec 3.1.1: Minimum packet size\r
+\r
+#define USB_NETWORK_CLASS   0x09    ///<  USB Network class code\r
+#define USB_BUS_TIMEOUT     1000    ///<  USB timeout in milliseconds\r
+\r
+#define TIMER_MSEC          20              ///<  Polling interval for the NIC\r
+#define TPL_AX88772         TPL_CALLBACK    ///<  TPL for routine synchronization\r
+\r
+/**\r
+  Verify new TPL value\r
+\r
+  This macro which is enabled when debug is enabled verifies that\r
+  the new TPL value is >= the current TPL value.\r
+**/\r
+#ifdef VERIFY_TPL\r
+#undef VERIFY_TPL\r
+#endif  //  VERIFY_TPL\r
+\r
+#if !defined(MDEPKG_NDEBUG)\r
+\r
+#define VERIFY_TPL(tpl)                           \\r
+{                                                 \\r
+  EFI_TPL PreviousTpl;                            \\r
+                                                  \\r
+  PreviousTpl = gBS->RaiseTPL ( TPL_HIGH_LEVEL ); \\r
+  gBS->RestoreTPL ( PreviousTpl );                \\r
+  if ( PreviousTpl > tpl ) {                      \\r
+    DEBUG (( DEBUG_ERROR, "Current TPL: %d, New TPL: %d\r\n", PreviousTpl, tpl ));  \\r
+    ASSERT ( PreviousTpl <= tpl );                \\r
+  }                                               \\r
+}\r
+\r
+#else   //  MDEPKG_NDEBUG\r
+\r
+#define VERIFY_TPL(tpl)\r
+\r
+#endif  //  MDEPKG_NDEBUG\r
+\r
+//------------------------------------------------------------------------------\r
+//  Hardware Definition\r
+//------------------------------------------------------------------------------\r
+\r
+#define DEV_SIGNATURE     SIGNATURE_32 ('A','X','8','8')  ///<  Signature of data structures in memory\r
+\r
+#define VENDOR_ID         0x0b95  ///<  Vendor ID for Asix\r
+#define PRODUCT_ID        0x7720  ///<  Product ID for the AX88772 USB 10/100 Ethernet controller\r
+\r
+#define RESET_MSEC        1000    ///<  Reset duration\r
+#define PHY_RESET_MSEC     500    ///<  PHY reset duration\r
+\r
+//\r
+//  RX Control register\r
+//\r
+\r
+#define RXC_PRO           0x0001  ///<  Receive all packets\r
+#define RXC_AMALL         0x0002  ///<  Receive all multicast packets\r
+#define RXC_SEP           0x0004  ///<  Save error packets\r
+#define RXC_AB            0x0008  ///<  Receive broadcast packets\r
+#define RXC_AM            0x0010  ///<  Use multicast destination address hash table\r
+#define RXC_AP            0x0020  ///<  Accept physical address from Multicast Filter\r
+#define RXC_SO            0x0080  ///<  Start operation\r
+#define RXC_MFB           0x0300  ///<  Maximum frame burst\r
+#define RXC_MFB_2048      0       ///<  Maximum frame size:  2048 bytes\r
+#define RXC_MFB_4096      0x0100  ///<  Maximum frame size:  4096 bytes\r
+#define RXC_MFB_8192      0x0200  ///<  Maximum frame size:  8192 bytes\r
+#define RXC_MFB_16384     0x0300  ///<  Maximum frame size: 16384 bytes\r
+\r
+//\r
+//  Medium Status register\r
+//\r
+\r
+#define MS_FD             0x0002  ///<  Full duplex\r
+#define MS_ONE            0x0004  ///<  Must be one\r
+#define MS_RFC            0x0010  ///<  RX flow control enable\r
+#define MS_TFC            0x0020  ///<  TX flow control enable\r
+#define MS_PF             0x0080  ///<  Pause frame enable\r
+#define MS_RE             0x0100  ///<  Receive enable\r
+#define MS_PS             0x0200  ///<  Port speed 1=100, 0=10 Mbps\r
+#define MS_SBP            0x0800  ///<  Stop back pressure\r
+#define MS_SM             0x1000  ///<  Super MAC support\r
+\r
+//\r
+//  Software PHY Select register\r
+//\r
+\r
+#define SPHY_PSEL         0x01    ///<  Select internal PHY\r
+#define SPHY_ASEL         0x02    ///<  1=Auto select, 0=Manual select\r
+\r
+//\r
+//  Software Reset register\r
+//\r
+\r
+#define SRR_RR            0x01    ///<  Clear receive frame length error\r
+#define SRR_RT            0x02    ///<  Clear transmit frame length error\r
+#define SRR_PRTE          0x04    ///<  External PHY reset pin tri-state enable\r
+#define SRR_PRL           0x08    ///<  External PHY reset pin level\r
+#define SRR_BZ            0x10    ///<  Force Bulk to return zero length packet\r
+#define SRR_IPRL          0x20    ///<  Internal PHY reset control\r
+#define SRR_IPPD          0x40    ///<  Internal PHY power down\r
+\r
+//\r
+//  PHY ID values\r
+//\r
+\r
+#define PHY_ID_INTERNAL   0x0010  ///<  Internal PHY\r
+\r
+//\r
+//  USB Commands\r
+//\r
+\r
+#define CMD_PHY_ACCESS_SOFTWARE   0x06  ///<  Software in control of PHY\r
+#define CMD_PHY_REG_READ          0x07  ///<  Read PHY register, Value: PHY, Index: Register, Data: Register value\r
+#define CMD_PHY_REG_WRITE         0x08  ///<  Write PHY register, Value: PHY, Index: Register, Data: New 16-bit value\r
+#define CMD_PHY_ACCESS_HARDWARE   0x0a  ///<  Hardware in control of PHY\r
+#define CMD_SROM_READ             0x0b  ///<  Read SROM register: Value: Address, Data: Value\r
+#define CMD_RX_CONTROL_WRITE      0x10  ///<  Set the RX control register, Value: New value\r
+#define CMD_GAPS_WRITE            0x12  ///<  Write the gaps register, Value: New value\r
+#define CMD_MAC_ADDRESS_READ      0x13  ///<  Read the MAC address, Data: 6 byte MAC address\r
+#define CMD_MAC_ADDRESS_WRITE     0x14  ///<  Set the MAC address, Data: New 6 byte MAC address\r
+#define CMD_MULTICAST_HASH_WRITE  0x16  ///<  Write the multicast hash table, Data: New 8 byte value\r
+#define CMD_MEDIUM_STATUS_READ    0x1a  ///<  Read medium status register, Data: Register value\r
+#define CMD_MEDIUM_STATUS_WRITE   0x1b  ///<  Write medium status register, Value: New value\r
+#define CMD_RESET                 0x20  ///<  Reset register, Value: New value\r
+#define CMD_PHY_SELECT            0x22  ///<  PHY select register, Value: New value\r
+\r
+//------------------------------\r
+//  USB Endpoints\r
+//------------------------------\r
+\r
+#define CONTROL_ENDPOINT                0       ///<  Control endpoint\r
+#define INTERRUPT_ENDPOINT              1       ///<  Interrupt endpoint\r
+#define BULK_IN_ENDPOINT                2       ///<  Receive endpoint\r
+#define BULK_OUT_ENDPOINT               3       ///<  Transmit endpoint\r
+\r
+//------------------------------\r
+//  PHY Registers\r
+//------------------------------\r
+\r
+#define PHY_BMCR                        0       ///<  Control register\r
+#define PHY_BMSR                        1       ///<  Status register\r
+#define PHY_ANAR                        4       ///<  Autonegotiation advertisement register\r
+#define PHY_ANLPAR                      5       ///<  Autonegotiation link parter ability register\r
+#define PHY_ANER                        6       ///<  Autonegotiation expansion register\r
+\r
+//  BMCR - Register 0\r
+\r
+#define BMCR_RESET                      0x8000  ///<  1 = Reset the PHY, bit clears after reset\r
+#define BMCR_LOOPBACK                   0x4000  ///<  1 = Loopback enabled\r
+#define BMCR_100MBPS                    0x2000  ///<  100 Mbits/Sec\r
+#define BMCR_10MBPS                     0       ///<  10 Mbits/Sec\r
+#define BMCR_AUTONEGOTIATION_ENABLE     0x1000  ///<  1 = Enable autonegotiation\r
+#define BMCR_POWER_DOWN                 0x0800  ///<  1 = Power down\r
+#define BMCR_ISOLATE                    0x0400  ///<  0 = Isolate PHY\r
+#define BMCR_RESTART_AUTONEGOTIATION    0x0200  ///<  1 = Restart autonegotiation\r
+#define BMCR_FULL_DUPLEX                0x0100  ///<  Full duplex operation\r
+#define BMCR_HALF_DUPLEX                0       ///<  Half duplex operation\r
+#define BMCR_COLLISION_TEST             0x0080  ///<  1 = Collision test enabled\r
+\r
+//  BSMR - Register 1\r
+\r
+#define BMSR_100BASET4                  0x8000  ///<  1 = 100BASE-T4 mode\r
+#define BMSR_100BASETX_FDX              0x4000  ///<  1 = 100BASE-TX full duplex\r
+#define BMSR_100BASETX_HDX              0x2000  ///<  1 = 100BASE-TX half duplex\r
+#define BMSR_10BASET_FDX                0x1000  ///<  1 = 10BASE-T full duplex\r
+#define BMSR_10BASET_HDX                0x0800  ///<  1 = 10BASE-T half duplex\r
+#define BMSR_MF                         0x0040  ///<  1 = PHY accepts frames with preamble suppressed\r
+#define BMSR_AUTONEG_CMPLT              0x0020  ///<  1 = Autonegotiation complete\r
+#define BMSR_RF                         0x0010  ///<  1 = Remote fault\r
+#define BMSR_AUTONEG                    0x0008  ///<  1 = Able to perform autonegotiation\r
+#define BMSR_LINKST                     0x0004  ///<  1 = Link up\r
+#define BMSR_JABBER_DETECT              0x0002  ///<  1 = jabber condition detected\r
+#define BMSR_EXTENDED_CAPABILITY        0x0001  ///<  1 = Extended register capable\r
+\r
+//  ANAR and ANLPAR Registers 4, 5\r
+\r
+#define AN_NP                           0x8000  ///<  1 = Next page available\r
+#define AN_ACK                          0x4000  ///<  1 = Link partner acknowledged\r
+#define AN_RF                           0x2000  ///<  1 = Remote fault indicated by link partner\r
+#define AN_FCS                          0x0400  ///<  1 = Flow control ability\r
+#define AN_T4                           0x0200  ///<  1 = 100BASE-T4 support\r
+#define AN_TX_FDX                       0x0100  ///<  1 = 100BASE-TX Full duplex\r
+#define AN_TX_HDX                       0x0080  ///<  1 = 100BASE-TX support\r
+#define AN_10_FDX                       0x0040  ///<  1 = 10BASE-T Full duplex\r
+#define AN_10_HDX                       0x0020  ///<  1 = 10BASE-T support\r
+#define AN_CSMA_CD                      0x0001  ///<  1 = IEEE 802.3 CSMA/CD support\r
+\r
+//------------------------------------------------------------------------------\r
+//  Data Types\r
+//------------------------------------------------------------------------------\r
+\r
+/**\r
+  Ethernet header layout\r
+\r
+  IEEE 802.3-2002 Part 3 specification, section 3.1.1.\r
+**/\r
+#pragma pack(1)\r
+typedef struct {\r
+  UINT8 dest_addr[PXE_HWADDR_LEN_ETHER];  ///<  Destination LAN address\r
+  UINT8 src_addr[PXE_HWADDR_LEN_ETHER];   ///<  Source LAN address\r
+  UINT16 type;                            ///<  Protocol or length\r
+} ETHERNET_HEADER;\r
+#pragma pack()\r
+\r
+/**\r
+  Receive and Transmit packet structure\r
+**/\r
+#pragma pack(1)\r
+typedef struct _RX_TX_PACKET {\r
+  struct _RX_TX_PACKET * pNext;       ///<  Next receive packet\r
+  UINT16 Length;                      ///<  Packet length\r
+  UINT16 LengthBar;                   ///<  Complement of the length\r
+  UINT8 Data[ AX88772_MAX_PKT_SIZE ]; ///<  Received packet data\r
+} RX_TX_PACKET;\r
+#pragma pack()\r
+\r
+/**\r
+  AX88772 control structure\r
+\r
+  The driver uses this structure to manage the Asix AX88772 10/100\r
+  Ethernet controller.\r
+**/\r
+typedef struct {\r
+  UINTN Signature;          ///<  Structure identification\r
+\r
+  //\r
+  //  USB data\r
+  //\r
+  EFI_HANDLE Controller;        ///<  Controller handle\r
+  EFI_USB_IO_PROTOCOL * pUsbIo; ///<  USB driver interface\r
+\r
+  //\r
+  //  Simple network protocol data\r
+  //\r
+  EFI_SIMPLE_NETWORK_PROTOCOL SimpleNetwork;  ///<  Driver's network stack interface\r
+  EFI_SIMPLE_NETWORK_MODE SimpleNetworkData;  ///<  Data for simple network\r
+\r
+  //\r
+  // Ethernet controller data\r
+  //\r
+  BOOLEAN bInitialized;     ///<  Controller initialized\r
+  VOID * pTxBuffer;         ///<  Last transmit buffer\r
+  UINT16 PhyId;             ///<  PHY ID\r
+\r
+  //\r
+  //  Link state\r
+  //\r
+  BOOLEAN b100Mbps;         ///<  Current link speed, FALSE = 10 Mbps\r
+  BOOLEAN bComplete;        ///<  Current state of auto-negotiation\r
+  BOOLEAN bFullDuplex;      ///<  Current duplex\r
+  BOOLEAN bLinkUp;          ///<  Current link state\r
+  BOOLEAN bLinkIdle;        ///<  TRUE = No received traffic\r
+  EFI_EVENT Timer;          ///<  Timer to monitor link state and receive packets\r
+  UINTN PollCount;          ///<  Number of times the autonegotiation status was polled\r
+\r
+  //\r
+  //  Receive buffer list\r
+  //\r
+  RX_TX_PACKET * pRxHead;   ///<  Head of receive packet list\r
+  RX_TX_PACKET * pRxTail;   ///<  Tail of receive packet list\r
+  RX_TX_PACKET * pRxFree;   ///<  Free packet list\r
+  INT32 MulticastHash[2];   ///<  Hash table for multicast destination addresses\r
+} NIC_DEVICE;\r
+\r
+#define DEV_FROM_SIMPLE_NETWORK(a)  CR (a, NIC_DEVICE, SimpleNetwork, DEV_SIGNATURE)  ///< Locate NIC_DEVICE from Simple Network Protocol\r
+\r
+//------------------------------------------------------------------------------\r
+// Simple Network Protocol\r
+//------------------------------------------------------------------------------\r
+\r
+/**\r
+  Reset the network adapter.\r
+\r
+  Resets a network adapter and reinitializes it with the parameters that\r
+  were provided in the previous call to Initialize ().  The transmit and\r
+  receive queues are cleared.  Receive filters, the station address, the\r
+  statistics, and the multicast-IP-to-HW MAC addresses are not reset by\r
+  this call.\r
+\r
+  This routine calls ::Ax88772Reset to perform the adapter specific\r
+  reset operation.  This routine also starts the link negotiation\r
+  by calling ::Ax88772NegotiateLinkStart.\r
+\r
+  @param [in] pSimpleNetwork    Protocol instance pointer\r
+  @param [in] bExtendedVerification  Indicates that the driver may perform a more\r
+                                exhaustive verification operation of the device\r
+                                during reset.\r
+\r
+  @retval EFI_SUCCESS           This operation was successful.\r
+  @retval EFI_NOT_STARTED       The network interface was not started.\r
+  @retval EFI_INVALID_PARAMETER pSimpleNetwork parameter was NULL or did not point to a valid\r
+                                EFI_SIMPLE_NETWORK_PROTOCOL structure.\r
+  @retval EFI_DEVICE_ERROR      The command could not be sent to the network interface.\r
+  @retval EFI_UNSUPPORTED       The increased buffer size feature is not supported.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SN_Reset (\r
+  IN EFI_SIMPLE_NETWORK_PROTOCOL * pSimpleNetwork,\r
+  IN BOOLEAN bExtendedVerification\r
+  );\r
+\r
+/**\r
+  Initialize the simple network protocol.\r
+\r
+  This routine calls ::Ax88772MacAddressGet to obtain the\r
+  MAC address.\r
+\r
+  @param [in] pNicDevice       NIC_DEVICE_INSTANCE pointer\r
+\r
+  @retval EFI_SUCCESS     Setup was successful\r
+\r
+**/\r
+EFI_STATUS\r
+SN_Setup (\r
+  IN NIC_DEVICE * pNicDevice\r
+  );\r
+\r
+/**\r
+  This routine starts the network interface.\r
+\r
+  @param [in] pSimpleNetwork    Protocol instance pointer\r
+\r
+  @retval EFI_SUCCESS           This operation was successful.\r
+  @retval EFI_ALREADY_STARTED   The network interface was already started.\r
+  @retval EFI_INVALID_PARAMETER pSimpleNetwork parameter was NULL or did not point to a valid\r
+                                EFI_SIMPLE_NETWORK_PROTOCOL structure.\r
+  @retval EFI_DEVICE_ERROR      The command could not be sent to the network interface.\r
+  @retval EFI_UNSUPPORTED       The increased buffer size feature is not supported.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SN_Start (\r
+  IN EFI_SIMPLE_NETWORK_PROTOCOL * pSimpleNetwork\r
+  );\r
+\r
+/**\r
+  Set the MAC address.\r
+  \r
+  This function modifies or resets the current station address of a\r
+  network interface.  If Reset is TRUE, then the current station address\r
+  is set ot the network interface's permanent address.  If Reset if FALSE\r
+  then the current station address is changed to the address specified by\r
+  pNew.\r
+\r
+  This routine calls ::Ax88772MacAddressSet to update the MAC address\r
+  in the network adapter.\r
+\r
+  @param [in] pSimpleNetwork    Protocol instance pointer\r
+  @param [in] bReset            Flag used to reset the station address to the\r
+                                network interface's permanent address.\r
+  @param [in] pNew              New station address to be used for the network\r
+                                interface.\r
+\r
+  @retval EFI_SUCCESS           This operation was successful.\r
+  @retval EFI_NOT_STARTED       The network interface was not started.\r
+  @retval EFI_INVALID_PARAMETER pSimpleNetwork parameter was NULL or did not point to a valid\r
+                                EFI_SIMPLE_NETWORK_PROTOCOL structure.\r
+  @retval EFI_DEVICE_ERROR      The command could not be sent to the network interface.\r
+  @retval EFI_UNSUPPORTED       The increased buffer size feature is not supported.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SN_StationAddress (\r
+  IN EFI_SIMPLE_NETWORK_PROTOCOL * pSimpleNetwork,\r
+  IN BOOLEAN bReset,\r
+  IN EFI_MAC_ADDRESS * pNew\r
+  );\r
+\r
+/**\r
+  This function resets or collects the statistics on a network interface.\r
+  If the size of the statistics table specified by StatisticsSize is not\r
+  big enough for all of the statistics that are collected by the network\r
+  interface, then a partial buffer of statistics is returned in\r
+  StatisticsTable.\r
+\r
+  @param [in] pSimpleNetwork    Protocol instance pointer\r
+  @param [in] bReset            Set to TRUE to reset the statistics for the network interface.\r
+  @param [in, out] pStatisticsSize  On input the size, in bytes, of StatisticsTable.  On output\r
+                                the size, in bytes, of the resulting table of statistics.\r
+  @param [out] pStatisticsTable A pointer to the EFI_NETWORK_STATISTICS structure that\r
+                                conains the statistics.\r
+\r
+  @retval EFI_SUCCESS           This operation was successful.\r
+  @retval EFI_NOT_STARTED       The network interface was not started.\r
+  @retval EFI_BUFFER_TOO_SMALL  The pStatisticsTable is NULL or the buffer is too small.\r
+  @retval EFI_INVALID_PARAMETER pSimpleNetwork parameter was NULL or did not point to a valid\r
+                                EFI_SIMPLE_NETWORK_PROTOCOL structure.\r
+  @retval EFI_DEVICE_ERROR      The command could not be sent to the network interface.\r
+  @retval EFI_UNSUPPORTED       The increased buffer size feature is not supported.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SN_Statistics (\r
+  IN EFI_SIMPLE_NETWORK_PROTOCOL * pSimpleNetwork,\r
+  IN BOOLEAN bReset,\r
+  IN OUT UINTN * pStatisticsSize,\r
+  OUT EFI_NETWORK_STATISTICS * pStatisticsTable\r
+  );\r
+\r
+/**\r
+  This function stops a network interface.  This call is only valid\r
+  if the network interface is in the started state.\r
+\r
+  @param [in] pSimpleNetwork    Protocol instance pointer\r
+\r
+  @retval EFI_SUCCESS           This operation was successful.\r
+  @retval EFI_NOT_STARTED       The network interface was not started.\r
+  @retval EFI_INVALID_PARAMETER pSimpleNetwork parameter was NULL or did not point to a valid\r
+                                EFI_SIMPLE_NETWORK_PROTOCOL structure.\r
+  @retval EFI_DEVICE_ERROR      The command could not be sent to the network interface.\r
+  @retval EFI_UNSUPPORTED       The increased buffer size feature is not supported.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SN_Stop (\r
+  IN EFI_SIMPLE_NETWORK_PROTOCOL * pSimpleNetwork\r
+  );\r
+\r
+/**\r
+  This function releases the memory buffers assigned in the Initialize() call.\r
+  Pending transmits and receives are lost, and interrupts are cleared and disabled.\r
+  After this call, only Initialize() and Stop() calls may be used.\r
+\r
+  @param [in] pSimpleNetwork    Protocol instance pointer\r
+\r
+  @retval EFI_SUCCESS           This operation was successful.\r
+  @retval EFI_NOT_STARTED       The network interface was not started.\r
+  @retval EFI_INVALID_PARAMETER pSimpleNetwork parameter was NULL or did not point to a valid\r
+                                EFI_SIMPLE_NETWORK_PROTOCOL structure.\r
+  @retval EFI_DEVICE_ERROR      The command could not be sent to the network interface.\r
+  @retval EFI_UNSUPPORTED       The increased buffer size feature is not supported.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SN_Shutdown (\r
+  IN EFI_SIMPLE_NETWORK_PROTOCOL * pSimpleNetwork\r
+  );\r
+\r
+/**\r
+  Send a packet over the network.\r
+\r
+  This function places the packet specified by Header and Buffer on\r
+  the transmit queue.  This function performs a non-blocking transmit\r
+  operation.  When the transmit is complete, the buffer is returned\r
+  via the GetStatus() call.\r
+\r
+  This routine calls ::Ax88772Rx to empty the network adapter of\r
+  receive packets.  The routine then passes the transmit packet\r
+  to the network adapter.\r
+\r
+  @param [in] pSimpleNetwork    Protocol instance pointer\r
+  @param [in] HeaderSize        The size, in bytes, of the media header to be filled in by\r
+                                the Transmit() function.  If HeaderSize is non-zero, then\r
+                                it must be equal to SimpleNetwork->Mode->MediaHeaderSize\r
+                                and DestAddr and Protocol parameters must not be NULL.\r
+  @param [in] BufferSize        The size, in bytes, of the entire packet (media header and\r
+                                data) to be transmitted through the network interface.\r
+  @param [in] pBuffer           A pointer to the packet (media header followed by data) to\r
+                                to be transmitted.  This parameter can not be NULL.  If\r
+                                HeaderSize is zero, then the media header is Buffer must\r
+                                already be filled in by the caller.  If HeaderSize is nonzero,\r
+                                then the media header will be filled in by the Transmit()\r
+                                function.\r
+  @param [in] pSrcAddr          The source HW MAC address.  If HeaderSize is zero, then\r
+                                this parameter is ignored.  If HeaderSize is nonzero and\r
+                                SrcAddr is NULL, then SimpleNetwork->Mode->CurrentAddress\r
+                                is used for the source HW MAC address.\r
+  @param [in] pDestAddr         The destination HW MAC address.  If HeaderSize is zero, then\r
+                                this parameter is ignored.\r
+  @param [in] pProtocol         The type of header to build.  If HeaderSize is zero, then\r
+                                this parameter is ignored.\r
+\r
+  @retval EFI_SUCCESS           This operation was successful.\r
+  @retval EFI_NOT_STARTED       The network interface was not started.\r
+  @retval EFI_NOT_READY         The network interface is too busy to accept this transmit request.\r
+  @retval EFI_BUFFER_TOO_SMALL  The BufferSize parameter is too small.\r
+  @retval EFI_INVALID_PARAMETER pSimpleNetwork parameter was NULL or did not point to a valid\r
+                                EFI_SIMPLE_NETWORK_PROTOCOL structure.\r
+  @retval EFI_DEVICE_ERROR      The command could not be sent to the network interface.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SN_Transmit (\r
+  IN EFI_SIMPLE_NETWORK_PROTOCOL * pSimpleNetwork,\r
+  IN UINTN HeaderSize,\r
+  IN UINTN BufferSize,\r
+  IN VOID * pBuffer,\r
+  IN EFI_MAC_ADDRESS * pSrcAddr,\r
+  IN EFI_MAC_ADDRESS * pDestAddr,\r
+  IN UINT16 * pProtocol\r
+  );\r
+\r
+//------------------------------------------------------------------------------\r
+// Support Routines\r
+//------------------------------------------------------------------------------\r
+\r
+/**\r
+  Get the MAC address\r
+\r
+  This routine calls ::Ax88772UsbCommand to request the MAC\r
+  address from the network adapter.\r
+\r
+  @param [in] pNicDevice       Pointer to the NIC_DEVICE structure\r
+  @param [out] pMacAddress      Address of a six byte buffer to receive the MAC address.\r
+\r
+  @retval EFI_SUCCESS          The MAC address is available.\r
+  @retval other                The MAC address is not valid.\r
+\r
+**/\r
+EFI_STATUS\r
+Ax88772MacAddressGet (\r
+  IN NIC_DEVICE * pNicDevice,\r
+  OUT UINT8 * pMacAddress\r
+  );\r
+\r
+/**\r
+  Set the MAC address\r
+\r
+  This routine calls ::Ax88772UsbCommand to set the MAC address\r
+  in the network adapter.\r
+\r
+  @param [in] pNicDevice       Pointer to the NIC_DEVICE structure\r
+  @param [in] pMacAddress      Address of a six byte buffer to containing the new MAC address.\r
+\r
+  @retval EFI_SUCCESS          The MAC address was set.\r
+  @retval other                The MAC address was not set.\r
+\r
+**/\r
+EFI_STATUS\r
+Ax88772MacAddressSet (\r
+  IN NIC_DEVICE * pNicDevice,\r
+  IN UINT8 * pMacAddress\r
+  );\r
+\r
+/**\r
+  Clear the multicast hash table\r
+\r
+  @param [in] pNicDevice       Pointer to the NIC_DEVICE structure\r
+\r
+**/\r
+VOID\r
+Ax88772MulticastClear (\r
+  IN NIC_DEVICE * pNicDevice\r
+  );\r
+\r
+/**\r
+  Enable a multicast address in the multicast hash table\r
+\r
+  This routine calls ::Ax88772Crc to compute the hash bit for\r
+  this MAC address.\r
+\r
+  @param [in] pNicDevice       Pointer to the NIC_DEVICE structure\r
+  @param [in] pMacAddress      Address of a six byte buffer to containing the MAC address.\r
+\r
+**/\r
+VOID\r
+Ax88772MulticastSet (\r
+  IN NIC_DEVICE * pNicDevice,\r
+  IN UINT8 * pMacAddress\r
+  );\r
+\r
+/**\r
+  Start the link negotiation\r
+\r
+  This routine calls ::Ax88772PhyWrite to start the PHY's link\r
+  negotiation.\r
+\r
+  @param [in] pNicDevice       Pointer to the NIC_DEVICE structure\r
+\r
+  @retval EFI_SUCCESS          The link negotiation was started.\r
+  @retval other                Failed to start the link negotiation.\r
+\r
+**/\r
+EFI_STATUS\r
+Ax88772NegotiateLinkStart (\r
+  IN NIC_DEVICE * pNicDevice\r
+  );\r
+\r
+/**\r
+  Complete the negotiation of the PHY link\r
+\r
+  This routine calls ::Ax88772PhyRead to determine if the\r
+  link negotiation is complete.\r
+\r
+  @param [in] pNicDevice       Pointer to the NIC_DEVICE structure\r
+  @param [in, out] pPollCount  Address of number of times this routine was polled\r
+  @param [out] pbComplete      Address of boolean to receive complate status.\r
+  @param [out] pbLinkUp        Address of boolean to receive link status, TRUE=up.\r
+  @param [out] pbHiSpeed       Address of boolean to receive link speed, TRUE=100Mbps.\r
+  @param [out] pbFullDuplex    Address of boolean to receive link duplex, TRUE=full.\r
+\r
+  @retval EFI_SUCCESS          The MAC address is available.\r
+  @retval other                The MAC address is not valid.\r
+\r
+**/\r
+EFI_STATUS\r
+Ax88772NegotiateLinkComplete (\r
+  IN NIC_DEVICE * pNicDevice,\r
+  IN OUT UINTN * pPollCount,\r
+  OUT BOOLEAN * pbComplete,\r
+  OUT BOOLEAN * pbLinkUp,\r
+  OUT BOOLEAN * pbHiSpeed,\r
+  OUT BOOLEAN * pbFullDuplex\r
+  );\r
+\r
+/**\r
+  Read a register from the PHY\r
+\r
+  This routine calls ::Ax88772UsbCommand to read a PHY register.\r
+\r
+  @param [in] pNicDevice       Pointer to the NIC_DEVICE structure\r
+  @param [in] RegisterAddress  Number of the register to read.\r
+  @param [in, out] pPhyData    Address of a buffer to receive the PHY register value\r
+\r
+  @retval EFI_SUCCESS          The PHY data is available.\r
+  @retval other                The PHY data is not valid.\r
+\r
+**/\r
+EFI_STATUS\r
+Ax88772PhyRead (\r
+  IN NIC_DEVICE * pNicDevice,\r
+  IN UINT8 RegisterAddress,\r
+  IN OUT UINT16 * pPhyData\r
+  );\r
+\r
+/**\r
+  Write to a PHY register\r
+\r
+  This routine calls ::Ax88772UsbCommand to write a PHY register.\r
+\r
+  @param [in] pNicDevice       Pointer to the NIC_DEVICE structure\r
+  @param [in] RegisterAddress  Number of the register to read.\r
+  @param [in] PhyData          Address of a buffer to receive the PHY register value\r
+\r
+  @retval EFI_SUCCESS          The PHY data was written.\r
+  @retval other                Failed to wwrite the PHY register.\r
+\r
+**/\r
+EFI_STATUS\r
+Ax88772PhyWrite (\r
+  IN NIC_DEVICE * pNicDevice,\r
+  IN UINT8 RegisterAddress,\r
+  IN UINT16 PhyData\r
+  );\r
+\r
+/**\r
+  Reset the AX88772\r
+\r
+  This routine uses ::Ax88772UsbCommand to reset the network\r
+  adapter.  This routine also uses ::Ax88772PhyWrite to reset\r
+  the PHY.\r
+\r
+  @param [in] pNicDevice       Pointer to the NIC_DEVICE structure\r
+\r
+  @retval EFI_SUCCESS          The MAC address is available.\r
+  @retval other                The MAC address is not valid.\r
+\r
+**/\r
+EFI_STATUS\r
+Ax88772Reset (\r
+  IN NIC_DEVICE * pNicDevice\r
+  );\r
+\r
+/**\r
+  Receive a frame from the network.\r
+\r
+  This routine polls the USB receive interface for a packet.  If a packet\r
+  is available, this routine adds the receive packet to the list of\r
+  pending receive packets.\r
+\r
+  This routine calls ::Ax88772NegotiateLinkComplete to verify\r
+  that the link is up.  This routine also calls ::SN_Reset to\r
+  reset the network adapter when necessary.  Finally this\r
+  routine attempts to receive one or more packets from the\r
+  network adapter.\r
+\r
+  @param [in] pNicDevice  Pointer to the NIC_DEVICE structure\r
+  @param [in] bUpdateLink TRUE = Update link status\r
+\r
+**/\r
+VOID\r
+Ax88772Rx (\r
+  IN NIC_DEVICE * pNicDevice,\r
+  IN BOOLEAN bUpdateLink\r
+  );\r
+\r
+/**\r
+  Enable or disable the receiver\r
+\r
+  This routine calls ::Ax88772UsbCommand to update the\r
+  receiver state.  This routine also calls ::Ax88772MacAddressSet\r
+  to establish the MAC address for the network adapter.\r
+\r
+  @param [in] pNicDevice       Pointer to the NIC_DEVICE structure\r
+  @param [in] RxFilter         Simple network RX filter mask value\r
+\r
+  @retval EFI_SUCCESS          The MAC address was set.\r
+  @retval other                The MAC address was not set.\r
+\r
+**/\r
+EFI_STATUS\r
+Ax88772RxControl (\r
+  IN NIC_DEVICE * pNicDevice,\r
+  IN UINT32 RxFilter\r
+  );\r
+\r
+/**\r
+  Read an SROM location\r
+\r
+  This routine calls ::Ax88772UsbCommand to read data from the\r
+  SROM.\r
+\r
+  @param [in] pNicDevice       Pointer to the NIC_DEVICE structure\r
+  @param [in] Address          SROM address\r
+  @param [out] pData           Buffer to receive the data\r
+\r
+  @retval EFI_SUCCESS          The read was successful\r
+  @retval other                The read failed\r
+\r
+**/\r
+EFI_STATUS\r
+Ax88772SromRead (\r
+  IN NIC_DEVICE * pNicDevice,\r
+  IN UINT32 Address,\r
+  OUT UINT16 * pData\r
+  );\r
+\r
+/**\r
+  This routine is called at a regular interval to poll for\r
+  receive packets.\r
+\r
+  This routine polls the link state and gets any receive packets\r
+  by calling ::Ax88772Rx.\r
+\r
+  @param [in] Event            Timer event\r
+  @param [in] pNicDevice       Pointer to the NIC_DEVICE structure\r
+\r
+**/\r
+VOID\r
+Ax88772Timer (\r
+  IN EFI_EVENT Event,\r
+  IN NIC_DEVICE * pNicDevice\r
+  );\r
+\r
+/**\r
+  Send a command to the USB device.\r
+\r
+  @param [in] pNicDevice       Pointer to the NIC_DEVICE structure\r
+  @param [in] pRequest         Pointer to the request structure\r
+  @param [in, out] pBuffer     Data buffer address\r
+\r
+  @retval EFI_SUCCESS          The USB transfer was successful\r
+  @retval other                The USB transfer failed\r
+\r
+**/\r
+EFI_STATUS\r
+Ax88772UsbCommand (\r
+  IN NIC_DEVICE * pNicDevice,\r
+  IN USB_DEVICE_REQUEST * pRequest,\r
+  IN OUT VOID * pBuffer\r
+  );\r
+\r
+//------------------------------------------------------------------------------\r
+// EFI Component Name Protocol Support\r
+//------------------------------------------------------------------------------\r
+\r
+extern EFI_COMPONENT_NAME_PROTOCOL   gComponentName;  ///<  Component name protocol declaration\r
+extern EFI_COMPONENT_NAME2_PROTOCOL  gComponentName2; ///<  Component name 2 protocol declaration\r
+\r
+/**\r
+  Retrieves a Unicode string that is the user readable name of the driver.\r
+\r
+  This function retrieves the user readable name of a driver in the form of a\r
+  Unicode string. If the driver specified by This has a user readable name in\r
+  the language specified by Language, then a pointer to the driver name is\r
+  returned in DriverName, and EFI_SUCCESS is returned. If the driver specified\r
+  by This does not support the language specified by Language,\r
+  then EFI_UNSUPPORTED is returned.\r
+\r
+  @param [in] pThis             A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or\r
+                                EFI_COMPONENT_NAME_PROTOCOL instance.\r
+  @param [in] pLanguage         A pointer to a Null-terminated ASCII string\r
+                                array indicating the language. This is the\r
+                                language of the driver name that the caller is\r
+                                requesting, and it must match one of the\r
+                                languages specified in SupportedLanguages. The\r
+                                number of languages supported by a driver is up\r
+                                to the driver writer. Language is specified\r
+                                in RFC 3066 or ISO 639-2 language code format.\r
+  @param [out] ppDriverName     A pointer to the Unicode string to return.\r
+                                This Unicode string is the name of the\r
+                                driver specified by This in the language\r
+                                specified by Language.\r
+\r
+  @retval EFI_SUCCESS           The Unicode string for the Driver specified by\r
+                                This and the language specified by Language was\r
+                                returned in DriverName.\r
+  @retval EFI_INVALID_PARAMETER Language is NULL.\r
+  @retval EFI_INVALID_PARAMETER DriverName is NULL.\r
+  @retval EFI_UNSUPPORTED       The driver specified by This does not support\r
+                                the language specified by Language.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+GetDriverName (\r
+  IN  EFI_COMPONENT_NAME_PROTOCOL * pThis,\r
+  IN  CHAR8 * pLanguage,\r
+  OUT CHAR16 ** ppDriverName\r
+  );\r
+\r
+\r
+/**\r
+  Retrieves a Unicode string that is the user readable name of the controller\r
+  that is being managed by a driver.\r
+\r
+  This function retrieves the user readable name of the controller specified by\r
+  ControllerHandle and ChildHandle in the form of a Unicode string. If the\r
+  driver specified by This has a user readable name in the language specified by\r
+  Language, then a pointer to the controller name is returned in ControllerName,\r
+  and EFI_SUCCESS is returned.  If the driver specified by This is not currently\r
+  managing the controller specified by ControllerHandle and ChildHandle,\r
+  then EFI_UNSUPPORTED is returned.  If the driver specified by This does not\r
+  support the language specified by Language, then EFI_UNSUPPORTED is returned.\r
+\r
+  @param [in] pThis             A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or\r
+                                EFI_COMPONENT_NAME_PROTOCOL instance.\r
+  @param [in] ControllerHandle  The handle of a controller that the driver\r
+                                specified by This is managing.  This handle\r
+                                specifies the controller whose name is to be\r
+                                returned.\r
+  @param [in] ChildHandle       The handle of the child controller to retrieve\r
+                                the name of.  This is an optional parameter that\r
+                                may be NULL.  It will be NULL for device\r
+                                drivers.  It will also be NULL for a bus drivers\r
+                                that wish to retrieve the name of the bus\r
+                                controller.  It will not be NULL for a bus\r
+                                driver that wishes to retrieve the name of a\r
+                                child controller.\r
+  @param [in] pLanguage         A pointer to a Null-terminated ASCII string\r
+                                array indicating the language.  This is the\r
+                                language of the driver name that the caller is\r
+                                requesting, and it must match one of the\r
+                                languages specified in SupportedLanguages. The\r
+                                number of languages supported by a driver is up\r
+                                to the driver writer. Language is specified in\r
+                                RFC 3066 or ISO 639-2 language code format.\r
+  @param [out] ppControllerName A pointer to the Unicode string to return.\r
+                                This Unicode string is the name of the\r
+                                controller specified by ControllerHandle and\r
+                                ChildHandle in the language specified by\r
+                                Language from the point of view of the driver\r
+                                specified by This.\r
+\r
+  @retval EFI_SUCCESS           The Unicode string for the user readable name in\r
+                                the language specified by Language for the\r
+                                driver specified by This was returned in\r
+                                DriverName.\r
+  @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE.\r
+  @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid\r
+                                EFI_HANDLE.\r
+  @retval EFI_INVALID_PARAMETER Language is NULL.\r
+  @retval EFI_INVALID_PARAMETER ControllerName is NULL.\r
+  @retval EFI_UNSUPPORTED       The driver specified by This is not currently\r
+                                managing the controller specified by\r
+                                ControllerHandle and ChildHandle.\r
+  @retval EFI_UNSUPPORTED       The driver specified by This does not support\r
+                                the language specified by Language.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+GetControllerName (\r
+  IN  EFI_COMPONENT_NAME_PROTOCOL * pThis,\r
+  IN  EFI_HANDLE ControllerHandle,\r
+  IN OPTIONAL EFI_HANDLE ChildHandle,\r
+  IN  CHAR8 * pLanguage,\r
+  OUT CHAR16 ** ppControllerName\r
+  );\r
+\r
+//------------------------------------------------------------------------------\r
+\r
+#endif  //  _AX88772_H_\r
diff --git a/OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772/Ax88772.inf b/OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772/Ax88772.inf
new file mode 100644 (file)
index 0000000..3e99dde
--- /dev/null
@@ -0,0 +1,72 @@
+#/** @file\r
+# Component description file for ASIX AX88772 USB/Ethernet driver.\r
+#\r
+# This module provides support for the ASIX AX88772 USB/Ethernet adapter.\r
+# Copyright (c) 2011, Intel Corporation\r
+#\r
+#  All rights reserved. This program and the accompanying materials\r
+#  are licensed and made available under the terms and conditions of the BSD License\r
+#  which accompanies this distribution. The full text of the license may be found at\r
+#  http://opensource.org/licenses/bsd-license.php\r
+#\r
+#  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+#  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+#**/\r
+\r
+[Defines]\r
+  INF_VERSION                    = 0x00010005\r
+  BASE_NAME                      = Ax88772\r
+  FILE_GUID                      = B15239D6-6A01-4808-A0F7-B7F20F073555\r
+  MODULE_TYPE                    = DXE_RUNTIME_DRIVER\r
+  VERSION_STRING                 = 1.0\r
+\r
+  ENTRY_POINT                    = EntryPoint\r
+\r
+#\r
+#  VALID_ARCHITECTURES           = IA32 X64 IPF EBC\r
+#\r
+\r
+[Sources.common]\r
+  Ax88772.h\r
+  Ax88772.c\r
+  ComponentName.c\r
+  DriverBinding.c\r
+  SimpleNetwork.c\r
+\r
+\r
+[Packages]\r
+  MdePkg/MdePkg.dec\r
+  MdeModulePkg/MdeModulePkg.dec\r
+\r
+[LibraryClasses]\r
+  UefiLib\r
+  UefiBootServicesTableLib\r
+  BaseMemoryLib\r
+  DebugLib\r
+  UefiRuntimeLib\r
+  UefiDriverEntryPoint\r
+\r
+[Protocols]\r
+  gEfiDevicePathProtocolGuid\r
+  gEfiSimpleNetworkProtocolGuid\r
+  gEfiUsbIoProtocolGuid                ## TO_START\r
+\r
+[Guids]\r
+  gEfiEventExitBootServicesGuid        ## PRODUCES ## Event\r
+  gEfiEventVirtualAddressChangeGuid    ## PRODUCES ## Event\r
+  gEfiNicIp4ConfigVariableGuid\r
+\r
+[Depex]\r
+  gEfiBdsArchProtocolGuid AND\r
+  gEfiCpuArchProtocolGuid AND\r
+  gEfiMetronomeArchProtocolGuid AND\r
+  gEfiMonotonicCounterArchProtocolGuid AND\r
+  gEfiRealTimeClockArchProtocolGuid AND\r
+  gEfiResetArchProtocolGuid AND\r
+  gEfiRuntimeArchProtocolGuid AND\r
+  gEfiSecurityArchProtocolGuid AND\r
+  gEfiTimerArchProtocolGuid AND\r
+  gEfiVariableWriteArchProtocolGuid AND\r
+  gEfiVariableArchProtocolGuid AND\r
+  gEfiWatchdogTimerArchProtocolGuid\r
diff --git a/OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772/ComponentName.c b/OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772/ComponentName.c
new file mode 100644 (file)
index 0000000..4d67f79
--- /dev/null
@@ -0,0 +1,184 @@
+/** @file\r
+  UEFI Component Name(2) protocol implementation.\r
+\r
+  Copyright (c) 2011, Intel Corporation\r
+  All rights reserved. This program and the accompanying materials\r
+  are licensed and made available under the terms and conditions of the BSD License\r
+  which accompanies this distribution.  The full text of the license may be found at\r
+  http://opensource.org/licenses/bsd-license.php\r
+\r
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "Ax88772.h"\r
+\r
+/**\r
+  EFI Component Name Protocol declaration\r
+**/\r
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL  gComponentName = {\r
+  GetDriverName,\r
+  GetControllerName,\r
+  "eng"\r
+};\r
+\r
+/**\r
+  EFI Component Name 2 Protocol declaration\r
+**/\r
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gComponentName2 = {\r
+  (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) GetDriverName,\r
+  (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) GetControllerName,\r
+  "en"\r
+};\r
+\r
+\r
+/**\r
+  Driver name table declaration\r
+**/\r
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE\r
+mDriverNameTable[] = {\r
+  {"eng;en", L"AX88772 Ethernet Driver"},\r
+  {NULL,  NULL}\r
+};\r
+\r
+/**\r
+  Retrieves a Unicode string that is the user readable name of the driver.\r
+\r
+  This function retrieves the user readable name of a driver in the form of a\r
+  Unicode string. If the driver specified by This has a user readable name in\r
+  the language specified by Language, then a pointer to the driver name is\r
+  returned in DriverName, and EFI_SUCCESS is returned. If the driver specified\r
+  by This does not support the language specified by Language,\r
+  then EFI_UNSUPPORTED is returned.\r
+\r
+  @param [in] pThis             A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or\r
+                                EFI_COMPONENT_NAME_PROTOCOL instance.\r
+  @param [in] pLanguage         A pointer to a Null-terminated ASCII string\r
+                                array indicating the language. This is the\r
+                                language of the driver name that the caller is\r
+                                requesting, and it must match one of the\r
+                                languages specified in SupportedLanguages. The\r
+                                number of languages supported by a driver is up\r
+                                to the driver writer. Language is specified\r
+                                in RFC 3066 or ISO 639-2 language code format.\r
+  @param [out] ppDriverName     A pointer to the Unicode string to return.\r
+                                This Unicode string is the name of the\r
+                                driver specified by This in the language\r
+                                specified by Language.\r
+\r
+  @retval EFI_SUCCESS           The Unicode string for the Driver specified by\r
+                                This and the language specified by Language was\r
+                                returned in DriverName.\r
+  @retval EFI_INVALID_PARAMETER Language is NULL.\r
+  @retval EFI_INVALID_PARAMETER DriverName is NULL.\r
+  @retval EFI_UNSUPPORTED       The driver specified by This does not support\r
+                                the language specified by Language.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+GetDriverName (\r
+  IN  EFI_COMPONENT_NAME_PROTOCOL * pThis,\r
+  IN  CHAR8 * pLanguage,\r
+  OUT CHAR16 ** ppDriverName\r
+  )\r
+{\r
+  EFI_STATUS Status;\r
+\r
+  DBG_ENTER ( );\r
+  Status = LookupUnicodeString2 (\r
+             pLanguage,\r
+             pThis->SupportedLanguages,\r
+             mDriverNameTable,\r
+             ppDriverName,\r
+             (BOOLEAN)(pThis == &gComponentName)\r
+             );\r
+  DBG_EXIT_HEX ( Status );\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Retrieves a Unicode string that is the user readable name of the controller\r
+  that is being managed by a driver.\r
+\r
+  This function retrieves the user readable name of the controller specified by\r
+  ControllerHandle and ChildHandle in the form of a Unicode string. If the\r
+  driver specified by This has a user readable name in the language specified by\r
+  Language, then a pointer to the controller name is returned in ControllerName,\r
+  and EFI_SUCCESS is returned.  If the driver specified by This is not currently\r
+  managing the controller specified by ControllerHandle and ChildHandle,\r
+  then EFI_UNSUPPORTED is returned.  If the driver specified by This does not\r
+  support the language specified by Language, then EFI_UNSUPPORTED is returned.\r
+\r
+  @param [in] pThis             A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or\r
+                                EFI_COMPONENT_NAME_PROTOCOL instance.\r
+  @param [in] ControllerHandle  The handle of a controller that the driver\r
+                                specified by This is managing.  This handle\r
+                                specifies the controller whose name is to be\r
+                                returned.\r
+  @param [in] ChildHandle       The handle of the child controller to retrieve\r
+                                the name of.  This is an optional parameter that\r
+                                may be NULL.  It will be NULL for device\r
+                                drivers.  It will also be NULL for a bus drivers\r
+                                that wish to retrieve the name of the bus\r
+                                controller.  It will not be NULL for a bus\r
+                                driver that wishes to retrieve the name of a\r
+                                child controller.\r
+  @param [in] pLanguage         A pointer to a Null-terminated ASCII string\r
+                                array indicating the language.  This is the\r
+                                language of the driver name that the caller is\r
+                                requesting, and it must match one of the\r
+                                languages specified in SupportedLanguages. The\r
+                                number of languages supported by a driver is up\r
+                                to the driver writer. Language is specified in\r
+                                RFC 3066 or ISO 639-2 language code format.\r
+  @param [out] ppControllerName A pointer to the Unicode string to return.\r
+                                This Unicode string is the name of the\r
+                                controller specified by ControllerHandle and\r
+                                ChildHandle in the language specified by\r
+                                Language from the point of view of the driver\r
+                                specified by This.\r
+\r
+  @retval EFI_SUCCESS           The Unicode string for the user readable name in\r
+                                the language specified by Language for the\r
+                                driver specified by This was returned in\r
+                                DriverName.\r
+  @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE.\r
+  @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid\r
+                                EFI_HANDLE.\r
+  @retval EFI_INVALID_PARAMETER Language is NULL.\r
+  @retval EFI_INVALID_PARAMETER ControllerName is NULL.\r
+  @retval EFI_UNSUPPORTED       The driver specified by This is not currently\r
+                                managing the controller specified by\r
+                                ControllerHandle and ChildHandle.\r
+  @retval EFI_UNSUPPORTED       The driver specified by This does not support\r
+                                the language specified by Language.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+GetControllerName (\r
+  IN  EFI_COMPONENT_NAME_PROTOCOL * pThis,\r
+  IN  EFI_HANDLE ControllerHandle,\r
+  IN OPTIONAL EFI_HANDLE ChildHandle,\r
+  IN  CHAR8 * pLanguage,\r
+  OUT CHAR16 ** ppControllerName\r
+  )\r
+{\r
+  EFI_STATUS Status;\r
+\r
+  DBG_ENTER ( );\r
+\r
+  //\r
+  // Set the controller name\r
+  //\r
+  *ppControllerName = L"AX88772 10/100 Ethernet";\r
+  Status = EFI_SUCCESS;\r
+\r
+  //\r
+  // Return the operation status\r
+  //\r
+  DBG_EXIT_HEX ( Status );\r
+  return Status;\r
+}\r
diff --git a/OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772/DriverBinding.c b/OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772/DriverBinding.c
new file mode 100644 (file)
index 0000000..5f0f286
--- /dev/null
@@ -0,0 +1,526 @@
+/** @file\r
+  Implement the driver binding protocol for Asix AX88772 Ethernet driver.\r
+\r
+  Copyright (c) 2011, Intel Corporation\r
+  All rights reserved. This program and the accompanying materials\r
+  are licensed and made available under the terms and conditions of the BSD License\r
+  which accompanies this distribution.  The full text of the license may be found at\r
+  http://opensource.org/licenses/bsd-license.php\r
+\r
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "Ax88772.h"\r
+\r
+/**\r
+  Verify the controller type\r
+\r
+  @param [in] pThis                Protocol instance pointer.\r
+  @param [in] Controller           Handle of device to test.\r
+  @param [in] pRemainingDevicePath Not used.\r
+\r
+  @retval EFI_SUCCESS          This driver supports this device.\r
+  @retval other                This driver does not support this device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+DriverSupported (\r
+  IN EFI_DRIVER_BINDING_PROTOCOL * pThis,\r
+  IN EFI_HANDLE Controller,\r
+  IN EFI_DEVICE_PATH_PROTOCOL * pRemainingDevicePath\r
+  )\r
+{\r
+  EFI_USB_DEVICE_DESCRIPTOR Device;\r
+  EFI_USB_IO_PROTOCOL * pUsbIo;\r
+  EFI_STATUS Status;\r
+\r
+  //\r
+  //  Connect to the USB stack\r
+  //\r
+  Status = gBS->OpenProtocol (\r
+                  Controller,\r
+                  &gEfiUsbIoProtocolGuid,\r
+                  (VOID **) &pUsbIo,\r
+                  pThis->DriverBindingHandle,\r
+                  Controller,\r
+                  EFI_OPEN_PROTOCOL_BY_DRIVER\r
+                  );\r
+  if (!EFI_ERROR ( Status )) {\r
+\r
+    //\r
+    //  Get the interface descriptor to check the USB class and find a transport\r
+    //  protocol handler.\r
+    //\r
+    Status = pUsbIo->UsbGetDeviceDescriptor ( pUsbIo, &Device );\r
+    if (!EFI_ERROR ( Status )) {\r
+\r
+      //\r
+      //  Validate the adapter\r
+      //\r
+      if (( VENDOR_ID != Device.IdVendor )\r
+        || ( PRODUCT_ID != Device.IdProduct )) {\r
+        Status = EFI_UNSUPPORTED;\r
+      }\r
+    }\r
+\r
+    //\r
+    //  Done with the USB stack\r
+    //\r
+    gBS->CloseProtocol (\r
+           Controller,\r
+           &gEfiUsbIoProtocolGuid,\r
+           pThis->DriverBindingHandle,\r
+           Controller\r
+           );\r
+  }\r
+\r
+  //\r
+  //  Return the device supported status\r
+  //\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Start this driver on Controller by opening UsbIo and DevicePath protocols.\r
+  Initialize PXE structures, create a copy of the Controller Device Path with the\r
+  NIC's MAC address appended to it, install the NetworkInterfaceIdentifier protocol\r
+  on the newly created Device Path.\r
+\r
+  @param [in] pThis                Protocol instance pointer.\r
+  @param [in] Controller           Handle of device to work with.\r
+  @param [in] pRemainingDevicePath Not used, always produce all possible children.\r
+\r
+  @retval EFI_SUCCESS          This driver is added to Controller.\r
+  @retval other                This driver does not support this device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+DriverStart (\r
+  IN EFI_DRIVER_BINDING_PROTOCOL * pThis,\r
+  IN EFI_HANDLE Controller,\r
+  IN EFI_DEVICE_PATH_PROTOCOL * pRemainingDevicePath\r
+  )\r
+{\r
+  EFI_STATUS Status;\r
+  NIC_DEVICE * pNicDevice;\r
+  UINTN LengthInBytes;\r
+\r
+  DBG_ENTER ( );\r
+\r
+  //\r
+  //  Allocate the device structure\r
+  //\r
+  LengthInBytes = sizeof ( *pNicDevice );\r
+  Status = gBS->AllocatePool (\r
+                  EfiRuntimeServicesData,\r
+                  LengthInBytes,\r
+                  (VOID **) &pNicDevice\r
+                  );\r
+  if ( !EFI_ERROR ( Status )) {\r
+    DEBUG (( DEBUG_POOL | DEBUG_INIT,\r
+              "0x%08x: Allocate pNicDevice, %d bytes\r\n",\r
+              pNicDevice,\r
+              sizeof ( *pNicDevice )));\r
+\r
+    //\r
+    //  Set the structure signature\r
+    //\r
+    ZeroMem ( pNicDevice, LengthInBytes );\r
+    pNicDevice->Signature = DEV_SIGNATURE;\r
+\r
+    //\r
+    //  Connect to the USB I/O protocol\r
+    //\r
+    Status = gBS->OpenProtocol (\r
+                    Controller,\r
+                    &gEfiUsbIoProtocolGuid,\r
+                    (VOID **) &pNicDevice->pUsbIo,\r
+                    pThis->DriverBindingHandle,\r
+                    Controller,\r
+                    EFI_OPEN_PROTOCOL_BY_DRIVER\r
+                    );\r
+\r
+    if ( !EFI_ERROR ( Status )) {\r
+      //\r
+      //  Allocate the necessary events\r
+      //\r
+      Status = gBS->CreateEvent ( EVT_TIMER,\r
+                                  TPL_AX88772,\r
+                                  (EFI_EVENT_NOTIFY)Ax88772Timer,\r
+                                  pNicDevice,\r
+                                  (VOID **)&pNicDevice->Timer );\r
+      if ( !EFI_ERROR ( Status )) {\r
+        DEBUG (( DEBUG_POOL | DEBUG_INIT | DEBUG_INFO,\r
+                  "0x%08x: Allocated timer\r\n",\r
+                  pNicDevice->Timer ));\r
+\r
+        //\r
+        //  Initialize the simple network protocol\r
+        //\r
+        pNicDevice->Controller = Controller;\r
+        SN_Setup ( pNicDevice );\r
+\r
+        //\r
+        //  Start the timer\r
+        //\r
+        Status = gBS->SetTimer ( pNicDevice->Timer,\r
+                                 TimerPeriodic,\r
+                                 TIMER_MSEC );\r
+        if ( !EFI_ERROR ( Status )) {\r
+          //\r
+          //  Install both the simple network and device path protocols.\r
+          //\r
+          Status = gBS->InstallMultipleProtocolInterfaces (\r
+                          &Controller,\r
+                          &gEfiCallerIdGuid,\r
+                          pNicDevice,\r
+                          &gEfiSimpleNetworkProtocolGuid,\r
+                          &pNicDevice->SimpleNetwork,\r
+                          NULL\r
+                          );\r
+\r
+          if ( !EFI_ERROR ( Status )) {\r
+            DEBUG (( DEBUG_POOL | DEBUG_INIT | DEBUG_INFO,\r
+                      "Installed: gEfiCallerIdGuid on   0x%08x\r\n",\r
+                      Controller ));\r
+            DEBUG (( DEBUG_POOL | DEBUG_INIT | DEBUG_INFO,\r
+                      "Installed: gEfiSimpleNetworkProtocolGuid on   0x%08x\r\n",\r
+                      Controller ));\r
+            DBG_EXIT_STATUS ( Status );\r
+            return Status;\r
+          }\r
+          DEBUG (( DEBUG_ERROR | DEBUG_INIT | DEBUG_INFO,\r
+                    "ERROR - Failed to install gEfiSimpleNetworkProtocol on 0x%08x\r\n",\r
+                    Controller ));\r
+        }\r
+        else {\r
+          DEBUG (( DEBUG_ERROR | DEBUG_INIT | DEBUG_INFO,\r
+                    "ERROR - Failed to start the timer, Status: %r\r\n",\r
+                    Status ));\r
+        }\r
+      }\r
+      else {\r
+        DEBUG (( DEBUG_ERROR | DEBUG_INIT | DEBUG_INFO,\r
+                  "ERROR - Failed to create timer event, Status: %r\r\n",\r
+                  Status ));\r
+      }\r
+\r
+      //\r
+      //  Done with the USB stack\r
+      //\r
+      gBS->CloseProtocol (\r
+             Controller,\r
+             &gEfiUsbIoProtocolGuid,\r
+             pThis->DriverBindingHandle,\r
+             Controller\r
+             );\r
+    }\r
+\r
+    //\r
+    //  Done with the device\r
+    //\r
+    gBS->FreePool ( pNicDevice );\r
+  }\r
+\r
+  //\r
+  //  Display the driver start status\r
+  //\r
+  DBG_EXIT_STATUS ( Status );\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Stop this driver on Controller by removing NetworkInterfaceIdentifier protocol and\r
+  closing the DevicePath and PciIo protocols on Controller.\r
+\r
+  @param [in] pThis                Protocol instance pointer.\r
+  @param [in] Controller           Handle of device to stop driver on.\r
+  @param [in] NumberOfChildren     How many children need to be stopped.\r
+  @param [in] pChildHandleBuffer   Not used.\r
+\r
+  @retval EFI_SUCCESS          This driver is removed Controller.\r
+  @retval EFI_DEVICE_ERROR     The device could not be stopped due to a device error.\r
+  @retval other                This driver was not removed from this device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+DriverStop (\r
+  IN  EFI_DRIVER_BINDING_PROTOCOL * pThis,\r
+  IN  EFI_HANDLE Controller,\r
+  IN  UINTN NumberOfChildren,\r
+  IN  EFI_HANDLE * pChildHandleBuffer\r
+  )\r
+{\r
+  NIC_DEVICE * pNicDevice;\r
+  EFI_STATUS Status;\r
+\r
+  DBG_ENTER ( );\r
+\r
+  //\r
+  //  Determine if this driver is already attached\r
+  //\r
+  Status = gBS->OpenProtocol (\r
+                  Controller,\r
+                  &gEfiCallerIdGuid,\r
+                  (VOID **) &pNicDevice,\r
+                  pThis->DriverBindingHandle,\r
+                  Controller,\r
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+                  );\r
+  if ( !EFI_ERROR ( Status )) {\r
+    //\r
+    //  AX88772 driver is no longer running on this device\r
+    //\r
+    gBS->UninstallMultipleProtocolInterfaces (\r
+              Controller,\r
+              &gEfiSimpleNetworkProtocolGuid,\r
+              &pNicDevice->SimpleNetwork,\r
+              &gEfiCallerIdGuid,\r
+              pNicDevice,\r
+              NULL );\r
+    DEBUG (( DEBUG_POOL | DEBUG_INIT,\r
+                "Removed:   gEfiSimpleNetworkProtocolGuid from 0x%08x\r\n",\r
+                Controller ));\r
+    DEBUG (( DEBUG_POOL | DEBUG_INIT,\r
+                "Removed:   gEfiCallerIdGuid from 0x%08x\r\n",\r
+                Controller ));\r
+\r
+    //\r
+    //  Stop the timer\r
+    //\r
+    if ( NULL != pNicDevice->Timer ) {\r
+      gBS->SetTimer ( pNicDevice->Timer, TimerCancel, 0 );\r
+      gBS->CloseEvent ( pNicDevice->Timer );\r
+      DEBUG (( DEBUG_POOL | DEBUG_INIT | DEBUG_INFO,\r
+                "0x%08x: Released timer\r\n",\r
+                pNicDevice->Timer ));\r
+    }\r
+\r
+    //\r
+    //  Done with the device context\r
+    //\r
+    DEBUG (( DEBUG_POOL | DEBUG_INIT,\r
+              "0x%08x: Free pNicDevice, %d bytes\r\n",\r
+              pNicDevice,\r
+              sizeof ( *pNicDevice )));\r
+    gBS->FreePool ( pNicDevice );\r
+  }\r
+\r
+  //\r
+  //  Return the shutdown status\r
+  //\r
+  DBG_EXIT_STATUS ( Status );\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Driver binding protocol declaration\r
+**/\r
+EFI_DRIVER_BINDING_PROTOCOL  gDriverBinding = {\r
+  DriverSupported,\r
+  DriverStart,\r
+  DriverStop,\r
+  0xa,\r
+  NULL,\r
+  NULL\r
+};\r
+\r
+\r
+/**\r
+  Ax88772 driver unload routine.\r
+\r
+  @param [in] ImageHandle       Handle for the image.\r
+\r
+  @retval EFI_SUCCESS           Image may be unloaded\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+DriverUnload (\r
+  IN EFI_HANDLE ImageHandle\r
+  )\r
+{\r
+  UINTN BufferSize;\r
+  UINTN Index;\r
+  UINTN Max;\r
+  EFI_HANDLE * pHandle;\r
+  EFI_STATUS Status;\r
+\r
+  //\r
+  //  Determine which devices are using this driver\r
+  //\r
+  BufferSize = 0;\r
+  pHandle = NULL;\r
+  Status = gBS->LocateHandle (\r
+                  ByProtocol,\r
+                  &gEfiCallerIdGuid,\r
+                  NULL,\r
+                  &BufferSize,\r
+                  NULL );\r
+  if ( EFI_BUFFER_TOO_SMALL == Status ) {\r
+    for ( ; ; ) {\r
+      //\r
+      //  One or more block IO devices are present\r
+      //\r
+      Status = gBS->AllocatePool (\r
+                      EfiRuntimeServicesData,\r
+                      BufferSize,\r
+                      (VOID **) &pHandle\r
+                      );\r
+      if ( EFI_ERROR ( Status )) {\r
+        DEBUG (( DEBUG_ERROR | DEBUG_POOL | DEBUG_INIT | DEBUG_INFO,\r
+                  "Insufficient memory, failed handle buffer allocation\r\n" ));\r
+        break;\r
+      }\r
+\r
+      //\r
+      //  Locate the block IO devices\r
+      //\r
+      Status = gBS->LocateHandle (\r
+                      ByProtocol,\r
+                      &gEfiCallerIdGuid,\r
+                      NULL,\r
+                      &BufferSize,\r
+                      pHandle );\r
+      if ( EFI_ERROR ( Status )) {\r
+        //\r
+        //  Error getting handles\r
+        //\r
+        DEBUG (( DEBUG_ERROR | DEBUG_INIT | DEBUG_INFO,\r
+                "Failure getting Telnet handles\r\n" ));\r
+        break;\r
+      }\r
+      \r
+      //\r
+      //  Remove any use of the driver\r
+      //\r
+      Max = BufferSize / sizeof ( pHandle[ 0 ]);\r
+      for ( Index = 0; Max > Index; Index++ ) {\r
+        Status = DriverStop ( &gDriverBinding,\r
+                              pHandle[ Index ],\r
+                              0,\r
+                              NULL );\r
+        if ( EFI_ERROR ( Status )) {\r
+          DEBUG (( DEBUG_WARN | DEBUG_INIT | DEBUG_INFO,\r
+                    "WARNING - Failed to shutdown the driver on handle %08x\r\n", pHandle[ Index ]));\r
+          break;\r
+        }\r
+      }\r
+      break;\r
+    }\r
+  }\r
+  else {\r
+    if ( EFI_NOT_FOUND == Status ) {\r
+      //\r
+      //  No devices were found\r
+      //\r
+      Status = EFI_SUCCESS;\r
+    }\r
+  }\r
+\r
+  //\r
+  //  Free the handle array\r
+  //\r
+  if ( NULL != pHandle ) {\r
+    gBS->FreePool ( pHandle );\r
+  }\r
+\r
+  //\r
+  //  Remove the protocols installed by the EntryPoint routine.\r
+  //\r
+  if ( !EFI_ERROR ( Status )) {\r
+    gBS->UninstallMultipleProtocolInterfaces (\r
+            ImageHandle,\r
+            &gEfiDriverBindingProtocolGuid,\r
+            &gDriverBinding,\r
+            &gEfiComponentNameProtocolGuid,\r
+            &gComponentName,\r
+            &gEfiComponentName2ProtocolGuid,\r
+            &gComponentName2,\r
+            NULL\r
+            );\r
+    DEBUG (( DEBUG_POOL | DEBUG_INIT | DEBUG_INFO,\r
+            "Removed:   gEfiComponentName2ProtocolGuid from 0x%08x\r\n",\r
+            ImageHandle ));\r
+    DEBUG (( DEBUG_POOL | DEBUG_INIT | DEBUG_INFO,\r
+              "Removed:   gEfiComponentNameProtocolGuid from 0x%08x\r\n",\r
+              ImageHandle ));\r
+    DEBUG (( DEBUG_POOL | DEBUG_INIT | DEBUG_INFO,\r
+              "Removed:   gEfiDriverBindingProtocolGuid from 0x%08x\r\n",\r
+              ImageHandle ));\r
+  }\r
+\r
+  //\r
+  //  Return the unload status\r
+  //\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+Ax88772 driver entry point.\r
+\r
+@param [in] ImageHandle       Handle for the image.\r
+@param [in] pSystemTable      Address of the system table.\r
+\r
+@retval EFI_SUCCESS           Image successfully loaded.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EntryPoint (\r
+  IN EFI_HANDLE ImageHandle,\r
+  IN EFI_SYSTEM_TABLE * pSystemTable\r
+  )\r
+{\r
+  EFI_LOADED_IMAGE_PROTOCOL * pLoadedImage;\r
+  EFI_STATUS    Status;\r
+\r
+  DBG_ENTER ( );\r
+\r
+  //\r
+  //  Enable unload support\r
+  //\r
+  Status = gBS->HandleProtocol (\r
+                  gImageHandle,\r
+                  &gEfiLoadedImageProtocolGuid,\r
+                  (VOID **)&pLoadedImage\r
+                  );\r
+  if (!EFI_ERROR (Status)) {\r
+    pLoadedImage->Unload = DriverUnload;\r
+  }\r
+\r
+  //\r
+  //  Add the driver to the list of drivers\r
+  //\r
+  Status = EfiLibInstallDriverBindingComponentName2 (\r
+             ImageHandle,\r
+             pSystemTable,\r
+             &gDriverBinding,\r
+             ImageHandle,\r
+             &gComponentName,\r
+             &gComponentName2\r
+             );\r
+  ASSERT_EFI_ERROR (Status);\r
+  if ( !EFI_ERROR ( Status )) {\r
+    DEBUG (( DEBUG_POOL | DEBUG_INIT | DEBUG_INFO,\r
+              "Installed: gEfiDriverBindingProtocolGuid on   0x%08x\r\n",\r
+              ImageHandle ));\r
+    DEBUG (( DEBUG_POOL | DEBUG_INIT | DEBUG_INFO,\r
+              "Installed: gEfiComponentNameProtocolGuid on   0x%08x\r\n",\r
+              ImageHandle ));\r
+    DEBUG (( DEBUG_POOL | DEBUG_INIT | DEBUG_INFO,\r
+              "Installed: gEfiComponentName2ProtocolGuid on   0x%08x\r\n",\r
+              ImageHandle ));\r
+  }\r
+  DBG_EXIT_STATUS ( Status );\r
+  return Status;\r
+}\r
diff --git a/OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772/SimpleNetwork.c b/OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772/SimpleNetwork.c
new file mode 100644 (file)
index 0000000..a0231d6
--- /dev/null
@@ -0,0 +1,1496 @@
+/** @file\r
+  Provides the Simple Network functions.\r
+\r
+  Copyright (c) 2011, Intel Corporation\r
+  All rights reserved. This program and the accompanying materials\r
+  are licensed and made available under the terms and conditions of the BSD License\r
+  which accompanies this distribution.  The full text of the license may be found at\r
+  http://opensource.org/licenses/bsd-license.php\r
+\r
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "Ax88772.h"\r
+\r
+/**\r
+  This function updates the filtering on the receiver.\r
+\r
+  This support routine calls ::Ax88772MacAddressSet to update\r
+  the MAC address.  This routine then rebuilds the multicast\r
+  hash by calling ::Ax88772MulticastClear and ::Ax88772MulticastSet.\r
+  Finally this routine enables the receiver by calling\r
+  ::Ax88772RxControl.\r
+\r
+  @param [in] pSimpleNetwork    Simple network mode pointer\r
+\r
+  @retval EFI_SUCCESS           This operation was successful.\r
+  @retval EFI_NOT_STARTED       The network interface was not started.\r
+  @retval EFI_INVALID_PARAMETER pSimpleNetwork parameter was NULL or did not point to a valid\r
+                                EFI_SIMPLE_NETWORK_PROTOCOL structure.\r
+  @retval EFI_DEVICE_ERROR      The command could not be sent to the network interface.\r
+  @retval EFI_UNSUPPORTED       The increased buffer size feature is not supported.\r
+\r
+**/\r
+EFI_STATUS\r
+ReceiveFilterUpdate (\r
+  IN EFI_SIMPLE_NETWORK_PROTOCOL * pSimpleNetwork\r
+  )\r
+{\r
+  EFI_SIMPLE_NETWORK_MODE * pMode;\r
+  NIC_DEVICE * pNicDevice;\r
+  EFI_STATUS Status;\r
+  UINT32 Index;\r
+\r
+  DBG_ENTER ( );\r
+\r
+  //\r
+  // Set the MAC address\r
+  //\r
+  pNicDevice = DEV_FROM_SIMPLE_NETWORK ( pSimpleNetwork );\r
+  pMode = pSimpleNetwork->Mode;\r
+  Status = Ax88772MacAddressSet ( pNicDevice,\r
+                                  &pMode->CurrentAddress.Addr[0]);\r
+  if ( !EFI_ERROR ( Status )) {\r
+    //\r
+    // Clear the multicast hash table\r
+    //\r
+    Ax88772MulticastClear ( pNicDevice );\r
+\r
+    //\r
+    // Load the multicast hash table\r
+    //\r
+    if ( 0 != ( pMode->ReceiveFilterSetting & EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST )) {\r
+      for ( Index = 0;\r
+            ( !EFI_ERROR ( Status )) && ( Index < pMode->MCastFilterCount );\r
+            Index++ ) {\r
+        //\r
+        // Enable the next multicast address\r
+        //\r
+        Ax88772MulticastSet ( pNicDevice,\r
+                              &pMode->MCastFilter[ Index ].Addr[0]);\r
+      }\r
+    }\r
+\r
+    //\r
+    // Enable the receiver\r
+    //\r
+    if ( !EFI_ERROR ( Status )) {\r
+      Status = Ax88772RxControl ( pNicDevice, pMode->ReceiveFilterSetting );\r
+    }\r
+  }\r
+\r
+  //\r
+  // Return the operation status\r
+  //\r
+  DBG_EXIT_STATUS ( Status );\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  This function updates the SNP driver status.\r
+  \r
+  This function gets the current interrupt and recycled transmit\r
+  buffer status from the network interface.  The interrupt status\r
+  and the media status are returned as a bit mask in InterruptStatus.\r
+  If InterruptStatus is NULL, the interrupt status will not be read.\r
+  Upon successful return of the media status, the MediaPresent field\r
+  of EFI_SIMPLE_NETWORK_MODE will be updated to reflect any change\r
+  of media status.  If TxBuf is not NULL, a recycled transmit buffer\r
+  address will be retrived.  If a recycled transmit buffer address\r
+  is returned in TxBuf, then the buffer has been successfully\r
+  transmitted, and the status for that buffer is cleared.\r
+\r
+  This function calls ::Ax88772Rx to update the media status and\r
+  queue any receive packets.\r
+\r
+  @param [in] pSimpleNetwork    Protocol instance pointer\r
+  @param [in] pInterruptStatus  A pointer to the bit mask of the current active interrupts.\r
+                                If this is NULL, the interrupt status will not be read from\r
+                                the device.  If this is not NULL, the interrupt status will\r
+                                be read from teh device.  When the interrupt status is read,\r
+                                it will also be cleared.  Clearing the transmit interrupt\r
+                                does not empty the recycled transmit buffer array.\r
+  @param [out] ppTxBuf          Recycled transmit buffer address.  The network interface will\r
+                                not transmit if its internal recycled transmit buffer array is\r
+                                full.  Reading the transmit buffer does not clear the transmit\r
+                                interrupt.  If this is NULL, then the transmit buffer status\r
+                                will not be read.  If there are not transmit buffers to recycle\r
+                                and TxBuf is not NULL, *TxBuf will be set to NULL.\r
+\r
+  @retval EFI_SUCCESS           This operation was successful.\r
+  @retval EFI_NOT_STARTED       The network interface was not started.\r
+  @retval EFI_INVALID_PARAMETER pSimpleNetwork parameter was NULL or did not point to a valid\r
+                                EFI_SIMPLE_NETWORK_PROTOCOL structure.\r
+  @retval EFI_DEVICE_ERROR      The command could not be sent to the network interface.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SN_GetStatus (\r
+  IN EFI_SIMPLE_NETWORK_PROTOCOL * pSimpleNetwork,\r
+  OUT UINT32 * pInterruptStatus,\r
+  OUT VOID ** ppTxBuf\r
+  )\r
+{\r
+  BOOLEAN bLinkIdle;\r
+  EFI_SIMPLE_NETWORK_MODE * pMode;\r
+  NIC_DEVICE * pNicDevice;\r
+  EFI_STATUS Status;\r
+  EFI_TPL TplPrevious;\r
+\r
+  DBG_ENTER ( );\r
+\r
+  //\r
+  // Verify the parameters\r
+  //\r
+  if (( NULL != pSimpleNetwork ) && ( NULL != pSimpleNetwork->Mode )) {\r
+    //\r
+    // Return the transmit buffer\r
+    //\r
+    pNicDevice = DEV_FROM_SIMPLE_NETWORK ( pSimpleNetwork );\r
+    if (( NULL != ppTxBuf ) && ( NULL != pNicDevice->pTxBuffer )) {\r
+      *ppTxBuf = pNicDevice->pTxBuffer;\r
+      pNicDevice->pTxBuffer = NULL;\r
+    }\r
+\r
+    //\r
+    // Determine if interface is running\r
+    //\r
+    pMode = pSimpleNetwork->Mode;\r
+    if ( EfiSimpleNetworkStopped != pMode->State ) {\r
+      //\r
+      //  Synchronize with Ax88772Timer\r
+      //\r
+      VERIFY_TPL ( TPL_AX88772 );\r
+      TplPrevious = gBS->RaiseTPL ( TPL_AX88772 );\r
+\r
+      //\r
+      // Update the link status\r
+      //\r
+      bLinkIdle = pNicDevice->bLinkIdle;\r
+      pNicDevice->bLinkIdle = TRUE;\r
+      Ax88772Rx ( pNicDevice, bLinkIdle );\r
+      pMode->MediaPresent = pNicDevice->bLinkUp;\r
+\r
+      //\r
+      //  Release the synchronization with Ax88772Timer\r
+      //\r
+      gBS->RestoreTPL ( TplPrevious );\r
+\r
+      //\r
+      // Return the interrupt status\r
+      //\r
+      if ( NULL != pInterruptStatus ) {\r
+        *pInterruptStatus = 0;\r
+      }\r
+      Status = EFI_SUCCESS;\r
+    }\r
+    else {\r
+      Status = EFI_NOT_STARTED;\r
+    }\r
+  }\r
+  else {\r
+    Status = EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  //\r
+  // Return the operation status\r
+  //\r
+  DBG_EXIT_STATUS ( Status );\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Resets the network adapter and allocates the transmit and receive buffers\r
+  required by the network interface; optionally, also requests allocation of\r
+  additional transmit and receive buffers.  This routine must be called before\r
+  any other routine in the Simple Network protocol is called.\r
+\r
+  @param [in] pSimpleNetwork    Protocol instance pointer\r
+  @param [in] ExtraRxBufferSize Size in bytes to add to the receive buffer allocation\r
+  @param [in] ExtraTxBufferSize Size in bytes to add to the transmit buffer allocation\r
+\r
+  @retval EFI_SUCCESS           This operation was successful.\r
+  @retval EFI_NOT_STARTED       The network interface was not started.\r
+  @retval EFI_OUT_OF_RESORUCES  There was not enough memory for the transmit and receive buffers\r
+  @retval EFI_INVALID_PARAMETER pSimpleNetwork parameter was NULL or did not point to a valid\r
+                                EFI_SIMPLE_NETWORK_PROTOCOL structure.\r
+  @retval EFI_DEVICE_ERROR      The command could not be sent to the network interface.\r
+  @retval EFI_UNSUPPORTED       The increased buffer size feature is not supported.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SN_Initialize (\r
+  IN EFI_SIMPLE_NETWORK_PROTOCOL * pSimpleNetwork,\r
+  IN UINTN ExtraRxBufferSize,\r
+  IN UINTN ExtraTxBufferSize\r
+  )\r
+{\r
+  EFI_SIMPLE_NETWORK_MODE * pMode;\r
+  EFI_STATUS Status;\r
+\r
+  DBG_ENTER ( );\r
+  \r
+  //\r
+  // Verify the parameters\r
+  //\r
+  if (( NULL != pSimpleNetwork ) && ( NULL != pSimpleNetwork->Mode )) {\r
+    //\r
+    // Determine if the interface is already started\r
+    //\r
+    pMode = pSimpleNetwork->Mode;\r
+    if ( EfiSimpleNetworkStarted == pMode->State ) {\r
+      if (( 0 == ExtraRxBufferSize ) && ( 0 == ExtraTxBufferSize )) {\r
+        //\r
+        // Start the adapter\r
+        //\r
+        Status = SN_Reset ( pSimpleNetwork, FALSE );\r
+        if ( !EFI_ERROR ( Status )) {\r
+          //\r
+          // Update the network state\r
+          //\r
+          pMode->State = EfiSimpleNetworkInitialized;\r
+        }\r
+      }\r
+      else {\r
+        Status = EFI_UNSUPPORTED;\r
+      }\r
+    }\r
+    else {\r
+      Status = EFI_NOT_STARTED;\r
+    }\r
+  }\r
+  else {\r
+    Status = EFI_INVALID_PARAMETER;\r
+  }\r
+  \r
+  //\r
+  // Return the operation status\r
+  //\r
+  DBG_EXIT_STATUS ( Status );\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  This function converts a multicast IP address to a multicast HW MAC address\r
+  for all packet transactions.\r
+\r
+  @param [in] pSimpleNetwork    Protocol instance pointer\r
+  @param [in] bIPv6             Set to TRUE if the multicast IP address is IPv6 [RFC2460].\r
+                                Set to FALSE if the multicast IP address is IPv4 [RFC 791].\r
+  @param [in] pIP               The multicast IP address that is to be converted to a\r
+                                multicast HW MAC address.\r
+  @param [in] pMAC              The multicast HW MAC address that is to be generated from IP.\r
+\r
+  @retval EFI_SUCCESS           This operation was successful.\r
+  @retval EFI_NOT_STARTED       The network interface was not started.\r
+  @retval EFI_INVALID_PARAMETER pSimpleNetwork parameter was NULL or did not point to a valid\r
+                                EFI_SIMPLE_NETWORK_PROTOCOL structure.\r
+  @retval EFI_DEVICE_ERROR      The command could not be sent to the network interface.\r
+  @retval EFI_UNSUPPORTED       The increased buffer size feature is not supported.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SN_MCastIPtoMAC (\r
+  IN EFI_SIMPLE_NETWORK_PROTOCOL * pSimpleNetwork,\r
+  IN BOOLEAN bIPv6,\r
+  IN EFI_IP_ADDRESS * pIP,\r
+  IN EFI_MAC_ADDRESS * pMAC\r
+  )\r
+{\r
+  EFI_STATUS Status;\r
+\r
+  DBG_ENTER ( );\r
+\r
+  //\r
+  // This is not currently supported\r
+  //\r
+  Status = EFI_UNSUPPORTED;\r
+\r
+  //\r
+  // Return the operation status\r
+  //\r
+  DBG_EXIT_STATUS ( Status );\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  This function performs read and write operations on the NVRAM device\r
+  attached to a network interface.\r
+\r
+  @param [in] pSimpleNetwork    Protocol instance pointer\r
+  @param [in] ReadWrite         TRUE for read operations, FALSE for write operations.\r
+  @param [in] Offset            Byte offset in the NVRAM device at which to start the\r
+                                read or write operation.  This must be a multiple of\r
+                                NvRamAccessSize and less than NvRamSize.\r
+  @param [in] BufferSize        The number of bytes to read or write from the NVRAM device.\r
+                                This must also be a multiple of NvramAccessSize.\r
+  @param [in, out] pBuffer      A pointer to the data buffer.\r
+\r
+  @retval EFI_SUCCESS           This operation was successful.\r
+  @retval EFI_NOT_STARTED       The network interface was not started.\r
+  @retval EFI_INVALID_PARAMETER pSimpleNetwork parameter was NULL or did not point to a valid\r
+                                EFI_SIMPLE_NETWORK_PROTOCOL structure.\r
+  @retval EFI_DEVICE_ERROR      The command could not be sent to the network interface.\r
+  @retval EFI_UNSUPPORTED       The increased buffer size feature is not supported.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SN_NvData (\r
+  IN EFI_SIMPLE_NETWORK_PROTOCOL * pSimpleNetwork,\r
+  IN BOOLEAN ReadWrite,\r
+  IN UINTN Offset,\r
+  IN UINTN BufferSize,\r
+  IN OUT VOID * pBuffer\r
+  )\r
+{\r
+  EFI_STATUS Status;\r
+\r
+  DBG_ENTER ( );\r
+\r
+  //\r
+  // This is not currently supported\r
+  //\r
+  Status = EFI_UNSUPPORTED;\r
+\r
+  //\r
+  // Return the operation status\r
+  //\r
+  DBG_EXIT_STATUS ( Status );\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Attempt to receive a packet from the network adapter.\r
+\r
+  This function retrieves one packet from the receive queue of the network\r
+  interface.  If there are no packets on the receive queue, then EFI_NOT_READY\r
+  will be returned.  If there is a packet on the receive queue, and the size\r
+  of the packet is smaller than BufferSize, then the contents of the packet\r
+  will be placed in Buffer, and BufferSize will be udpated with the actual\r
+  size of the packet.  In addition, if SrcAddr, DestAddr, and Protocol are\r
+  not NULL, then these values will be extracted from the media header and\r
+  returned.  If BufferSize is smaller than the received packet, then the\r
+  size of the receive packet will be placed in BufferSize and\r
+  EFI_BUFFER_TOO_SMALL will be returned.\r
+\r
+  This routine calls ::Ax88772Rx to update the media status and\r
+  empty the network adapter of receive packets.\r
+\r
+  @param [in] pSimpleNetwork    Protocol instance pointer\r
+  @param [out] pHeaderSize      The size, in bytes, of the media header to be filled in by\r
+                                the Transmit() function.  If HeaderSize is non-zero, then\r
+                                it must be equal to SimpleNetwork->Mode->MediaHeaderSize\r
+                                and DestAddr and Protocol parameters must not be NULL.\r
+  @param [out] pBufferSize      The size, in bytes, of the entire packet (media header and\r
+                                data) to be transmitted through the network interface.\r
+  @param [out] pBuffer          A pointer to the packet (media header followed by data) to\r
+                                to be transmitted.  This parameter can not be NULL.  If\r
+                                HeaderSize is zero, then the media header is Buffer must\r
+                                already be filled in by the caller.  If HeaderSize is nonzero,\r
+                                then the media header will be filled in by the Transmit()\r
+                                function.\r
+  @param [out] pSrcAddr         The source HW MAC address.  If HeaderSize is zero, then\r
+                                this parameter is ignored.  If HeaderSize is nonzero and\r
+                                SrcAddr is NULL, then SimpleNetwork->Mode->CurrentAddress\r
+                                is used for the source HW MAC address.\r
+  @param [out] pDestAddr        The destination HW MAC address.  If HeaderSize is zero, then\r
+                                this parameter is ignored.\r
+  @param [out] pProtocol        The type of header to build.  If HeaderSize is zero, then\r
+                                this parameter is ignored.\r
+\r
+  @retval EFI_SUCCESS           This operation was successful.\r
+  @retval EFI_NOT_STARTED       The network interface was not started.\r
+  @retval EFI_NOT_READY         No packets have been received on the network interface.\r
+  @retval EFI_BUFFER_TOO_SMALL  The packet is larger than BufferSize bytes.\r
+  @retval EFI_INVALID_PARAMETER pSimpleNetwork parameter was NULL or did not point to a valid\r
+                                EFI_SIMPLE_NETWORK_PROTOCOL structure.\r
+  @retval EFI_DEVICE_ERROR      The command could not be sent to the network interface.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SN_Receive (\r
+  IN EFI_SIMPLE_NETWORK_PROTOCOL * pSimpleNetwork,\r
+  OUT UINTN                      * pHeaderSize,\r
+  OUT UINTN                      * pBufferSize,\r
+  OUT VOID                       * pBuffer,\r
+  OUT EFI_MAC_ADDRESS            * pSrcAddr,\r
+  OUT EFI_MAC_ADDRESS            * pDestAddr,\r
+  OUT UINT16                     * pProtocol\r
+  )\r
+{\r
+  ETHERNET_HEADER * pHeader;\r
+  EFI_SIMPLE_NETWORK_MODE * pMode;\r
+  NIC_DEVICE * pNicDevice;\r
+  RX_TX_PACKET * pRxPacket;\r
+  EFI_STATUS Status;\r
+  EFI_TPL TplPrevious;\r
+  UINT16 Type;\r
+\r
+  DBG_ENTER ( );\r
+\r
+  //\r
+  // Verify the parameters\r
+  //\r
+  if (( NULL != pSimpleNetwork ) && ( NULL != pSimpleNetwork->Mode )) {\r
+    //\r
+    // The interface must be running\r
+    //\r
+    pMode = pSimpleNetwork->Mode;\r
+    if ( EfiSimpleNetworkInitialized == pMode->State ) {\r
+      //\r
+      //  Synchronize with Ax88772Timer\r
+      //\r
+      VERIFY_TPL ( TPL_AX88772 );\r
+      TplPrevious = gBS->RaiseTPL ( TPL_AX88772 );\r
+\r
+      //\r
+      // Update the link status\r
+      //\r
+      pNicDevice = DEV_FROM_SIMPLE_NETWORK ( pSimpleNetwork );\r
+      Ax88772Rx ( pNicDevice, FALSE );\r
+      pMode->MediaPresent = pNicDevice->bLinkUp;\r
+      if ( pMode->MediaPresent ) {\r
+        //\r
+        //  Attempt to receive a packet\r
+        //\r
+        pRxPacket = pNicDevice->pRxHead;\r
+        if ( NULL != pRxPacket ) {\r
+          pNicDevice->pRxHead = pRxPacket->pNext;\r
+          if ( NULL == pNicDevice->pRxHead ) {\r
+            pNicDevice->pRxTail = NULL;\r
+          }\r
+\r
+          //\r
+          // Copy the received packet into the receive buffer\r
+          //\r
+          *pBufferSize = pRxPacket->Length;\r
+          CopyMem ( pBuffer, &pRxPacket->Data[0], pRxPacket->Length );\r
+          pHeader = (ETHERNET_HEADER *) &pRxPacket->Data[0];\r
+          if ( NULL != pHeaderSize ) {\r
+            *pHeaderSize = sizeof ( *pHeader );\r
+          }\r
+          if ( NULL != pDestAddr ) {\r
+            CopyMem ( pDestAddr, &pHeader->dest_addr, PXE_HWADDR_LEN_ETHER );\r
+          }\r
+          if ( NULL != pSrcAddr ) {\r
+            CopyMem ( pSrcAddr, &pHeader->src_addr, PXE_HWADDR_LEN_ETHER );\r
+          }\r
+          if ( NULL != pProtocol ) {\r
+            Type = pHeader->type;\r
+            Type = (UINT16)(( Type >> 8 ) | ( Type << 8 ));\r
+            *pProtocol = Type;\r
+          }\r
+          Status = EFI_SUCCESS;\r
+        }\r
+        else {\r
+          //\r
+          //  No receive packets available\r
+          //\r
+          Status = EFI_NOT_READY;\r
+        }\r
+      }\r
+      else {\r
+        //\r
+        //  Link no up\r
+        //\r
+        Status = EFI_NOT_READY;\r
+      }\r
+\r
+      //\r
+      //  Release the synchronization with Ax88772Timer\r
+      //\r
+      gBS->RestoreTPL ( TplPrevious );\r
+    }\r
+    else {\r
+      Status = EFI_NOT_STARTED;\r
+    }\r
+  }\r
+  else {\r
+    Status = EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  //\r
+  // Return the operation status\r
+  //\r
+  DBG_EXIT_STATUS ( Status );\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  This function is used to enable and disable the hardware and software receive\r
+  filters for the underlying network device.\r
+\r
+  The receive filter change is broken down into three steps:\r
+\r
+    1.  The filter mask bits that are set (ON) in the Enable parameter\r
+        are added to the current receive filter settings.\r
+\r
+    2.  The filter mask bits that are set (ON) in the Disable parameter\r
+        are subtracted from the updated receive filter settins.\r
+\r
+    3.  If the resulting filter settigns is not supported by the hardware\r
+        a more liberal setting is selected.\r
+\r
+  If the same bits are set in the Enable and Disable parameters, then the bits\r
+  in the Disable parameter takes precedence.\r
+\r
+  If the ResetMCastFilter parameter is TRUE, then the multicast address list\r
+  filter is disabled (irregardless of what other multicast bits are set in\r
+  the enable and Disable parameters).  The SNP->Mode->MCastFilterCount field\r
+  is set to zero.  The SNP->Mode->MCastFilter contents are undefined.\r
+\r
+  After enableing or disabling receive filter settings, software should\r
+  verify the new settings by checking the SNP->Mode->ReceeiveFilterSettings,\r
+  SNP->Mode->MCastFilterCount and SNP->Mode->MCastFilter fields.\r
+\r
+  Note: Some network drivers and/or devices will automatically promote\r
+  receive filter settings if the requested setting can not be honored.\r
+  For example, if a request for four multicast addresses is made and\r
+  the underlying hardware only supports two multicast addresses the\r
+  driver might set the promiscuous or promiscuous multicast receive filters\r
+  instead.  The receiving software is responsible for discarding any extra\r
+  packets that get through the hardware receive filters.\r
+\r
+  If ResetMCastFilter is TRUE, then the multicast receive filter list\r
+  on the network interface will be reset to the default multicast receive\r
+  filter list.  If ResetMCastFilter is FALSE, and this network interface\r
+  allows the multicast receive filter list to be modified, then the\r
+  MCastFilterCnt and MCastFilter are used to update the current multicast\r
+  receive filter list.  The modified receive filter list settings can be\r
+  found in the MCastFilter field of EFI_SIMPLE_NETWORK_MODE.\r
+\r
+  This routine calls ::ReceiveFilterUpdate to update the receive\r
+  state in the network adapter.\r
+\r
+  @param [in] pSimpleNetwork    Protocol instance pointer\r
+  @param [in] Enable            A bit mask of receive filters to enable on the network interface.\r
+  @param [in] Disable           A bit mask of receive filters to disable on the network interface.\r
+                                For backward compatibility with EFI 1.1 platforms, the\r
+                                EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST bit must be set\r
+                                when the ResetMCastFilter parameter is TRUE.\r
+  @param [in] bResetMCastFilter Set to TRUE to reset the contents of the multicast receive\r
+                                filters on the network interface to their default values.\r
+  @param [in] MCastFilterCnt    Number of multicast HW MAC address in the new MCastFilter list.\r
+                                This value must be less than or equal to the MaxMCastFilterCnt\r
+                                field of EFI_SIMPLE_NETWORK_MODE.  This field is optional if\r
+                                ResetMCastFilter is TRUE.\r
+  @param [in] pMCastFilter      A pointer to a list of new multicast receive filter HW MAC\r
+                                addresses.  This list will replace any existing multicast\r
+                                HW MAC address list.  This field is optional if ResetMCastFilter\r
+                                is TRUE.\r
+\r
+  @retval EFI_SUCCESS           This operation was successful.\r
+  @retval EFI_NOT_STARTED       The network interface was not started.\r
+  @retval EFI_INVALID_PARAMETER pSimpleNetwork parameter was NULL or did not point to a valid\r
+                                EFI_SIMPLE_NETWORK_PROTOCOL structure.\r
+  @retval EFI_DEVICE_ERROR      The command could not be sent to the network interface.\r
+  @retval EFI_UNSUPPORTED       The increased buffer size feature is not supported.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SN_ReceiveFilters (\r
+  IN EFI_SIMPLE_NETWORK_PROTOCOL * pSimpleNetwork,\r
+  IN UINT32 Enable,\r
+  IN UINT32 Disable,\r
+  IN BOOLEAN bResetMCastFilter,\r
+  IN UINTN MCastFilterCnt,\r
+  IN EFI_MAC_ADDRESS * pMCastFilter\r
+  )\r
+{\r
+  EFI_SIMPLE_NETWORK_MODE * pMode;\r
+  EFI_MAC_ADDRESS * pMulticastAddress;\r
+  EFI_MAC_ADDRESS * pTableEnd;\r
+  EFI_STATUS Status;\r
+\r
+  DBG_ENTER ( );\r
+\r
+  //\r
+  // Verify the parameters\r
+  //\r
+  Status = EFI_INVALID_PARAMETER;\r
+  if (( NULL != pSimpleNetwork ) && ( NULL != pSimpleNetwork->Mode )) {\r
+    pMode = pSimpleNetwork->Mode;\r
+\r
+    //\r
+    //  Update the multicast list if necessary\r
+    //\r
+    if ( !bResetMCastFilter ) {\r
+      if ( 0 != MCastFilterCnt ) {\r
+        if (( MAX_MCAST_FILTER_CNT >= MCastFilterCnt )\r
+          && ( NULL != pMCastFilter )) {\r
+          //\r
+          // Verify the multicast addresses\r
+          //\r
+          pMulticastAddress = pMCastFilter;\r
+          pTableEnd = pMulticastAddress + MCastFilterCnt;\r
+          while ( pTableEnd > pMulticastAddress ) {\r
+            //\r
+            // The first digit of the multicast address must have the LSB set\r
+            //\r
+            if ( 0 == ( pMulticastAddress->Addr[0] & 1 )) {\r
+              //\r
+              // Invalid multicast address\r
+              //\r
+              break;\r
+            }\r
+            pMulticastAddress += 1;\r
+          }\r
+          if ( pTableEnd == pMulticastAddress ) {\r
+            //\r
+            // Update the multicast filter list.\r
+            //\r
+            CopyMem (&pMode->MCastFilter[0],\r
+                     pMCastFilter,\r
+                     MCastFilterCnt * sizeof ( *pMCastFilter ));\r
+            Status = EFI_SUCCESS;\r
+          }\r
+        }\r
+      }\r
+      else {\r
+        Status = EFI_SUCCESS;\r
+      }\r
+    }\r
+    else {\r
+      //\r
+      // No multicast address list is specified\r
+      //\r
+      MCastFilterCnt = 0;\r
+      Status = EFI_SUCCESS;\r
+    }\r
+    if ( !EFI_ERROR ( Status )) {\r
+      //\r
+      // The parameters are valid!\r
+      //\r
+      pMode->ReceiveFilterSetting |= Enable;\r
+      pMode->ReceiveFilterSetting &= ~Disable;\r
+      pMode->MCastFilterCount = (UINT32)MCastFilterCnt;\r
+\r
+      //\r
+      // Update the receive filters in the adapter\r
+      //\r
+      Status = ReceiveFilterUpdate ( pSimpleNetwork );\r
+    }\r
+  }\r
+\r
+  //\r
+  // Return the operation status\r
+  //\r
+  DBG_EXIT_STATUS ( Status );\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Reset the network adapter.\r
+\r
+  Resets a network adapter and reinitializes it with the parameters that\r
+  were provided in the previous call to Initialize ().  The transmit and\r
+  receive queues are cleared.  Receive filters, the station address, the\r
+  statistics, and the multicast-IP-to-HW MAC addresses are not reset by\r
+  this call.\r
+\r
+  This routine calls ::Ax88772Reset to perform the adapter specific\r
+  reset operation.  This routine also starts the link negotiation\r
+  by calling ::Ax88772NegotiateLinkStart.\r
+\r
+  @param [in] pSimpleNetwork    Protocol instance pointer\r
+  @param [in] bExtendedVerification  Indicates that the driver may perform a more\r
+                                exhaustive verification operation of the device\r
+                                during reset.\r
+\r
+  @retval EFI_SUCCESS           This operation was successful.\r
+  @retval EFI_NOT_STARTED       The network interface was not started.\r
+  @retval EFI_INVALID_PARAMETER pSimpleNetwork parameter was NULL or did not point to a valid\r
+                                EFI_SIMPLE_NETWORK_PROTOCOL structure.\r
+  @retval EFI_DEVICE_ERROR      The command could not be sent to the network interface.\r
+  @retval EFI_UNSUPPORTED       The increased buffer size feature is not supported.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SN_Reset (\r
+  IN EFI_SIMPLE_NETWORK_PROTOCOL * pSimpleNetwork,\r
+  IN BOOLEAN bExtendedVerification\r
+  )\r
+{\r
+  EFI_SIMPLE_NETWORK_MODE * pMode;\r
+  NIC_DEVICE * pNicDevice;\r
+  RX_TX_PACKET * pRxPacket;\r
+  EFI_STATUS Status;\r
+  EFI_TPL TplPrevious;\r
+\r
+  DBG_ENTER ( );\r
+\r
+  //\r
+  //  Verify the parameters\r
+  //\r
+  if (( NULL != pSimpleNetwork ) && ( NULL != pSimpleNetwork->Mode )) {\r
+    //\r
+    //  Synchronize with Ax88772Timer\r
+    //\r
+    VERIFY_TPL ( TPL_AX88772 );\r
+    TplPrevious = gBS->RaiseTPL ( TPL_AX88772 );\r
+\r
+    //\r
+    //  Update the device state\r
+    //\r
+    pNicDevice = DEV_FROM_SIMPLE_NETWORK ( pSimpleNetwork );\r
+    pNicDevice->bComplete = FALSE;\r
+    pNicDevice->bLinkUp = FALSE;\r
+\r
+    pMode = pSimpleNetwork->Mode;\r
+    pMode->MediaPresent = FALSE;\r
+\r
+    //\r
+    //  Discard any received packets\r
+    //\r
+    while ( NULL != pNicDevice->pRxHead ) {\r
+      //\r
+      //  Remove the packet from the received packet list\r
+      //\r
+      pRxPacket = pNicDevice->pRxHead;\r
+      pNicDevice->pRxHead = pRxPacket->pNext;\r
+\r
+      //\r
+      //  Queue the packet to the free list\r
+      //\r
+      pRxPacket->pNext = pNicDevice->pRxFree;\r
+      pNicDevice->pRxFree = pRxPacket;\r
+    }\r
+    pNicDevice->pRxTail = NULL;\r
+\r
+    //\r
+    //  Reset the device\r
+    //\r
+    Status = Ax88772Reset ( pNicDevice );\r
+    if ( !EFI_ERROR ( Status )) {\r
+      //\r
+      //  Update the receive filters in the adapter\r
+      //\r
+      Status = ReceiveFilterUpdate ( pSimpleNetwork );\r
+\r
+      //\r
+      //  Try to get a connection to the network\r
+      //\r
+      if ( !EFI_ERROR ( Status )) {\r
+        //\r
+        //  Start the autonegotiation\r
+        //\r
+        Status = Ax88772NegotiateLinkStart ( pNicDevice );\r
+      }\r
+    }\r
+\r
+    //\r
+    //  Release the synchronization with Ax88772Timer\r
+    //\r
+    gBS->RestoreTPL ( TplPrevious );\r
+  }\r
+  else {\r
+    Status = EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  //\r
+  // Return the operation status\r
+  //\r
+  DBG_EXIT_STATUS ( Status );\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Initialize the simple network protocol.\r
+\r
+  This routine calls ::Ax88772MacAddressGet to obtain the\r
+  MAC address.\r
+\r
+  @param [in] pNicDevice       NIC_DEVICE_INSTANCE pointer\r
+\r
+  @retval EFI_SUCCESS     Setup was successful\r
+\r
+**/\r
+EFI_STATUS\r
+SN_Setup (\r
+  IN NIC_DEVICE * pNicDevice\r
+  )\r
+{\r
+  EFI_SIMPLE_NETWORK_MODE * pMode;\r
+  EFI_SIMPLE_NETWORK_PROTOCOL * pSimpleNetwork;\r
+  EFI_STATUS Status;\r
+\r
+  DBG_ENTER ( );\r
+\r
+  //\r
+  // Initialize the simple network protocol\r
+  //\r
+  pSimpleNetwork = &pNicDevice->SimpleNetwork;\r
+  pSimpleNetwork->Revision = EFI_SIMPLE_NETWORK_PROTOCOL_REVISION;\r
+  pSimpleNetwork->Start = (EFI_SIMPLE_NETWORK_START)SN_Start;\r
+  pSimpleNetwork->Stop = (EFI_SIMPLE_NETWORK_STOP)SN_Stop;\r
+  pSimpleNetwork->Initialize = (EFI_SIMPLE_NETWORK_INITIALIZE)SN_Initialize;\r
+  pSimpleNetwork->Reset = (EFI_SIMPLE_NETWORK_RESET)SN_Reset;\r
+  pSimpleNetwork->Shutdown = (EFI_SIMPLE_NETWORK_SHUTDOWN)SN_Shutdown;\r
+  pSimpleNetwork->ReceiveFilters = (EFI_SIMPLE_NETWORK_RECEIVE_FILTERS)SN_ReceiveFilters;\r
+  pSimpleNetwork->StationAddress = (EFI_SIMPLE_NETWORK_STATION_ADDRESS)SN_StationAddress;\r
+  pSimpleNetwork->Statistics = (EFI_SIMPLE_NETWORK_STATISTICS)SN_Statistics;\r
+  pSimpleNetwork->MCastIpToMac = (EFI_SIMPLE_NETWORK_MCAST_IP_TO_MAC)SN_MCastIPtoMAC;\r
+  pSimpleNetwork->NvData = (EFI_SIMPLE_NETWORK_NVDATA)SN_NvData;\r
+  pSimpleNetwork->GetStatus = (EFI_SIMPLE_NETWORK_GET_STATUS)SN_GetStatus;\r
+  pSimpleNetwork->Transmit = (EFI_SIMPLE_NETWORK_TRANSMIT)SN_Transmit;\r
+  pSimpleNetwork->Receive = (EFI_SIMPLE_NETWORK_RECEIVE)SN_Receive;\r
+  pSimpleNetwork->WaitForPacket = NULL;\r
+  pMode = &pNicDevice->SimpleNetworkData;\r
+  pSimpleNetwork->Mode = pMode;\r
+\r
+  pMode->State = EfiSimpleNetworkStopped;\r
+  pMode->HwAddressSize = PXE_HWADDR_LEN_ETHER;\r
+  pMode->MediaHeaderSize = sizeof ( ETHERNET_HEADER );\r
+  pMode->MaxPacketSize = AX88772_MAX_PKT_SIZE;\r
+  pMode->NvRamSize = 0;\r
+  pMode->NvRamAccessSize = 0;\r
+  pMode->ReceiveFilterMask = EFI_SIMPLE_NETWORK_RECEIVE_UNICAST\r
+                           | EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST\r
+                           | EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST\r
+                           | EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS\r
+                           | EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST;\r
+  pMode->ReceiveFilterSetting = EFI_SIMPLE_NETWORK_RECEIVE_UNICAST\r
+                              | EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST;\r
+  pMode->MaxMCastFilterCount = MAX_MCAST_FILTER_CNT;\r
+  pMode->MCastFilterCount = 0;\r
+  SetMem ( &pMode->BroadcastAddress,\r
+           PXE_HWADDR_LEN_ETHER,\r
+           0xff );\r
+  pMode->IfType = EfiNetworkInterfaceUndi;\r
+  pMode->MacAddressChangeable = TRUE;\r
+  pMode->MultipleTxSupported = TRUE;\r
+  pMode->MediaPresentSupported = TRUE;\r
+  pMode->MediaPresent = FALSE;\r
+\r
+  //\r
+  //  Read the MAC address\r
+  //\r
+  pNicDevice->PhyId = PHY_ID_INTERNAL;\r
+  pNicDevice->b100Mbps = TRUE;\r
+  pNicDevice->bFullDuplex = TRUE;\r
+  Status = Ax88772MacAddressGet (\r
+                pNicDevice,\r
+                &pMode->PermanentAddress.Addr[0]);\r
+  if ( !EFI_ERROR ( Status )) {\r
+    //\r
+    //  Display the MAC address\r
+    //\r
+    DEBUG (( DEBUG_MAC_ADDRESS | DEBUG_INFO,\r
+              "MAC: %02x-%02x-%02x-%02x-%02x-%02x\n",\r
+              pMode->PermanentAddress.Addr[0],\r
+              pMode->PermanentAddress.Addr[1],\r
+              pMode->PermanentAddress.Addr[2],\r
+              pMode->PermanentAddress.Addr[3],\r
+              pMode->PermanentAddress.Addr[4],\r
+              pMode->PermanentAddress.Addr[5]));\r
+\r
+    //\r
+    //  Use the hardware address as the current address\r
+    //\r
+    CopyMem ( &pMode->CurrentAddress,\r
+              &pMode->PermanentAddress,\r
+              PXE_HWADDR_LEN_ETHER );\r
+  }\r
+\r
+  //\r
+  //  Return the setup status\r
+  //\r
+  DBG_EXIT_STATUS ( Status );\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  This routine starts the network interface.\r
+\r
+  @param [in] pSimpleNetwork    Protocol instance pointer\r
+\r
+  @retval EFI_SUCCESS           This operation was successful.\r
+  @retval EFI_ALREADY_STARTED   The network interface was already started.\r
+  @retval EFI_INVALID_PARAMETER pSimpleNetwork parameter was NULL or did not point to a valid\r
+                                EFI_SIMPLE_NETWORK_PROTOCOL structure.\r
+  @retval EFI_DEVICE_ERROR      The command could not be sent to the network interface.\r
+  @retval EFI_UNSUPPORTED       The increased buffer size feature is not supported.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SN_Start (\r
+  IN EFI_SIMPLE_NETWORK_PROTOCOL * pSimpleNetwork\r
+  )\r
+{\r
+  NIC_DEVICE * pNicDevice;\r
+  EFI_SIMPLE_NETWORK_MODE * pMode;\r
+  EFI_STATUS Status;\r
+  \r
+  DBG_ENTER ( );\r
+  \r
+  //\r
+  // Verify the parameters\r
+  //\r
+  Status = EFI_INVALID_PARAMETER;\r
+  if (( NULL != pSimpleNetwork ) && ( NULL != pSimpleNetwork->Mode )) {\r
+    pMode = pSimpleNetwork->Mode;\r
+    if ( EfiSimpleNetworkStopped == pMode->State ) {\r
+      //\r
+      // Initialize the mode structure\r
+      // NVRAM access is not supported\r
+      //\r
+      ZeroMem ( pMode, sizeof ( *pMode ));\r
+  \r
+      pMode->State = EfiSimpleNetworkStarted;\r
+      pMode->HwAddressSize = PXE_HWADDR_LEN_ETHER;\r
+      pMode->MediaHeaderSize = sizeof ( ETHERNET_HEADER );\r
+      pMode->MaxPacketSize = AX88772_MAX_PKT_SIZE;\r
+      pMode->ReceiveFilterMask = EFI_SIMPLE_NETWORK_RECEIVE_UNICAST\r
+                               | EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST\r
+                               | EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST\r
+                               | EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS\r
+                               | EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST;\r
+      pMode->ReceiveFilterSetting = EFI_SIMPLE_NETWORK_RECEIVE_UNICAST;\r
+      pMode->MaxMCastFilterCount = MAX_MCAST_FILTER_CNT;\r
+      pNicDevice = DEV_FROM_SIMPLE_NETWORK ( pSimpleNetwork );\r
+      Status = Ax88772MacAddressGet ( pNicDevice, &pMode->PermanentAddress.Addr[0]);\r
+      CopyMem ( &pMode->CurrentAddress,\r
+                &pMode->PermanentAddress,\r
+                sizeof ( pMode->CurrentAddress ));\r
+      pMode->BroadcastAddress.Addr[0] = 0xff;\r
+      pMode->BroadcastAddress.Addr[1] = 0xff;\r
+      pMode->BroadcastAddress.Addr[2] = 0xff;\r
+      pMode->BroadcastAddress.Addr[3] = 0xff;\r
+      pMode->BroadcastAddress.Addr[4] = 0xff;\r
+      pMode->BroadcastAddress.Addr[5] = 0xff;\r
+      pMode->IfType = 1;\r
+      pMode->MacAddressChangeable = TRUE;\r
+      pMode->MultipleTxSupported = TRUE;\r
+      pMode->MediaPresentSupported = TRUE;\r
+      pMode->MediaPresent = FALSE;\r
+    }\r
+    else {\r
+      Status = EFI_ALREADY_STARTED;\r
+    }\r
+  }\r
+  \r
+  //\r
+  // Return the operation status\r
+  //\r
+  DBG_EXIT_STATUS ( Status );\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Set the MAC address.\r
+  \r
+  This function modifies or resets the current station address of a\r
+  network interface.  If Reset is TRUE, then the current station address\r
+  is set ot the network interface's permanent address.  If Reset if FALSE\r
+  then the current station address is changed to the address specified by\r
+  pNew.\r
+\r
+  This routine calls ::Ax88772MacAddressSet to update the MAC address\r
+  in the network adapter.\r
+\r
+  @param [in] pSimpleNetwork    Protocol instance pointer\r
+  @param [in] bReset            Flag used to reset the station address to the\r
+                                network interface's permanent address.\r
+  @param [in] pNew              New station address to be used for the network\r
+                                interface.\r
+\r
+  @retval EFI_SUCCESS           This operation was successful.\r
+  @retval EFI_NOT_STARTED       The network interface was not started.\r
+  @retval EFI_INVALID_PARAMETER pSimpleNetwork parameter was NULL or did not point to a valid\r
+                                EFI_SIMPLE_NETWORK_PROTOCOL structure.\r
+  @retval EFI_DEVICE_ERROR      The command could not be sent to the network interface.\r
+  @retval EFI_UNSUPPORTED       The increased buffer size feature is not supported.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SN_StationAddress (\r
+  IN EFI_SIMPLE_NETWORK_PROTOCOL * pSimpleNetwork,\r
+  IN BOOLEAN bReset,\r
+  IN EFI_MAC_ADDRESS * pNew\r
+  )\r
+{\r
+  NIC_DEVICE * pNicDevice;\r
+  EFI_SIMPLE_NETWORK_MODE * pMode;\r
+  EFI_STATUS Status;\r
+\r
+  DBG_ENTER ( );\r
+\r
+  //\r
+  // Verify the parameters\r
+  //\r
+  if (( NULL != pSimpleNetwork )\r
+    && ( NULL != pSimpleNetwork->Mode )\r
+    && (( !bReset ) || ( bReset && ( NULL != pNew )))) {\r
+    //\r
+    // Verify that the adapter is already started\r
+    //\r
+    pNicDevice = DEV_FROM_SIMPLE_NETWORK ( pSimpleNetwork );\r
+    pMode = pSimpleNetwork->Mode;\r
+    if ( EfiSimpleNetworkStarted == pMode->State ) {\r
+      //\r
+      // Determine the adapter MAC address\r
+      //\r
+      if ( bReset ) {\r
+        //\r
+        // Use the permanent address\r
+        //\r
+        CopyMem ( &pMode->CurrentAddress,\r
+                  &pMode->PermanentAddress,\r
+                  sizeof ( pMode->CurrentAddress ));\r
+      }\r
+      else {\r
+        //\r
+        // Use the specified address\r
+        //\r
+        CopyMem ( &pMode->CurrentAddress,\r
+                  pNew,\r
+                  sizeof ( pMode->CurrentAddress ));\r
+      }\r
+\r
+      //\r
+      // Update the address on the adapter\r
+      //\r
+      Status = Ax88772MacAddressSet ( pNicDevice, &pMode->CurrentAddress.Addr[0]);\r
+    }\r
+    else {\r
+      Status = EFI_NOT_STARTED;\r
+    }\r
+  }\r
+  else {\r
+    Status = EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  //\r
+  // Return the operation status\r
+  //\r
+  DBG_EXIT_STATUS ( Status );\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  This function resets or collects the statistics on a network interface.\r
+  If the size of the statistics table specified by StatisticsSize is not\r
+  big enough for all of the statistics that are collected by the network\r
+  interface, then a partial buffer of statistics is returned in\r
+  StatisticsTable.\r
+\r
+  @param [in] pSimpleNetwork    Protocol instance pointer\r
+  @param [in] bReset            Set to TRUE to reset the statistics for the network interface.\r
+  @param [in, out] pStatisticsSize  On input the size, in bytes, of StatisticsTable.  On output\r
+                                the size, in bytes, of the resulting table of statistics.\r
+  @param [out] pStatisticsTable A pointer to the EFI_NETWORK_STATISTICS structure that\r
+                                conains the statistics.\r
+\r
+  @retval EFI_SUCCESS           This operation was successful.\r
+  @retval EFI_NOT_STARTED       The network interface was not started.\r
+  @retval EFI_BUFFER_TOO_SMALL  The pStatisticsTable is NULL or the buffer is too small.\r
+  @retval EFI_INVALID_PARAMETER pSimpleNetwork parameter was NULL or did not point to a valid\r
+                                EFI_SIMPLE_NETWORK_PROTOCOL structure.\r
+  @retval EFI_DEVICE_ERROR      The command could not be sent to the network interface.\r
+  @retval EFI_UNSUPPORTED       The increased buffer size feature is not supported.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SN_Statistics (\r
+  IN EFI_SIMPLE_NETWORK_PROTOCOL * pSimpleNetwork,\r
+  IN BOOLEAN bReset,\r
+  IN OUT UINTN * pStatisticsSize,\r
+  OUT EFI_NETWORK_STATISTICS * pStatisticsTable\r
+  )\r
+{\r
+  EFI_STATUS Status;\r
+\r
+  DBG_ENTER ( );\r
+\r
+  //\r
+  // This is not currently supported\r
+  //\r
+  Status = EFI_UNSUPPORTED;\r
+\r
+  //\r
+  // Return the operation status\r
+  //\r
+  DBG_EXIT_STATUS ( Status );\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  This function stops a network interface.  This call is only valid\r
+  if the network interface is in the started state.\r
+\r
+  @param [in] pSimpleNetwork    Protocol instance pointer\r
+\r
+  @retval EFI_SUCCESS           This operation was successful.\r
+  @retval EFI_NOT_STARTED       The network interface was not started.\r
+  @retval EFI_INVALID_PARAMETER pSimpleNetwork parameter was NULL or did not point to a valid\r
+                                EFI_SIMPLE_NETWORK_PROTOCOL structure.\r
+  @retval EFI_DEVICE_ERROR      The command could not be sent to the network interface.\r
+  @retval EFI_UNSUPPORTED       The increased buffer size feature is not supported.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SN_Stop (\r
+  IN EFI_SIMPLE_NETWORK_PROTOCOL * pSimpleNetwork\r
+  )\r
+{\r
+  EFI_SIMPLE_NETWORK_MODE * pMode;\r
+  EFI_STATUS Status;\r
+  \r
+  DBG_ENTER ( );\r
+  \r
+  //\r
+  // Verify the parameters\r
+  //\r
+  if (( NULL != pSimpleNetwork ) && ( NULL != pSimpleNetwork->Mode )) {\r
+    //\r
+    // Determine if the interface is started\r
+    //\r
+    pMode = pSimpleNetwork->Mode;\r
+    if ( EfiSimpleNetworkStopped != pMode->State ) {\r
+      if ( EfiSimpleNetworkStarted == pMode->State ) {\r
+        //\r
+        //  Release the resources acquired in SN_Start\r
+        //\r
+\r
+        //\r
+        //  Mark the adapter as stopped\r
+        //\r
+        pMode->State = EfiSimpleNetworkStopped;\r
+        Status = EFI_SUCCESS;\r
+      }\r
+      else {\r
+        Status = EFI_UNSUPPORTED;\r
+      }\r
+    }\r
+    else {\r
+      Status = EFI_NOT_STARTED;\r
+    }\r
+  }\r
+  else {\r
+    Status = EFI_INVALID_PARAMETER;\r
+  }\r
+  \r
+  //\r
+  // Return the operation status\r
+  //\r
+  DBG_EXIT_STATUS ( Status );\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  This function releases the memory buffers assigned in the Initialize() call.\r
+  Pending transmits and receives are lost, and interrupts are cleared and disabled.\r
+  After this call, only Initialize() and Stop() calls may be used.\r
+\r
+  @param [in] pSimpleNetwork    Protocol instance pointer\r
+\r
+  @retval EFI_SUCCESS           This operation was successful.\r
+  @retval EFI_NOT_STARTED       The network interface was not started.\r
+  @retval EFI_INVALID_PARAMETER pSimpleNetwork parameter was NULL or did not point to a valid\r
+                                EFI_SIMPLE_NETWORK_PROTOCOL structure.\r
+  @retval EFI_DEVICE_ERROR      The command could not be sent to the network interface.\r
+  @retval EFI_UNSUPPORTED       The increased buffer size feature is not supported.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SN_Shutdown (\r
+  IN EFI_SIMPLE_NETWORK_PROTOCOL * pSimpleNetwork\r
+  )\r
+{\r
+  EFI_SIMPLE_NETWORK_MODE * pMode;\r
+  UINT32 RxFilter;\r
+  EFI_STATUS Status;\r
+  \r
+  DBG_ENTER ( );\r
+  \r
+  //\r
+  // Verify the parameters\r
+  //\r
+  if (( NULL != pSimpleNetwork ) && ( NULL != pSimpleNetwork->Mode )) {\r
+    //\r
+    // Determine if the interface is already started\r
+    //\r
+    pMode = pSimpleNetwork->Mode;\r
+    if ( EfiSimpleNetworkInitialized == pMode->State ) {\r
+      //\r
+      // Stop the adapter\r
+      //\r
+      RxFilter = pMode->ReceiveFilterSetting;\r
+      pMode->ReceiveFilterSetting = 0;\r
+      Status = SN_Reset ( pSimpleNetwork, FALSE );\r
+      pMode->ReceiveFilterSetting = RxFilter;\r
+      if ( !EFI_ERROR ( Status )) {\r
+        //\r
+        // Release the resources acquired by SN_Initialize\r
+        //\r
+\r
+        //\r
+        // Update the network state\r
+        //\r
+        pMode->State = EfiSimpleNetworkStarted;\r
+      }\r
+    }\r
+    else {\r
+      Status = EFI_NOT_STARTED;\r
+    }\r
+  }\r
+  else {\r
+    Status = EFI_INVALID_PARAMETER;\r
+  }\r
+  \r
+  //\r
+  // Return the operation status\r
+  //\r
+  DBG_EXIT_STATUS ( Status );\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Send a packet over the network.\r
+\r
+  This function places the packet specified by Header and Buffer on\r
+  the transmit queue.  This function performs a non-blocking transmit\r
+  operation.  When the transmit is complete, the buffer is returned\r
+  via the GetStatus() call.\r
+\r
+  This routine calls ::Ax88772Rx to empty the network adapter of\r
+  receive packets.  The routine then passes the transmit packet\r
+  to the network adapter.\r
+\r
+  @param [in] pSimpleNetwork    Protocol instance pointer\r
+  @param [in] HeaderSize        The size, in bytes, of the media header to be filled in by\r
+                                the Transmit() function.  If HeaderSize is non-zero, then\r
+                                it must be equal to SimpleNetwork->Mode->MediaHeaderSize\r
+                                and DestAddr and Protocol parameters must not be NULL.\r
+  @param [in] BufferSize        The size, in bytes, of the entire packet (media header and\r
+                                data) to be transmitted through the network interface.\r
+  @param [in] pBuffer           A pointer to the packet (media header followed by data) to\r
+                                to be transmitted.  This parameter can not be NULL.  If\r
+                                HeaderSize is zero, then the media header is Buffer must\r
+                                already be filled in by the caller.  If HeaderSize is nonzero,\r
+                                then the media header will be filled in by the Transmit()\r
+                                function.\r
+  @param [in] pSrcAddr          The source HW MAC address.  If HeaderSize is zero, then\r
+                                this parameter is ignored.  If HeaderSize is nonzero and\r
+                                SrcAddr is NULL, then SimpleNetwork->Mode->CurrentAddress\r
+                                is used for the source HW MAC address.\r
+  @param [in] pDestAddr         The destination HW MAC address.  If HeaderSize is zero, then\r
+                                this parameter is ignored.\r
+  @param [in] pProtocol         The type of header to build.  If HeaderSize is zero, then\r
+                                this parameter is ignored.\r
+\r
+  @retval EFI_SUCCESS           This operation was successful.\r
+  @retval EFI_NOT_STARTED       The network interface was not started.\r
+  @retval EFI_NOT_READY         The network interface is too busy to accept this transmit request.\r
+  @retval EFI_BUFFER_TOO_SMALL  The BufferSize parameter is too small.\r
+  @retval EFI_INVALID_PARAMETER pSimpleNetwork parameter was NULL or did not point to a valid\r
+                                EFI_SIMPLE_NETWORK_PROTOCOL structure.\r
+  @retval EFI_DEVICE_ERROR      The command could not be sent to the network interface.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SN_Transmit (\r
+  IN EFI_SIMPLE_NETWORK_PROTOCOL * pSimpleNetwork,\r
+  IN UINTN HeaderSize,\r
+  IN UINTN BufferSize,\r
+  IN VOID * pBuffer,\r
+  IN EFI_MAC_ADDRESS * pSrcAddr,\r
+  IN EFI_MAC_ADDRESS * pDestAddr,\r
+  IN UINT16 * pProtocol\r
+  )\r
+{\r
+  RX_TX_PACKET Packet;\r
+  ETHERNET_HEADER * pHeader;\r
+  EFI_SIMPLE_NETWORK_MODE * pMode;\r
+  NIC_DEVICE * pNicDevice;\r
+  EFI_USB_IO_PROTOCOL * pUsbIo;\r
+  EFI_STATUS Status;\r
+  EFI_TPL TplPrevious;\r
+  UINTN TransferLength;\r
+  UINT32 TransferStatus;\r
+  UINT16 Type;\r
+\r
+  DBG_ENTER ( );\r
+\r
+  //\r
+  // Verify the parameters\r
+  //\r
+  if (( NULL != pSimpleNetwork ) && ( NULL != pSimpleNetwork->Mode )) {\r
+    //\r
+    // The interface must be running\r
+    //\r
+    pMode = pSimpleNetwork->Mode;\r
+    if ( EfiSimpleNetworkInitialized == pMode->State ) {\r
+      //\r
+      //  Synchronize with Ax88772Timer\r
+      //\r
+      VERIFY_TPL ( TPL_AX88772 );\r
+      TplPrevious = gBS->RaiseTPL ( TPL_AX88772 );\r
+\r
+      //\r
+      // Update the link status\r
+      //\r
+      pNicDevice = DEV_FROM_SIMPLE_NETWORK ( pSimpleNetwork );\r
+      Ax88772Rx ( pNicDevice, FALSE );\r
+      pMode->MediaPresent = pNicDevice->bLinkUp;\r
+\r
+      //\r
+      //  Release the synchronization with Ax88772Timer\r
+      //\r
+      gBS->RestoreTPL ( TplPrevious );\r
+      if ( pMode->MediaPresent ) {\r
+        //\r
+        //  Copy the packet into the USB buffer\r
+        //\r
+        CopyMem ( &Packet.Data[0], pBuffer, BufferSize );\r
+        Packet.Length = (UINT16) BufferSize;\r
+\r
+        //\r
+        //  Transmit the packet\r
+        //\r
+        pHeader = (ETHERNET_HEADER *) &Packet.Data[0];\r
+        if ( 0 != HeaderSize ) {\r
+          if ( NULL != pDestAddr ) {\r
+            CopyMem ( &pHeader->dest_addr, pDestAddr, PXE_HWADDR_LEN_ETHER );\r
+          }\r
+          if ( NULL != pSrcAddr ) {\r
+            CopyMem ( &pHeader->src_addr, pSrcAddr, PXE_HWADDR_LEN_ETHER );\r
+          }\r
+          else {\r
+            CopyMem ( &pHeader->src_addr, &pMode->CurrentAddress.Addr[0], PXE_HWADDR_LEN_ETHER );\r
+          }\r
+          if ( NULL != pProtocol ) {\r
+            Type = *pProtocol;\r
+          }\r
+          else {\r
+            Type = Packet.Length;\r
+          }\r
+          Type = (UINT16)(( Type >> 8 ) | ( Type << 8 ));\r
+          pHeader->type = Type;\r
+        }\r
+        if ( Packet.Length < MIN_ETHERNET_PKT_SIZE ) {\r
+          Packet.Length = MIN_ETHERNET_PKT_SIZE;\r
+          ZeroMem ( &Packet.Data[ BufferSize ],\r
+                    Packet.Length - BufferSize );\r
+        }\r
+        DEBUG (( DEBUG_TX | DEBUG_INFO,\r
+                  "TX: %02x-%02x-%02x-%02x-%02x-%02x  %02x-%02x-%02x-%02x-%02x-%02x  %02x-%02x  %d bytes\r\n",\r
+                  Packet.Data[0],\r
+                  Packet.Data[1],\r
+                  Packet.Data[2],\r
+                  Packet.Data[3],\r
+                  Packet.Data[4],\r
+                  Packet.Data[5],\r
+                  Packet.Data[6],\r
+                  Packet.Data[7],\r
+                  Packet.Data[8],\r
+                  Packet.Data[9],\r
+                  Packet.Data[10],\r
+                  Packet.Data[11],\r
+                  Packet.Data[12],\r
+                  Packet.Data[13],\r
+                  Packet.Length ));\r
+        Packet.LengthBar = ~Packet.Length;\r
+        TransferLength = sizeof ( Packet.Length )\r
+                       + sizeof ( Packet.LengthBar )\r
+                       + Packet.Length;\r
+\r
+        //\r
+        //  Work around USB bus driver bug where a timeout set by receive\r
+        //  succeeds but the timeout expires immediately after, causing the\r
+        //  transmit operation to timeout.\r
+        //\r
+        pUsbIo = pNicDevice->pUsbIo;\r
+        Status = pUsbIo->UsbBulkTransfer ( pUsbIo,\r
+                                           BULK_OUT_ENDPOINT,\r
+                                           &Packet.Length,\r
+                                           &TransferLength,\r
+                                           0xfffffffe,\r
+                                           &TransferStatus );\r
+        if ( !EFI_ERROR ( Status )) {\r
+          Status = TransferStatus;\r
+        }\r
+        if (( !EFI_ERROR ( Status ))\r
+          && ( TransferLength != (UINTN)( Packet.Length + 4 ))) {\r
+          Status = EFI_WARN_WRITE_FAILURE;\r
+        }\r
+        if ( EFI_SUCCESS == Status ) {\r
+          pNicDevice->pTxBuffer = pBuffer;\r
+        }\r
+        else {\r
+          DEBUG (( DEBUG_ERROR | DEBUG_INFO,\r
+                    "Ax88772 USB transmit error, TransferLength: %d, Status: %r\r\n",\r
+                    sizeof ( Packet.Length ) + Packet.Length,\r
+                    Status ));\r
+          //\r
+          //  Reset the controller to fix the error\r
+          //\r
+          if ( EFI_DEVICE_ERROR == Status ) {\r
+            SN_Reset ( pSimpleNetwork, FALSE );\r
+          }\r
+        }\r
+      }\r
+      else {\r
+        //\r
+        // No packets available.\r
+        //\r
+        Status = EFI_NOT_READY;\r
+      }\r
+    }\r
+    else {\r
+      Status = EFI_NOT_STARTED;\r
+    }\r
+  }\r
+  else {\r
+    DEBUG (( DEBUG_ERROR | DEBUG_INFO,\r
+              "Ax88772 invalid transmit parameter\r\n"\r
+              "  0x%08x: HeaderSize\r\n"\r
+              "  0x%08x: BufferSize\r\n"\r
+              "  0x%08x: Buffer\r\n"\r
+              "  0x%08x: SrcAddr\r\n"\r
+              "  0x%08x: DestAddr\r\n"\r
+              "  0x%04x:     Protocol\r\n",\r
+              HeaderSize,\r
+              BufferSize,\r
+              pBuffer,\r
+              pSrcAddr,\r
+              pDestAddr,\r
+              pProtocol ));\r
+    Status = EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  //\r
+  // Return the operation status\r
+  //\r
+  DBG_EXIT_STATUS ( Status );\r
+  return Status;\r
+}\r