]> git.proxmox.com Git - mirror_edk2.git/blobdiff - OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772b/SimpleNetwork.c
Contributed-under: TianoCore Contribution Agreement 1.0
[mirror_edk2.git] / OptionRomPkg / Bus / Usb / UsbNetworking / Ax88772b / SimpleNetwork.c
diff --git a/OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772b/SimpleNetwork.c b/OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772b/SimpleNetwork.c
new file mode 100644 (file)
index 0000000..be75161
--- /dev/null
@@ -0,0 +1,1574 @@
+/** @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
+  //\r
+  // Set the MAC address\r
+  //\r
+  pNicDevice = DEV_FROM_SIMPLE_NETWORK ( pSimpleNetwork );\r
+  pMode = pSimpleNetwork->Mode;\r
+\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; Index < pMode->MCastFilterCount; Index++ ) {\r
+        //\r
+        // Enable the next multicast address\r
+        //\r
+        Ax88772MulticastSet ( pNicDevice,\r
+                              &pMode->MCastFilter[ Index ].Addr[0]);\r
+      }\r
+  }\r
+\r
+  Status = Ax88772RxControl ( pNicDevice, pMode->ReceiveFilterSetting );\r
+\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
+  EFI_SIMPLE_NETWORK_MODE * pMode;\r
+  NIC_DEVICE * pNicDevice;\r
+  EFI_STATUS Status;\r
+  BOOLEAN bFullDuplex;\r
+  BOOLEAN bLinkUp;\r
+  BOOLEAN bSpeed100;\r
+  EFI_TPL TplPrevious;\r
\r
+  TplPrevious = gBS->RaiseTPL(TPL_CALLBACK);\r
+  //\r
+  // Verify the parameters\r
+  //\r
+  if (( NULL != pSimpleNetwork ) && ( NULL != pSimpleNetwork->Mode )) {\r
+    //\r
+    // Return the transmit buffer\r
+    //\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 ( EfiSimpleNetworkInitialized == pMode->State ) {\r
+\r
+      if ( pNicDevice->LinkIdleCnt > MAX_LINKIDLE_THRESHOLD) {\r
+\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 (( EFI_D_INFO , "Reset to establish proper link setup: %d Mbps, %a duplex\r\n",\r
+                                    pNicDevice->b100Mbps ? 100 : 10, pNicDevice->bFullDuplex ? "Full" : "Half"));\r
+                          Status = SN_Reset ( &pNicDevice->SimpleNetwork, FALSE );\r
+                  }\r
+                  if (( !bLinkUp ) && pNicDevice->bLinkUp ) {\r
+                      //\r
+                      // Display the autonegotiation status\r
+                      //\r
+                      DEBUG (( EFI_D_INFO , "Link: Up, %d Mbps, %a duplex\r\n",\r
+                                pNicDevice->b100Mbps ? 100 : 10, pNicDevice->bFullDuplex ? "Full" : "Half"));\r
+\r
+                  }\r
+                  pNicDevice->LinkIdleCnt = 0;\r
+            }\r
+        }\r
+        //\r
+        //  Update the link status\r
+        //\r
+        if ( bLinkUp && ( !pNicDevice->bLinkUp )) {\r
+            DEBUG (( EFI_D_INFO , "Link: Down\r\n"));\r
+        }\r
+      }\r
+\r
+      pMode->MediaPresent = pNicDevice->bLinkUp;\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
+  }\r
+  else {\r
+    Status = EFI_INVALID_PARAMETER;\r
+  }\r
+  gBS->RestoreTPL(TplPrevious) ;\r
+\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
+  UINT32  TmpState;\r
+   EFI_TPL TplPrevious;\r
+   \r
+   TplPrevious = gBS->RaiseTPL (TPL_CALLBACK);\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
+        TmpState = pMode->State;\r
+        pMode->State = EfiSimpleNetworkInitialized;\r
+        Status = SN_Reset ( pSimpleNetwork, FALSE );\r
+        if ( EFI_ERROR ( Status )) {\r
+          //\r
+          // Update the network state\r
+          //\r
+          pMode->State = TmpState;\r
+          DEBUG (( EFI_D_ERROR , "SN_reset failed\n"));\r
+        }\r
+      }\r
+      else {\r
+        DEBUG (( EFI_D_ERROR , "Increase ExtraRxBufferSize = %d ExtraTxBufferSize=%d\n", \r
+              ExtraRxBufferSize, ExtraTxBufferSize));\r
+        Status = EFI_UNSUPPORTED;\r
+      }\r
+    }\r
+    else {\r
+      Status = EFI_NOT_STARTED;\r
+    }\r
+  }\r
+  else {\r
+    Status = EFI_INVALID_PARAMETER;\r
+  }\r
+  gBS->RestoreTPL (TplPrevious);\r
+\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
+  EFI_TPL TplPrevious;\r
+\r
+  TplPrevious = gBS->RaiseTPL(TPL_CALLBACK);\r
+  //\r
+  // Get pointer to SNP driver instance for *this.\r
+  //\r
+  if (pSimpleNetwork == NULL) {\r
+    gBS->RestoreTPL(TplPrevious);\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (pIP == NULL || pMAC == NULL) {\r
+    gBS->RestoreTPL(TplPrevious);\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (bIPv6){\r
+    Status = EFI_UNSUPPORTED;\r
+  }  \r
+  else {\r
+      //\r
+      // check if the ip given is a mcast IP\r
+      //\r
+      if ((pIP->v4.Addr[0] & 0xF0) != 0xE0) {\r
+        gBS->RestoreTPL(TplPrevious);\r
+        return EFI_INVALID_PARAMETER;\r
+      }\r
+      else {\r
+        pMAC->Addr[0] = 0x01;\r
+        pMAC->Addr[1] = 0x00;\r
+        pMAC->Addr[2] = 0x5e;\r
+        pMAC->Addr[3] = (UINT8) (pIP->v4.Addr[1] & 0x7f);\r
+        pMAC->Addr[4] = (UINT8) pIP->v4.Addr[2];\r
+        pMAC->Addr[5] = (UINT8) pIP->v4.Addr[3];\r
+        Status = EFI_SUCCESS;\r
+        gBS->RestoreTPL(TplPrevious);\r
+      }\r
+  }\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
+  // This is not currently supported\r
+  //\r
+  Status = EFI_UNSUPPORTED;\r
+  return Status;\r
+}\r
+\r
+VOID \r
+FillPkt2Queue (\r
+  IN EFI_SIMPLE_NETWORK_PROTOCOL * pSimpleNetwork,\r
+  IN UINTN BufLength)\r
+{\r
+\r
+  UINT16 * pLength;\r
+  UINT16 * pLengthBar;\r
+  UINT8* pData;\r
+  UINT32 offset;\r
+  NIC_DEVICE * pNicDevice;\r
+  \r
+  pNicDevice = DEV_FROM_SIMPLE_NETWORK ( pSimpleNetwork);\r
+  for ( offset = 0; offset < BufLength; ){\r
+      pLength = (UINT16*) (pNicDevice->pBulkInBuff + offset);\r
+      pLengthBar = (UINT16*) (pNicDevice->pBulkInBuff + offset +2);\r
+      \r
+      *pLength &= 0x7ff;\r
+      *pLengthBar &= 0x7ff;\r
+      *pLengthBar |= 0xf800;\r
+      \r
+      if ((*pLength ^ *pLengthBar ) != 0xFFFF) {\r
+          DEBUG (( EFI_D_ERROR , "Pkt length error. BufLength = %d\n", BufLength));\r
+          return;\r
+      }          \r
+      \r
+      if (TRUE == pNicDevice->pNextFill->f_Used) {\r
+        return;\r
+      }\r
+      else {\r
+          pData = pNicDevice->pBulkInBuff + offset + 4;\r
+          pNicDevice->pNextFill->f_Used = TRUE;\r
+          pNicDevice->pNextFill->Length = *pLength;\r
+          CopyMem (&pNicDevice->pNextFill->Data[0], pData, *pLength);\r
+          \r
+          pNicDevice->pNextFill = pNicDevice->pNextFill->pNext;\r
+          offset += ((*pLength + HW_HDR_LENGTH - 1) &~3) + 1;\r
+          pNicDevice->PktCntInQueue++;\r
+      }\r
+              \r
+  }\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
+  EFI_SIMPLE_NETWORK_MODE * pMode;\r
+  NIC_DEVICE * pNicDevice;\r
+  EFI_STATUS Status;\r
+  EFI_TPL TplPrevious;\r
+  UINT16 Type;\r
+  EFI_USB_IO_PROTOCOL *pUsbIo;\r
+  UINTN LengthInBytes;\r
+  UINT32 TransferStatus;\r
+  RX_PKT * pFirstFill;\r
+  TplPrevious = gBS->RaiseTPL (TPL_CALLBACK);\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
+      // Update the link status\r
+      //\r
+      pNicDevice = DEV_FROM_SIMPLE_NETWORK ( pSimpleNetwork );\r
+      pNicDevice->LinkIdleCnt++;\r
+      pMode->MediaPresent = pNicDevice->bLinkUp;\r
+      \r
+      if ( pMode->MediaPresent && pNicDevice->bComplete) {\r
+      \r
+      \r
+        if (pNicDevice->PktCntInQueue != 0 ) {\r
+            DEBUG (( EFI_D_INFO, "pNicDevice->PktCntInQueue = %d\n",\r
+                pNicDevice->PktCntInQueue));\r
+        }\r
+        \r
+        LengthInBytes = MAX_BULKIN_SIZE;\r
+        if (pNicDevice->PktCntInQueue == 0 ){\r
+            //\r
+            // Attempt to do bulk in\r
+            //\r
+            SetMem (&pNicDevice->pBulkInBuff[0], 4, 0);\r
+            pUsbIo = pNicDevice->pUsbIo;\r
+            Status = pUsbIo->UsbBulkTransfer ( pUsbIo,\r
+                                       USB_ENDPOINT_DIR_IN | BULK_IN_ENDPOINT,\r
+                                       &pNicDevice->pBulkInBuff[0],\r
+                                       &LengthInBytes,\r
+                                       BULKIN_TIMEOUT,\r
+                                       &TransferStatus );\r
+                                       \r
+            if (LengthInBytes != 0 && !EFI_ERROR(Status) && !EFI_ERROR(TransferStatus) ){\r
+                FillPkt2Queue(pSimpleNetwork, LengthInBytes);\r
+            }\r
+        }\r
+        \r
+        pFirstFill = pNicDevice->pFirstFill;\r
+         \r
+        if (TRUE == pFirstFill->f_Used) {\r
+            ETHERNET_HEADER * pHeader;\r
+            pNicDevice->LinkIdleCnt = 0;\r
+            CopyMem (pBuffer,  &pFirstFill->Data[0], pFirstFill->Length);\r
+            pHeader = (ETHERNET_HEADER *) &pFirstFill->Data[0];\r
+                     \r
+            DEBUG (( EFI_D_INFO, "RX: %02x-%02x-%02x-%02x-%02x-%02x " \r
+                      "%02x-%02x-%02x-%02x-%02x-%02x  %02x-%02x  %d bytes\r\n",\r
+                      pFirstFill->Data[0],\r
+                      pFirstFill->Data[1],\r
+                      pFirstFill->Data[2],\r
+                      pFirstFill->Data[3],\r
+                      pFirstFill->Data[4],\r
+                      pFirstFill->Data[5],\r
+                      pFirstFill->Data[6],\r
+                      pFirstFill->Data[7],\r
+                      pFirstFill->Data[8],\r
+                      pFirstFill->Data[9],\r
+                      pFirstFill->Data[10],\r
+                      pFirstFill->Data[11],\r
+                      pFirstFill->Data[12],\r
+                      pFirstFill->Data[13],\r
+                      pFirstFill->Length));   \r
+            \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
+            if (*pBufferSize < pFirstFill->Length) {\r
+                  DEBUG (( EFI_D_ERROR, "RX: Buffer was too small"));\r
+                  Status = EFI_BUFFER_TOO_SMALL;\r
+            }\r
+            *pBufferSize =  pFirstFill->Length;\r
+            pFirstFill->f_Used = FALSE;\r
+            pNicDevice->pFirstFill = pFirstFill->pNext;\r
+            pNicDevice->PktCntInQueue--;\r
+        }\r
+        else {\r
+            pNicDevice->LinkIdleCnt++;\r
+            Status = EFI_NOT_READY;\r
+        }\r
+      }\r
+      else {\r
+        //\r
+        //  Link no up\r
+        //\r
+        pNicDevice->LinkIdleCnt++;\r
+        Status = EFI_NOT_READY; \r
+      }\r
+      \r
+    }\r
+    else {\r
+      Status = EFI_NOT_STARTED;\r
+    }\r
+  }\r
+  else {\r
+    Status = EFI_INVALID_PARAMETER;\r
+  }                              \r
+  gBS->RestoreTPL (TplPrevious);\r
+  return Status;\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
+/*\r
+#define EFI_SIMPLE_NETWORK_RECEIVE_UNICAST               0x01\r
+#define EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST             0x02\r
+#define EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST             0x04\r
+#define EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS           0x08\r
+#define EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST 0x10\r
+*/\r
+  IN BOOLEAN bResetMCastFilter,\r
+  IN UINTN MCastFilterCnt,\r
+  IN EFI_MAC_ADDRESS * pMCastFilter\r
+  )\r
+{\r
+  EFI_SIMPLE_NETWORK_MODE * pMode;\r
+  EFI_STATUS Status = EFI_SUCCESS;   \r
+  EFI_TPL TplPrevious; \r
+  NIC_DEVICE * pNicDevice;\r
+\r
+  TplPrevious = gBS->RaiseTPL(TPL_CALLBACK);\r
+  pNicDevice = DEV_FROM_SIMPLE_NETWORK ( pSimpleNetwork );\r
+  pMode = pSimpleNetwork->Mode;\r
+\r
+  if (pSimpleNetwork == NULL) {\r
+    gBS->RestoreTPL(TplPrevious);\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  switch (pMode->State) {\r
+    case EfiSimpleNetworkInitialized:\r
+      break;\r
+    case EfiSimpleNetworkStopped:\r
+      Status = EFI_NOT_STARTED;\r
+      gBS->RestoreTPL(TplPrevious);\r
+      return Status;\r
+    default:\r
+      Status = EFI_DEVICE_ERROR;\r
+      gBS->RestoreTPL(TplPrevious);\r
+      return Status;\r
+  }\r
+\r
+  //\r
+  // check if we are asked to enable or disable something that the UNDI\r
+  // does not even support!\r
+  //\r
+  if (((Enable &~pMode->ReceiveFilterMask) != 0) ||\r
+    ((Disable &~pMode->ReceiveFilterMask) != 0)) {\r
+    Status = EFI_INVALID_PARAMETER;\r
+    gBS->RestoreTPL(TplPrevious);\r
+    return Status;\r
+  }\r
+  \r
+  if (bResetMCastFilter) {\r
+    Disable |= (EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST & pMode->ReceiveFilterMask);\r
+      pMode->MCastFilterCount = 0;\r
+      if ( (0 == (pMode->ReceiveFilterSetting & EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST)) \r
+            && Enable == 0 && Disable == 2) {\r
+            gBS->RestoreTPL(TplPrevious);\r
+            return EFI_SUCCESS;\r
+      }\r
+  } \r
+  else {\r
+    if (MCastFilterCnt != 0) {\r
+      UINTN i; \r
+      EFI_MAC_ADDRESS * pMulticastAddress;\r
+      pMulticastAddress =  pMCastFilter;\r
+      \r
+      if ((MCastFilterCnt > pMode->MaxMCastFilterCount) ||\r
+          (pMCastFilter == NULL)) {\r
+        Status = EFI_INVALID_PARAMETER;\r
+        gBS->RestoreTPL(TplPrevious);\r
+        return Status;\r
+      }\r
+      \r
+      for ( i = 0 ; i < MCastFilterCnt ; i++ ) {\r
+          UINT8  tmp;\r
+          tmp = pMulticastAddress->Addr[0];\r
+          if ( (tmp & 0x01) != 0x01 ) {\r
+            gBS->RestoreTPL(TplPrevious);\r
+            return EFI_INVALID_PARAMETER;\r
+          }\r
+          pMulticastAddress++;\r
+      }\r
+      \r
+      pMode->MCastFilterCount = (UINT32)MCastFilterCnt;\r
+      CopyMem (&pMode->MCastFilter[0],\r
+                     pMCastFilter,\r
+                     MCastFilterCnt * sizeof ( EFI_MAC_ADDRESS));\r
+    }\r
+  }\r
+  \r
+  if (Enable == 0 && Disable == 0 && !bResetMCastFilter && MCastFilterCnt == 0) {\r
+    Status = EFI_SUCCESS;\r
+    gBS->RestoreTPL(TplPrevious);\r
+    return Status;\r
+  }\r
+\r
+  if ((Enable & EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST) != 0 && MCastFilterCnt == 0) {\r
+    Status = EFI_INVALID_PARAMETER;\r
+    gBS->RestoreTPL(TplPrevious);\r
+    return Status;\r
+  }\r
+  \r
+  pMode->ReceiveFilterSetting |= Enable;\r
+  pMode->ReceiveFilterSetting &= ~Disable;\r
+  Status = ReceiveFilterUpdate (pSimpleNetwork);\r
+  \r
+  if (EFI_DEVICE_ERROR == Status || EFI_INVALID_PARAMETER == Status)\r
+      Status = EFI_SUCCESS;\r
+\r
+  gBS->RestoreTPL(TplPrevious);\r
+  return Status;\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
+  EFI_STATUS Status;\r
+  EFI_TPL TplPrevious;\r
+\r
+  TplPrevious = gBS->RaiseTPL(TPL_CALLBACK);\r
+  //\r
+  //  Verify the parameters\r
+  //\r
+  if (( NULL != pSimpleNetwork ) && ( NULL != pSimpleNetwork->Mode )) {\r
+               pMode = pSimpleNetwork->Mode;\r
+               if ( EfiSimpleNetworkInitialized == pMode->State ) {\r
+       //\r
+       //  Update the device state\r
+       //\r
+       pNicDevice = DEV_FROM_SIMPLE_NETWORK ( pSimpleNetwork );\r
+       pNicDevice->bComplete = FALSE;\r
+       pNicDevice->bLinkUp = FALSE; \r
+       pNicDevice->bHavePkt = FALSE;\r
+       pMode = pSimpleNetwork->Mode;\r
+       pMode->MediaPresent = FALSE;\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
+       else {\r
+               Status = EFI_NOT_STARTED;\r
+       }  \r
+  }\r
+  else {\r
+    Status = EFI_INVALID_PARAMETER;\r
+  }\r
+  gBS->RestoreTPL ( TplPrevious );\r
+  return Status;\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
+\r
+  EFI_SIMPLE_NETWORK_MODE * pMode;\r
+  EFI_SIMPLE_NETWORK_PROTOCOL * pSimpleNetwork;\r
+  EFI_STATUS Status;\r
+  RX_PKT * pCurr = NULL;\r
+  RX_PKT * pPrev = NULL;\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
+  pMode->State = EfiSimpleNetworkStopped;\r
+  pMode->HwAddressSize = PXE_HWADDR_LEN_ETHER;\r
+  pMode->MediaHeaderSize = sizeof ( ETHERNET_HEADER );\r
+  pMode->MaxPacketSize = MAX_ETHERNET_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 = FALSE;\r
+  pMode->MediaPresentSupported = TRUE;\r
+  pMode->MediaPresent = FALSE;\r
+  pNicDevice->LinkIdleCnt = 0;\r
+  //\r
+  //  Read the MAC address\r
+  //\r
+  pNicDevice->PhyId = PHY_ID_INTERNAL;\r
+  pNicDevice->b100Mbps = TRUE;\r
+  pNicDevice->bFullDuplex = TRUE;\r
+  \r
+  Status = Ax88772MacAddressGet (\r
+                pNicDevice,\r
+                &pMode->PermanentAddress.Addr[0]);\r
+\r
+  if ( !EFI_ERROR ( Status )) {\r
+    int i; \r
+    //\r
+    //  Use the hardware address as the current address\r
+    //\r
+\r
+    CopyMem ( &pMode->CurrentAddress,\r
+              &pMode->PermanentAddress,\r
+              PXE_HWADDR_LEN_ETHER );\r
+              \r
+    CopyMem ( &pNicDevice->MAC,\r
+              &pMode->PermanentAddress,\r
+              PXE_HWADDR_LEN_ETHER );\r
+              \r
+    pNicDevice->PktCntInQueue = 0;\r
+    \r
+    for ( i = 0 ; i < MAX_QUEUE_SIZE ; i++) {\r
+        Status = gBS->AllocatePool ( EfiRuntimeServicesData, \r
+                                      sizeof (RX_PKT),\r
+                                      (VOID **) &pCurr);\r
+        if ( EFI_ERROR(Status)) {\r
+            DEBUG (( EFI_D_ERROR, "Memory are not enough\n"));\r
+            return Status;\r
+        }                              \r
+        pCurr->f_Used = FALSE;\r
+        \r
+        if ( i ) {\r
+            pPrev->pNext = pCurr;\r
+        }\r
+        else {\r
+            pNicDevice->QueueHead = pCurr;\r
+        }\r
+        \r
+        if (MAX_QUEUE_SIZE - 1 == i) {\r
+            pCurr->pNext = pNicDevice->QueueHead;\r
+        }\r
+        \r
+        pPrev = pCurr;\r
+    }\r
+    \r
+    pNicDevice->pNextFill = pNicDevice->QueueHead;\r
+    pNicDevice->pFirstFill = pNicDevice->QueueHead;\r
+    \r
+    Status = gBS->AllocatePool (EfiRuntimeServicesData,\r
+                                MAX_BULKIN_SIZE,\r
+                                (VOID **) &pNicDevice->pBulkInBuff);\r
+                                \r
+    if (EFI_ERROR(Status)) {\r
+        DEBUG (( EFI_D_ERROR, "gBS->AllocatePool for pBulkInBuff error. Status = %r\n",\r
+              Status));\r
+        return Status;\r
+    }\r
+  }\r
+  else {\r
+    DEBUG (( EFI_D_ERROR, "Ax88772MacAddressGet error. Status = %r\n", Status));\r
+               return Status;\r
+  }\r
+  \r
+  Status = gBS->AllocatePool ( EfiRuntimeServicesData,\r
+                                   sizeof ( RX_TX_PACKET ),\r
+                                   (VOID **) &pNicDevice->pRxTest );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG (( EFI_D_ERROR, "gBS->AllocatePool:pNicDevice->pRxTest error. Status = %r\n",\r
+              Status));\r
+         return Status;\r
+  }\r
+                                   \r
+  Status = gBS->AllocatePool ( EfiRuntimeServicesData,\r
+                                   sizeof ( RX_TX_PACKET ),\r
+                                   (VOID **) &pNicDevice->pTxTest );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG (( EFI_D_ERROR, "gBS->AllocatePool:pNicDevice->pTxTest error. Status = %r\n",\r
+              Status));\r
+         gBS->FreePool (pNicDevice->pRxTest);\r
+  }\r
+\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
+  EFI_TPL TplPrevious;\r
+  int i = 0;\r
+  RX_PKT * pCurr = NULL;\r
+\r
+  TplPrevious = gBS->RaiseTPL(TPL_CALLBACK);\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 structuref\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 = MAX_ETHERNET_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
+      SetMem(&pMode->BroadcastAddress, PXE_HWADDR_LEN_ETHER, 0xff);\r
+      pMode->IfType = EfiNetworkInterfaceUndi;\r
+      pMode->MacAddressChangeable = TRUE;\r
+      pMode->MultipleTxSupported = FALSE;\r
+      pMode->MediaPresentSupported = TRUE;\r
+      pMode->MediaPresent = FALSE; \r
+      pNicDevice->PktCntInQueue = 0;\r
+      pNicDevice->pNextFill = pNicDevice->QueueHead;\r
+      pNicDevice->pFirstFill = pNicDevice->QueueHead;\r
+      pCurr = pNicDevice->QueueHead;\r
+      \r
+      for ( i = 0 ; i < MAX_QUEUE_SIZE ; i++) { \r
+        pCurr->f_Used = FALSE;\r
+        pCurr = pCurr->pNext;\r
+      }\r
+      \r
+    }\r
+    else {\r
+      Status = EFI_ALREADY_STARTED;\r
+    }\r
+  }\r
+  gBS->RestoreTPL ( TplPrevious );\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
+  EFI_TPL TplPrevious;\r
+  \r
+  TplPrevious = gBS->RaiseTPL(TPL_CALLBACK);\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
+  gBS->RestoreTPL ( TplPrevious );\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
+  typedef struct {\r
+  UINT64 RxTotalFrames;\r
+  UINT64 RxGoodFrames;\r
+  UINT64 RxUndersizeFrames;\r
+  UINT64 RxOversizeFrames;\r
+  UINT64 RxDroppedFrames;\r
+  UINT64 RxUnicastFrames;\r
+  UINT64 RxBroadcastFrames;\r
+  UINT64 RxMulticastFrames;\r
+  UINT64 RxCrcErrorFrames;\r
+  UINT64 RxTotalBytes;\r
+  UINT64 TxTotalFrames;\r
+  UINT64 TxGoodFrames;\r
+  UINT64 TxUndersizeFrames;\r
+  UINT64 TxOversizeFrames;\r
+  UINT64 TxDroppedFrames;\r
+  UINT64 TxUnicastFrames;\r
+  UINT64 TxBroadcastFrames;\r
+  UINT64 TxMulticastFrames;\r
+  UINT64 TxCrcErrorFrames;\r
+  UINT64 TxTotalBytes;\r
+  UINT64 Collisions;\r
+  UINT64 UnsupportedProtocol;\r
+  } EFI_NETWORK_STATISTICS;\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
+  Status = EFI_UNSUPPORTED;\r
+\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
+  EFI_TPL TplPrevious;\r
+  \r
+  TplPrevious = gBS->RaiseTPL(TPL_CALLBACK);\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 ( EfiSimpleNetworkStarted == pMode->State ) {\r
+        pMode->State = EfiSimpleNetworkStopped;\r
+        Status = EFI_SUCCESS; \r
+    }\r
+    else {\r
+        Status = EFI_NOT_STARTED;\r
+    }\r
+  } \r
+  else {\r
+    Status = EFI_INVALID_PARAMETER;\r
+  }\r
+  \r
+  gBS->RestoreTPL ( TplPrevious );\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
+  EFI_TPL TplPrevious;\r
+  \r
+  TplPrevious = gBS->RaiseTPL(TPL_CALLBACK);\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
+        //\r
+        // Update the network state\r
+        //\r
+        pMode->State = EfiSimpleNetworkStarted;\r
+      }\r
+      else if ( EFI_DEVICE_ERROR == Status ) {\r
+       pMode->State = EfiSimpleNetworkStopped;\r
+      }\r
+    }\r
+    else {\r
+      Status = EFI_NOT_STARTED;\r
+    }\r
+  }\r
+  else {\r
+    Status = EFI_INVALID_PARAMETER;\r
+  }\r
+  gBS->RestoreTPL ( TplPrevious );\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
+  ETHERNET_HEADER * pHeader;\r
+  EFI_SIMPLE_NETWORK_MODE * pMode;\r
+  NIC_DEVICE * pNicDevice;\r
+  EFI_USB_IO_PROTOCOL * pUsbIo;\r
+  EFI_STATUS Status;\r
+  UINTN TransferLength;\r
+  UINT32 TransferStatus;\r
+  UINT16 Type;\r
+  EFI_TPL TplPrevious;\r
+\r
+  TplPrevious = gBS->RaiseTPL(TPL_CALLBACK);\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
+      // Update the link status\r
+      //\r
+      pNicDevice = DEV_FROM_SIMPLE_NETWORK ( pSimpleNetwork );\r
+      pMode->MediaPresent = pNicDevice->bLinkUp;\r
+\r
+      //\r
+      //  Release the synchronization with Ax88772Timer\r
+      //      \r
+      if ( pMode->MediaPresent && pNicDevice->bComplete) {\r
+        //\r
+        //  Copy the packet into the USB buffer\r
+        //\r
+\r
+        CopyMem ( &pNicDevice->pTxTest->Data[0], pBuffer, BufferSize ); \r
+        pNicDevice->pTxTest->Length = (UINT16) BufferSize;\r
+\r
+        //\r
+        //  Transmit the packet\r
+        //\r
+        pHeader = (ETHERNET_HEADER *) &pNicDevice->pTxTest->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 = pNicDevice->pTxTest->Length;\r
+          }\r
+          Type = (UINT16)(( Type >> 8 ) | ( Type << 8 ));\r
+          pHeader->type = Type;\r
+        }\r
+        if ( pNicDevice->pTxTest->Length < MIN_ETHERNET_PKT_SIZE ) {\r
+          pNicDevice->pTxTest->Length = MIN_ETHERNET_PKT_SIZE;\r
+          ZeroMem ( &pNicDevice->pTxTest->Data[ BufferSize ],\r
+                    pNicDevice->pTxTest->Length - BufferSize );\r
+        }\r
+    \r
+        DEBUG ((EFI_D_INFO, "TX: %02x-%02x-%02x-%02x-%02x-%02x  %02x-%02x-%02x-%02x-%02x-%02x"\r
+                  "  %02x-%02x  %d bytes\r\n",\r
+                  pNicDevice->pTxTest->Data[0],\r
+                  pNicDevice->pTxTest->Data[1],\r
+                  pNicDevice->pTxTest->Data[2],\r
+                  pNicDevice->pTxTest->Data[3],\r
+                  pNicDevice->pTxTest->Data[4],\r
+                  pNicDevice->pTxTest->Data[5],\r
+                  pNicDevice->pTxTest->Data[6],\r
+                  pNicDevice->pTxTest->Data[7],\r
+                  pNicDevice->pTxTest->Data[8],\r
+                  pNicDevice->pTxTest->Data[9],\r
+                  pNicDevice->pTxTest->Data[10],\r
+                  pNicDevice->pTxTest->Data[11],\r
+                  pNicDevice->pTxTest->Data[12],\r
+                  pNicDevice->pTxTest->Data[13],\r
+                  pNicDevice->pTxTest->Length ));\r
+\r
+        pNicDevice->pTxTest->LengthBar = ~(pNicDevice->pTxTest->Length);\r
+        TransferLength = sizeof ( pNicDevice->pTxTest->Length )\r
+                       + sizeof ( pNicDevice->pTxTest->LengthBar )\r
+                       + pNicDevice->pTxTest->Length;\r
+                       \r
+        if (TransferLength % 512 == 0 || TransferLength % 1024 == 0)\r
+            TransferLength +=4;\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
+                                           &pNicDevice->pTxTest->Length,\r
+                                           &TransferLength,\r
+                                           0xfffffffe, \r
+                                           &TransferStatus );\r
+        if ( !EFI_ERROR ( Status )) {\r
+          Status = TransferStatus;\r
+        }\r
+\r
+        if ( !EFI_ERROR ( Status )) {\r
+          pNicDevice->pTxBuffer = pBuffer;\r
+        }\r
+        else {\r
+          if ((TransferLength != (UINTN)( pNicDevice->pTxTest->Length + 4 )) &&\r
+               (TransferLength != (UINTN)(( pNicDevice->pTxTest->Length + 4 ) + 4))) {\r
+            DEBUG ((EFI_D_INFO, "TransferLength didn't match Packet Length\n"));\r
+          }\r
+          //\r
+          //  Reset the controller to fix the error\r
+          //\r
+          if ( EFI_DEVICE_ERROR == Status ) {\r
+                SN_Reset ( pSimpleNetwork, FALSE );\r
+          }\r
+          Status = EFI_NOT_READY;\r
+        }\r
+      }\r
+      else {\r
+        //\r
+        // No packets available.\r
+        //\r
+        Status = EFI_NOT_READY;\r
+      }\r
+      \r
+    }\r
+    else {\r
+      Status = EFI_NOT_STARTED ;\r
+    }\r
+  }\r
+  else {\r
+    Status = EFI_INVALID_PARAMETER;\r
+  }\r
+  \r
+  gBS->RestoreTPL (TplPrevious);\r
+\r
+  return Status;\r
+}\r