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