From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from foss.arm.com (foss.arm.com []) by mx.groups.io with SMTP id smtpd.web11.12982.1589109336645037772 for ; Sun, 10 May 2020 04:15:38 -0700 Authentication-Results: mx.groups.io; dkim=missing; spf=fail (domain: arm.com, ip: , mailfrom: samer.el-haj-mahmoud@arm.com) Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 75C8C11D4; Sun, 10 May 2020 04:15:37 -0700 (PDT) Received: from localhost.localdomain (unknown [172.31.20.19]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id DBBFD3F68F; Sun, 10 May 2020 04:15:36 -0700 (PDT) From: "Samer El-Haj-Mahmoud" To: devel@edk2.groups.io Cc: Ray Ni , Leif Lindholm , Ard Biesheuvel , Michael D Kinney Subject: [edk2-platform][PATCH v1 4/4] Silicon/AsixPkg: Add ASIX Ax88772c driver Date: Sun, 10 May 2020 07:15:30 -0400 Message-Id: <20200510111530.26225-5-Samer.El-Haj-Mahmoud@arm.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20200510111530.26225-1-Samer.El-Haj-Mahmoud@arm.com> References: <20200510111530.26225-1-Samer.El-Haj-Mahmoud@arm.com> This is the initial revision of ASIX USB networking UEFI driver version 2.8.0 for Ax88772c / Ax88772b / Ax88772a https://www.asix.com.tw/download.php?sub=driverdetail&PItemID=136 Source code contributed by ASIX. Cc: Ray Ni Cc: Leif Lindholm Cc: Ard Biesheuvel Cc: Michael D Kinney Signed-off-by: Samer El-Haj-Mahmoud --- Silicon/ASIX/AsixPkg.dsc | 1 + Silicon/ASIX/Drivers/Bus/Usb/UsbNetworking/Ax88772c/Ax88772c.inf | 65 + Silicon/ASIX/Drivers/Bus/Usb/UsbNetworking/Ax88772c/Ax88772.h | 1097 +++++++++++++ Silicon/ASIX/Drivers/Bus/Usb/UsbNetworking/Ax88772c/Ax88772.c | 1296 ++++++++++++++++ Silicon/ASIX/Drivers/Bus/Usb/UsbNetworking/Ax88772c/ComponentName.c | 246 +++ Silicon/ASIX/Drivers/Bus/Usb/UsbNetworking/Ax88772c/DriverBinding.c | 637 ++++++++ Silicon/ASIX/Drivers/Bus/Usb/UsbNetworking/Ax88772c/SimpleNetwork.c | 1612 ++++++++++++++++++++ 7 files changed, 4954 insertions(+) diff --git a/Silicon/ASIX/AsixPkg.dsc b/Silicon/ASIX/AsixPkg.dsc index 5e860d7b3c8f..5227a3f30930 100644 --- a/Silicon/ASIX/AsixPkg.dsc +++ b/Silicon/ASIX/AsixPkg.dsc @@ -67,3 +67,4 @@ [Components] Silicon/ASIX/Drivers/Bus/Usb/UsbNetworking/Ax88179/Ax88179.inf Silicon/ASIX/Drivers/Bus/Usb/UsbNetworking/Ax88772/Ax88772.inf Silicon/ASIX/Drivers/Bus/Usb/UsbNetworking/Ax88772b/Ax88772b.inf +Silicon/ASIX/Drivers/Bus/Usb/UsbNetworking/Ax88772c/Ax88772c.inf diff --git a/Silicon/ASIX/Drivers/Bus/Usb/UsbNetworking/Ax88772c/Ax88772c.inf b/Silicon/ASIX/Drivers/Bus/Usb/UsbNetworking/Ax88772c/Ax88772c.inf new file mode 100644 index 000000000000..1d37a5dae34b --- /dev/null +++ b/Silicon/ASIX/Drivers/Bus/Usb/UsbNetworking/Ax88772c/Ax88772c.inf @@ -0,0 +1,65 @@ +## @file +# Component description file for ASIX AX88772 USB/Ethernet driver. +# +# This module provides support for the ASIX AX88772 USB/Ethernet adapter. +# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x00010018 + BASE_NAME = Ax88772c + FILE_GUID = B15239D6-6A01-4808-A0F7-B7F20F073555 + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + + ENTRY_POINT = EntryPoint + +# +# VALID_ARCHITECTURES = IA32 X64 EBC +# + +[Sources.common] + Ax88772.h + Ax88772.c + ComponentName.c + DriverBinding.c + SimpleNetwork.c + + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + +[LibraryClasses] + UefiLib + UefiBootServicesTableLib + BaseMemoryLib + DebugLib + UefiDriverEntryPoint + +[Protocols] + gEfiDevicePathProtocolGuid ## BY_START + gEfiSimpleNetworkProtocolGuid ## BY_START + gEfiUsbIoProtocolGuid ## TO_START + +#[Guids] +# gEfiEventExitBootServicesGuid ## PRODUCES ## Event +# gEfiEventVirtualAddressChangeGuid ## PRODUCES ## Event +# gEfiNicIp4ConfigVariableGuid + +[Depex] + gEfiBdsArchProtocolGuid AND + gEfiCpuArchProtocolGuid AND + gEfiMetronomeArchProtocolGuid AND + gEfiMonotonicCounterArchProtocolGuid AND + gEfiRealTimeClockArchProtocolGuid AND + gEfiResetArchProtocolGuid AND + gEfiRuntimeArchProtocolGuid AND + gEfiSecurityArchProtocolGuid AND + gEfiTimerArchProtocolGuid AND + gEfiVariableWriteArchProtocolGuid AND + gEfiVariableArchProtocolGuid AND + gEfiWatchdogTimerArchProtocolGuid diff --git a/Silicon/ASIX/Drivers/Bus/Usb/UsbNetworking/Ax88772c/Ax88772.h b/Silicon/ASIX/Drivers/Bus/Usb/UsbNetworking/Ax88772c/Ax88772.h new file mode 100644 index 000000000000..18317fd5c4f7 --- /dev/null +++ b/Silicon/ASIX/Drivers/Bus/Usb/UsbNetworking/Ax88772c/Ax88772.h @@ -0,0 +1,1097 @@ +/** @file + Definitions for ASIX AX88772 Ethernet adapter. + + Copyright (c) 2011 - 2015, Intel Corporation. All rights reserved. + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _AX88772_H_ +#define _AX88772_H_ + +#include + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#define MAX_QUEUE_SIZE 50 +#define MAX_BULKIN_SIZE 16384 +#define HW_HDR_LENGTH 8 +#define PASS_SCT 0 +#define REPORTLINK 1 + +#define ARM 0 + +#if ARM +#define MAX_LINKIDLE_THRESHOLD 100 +#else +#define MAX_LINKIDLE_THRESHOLD 30 +#endif + +#define AMI 1 +#define ASIX_MCAST_FILTER_CNT 8 +#define RXTHOU 0 + +#if 0 +//------------------------------------------------------------------------------ +// Macros +//------------------------------------------------------------------------------ + +#if defined(_MSC_VER) /* Handle Microsoft VC++ compiler specifics. */ +#define DBG_ENTER() DEBUG (( 0xffffffff, "Entering " __FUNCTION__ "\n" )) ///< Display routine entry +#define DBG_EXIT() DEBUG (( 0xffffffff, "Exiting " __FUNCTION__ "\n" )) ///< Display routine exit +#define DBG_EXIT_DEC(Status) DEBUG (( 0xffffffff, "Exiting " __FUNCTION__ ", Status: %d\n", Status )) ///< Display routine exit with decimal value +#define DBG_EXIT_HEX(Status) DEBUG (( 0xffffffff, "Exiting " __FUNCTION__ ", Status: 0x%08x\n", Status )) ///< Display routine exit with hex value +#define DBG_EXIT_STATUS(Status) DEBUG (( 0xffffffff, "Exiting " __FUNCTION__ ", Status: %r\n", Status )) ///< Display routine exit with status value +#define DBG_EXIT_TF(Status) DEBUG (( 0xffffffff, "Exiting " __FUNCTION__ ", returning %s\n", (FALSE == Status) ? L"FALSE" : L"TRUE" )) ///< Display routine with TRUE/FALSE value +#else // _MSC_VER +#define DBG_ENTER() ///< Display routine entry +#define DBG_EXIT() ///< Display routine exit +#define DBG_EXIT_DEC(Status) ///< Display routine exit with decimal value +#define DBG_EXIT_HEX(Status) ///< Display routine exit with hex value +#define DBG_EXIT_STATUS(Status) ///< Display routine exit with status value +#define DBG_EXIT_TF(Status) ///< Display routine with TRUE/FALSE value +#endif // _MSC_VER + +#endif + +#define USB_IS_IN_ENDPOINT(EndPointAddr) (((EndPointAddr) & BIT7) != 0) ///< Return TRUE/FALSE for IN direction +#define USB_IS_OUT_ENDPOINT(EndPointAddr) (((EndPointAddr) & BIT7) == 0) ///< Return TRUE/FALSE for OUT direction +#define USB_IS_BULK_ENDPOINT(Attribute) (((Attribute) & (BIT0 | BIT1)) == USB_ENDPOINT_BULK) ///< Return TRUE/FALSE for BULK type +#define USB_IS_INTERRUPT_ENDPOINT(Attribute) (((Attribute) & (BIT0 | BIT1)) == USB_ENDPOINT_INTERRUPT) ///< Return TRUE/FALSE for INTERRUPT type + + +#define PRINT(_L_STR) (gST->ConOut->OutputString(gST->ConOut,(_L_STR))) +//------------------------------------------------------------------------------ +// Constants +//------------------------------------------------------------------------------ + +#define DEBUG_RX_BROADCAST 0x40000000 ///< Display RX broadcast messages +#define DEBUG_RX_MULTICAST 0x20000000 ///< Display RX multicast messages +#define DEBUG_RX_UNICAST 0x10000000 ///< Display RX unicast messages +#define DEBUG_MAC_ADDRESS 0x08000000 ///< Display the MAC address +#define DEBUG_LINK 0x04000000 ///< Display the link status +#define DEBUG_TX 0x02000000 ///< Display the TX messages +#define DEBUG_PHY 0x01000000 ///< Display the PHY register values +#define DEBUG_SROM 0x00800000 ///< Display the SROM contents +#define DEBUG_TIMER 0x00400000 ///< Display the timer routine entry/exit +#define DEBUG_TPL 0x00200000 ///< Display the timer routine entry/exit + +#if RXTHOU +#define AX88772_MAX_BULKIN_SIZE 1024 * 17 //32 +#else +#define AX88772_MAX_BULKIN_SIZE 1024 * 3 +#endif + +#define AX88772_MAX_PKT_SIZE 2048 ///< Maximum packet size + +#define ETHERNET_HEADER_SIZE sizeof ( ETHERNET_HEADER ) ///< Size in bytes of the Ethernet header +#define MIN_ETHERNET_PKT_SIZE 60 ///< Minimum packet size including Ethernet header +#define MAX_ETHERNET_PKT_SIZE 1500 ///< Ethernet spec 3.1.1: Minimum packet size + +#define USB_NETWORK_CLASS 0x09 ///< USB Network class code +#define USB_BUS_TIMEOUT 1000 ///< USB timeout in milliseconds + +#define TIMER_MSEC 20 ///< Polling interval for the NIC +//#define TPL_AX88772 TPL_CALLBACK ///< TPL for routine synchronization + +#define HC_DEBUG 0 + +#if RXTHOU +#define BULKIN_TIMEOUT 3 //10 //100 //1000 +#else +#define BULKIN_TIMEOUT 3000 +#endif + +#define AUTONEG_DELAY 2000000 +#define AUTONEG_POLL_CNT 5 + +/** + Verify new TPL value + + This macro which is enabled when debug is enabled verifies that + the new TPL value is >= the current TPL value. +**/ +#ifdef VERIFY_TPL +#undef VERIFY_TPL +#endif // VERIFY_TPL + +#if !defined(MDEPKG_NDEBUG) + +#define VERIFY_TPL(tpl) \ +{ \ + EFI_TPL PreviousTpl; \ + \ + PreviousTpl = gBS->RaiseTPL ( TPL_HIGH_LEVEL ); \ + gBS->RestoreTPL ( PreviousTpl ); \ + if ( PreviousTpl > tpl ) { \ + DEBUG (( DEBUG_ERROR, "Current TPL: %d, New TPL: %d\r\n", PreviousTpl, tpl )); \ + ASSERT ( PreviousTpl <= tpl ); \ + } \ +} + +#else // MDEPKG_NDEBUG + +#define VERIFY_TPL(tpl) + +#endif // MDEPKG_NDEBUG + +//------------------------------------------------------------------------------ +// Hardware Definition +//------------------------------------------------------------------------------ + +#define FreeQueueSize 10 + +#define DEV_SIGNATURE SIGNATURE_32 ('A','X','8','8') ///< Signature of data structures in memory + +#define VENDOR_ID 0x0B95 ///< Vendor ID for Asix +#define VENDOR_AX88772B_LENOVO_ID 0x17EF + + +/* Freddy */ +#define PRODUCT_ID 0x7720 ///< Product ID for the AX88772 USB 10/100 Ethernet controller +#define PRODUCT_AX88772A_ID 0x772A +#define PRODUCT_AX88772B_ID 0x772b +#define PRODUCT_AX88772B_ASUS_ID 0x7e2b +#define PRODUCT_AX88772B_LENOVO_ID 0x7203 +/* Freddy */ + + +#define RESET_MSEC 1000 ///< Reset duration +#define PHY_RESET_MSEC 500 ///< PHY reset duration + +// +// RX Control register +// + +#define RXC_PRO 0x0001 ///< Receive all packets +#define RXC_AMALL 0x0002 ///< Receive all multicast packets +#define RXC_SEP 0x0004 ///< Save error packets +#define RXC_AB 0x0008 ///< Receive broadcast packets +#define RXC_AM 0x0010 ///< Use multicast destination address hash table +#define RXC_AP 0x0020 ///< Accept physical address from Multicast Filter +#define RXC_SO 0x0080 ///< Start operation +#define RXC_MFB 0x0300 ///< Maximum frame burst +#define RXC_MFB_2048 0 ///< Maximum frame size: 2048 bytes +#define RXC_MFB_4096 0x0100 ///< Maximum frame size: 4096 bytes +#define RXC_MFB_8192 0x0200 ///< Maximum frame size: 8192 bytes +#define RXC_MFB_16384 0x0300 ///< Maximum frame size: 16384 bytes + +/*Freddy*/ +#define RXC_RH1M 0x0100 ///< Rx header 1 +#define RXC_RH2M 0x0200 ///< Rx header 2 +#define RXC_RH3M 0x0400 ///< Rx header 3 +/*Freddy*/ + +// +// Medium Status register +// + +#define MS_FD 0x0002 ///< Full duplex +#define MS_ONE 0x0004 ///< Must be one +#define MS_RFC 0x0010 ///< RX flow control enable +#define MS_TFC 0x0020 ///< TX flow control enable +#define MS_PF 0x0080 ///< Pause frame enable +#define MS_RE 0x0100 ///< Receive enable +#define MS_PS 0x0200 ///< Port speed 1=100, 0=10 Mbps +#define MS_SBP 0x0800 ///< Stop back pressure +#define MS_SM 0x1000 ///< Super MAC support + +// +// Software PHY Select register +// + +#define SPHY_PSEL (1 << 0) ///< Select internal PHY +#define SPHY_SSMII (1 << 2) +#define SPHY_SSEN (1 << 4) +#define SPHY_ASEL 0x02 ///< 1=Auto select, 0=Manual select + +// +// Software Reset register +// + +#define SRR_RR 0x01 ///< Clear receive frame length error +#define SRR_RT 0x02 ///< Clear transmit frame length error +#define SRR_BZTYPE 0x04 ///< External PHY reset pin tri-state enable +#define SRR_PRL 0x08 ///< External PHY reset pin level +#define SRR_BZ 0x10 ///< Force Bulk to return zero length packet +#define SRR_IPRL 0x20 ///< Internal PHY reset control +#define SRR_IPPD 0x40 ///< Internal PHY power down + +// +// PHY ID values +// + +#define PHY_ID_INTERNAL 0x0010 ///< Internal PHY + +// +// USB Commands +// + +#define CMD_PHY_ACCESS_SOFTWARE 0x06 ///< Software in control of PHY +#define CMD_PHY_REG_READ 0x07 ///< Read PHY register, Value: PHY, Index: Register, Data: Register value +#define CMD_PHY_REG_WRITE 0x08 ///< Write PHY register, Value: PHY, Index: Register, Data: New 16-bit value +#define CMD_PHY_ACCESS_HARDWARE 0x0a ///< Hardware in control of PHY +#define CMD_SROM_READ 0x0b ///< Read SROM register: Value: Address, Data: Value +#define CMD_SROM_WRITE 0x0c ///< Read SROM register: Value: Address, Data: Value +#define CMD_SROM_WRITE_EN 0x0d +#define CMD_SROM_WRITE_DIS 0x0e +#define CMD_RX_CONTROL_WRITE 0x10 ///< Set the RX control register, Value: New value +#define CMD_GAPS_WRITE 0x12 ///< Write the gaps register, Value: New value +#define CMD_MAC_ADDRESS_READ 0x13 ///< Read the MAC address, Data: 6 byte MAC address +#define CMD_MAC_ADDRESS_WRITE 0x14 ///< Set the MAC address, Data: New 6 byte MAC address +#define CMD_MULTICAST_HASH_READ 0x15 ///< Read the multicast hash table +#define CMD_MULTICAST_HASH_WRITE 0x16 ///< Write the multicast hash table, Data: New 8 byte value +#define CMD_MEDIUM_STATUS_READ 0x1a ///< Read medium status register, Data: Register value +#define CMD_MEDIUM_STATUS_WRITE 0x1b ///< Write medium status register, Value: New value +#define CMD_WRITE_GPIOS 0x1f +#define CMD_RESET 0x20 ///< Reset register, Value: New value +#define CMD_PHY_SELECT 0x22 ///< PHY select register, Value: New value + +/*Freddy*/ +#define CMD_RXQTC 0x2a ///< RX Queue Cascade Threshold Control Register +/*Freddy*/ + +//------------------------------ +// USB Endpoints +//------------------------------ + +#define CONTROL_ENDPOINT 0 ///< Control endpoint +#define INTERRUPT_ENDPOINT 1 ///< Interrupt endpoint +#define BULK_IN_ENDPOINT 2 ///< Receive endpoint +#define BULK_OUT_ENDPOINT 3 ///< Transmit endpoint + +//------------------------------ +// PHY Registers +//------------------------------ + +#define PHY_BMCR 0 ///< Control register +#define PHY_BMSR 1 ///< Status register +#define PHY_ANAR 4 ///< Autonegotiation advertisement register +#define PHY_ANLPAR 5 ///< Autonegotiation link parter ability register +#define PHY_ANER 6 ///< Autonegotiation expansion register + +// BMCR - Register 0 + +#define BMCR_RESET 0x8000 ///< 1 = Reset the PHY, bit clears after reset +#define BMCR_LOOPBACK 0x4000 ///< 1 = Loopback enabled +#define BMCR_100MBPS 0x2000 ///< 100 Mbits/Sec +#define BMCR_10MBPS 0 ///< 10 Mbits/Sec +#define BMCR_AUTONEGOTIATION_ENABLE 0x1000 ///< 1 = Enable autonegotiation +#define BMCR_POWER_DOWN 0x0800 ///< 1 = Power down +#define BMCR_ISOLATE 0x0400 ///< 0 = Isolate PHY +#define BMCR_RESTART_AUTONEGOTIATION 0x0200 ///< 1 = Restart autonegotiation +#define BMCR_FULL_DUPLEX 0x0100 ///< Full duplex operation +#define BMCR_HALF_DUPLEX 0 ///< Half duplex operation +#define BMCR_COLLISION_TEST 0x0080 ///< 1 = Collision test enabled + +// BSMR - Register 1 + +#define BMSR_100BASET4 0x8000 ///< 1 = 100BASE-T4 mode +#define BMSR_100BASETX_FDX 0x4000 ///< 1 = 100BASE-TX full duplex +#define BMSR_100BASETX_HDX 0x2000 ///< 1 = 100BASE-TX half duplex +#define BMSR_10BASET_FDX 0x1000 ///< 1 = 10BASE-T full duplex +#define BMSR_10BASET_HDX 0x0800 ///< 1 = 10BASE-T half duplex +#define BMSR_MF 0x0040 ///< 1 = PHY accepts frames with preamble suppressed +#define BMSR_AUTONEG_CMPLT 0x0020 ///< 1 = Autonegotiation complete +#define BMSR_RF 0x0010 ///< 1 = Remote fault +#define BMSR_AUTONEG 0x0008 ///< 1 = Able to perform autonegotiation +#define BMSR_LINKST 0x0004 ///< 1 = Link up +#define BMSR_JABBER_DETECT 0x0002 ///< 1 = jabber condition detected +#define BMSR_EXTENDED_CAPABILITY 0x0001 ///< 1 = Extended register capable + +// ANAR and ANLPAR Registers 4, 5 + +#define AN_NP 0x8000 ///< 1 = Next page available +#define AN_ACK 0x4000 ///< 1 = Link partner acknowledged +#define AN_RF 0x2000 ///< 1 = Remote fault indicated by link partner +#define AN_FCS 0x0400 ///< 1 = Flow control ability +#define AN_T4 0x0200 ///< 1 = 100BASE-T4 support +#define AN_TX_FDX 0x0100 ///< 1 = 100BASE-TX Full duplex +#define AN_TX_HDX 0x0080 ///< 1 = 100BASE-TX support +#define AN_10_FDX 0x0040 ///< 1 = 10BASE-T Full duplex +#define AN_10_HDX 0x0020 ///< 1 = 10BASE-T support +#define AN_CSMA_CD 0x0001 ///< 1 = IEEE 802.3 CSMA/CD support + + + +//------------------------------------------------------------------------------ +// Data Types +//------------------------------------------------------------------------------ + +/** + Ethernet header layout + + IEEE 802.3-2002 Part 3 specification, section 3.1.1. +**/ +#pragma pack(1) +typedef struct { + UINT8 dest_addr[PXE_HWADDR_LEN_ETHER]; ///< Destination LAN address + UINT8 src_addr[PXE_HWADDR_LEN_ETHER]; ///< Source LAN address + UINT16 type; ///< Protocol or length +} ETHERNET_HEADER; +#pragma pack() + +/** + Receive and Transmit packet structure +**/ +#pragma pack(1) +typedef struct _RX_TX_PACKET { + struct _RX_TX_PACKET * pNext; ///< Next receive packet + UINT16 Length; ///< Packet length + UINT16 LengthBar; ///< Complement of the length + UINT8 Data[ AX88772_MAX_PKT_SIZE ]; ///< Received packet data +} RX_TX_PACKET; +#pragma pack() + +/** + AX88772 control structure + + The driver uses this structure to manage the Asix AX88772 10/100 + Ethernet controller. +**/ +typedef struct { + UINTN Signature; ///< Structure identification + + // + // USB data + // + EFI_HANDLE Controller; ///< Controller handle + EFI_USB_IO_PROTOCOL * pUsbIo; ///< USB driver interface + + // + // Simple network protocol data + // + EFI_SIMPLE_NETWORK_PROTOCOL SimpleNetwork; ///< Driver's network stack interface + EFI_SIMPLE_NETWORK_MODE SimpleNetworkData; ///< Data for simple network + + // + // Ethernet controller data + // + BOOLEAN bInitialized; ///< Controller initialized + UINT16 PhyId; ///< PHY ID + + // + // Link state + // + BOOLEAN b100Mbps; ///< Current link speed, FALSE = 10 Mbps + BOOLEAN bComplete; ///< Current state of auto-negotiation + BOOLEAN bFullDuplex; ///< Current duplex + BOOLEAN bLinkUp; ///< Current link state + UINTN PollCount; ///< Number of times the autonegotiation status was polled + UINT16 CurRxControl; + VOID * pTxBuffer; + // + // Receive buffer list + // + UINT8 *pBulkInbuf; + UINT8 * pCurPktHdrOff; + UINT8 *pCurPktOff; + UINT16 PktCnt; + + RX_TX_PACKET * pTxTest; + + UINT8 MulticastHash[8]; + EFI_MAC_ADDRESS MAC; + + EFI_DEVICE_PATH_PROTOCOL *MyDevPath; + BOOLEAN Grub_f; + BOOLEAN bFirstRst; + BOOLEAN Flag772A; +#if RXTHOU + UINT8 rxburst; +#endif + +} NIC_DEVICE; + + +// +// Global Variables +// +extern EFI_DRIVER_BINDING_PROTOCOL gDriverBinding; +extern EFI_COMPONENT_NAME_PROTOCOL gComponentName; +extern EFI_COMPONENT_NAME2_PROTOCOL gComponentName2; + +#define DEV_FROM_SIMPLE_NETWORK(a) CR (a, NIC_DEVICE, SimpleNetwork, DEV_SIGNATURE) ///< Locate NIC_DEVICE from Simple Network Protocol + +//------------------------------------------------------------------------------ +// Simple Network Protocol +//------------------------------------------------------------------------------ + +/** + Reset the network adapter. + + Resets a network adapter and reinitializes it with the parameters that + were provided in the previous call to Initialize (). The transmit and + receive queues are cleared. Receive filters, the station address, the + statistics, and the multicast-IP-to-HW MAC addresses are not reset by + this call. + + This routine calls ::Ax88772Reset to perform the adapter specific + reset operation. This routine also starts the link negotiation + by calling ::Ax88772NegotiateLinkStart. + + @param [in] pSimpleNetwork Protocol instance pointer + @param [in] bExtendedVerification Indicates that the driver may perform a more + exhaustive verification operation of the device + during reset. + + @retval EFI_SUCCESS This operation was successful. + @retval EFI_NOT_STARTED The network interface was not started. + @retval EFI_INVALID_PARAMETER pSimpleNetwork parameter was NULL or did not point to a valid + EFI_SIMPLE_NETWORK_PROTOCOL structure. + @retval EFI_DEVICE_ERROR The command could not be sent to the network interface. + @retval EFI_UNSUPPORTED The increased buffer size feature is not supported. + +**/ +EFI_STATUS +EFIAPI +SN_Reset ( + IN EFI_SIMPLE_NETWORK_PROTOCOL * pSimpleNetwork, + IN BOOLEAN bExtendedVerification + ); + +/** + Initialize the simple network protocol. + + This routine calls ::Ax88772MacAddressGet to obtain the + MAC address. + + @param [in] pNicDevice NIC_DEVICE_INSTANCE pointer + + @retval EFI_SUCCESS Setup was successful + +**/ +EFI_STATUS +SN_Setup ( + IN NIC_DEVICE * pNicDevice + ); + +/** + This routine starts the network interface. + + @param [in] pSimpleNetwork Protocol instance pointer + + @retval EFI_SUCCESS This operation was successful. + @retval EFI_ALREADY_STARTED The network interface was already started. + @retval EFI_INVALID_PARAMETER pSimpleNetwork parameter was NULL or did not point to a valid + EFI_SIMPLE_NETWORK_PROTOCOL structure. + @retval EFI_DEVICE_ERROR The command could not be sent to the network interface. + @retval EFI_UNSUPPORTED The increased buffer size feature is not supported. + +**/ +EFI_STATUS +EFIAPI +SN_Start ( + IN EFI_SIMPLE_NETWORK_PROTOCOL * pSimpleNetwork + ); + +/** + Set the MAC address. + + This function modifies or resets the current station address of a + network interface. If Reset is TRUE, then the current station address + is set ot the network interface's permanent address. If Reset if FALSE + then the current station address is changed to the address specified by + pNew. + + This routine calls ::Ax88772MacAddressSet to update the MAC address + in the network adapter. + + @param [in] pSimpleNetwork Protocol instance pointer + @param [in] bReset Flag used to reset the station address to the + network interface's permanent address. + @param [in] pNew New station address to be used for the network + interface. + + @retval EFI_SUCCESS This operation was successful. + @retval EFI_NOT_STARTED The network interface was not started. + @retval EFI_INVALID_PARAMETER pSimpleNetwork parameter was NULL or did not point to a valid + EFI_SIMPLE_NETWORK_PROTOCOL structure. + @retval EFI_DEVICE_ERROR The command could not be sent to the network interface. + @retval EFI_UNSUPPORTED The increased buffer size feature is not supported. + +**/ +EFI_STATUS +EFIAPI +SN_StationAddress ( + IN EFI_SIMPLE_NETWORK_PROTOCOL * pSimpleNetwork, + IN BOOLEAN bReset, + IN EFI_MAC_ADDRESS * pNew + ); + +/** + This function resets or collects the statistics on a network interface. + If the size of the statistics table specified by StatisticsSize is not + big enough for all of the statistics that are collected by the network + interface, then a partial buffer of statistics is returned in + StatisticsTable. + + @param [in] pSimpleNetwork Protocol instance pointer + @param [in] bReset Set to TRUE to reset the statistics for the network interface. + @param [in, out] pStatisticsSize On input the size, in bytes, of StatisticsTable. On output + the size, in bytes, of the resulting table of statistics. + @param [out] pStatisticsTable A pointer to the EFI_NETWORK_STATISTICS structure that + conains the statistics. + + @retval EFI_SUCCESS This operation was successful. + @retval EFI_NOT_STARTED The network interface was not started. + @retval EFI_BUFFER_TOO_SMALL The pStatisticsTable is NULL or the buffer is too small. + @retval EFI_INVALID_PARAMETER pSimpleNetwork parameter was NULL or did not point to a valid + EFI_SIMPLE_NETWORK_PROTOCOL structure. + @retval EFI_DEVICE_ERROR The command could not be sent to the network interface. + @retval EFI_UNSUPPORTED The increased buffer size feature is not supported. + +**/ +EFI_STATUS +EFIAPI +SN_Statistics ( + IN EFI_SIMPLE_NETWORK_PROTOCOL * pSimpleNetwork, + IN BOOLEAN bReset, + IN OUT UINTN * pStatisticsSize, + OUT EFI_NETWORK_STATISTICS * pStatisticsTable + ); + +/** + This function stops a network interface. This call is only valid + if the network interface is in the started state. + + @param [in] pSimpleNetwork Protocol instance pointer + + @retval EFI_SUCCESS This operation was successful. + @retval EFI_NOT_STARTED The network interface was not started. + @retval EFI_INVALID_PARAMETER pSimpleNetwork parameter was NULL or did not point to a valid + EFI_SIMPLE_NETWORK_PROTOCOL structure. + @retval EFI_DEVICE_ERROR The command could not be sent to the network interface. + @retval EFI_UNSUPPORTED The increased buffer size feature is not supported. + +**/ +EFI_STATUS +EFIAPI +SN_Stop ( + IN EFI_SIMPLE_NETWORK_PROTOCOL * pSimpleNetwork + ); + +/** + This function releases the memory buffers assigned in the Initialize() call. + Pending transmits and receives are lost, and interrupts are cleared and disabled. + After this call, only Initialize() and Stop() calls may be used. + + @param [in] pSimpleNetwork Protocol instance pointer + + @retval EFI_SUCCESS This operation was successful. + @retval EFI_NOT_STARTED The network interface was not started. + @retval EFI_INVALID_PARAMETER pSimpleNetwork parameter was NULL or did not point to a valid + EFI_SIMPLE_NETWORK_PROTOCOL structure. + @retval EFI_DEVICE_ERROR The command could not be sent to the network interface. + @retval EFI_UNSUPPORTED The increased buffer size feature is not supported. + +**/ +EFI_STATUS +EFIAPI +SN_Shutdown ( + IN EFI_SIMPLE_NETWORK_PROTOCOL * pSimpleNetwork + ); + +/** + Send a packet over the network. + + This function places the packet specified by Header and Buffer on + the transmit queue. This function performs a non-blocking transmit + operation. When the transmit is complete, the buffer is returned + via the GetStatus() call. + + This routine calls ::Ax88772Rx to empty the network adapter of + receive packets. The routine then passes the transmit packet + to the network adapter. + + @param [in] pSimpleNetwork Protocol instance pointer + @param [in] HeaderSize The size, in bytes, of the media header to be filled in by + the Transmit() function. If HeaderSize is non-zero, then + it must be equal to SimpleNetwork->Mode->MediaHeaderSize + and DestAddr and Protocol parameters must not be NULL. + @param [in] BufferSize The size, in bytes, of the entire packet (media header and + data) to be transmitted through the network interface. + @param [in] pBuffer A pointer to the packet (media header followed by data) to + to be transmitted. This parameter can not be NULL. If + HeaderSize is zero, then the media header is Buffer must + already be filled in by the caller. If HeaderSize is nonzero, + then the media header will be filled in by the Transmit() + function. + @param [in] pSrcAddr The source HW MAC address. If HeaderSize is zero, then + this parameter is ignored. If HeaderSize is nonzero and + SrcAddr is NULL, then SimpleNetwork->Mode->CurrentAddress + is used for the source HW MAC address. + @param [in] pDestAddr The destination HW MAC address. If HeaderSize is zero, then + this parameter is ignored. + @param [in] pProtocol The type of header to build. If HeaderSize is zero, then + this parameter is ignored. + + @retval EFI_SUCCESS This operation was successful. + @retval EFI_NOT_STARTED The network interface was not started. + @retval EFI_NOT_READY The network interface is too busy to accept this transmit request. + @retval EFI_BUFFER_TOO_SMALL The BufferSize parameter is too small. + @retval EFI_INVALID_PARAMETER pSimpleNetwork parameter was NULL or did not point to a valid + EFI_SIMPLE_NETWORK_PROTOCOL structure. + @retval EFI_DEVICE_ERROR The command could not be sent to the network interface. + +**/ +EFI_STATUS +EFIAPI +SN_Transmit ( + IN EFI_SIMPLE_NETWORK_PROTOCOL * pSimpleNetwork, + IN UINTN HeaderSize, + IN UINTN BufferSize, + IN VOID * pBuffer, + IN EFI_MAC_ADDRESS * pSrcAddr, + IN EFI_MAC_ADDRESS * pDestAddr, + IN UINT16 * pProtocol + ); + +//------------------------------------------------------------------------------ +// Support Routines +//------------------------------------------------------------------------------ + +/** + Get the MAC address + + This routine calls ::Ax88772UsbCommand to request the MAC + address from the network adapter. + + @param [in] pNicDevice Pointer to the NIC_DEVICE structure + @param [out] pMacAddress Address of a six byte buffer to receive the MAC address. + + @retval EFI_SUCCESS The MAC address is available. + @retval other The MAC address is not valid. + +**/ +EFI_STATUS +Ax88772MacAddressGet ( + IN NIC_DEVICE * pNicDevice, + OUT UINT8 * pMacAddress + ); + +/** + Set the MAC address + + This routine calls ::Ax88772UsbCommand to set the MAC address + in the network adapter. + + @param [in] pNicDevice Pointer to the NIC_DEVICE structure + @param [in] pMacAddress Address of a six byte buffer to containing the new MAC address. + + @retval EFI_SUCCESS The MAC address was set. + @retval other The MAC address was not set. + +**/ +EFI_STATUS +Ax88772MacAddressSet ( + IN NIC_DEVICE * pNicDevice, + IN UINT8 * pMacAddress + ); + +/** + Clear the multicast hash table + + @param [in] pNicDevice Pointer to the NIC_DEVICE structure + +**/ +VOID +Ax88772MulticastClear ( + IN NIC_DEVICE * pNicDevice + ); + +/** + Enable a multicast address in the multicast hash table + + This routine calls ::Ax88772Crc to compute the hash bit for + this MAC address. + + @param [in] pNicDevice Pointer to the NIC_DEVICE structure + @param [in] pMacAddress Address of a six byte buffer to containing the MAC address. + +**/ +VOID +Ax88772MulticastSet ( + IN NIC_DEVICE * pNicDevice, + IN UINT8 * pMacAddress + ); + +/** + Start the link negotiation + + This routine calls ::Ax88772PhyWrite to start the PHY's link + negotiation. + + @param [in] pNicDevice Pointer to the NIC_DEVICE structure + + @retval EFI_SUCCESS The link negotiation was started. + @retval other Failed to start the link negotiation. + +**/ +EFI_STATUS +Ax88772NegotiateLinkStart ( + IN NIC_DEVICE * pNicDevice + ); + +/** + Complete the negotiation of the PHY link + + This routine calls ::Ax88772PhyRead to determine if the + link negotiation is complete. + + @param [in] pNicDevice Pointer to the NIC_DEVICE structure + @param [in, out] pPollCount Address of number of times this routine was polled + @param [out] pbComplete Address of boolean to receive complate status. + @param [out] pbLinkUp Address of boolean to receive link status, TRUE=up. + @param [out] pbHiSpeed Address of boolean to receive link speed, TRUE=100Mbps. + @param [out] pbFullDuplex Address of boolean to receive link duplex, TRUE=full. + + @retval EFI_SUCCESS The MAC address is available. + @retval other The MAC address is not valid. + +**/ +EFI_STATUS +Ax88772NegotiateLinkComplete ( + IN NIC_DEVICE * pNicDevice, + IN OUT UINTN * pPollCount, + OUT BOOLEAN * pbComplete, + OUT BOOLEAN * pbLinkUp, + OUT BOOLEAN * pbHiSpeed, + OUT BOOLEAN * pbFullDuplex + ); + +/** + Read a register from the PHY + + This routine calls ::Ax88772UsbCommand to read a PHY register. + + @param [in] pNicDevice Pointer to the NIC_DEVICE structure + @param [in] RegisterAddress Number of the register to read. + @param [in, out] pPhyData Address of a buffer to receive the PHY register value + + @retval EFI_SUCCESS The PHY data is available. + @retval other The PHY data is not valid. + +**/ +EFI_STATUS +Ax88772PhyRead ( + IN NIC_DEVICE * pNicDevice, + IN UINT8 RegisterAddress, + IN OUT UINT16 * pPhyData + ); + +/** + Write to a PHY register + + This routine calls ::Ax88772UsbCommand to write a PHY register. + + @param [in] pNicDevice Pointer to the NIC_DEVICE structure + @param [in] RegisterAddress Number of the register to read. + @param [in] PhyData Address of a buffer to receive the PHY register value + + @retval EFI_SUCCESS The PHY data was written. + @retval other Failed to wwrite the PHY register. + +**/ +EFI_STATUS +Ax88772PhyWrite ( + IN NIC_DEVICE * pNicDevice, + IN UINT8 RegisterAddress, + IN UINT16 PhyData + ); + +/** + Reset the AX88772 + + This routine uses ::Ax88772UsbCommand to reset the network + adapter. This routine also uses ::Ax88772PhyWrite to reset + the PHY. + + @param [in] pNicDevice Pointer to the NIC_DEVICE structure + + @retval EFI_SUCCESS The MAC address is available. + @retval other The MAC address is not valid. + +**/ +EFI_STATUS +Ax88772Reset ( + IN NIC_DEVICE * pNicDevice + ); + +VOID +Ax88772ChkLink ( + IN NIC_DEVICE * pNicDevice, + IN BOOLEAN bUpdateLink + ); + +/** + Receive a frame from the network. + + This routine polls the USB receive interface for a packet. If a packet + is available, this routine adds the receive packet to the list of + pending receive packets. + + This routine calls ::Ax88772NegotiateLinkComplete to verify + that the link is up. This routine also calls ::SN_Reset to + reset the network adapter when necessary. Finally this + routine attempts to receive one or more packets from the + network adapter. + + @param [in] pNicDevice Pointer to the NIC_DEVICE structure + @param [in] bUpdateLink TRUE = Update link status + +**/ +VOID +Ax88772Rx ( + IN NIC_DEVICE * pNicDevice, + IN BOOLEAN bUpdateLink + ); + +/** + Enable or disable the receiver + + This routine calls ::Ax88772UsbCommand to update the + receiver state. This routine also calls ::Ax88772MacAddressSet + to establish the MAC address for the network adapter. + + @param [in] pNicDevice Pointer to the NIC_DEVICE structure + @param [in] RxFilter Simple network RX filter mask value + + @retval EFI_SUCCESS The MAC address was set. + @retval other The MAC address was not set. + +**/ +EFI_STATUS +Ax88772RxControl ( + IN NIC_DEVICE * pNicDevice, + IN UINT32 RxFilter + ); + +EFI_STATUS +Ax88772ReloadSrom ( + IN NIC_DEVICE * pNicDevice + ); + +/** + Read an SROM location + + This routine calls ::Ax88772UsbCommand to read data from the + SROM. + + @param [in] pNicDevice Pointer to the NIC_DEVICE structure + @param [in] Address SROM address + @param [out] pData Buffer to receive the data + + @retval EFI_SUCCESS The read was successful + @retval other The read failed + +**/ +EFI_STATUS +Ax88772SromRead ( + IN NIC_DEVICE * pNicDevice, + IN UINT32 Address, + OUT UINT16 * pData + ); + + +EFI_STATUS +Ax88772EnableSromWrite ( + IN NIC_DEVICE * pNicDevice + ); + + +EFI_STATUS +Ax88772DisableSromWrite ( + IN NIC_DEVICE * pNicDevice + ); + +EFI_STATUS +Ax88772SromWrite ( + IN NIC_DEVICE * pNicDevice, + IN UINT32 Address, + OUT UINT16 * pData + ); +#if 0 +/** + This routine is called at a regular interval to poll for + receive packets. + + This routine polls the link state and gets any receive packets + by calling ::Ax88772Rx. + + @param [in] Event Timer event + @param [in] pNicDevice Pointer to the NIC_DEVICE structure + +**/ +VOID +Ax88772Timer ( + IN EFI_EVENT Event, + IN NIC_DEVICE * pNicDevice + ); +#endif +/** + Send a command to the USB device. + + @param [in] pNicDevice Pointer to the NIC_DEVICE structure + @param [in] pRequest Pointer to the request structure + @param [in, out] pBuffer Data buffer address + + @retval EFI_SUCCESS The USB transfer was successful + @retval other The USB transfer failed + +**/ +EFI_STATUS +Ax88772UsbCommand ( + IN NIC_DEVICE * pNicDevice, + IN USB_DEVICE_REQUEST * pRequest, + IN OUT VOID * pBuffer + ); + +BOOLEAN +Ax88772GetLinkStatus ( + IN NIC_DEVICE * pNicDevice +) ; + +//------------------------------------------------------------------------------ +// EFI Component Name Protocol Support +//------------------------------------------------------------------------------ + +extern EFI_COMPONENT_NAME_PROTOCOL gComponentName; ///< Component name protocol declaration +extern EFI_COMPONENT_NAME2_PROTOCOL gComponentName2; ///< Component name 2 protocol declaration + +/** + Retrieves a Unicode string that is the user readable name of the driver. + + This function retrieves the user readable name of a driver in the form of a + Unicode string. If the driver specified by This has a user readable name in + the language specified by Language, then a pointer to the driver name is + returned in DriverName, and EFI_SUCCESS is returned. If the driver specified + by This does not support the language specified by Language, + then EFI_UNSUPPORTED is returned. + + @param [in] pThis A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or + EFI_COMPONENT_NAME_PROTOCOL instance. + @param [in] pLanguage A pointer to a Null-terminated ASCII string + array indicating the language. This is the + language of the driver name that the caller is + requesting, and it must match one of the + languages specified in SupportedLanguages. The + number of languages supported by a driver is up + to the driver writer. Language is specified + in RFC 3066 or ISO 639-2 language code format. + @param [out] ppDriverName A pointer to the Unicode string to return. + This Unicode string is the name of the + driver specified by This in the language + specified by Language. + + @retval EFI_SUCCESS The Unicode string for the Driver specified by + This and the language specified by Language was + returned in DriverName. + @retval EFI_INVALID_PARAMETER Language is NULL. + @retval EFI_INVALID_PARAMETER DriverName is NULL. + @retval EFI_UNSUPPORTED The driver specified by This does not support + the language specified by Language. + +**/ +EFI_STATUS +EFIAPI +GetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL * pThis, + IN CHAR8 * pLanguage, + OUT CHAR16 ** ppDriverName + ); + + +/** + Retrieves a Unicode string that is the user readable name of the controller + that is being managed by a driver. + + This function retrieves the user readable name of the controller specified by + ControllerHandle and ChildHandle in the form of a Unicode string. If the + driver specified by This has a user readable name in the language specified by + Language, then a pointer to the controller name is returned in ControllerName, + and EFI_SUCCESS is returned. If the driver specified by This is not currently + managing the controller specified by ControllerHandle and ChildHandle, + then EFI_UNSUPPORTED is returned. If the driver specified by This does not + support the language specified by Language, then EFI_UNSUPPORTED is returned. + + @param [in] pThis A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or + EFI_COMPONENT_NAME_PROTOCOL instance. + @param [in] ControllerHandle The handle of a controller that the driver + specified by This is managing. This handle + specifies the controller whose name is to be + returned. + @param [in] ChildHandle The handle of the child controller to retrieve + the name of. This is an optional parameter that + may be NULL. It will be NULL for device + drivers. It will also be NULL for a bus drivers + that wish to retrieve the name of the bus + controller. It will not be NULL for a bus + driver that wishes to retrieve the name of a + child controller. + @param [in] pLanguage A pointer to a Null-terminated ASCII string + array indicating the language. This is the + language of the driver name that the caller is + requesting, and it must match one of the + languages specified in SupportedLanguages. The + number of languages supported by a driver is up + to the driver writer. Language is specified in + RFC 3066 or ISO 639-2 language code format. + @param [out] ppControllerName A pointer to the Unicode string to return. + This Unicode string is the name of the + controller specified by ControllerHandle and + ChildHandle in the language specified by + Language from the point of view of the driver + specified by This. + + @retval EFI_SUCCESS The Unicode string for the user readable name in + the language specified by Language for the + driver specified by This was returned in + DriverName. + @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE. + @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid + EFI_HANDLE. + @retval EFI_INVALID_PARAMETER Language is NULL. + @retval EFI_INVALID_PARAMETER ControllerName is NULL. + @retval EFI_UNSUPPORTED The driver specified by This is not currently + managing the controller specified by + ControllerHandle and ChildHandle. + @retval EFI_UNSUPPORTED The driver specified by This does not support + the language specified by Language. + +**/ +EFI_STATUS +EFIAPI +GetControllerName ( + IN EFI_COMPONENT_NAME_PROTOCOL * pThis, + IN EFI_HANDLE ControllerHandle, + IN OPTIONAL EFI_HANDLE ChildHandle, + IN CHAR8 * pLanguage, + OUT CHAR16 ** ppControllerName + ); + + +EFI_STATUS +Ax88772BulkIn( + IN NIC_DEVICE * pNicDevice +); + +//------------------------------------------------------------------------------ + +#endif // _AX88772_H_ diff --git a/Silicon/ASIX/Drivers/Bus/Usb/UsbNetworking/Ax88772c/Ax88772.c b/Silicon/ASIX/Drivers/Bus/Usb/UsbNetworking/Ax88772c/Ax88772.c new file mode 100644 index 000000000000..a905dc548197 --- /dev/null +++ b/Silicon/ASIX/Drivers/Bus/Usb/UsbNetworking/Ax88772c/Ax88772.c @@ -0,0 +1,1296 @@ +/** @file + Implement the interface to the AX88772 Ethernet controller. + + This module implements the interface to the ASIX AX88772 + USB to Ethernet MAC with integrated 10/100 PHY. Note that this implementation + only supports the integrated PHY since no other test cases were available. + + Copyright (c) 2011, Intel Corporation. All rights reserved. + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "Ax88772.h" + + +/** + Compute the CRC + + @param [in] pMacAddress Address of a six byte buffer to containing the MAC address. + + @returns The CRC-32 value associated with this MAC address + +**/ +UINT32 +Ax88772Crc ( + IN UINT8 * pMacAddress + ) +{ + UINT32 BitNumber; + INT32 Carry; + INT32 Crc; + UINT32 Data; + UINT8 * pEnd; + + // + // Walk the MAC address + // + Crc = -1; + pEnd = &pMacAddress[ PXE_HWADDR_LEN_ETHER ]; + while ( pEnd > pMacAddress ) { + Data = *pMacAddress++; + + + // + // CRC32: x32 + x26 + x23 + x22 + x16 + x12 + x11 + x10 + x8 + x7 + x5 + x4 + x2 + x + 1 + // + // 1 0000 0100 1100 0001 0001 1101 1011 0111 + // + for ( BitNumber = 0; 8 > BitNumber; BitNumber++ ) { + Carry = (( Crc >> 31 ) & 1 ) ^ ( Data & 1 ); + Crc <<= 1; + if ( 0 != Carry ) { + Crc ^= 0x04c11db7; + } + Data >>= 1; + } + } + + // + // Return the CRC value + // + + return (UINT32) Crc; +} + + +/** + Get the MAC address + + This routine calls ::Ax88772UsbCommand to request the MAC + address from the network adapter. + + @param [in] pNicDevice Pointer to the NIC_DEVICE structure + @param [out] pMacAddress Address of a six byte buffer to receive the MAC address. + + @retval EFI_SUCCESS The MAC address is available. + @retval other The MAC address is not valid. + +**/ +EFI_STATUS +Ax88772MacAddressGet ( + IN NIC_DEVICE * pNicDevice, + OUT UINT8 * pMacAddress + ) +{ + USB_DEVICE_REQUEST SetupMsg; + EFI_STATUS Status; + + // + // Set the register address. + // + SetupMsg.RequestType = USB_ENDPOINT_DIR_IN + | USB_REQ_TYPE_VENDOR + | USB_TARGET_DEVICE; + SetupMsg.Request = CMD_MAC_ADDRESS_READ; + SetupMsg.Value = 0; + SetupMsg.Index = 0; + SetupMsg.Length = PXE_HWADDR_LEN_ETHER; + + // + // Read the PHY register + // + Status = Ax88772UsbCommand ( pNicDevice, + &SetupMsg, + pMacAddress ); + + // + // Return the operation status + // + return Status; +} + + +/** + Set the MAC address + + This routine calls ::Ax88772UsbCommand to set the MAC address + in the network adapter. + + @param [in] pNicDevice Pointer to the NIC_DEVICE structure + @param [in] pMacAddress Address of a six byte buffer to containing the new MAC address. + + @retval EFI_SUCCESS The MAC address was set. + @retval other The MAC address was not set. + +**/ +EFI_STATUS +Ax88772MacAddressSet ( + IN NIC_DEVICE * pNicDevice, + IN UINT8 * pMacAddress + ) +{ + USB_DEVICE_REQUEST SetupMsg; + EFI_STATUS Status; + + // + // Set the register address. + // + SetupMsg.RequestType = USB_REQ_TYPE_VENDOR + | USB_TARGET_DEVICE; + SetupMsg.Request = CMD_MAC_ADDRESS_WRITE; + SetupMsg.Value = 0; + SetupMsg.Index = 0; + SetupMsg.Length = PXE_HWADDR_LEN_ETHER; + + // + // Read the PHY register + // + Status = Ax88772UsbCommand ( pNicDevice, + &SetupMsg, + pMacAddress ); + + // + // Return the operation status + // + return Status; +} + +/** + Clear the multicast hash table + + @param [in] pNicDevice Pointer to the NIC_DEVICE structure + +**/ +VOID +Ax88772MulticastClear ( + IN NIC_DEVICE * pNicDevice + ) +{ + int i = 0; + // + // Clear the multicast hash table + // + for ( i = 0 ; i < 8 ; i ++ ) + pNicDevice->MulticastHash[i] = 0; +} + + +/** + Enable a multicast address in the multicast hash table + + This routine calls ::Ax88772Crc to compute the hash bit for + this MAC address. + + @param [in] pNicDevice Pointer to the NIC_DEVICE structure + @param [in] pMacAddress Address of a six byte buffer to containing the MAC address. + +**/ +VOID +Ax88772MulticastSet ( + IN NIC_DEVICE * pNicDevice, + IN UINT8 * pMacAddress + ) +{ + UINT32 Crc; + + // + // Compute the CRC on the destination address + // + Crc = Ax88772Crc ( pMacAddress ) >> 26; + + // + // Set the bit corresponding to the destination address + // + pNicDevice->MulticastHash [ Crc >> 3 ] |= ( 1<< (Crc& 7)); + +} + +/** + Start the link negotiation + + This routine calls ::Ax88772PhyWrite to start the PHY's link + negotiation. + + @param [in] pNicDevice Pointer to the NIC_DEVICE structure + + @retval EFI_SUCCESS The link negotiation was started. + @retval other Failed to start the link negotiation. + +**/ +EFI_STATUS +Ax88772NegotiateLinkStart ( + IN NIC_DEVICE * pNicDevice + ) +{ + UINT16 Control; + EFI_STATUS Status; + + // + // Set the supported capabilities. + // + Status = Ax88772PhyWrite ( pNicDevice, + PHY_ANAR, + AN_CSMA_CD + | AN_TX_FDX | AN_TX_HDX + | AN_10_FDX | AN_10_HDX | AN_FCS ); + if ( !EFI_ERROR ( Status )) { + // + // Set the link speed and duplex + // + Control = BMCR_AUTONEGOTIATION_ENABLE + | BMCR_RESTART_AUTONEGOTIATION; + if ( pNicDevice->b100Mbps ) { + Control |= BMCR_100MBPS; + } + if ( pNicDevice->bFullDuplex ) { + Control |= BMCR_FULL_DUPLEX; + } + Status = Ax88772PhyWrite ( pNicDevice, PHY_BMCR, Control ); + + if (!EFI_ERROR(Status)) + gBS->Stall(3000000); + } + return Status; +} + + + +/** + Complete the negotiation of the PHY link + + This routine calls ::Ax88772PhyRead to determine if the + link negotiation is complete. + + @param [in] pNicDevice Pointer to the NIC_DEVICE structure + @param [in, out] pPollCount Address of number of times this routine was polled + @param [out] pbComplete Address of boolean to receive complate status. + @param [out] pbLinkUp Address of boolean to receive link status, TRUE=up. + @param [out] pbHiSpeed Address of boolean to receive link speed, TRUE=100Mbps. + @param [out] pbFullDuplex Address of boolean to receive link duplex, TRUE=full. + + @retval EFI_SUCCESS The MAC address is available. + @retval other The MAC address is not valid. + +**/ +EFI_STATUS +Ax88772NegotiateLinkComplete ( + IN NIC_DEVICE * pNicDevice, + IN OUT UINTN * pPollCount, + OUT BOOLEAN * pbComplete, + OUT BOOLEAN * pbLinkUp, + OUT BOOLEAN * pbHiSpeed, + OUT BOOLEAN * pbFullDuplex + ) +{ + UINT16 Mask; + UINT16 PhyData; + EFI_STATUS Status; + + // + // Determine if the link is up. + // + *pbComplete = FALSE; + + // + // Get the link status + // + Status = Ax88772PhyRead ( pNicDevice, + PHY_BMSR, + &PhyData ); + + if ( !EFI_ERROR ( Status )) { + *pbLinkUp = (BOOLEAN)( 0 != ( PhyData & BMSR_LINKST )); + if ( 0 == *pbLinkUp ) { + } else { + *pbComplete = (BOOLEAN)( 0 != ( PhyData & 0x20 )); + if ( 0 == *pbComplete ) { + } else { + Status = Ax88772PhyRead ( pNicDevice, + PHY_ANLPAR, + &PhyData ); + if ( !EFI_ERROR ( Status )) { + // + // Autonegotiation is complete + // Determine the link speed. + // + *pbHiSpeed = (BOOLEAN)( 0 != ( PhyData & ( AN_TX_FDX | AN_TX_HDX ))); + + // + // Determine the link duplex. + // + Mask = ( *pbHiSpeed ) ? AN_TX_FDX : AN_10_FDX; + *pbFullDuplex = (BOOLEAN)( 0 != ( PhyData & Mask )); + } + } + } + } else { + } + return Status; +} + + +/** + Read a register from the PHY + + This routine calls ::Ax88772UsbCommand to read a PHY register. + + @param [in] pNicDevice Pointer to the NIC_DEVICE structure + @param [in] RegisterAddress Number of the register to read. + @param [in, out] pPhyData Address of a buffer to receive the PHY register value + + @retval EFI_SUCCESS The PHY data is available. + @retval other The PHY data is not valid. + +**/ +EFI_STATUS +Ax88772PhyRead ( + IN NIC_DEVICE * pNicDevice, + IN UINT8 RegisterAddress, + IN OUT UINT16 * pPhyData + ) +{ + USB_DEVICE_REQUEST SetupMsg; + EFI_STATUS Status; + + // + // Request access to the PHY + // + SetupMsg.RequestType = USB_REQ_TYPE_VENDOR + | USB_TARGET_DEVICE; + SetupMsg.Request = CMD_PHY_ACCESS_SOFTWARE; + SetupMsg.Value = 0; + SetupMsg.Index = 0; + SetupMsg.Length = 0; + Status = Ax88772UsbCommand ( pNicDevice, + &SetupMsg, + NULL ); + if ( !EFI_ERROR ( Status )) { + // + // Read the PHY register address. + // + SetupMsg.RequestType = USB_ENDPOINT_DIR_IN + | USB_REQ_TYPE_VENDOR + | USB_TARGET_DEVICE; + SetupMsg.Request = CMD_PHY_REG_READ; + SetupMsg.Value = pNicDevice->PhyId; + SetupMsg.Index = RegisterAddress; + SetupMsg.Length = sizeof ( *pPhyData ); + Status = Ax88772UsbCommand ( pNicDevice, + &SetupMsg, + pPhyData ); + if ( !EFI_ERROR ( Status )) { + + // + // Release the PHY to the hardware + // + SetupMsg.RequestType = USB_REQ_TYPE_VENDOR + | USB_TARGET_DEVICE; + SetupMsg.Request = CMD_PHY_ACCESS_HARDWARE; + SetupMsg.Value = 0; + SetupMsg.Index = 0; + SetupMsg.Length = 0; + Status = Ax88772UsbCommand ( pNicDevice, + &SetupMsg, + NULL ); + } + } + + // + // Return the operation status. + // + return Status; +} + + +/** + Write to a PHY register + + This routine calls ::Ax88772UsbCommand to write a PHY register. + + @param [in] pNicDevice Pointer to the NIC_DEVICE structure + @param [in] RegisterAddress Number of the register to read. + @param [in] PhyData Address of a buffer to receive the PHY register value + + @retval EFI_SUCCESS The PHY data was written. + @retval other Failed to wwrite the PHY register. + +**/ +EFI_STATUS +Ax88772PhyWrite ( + IN NIC_DEVICE * pNicDevice, + IN UINT8 RegisterAddress, + IN UINT16 PhyData + ) +{ + USB_DEVICE_REQUEST SetupMsg; + EFI_STATUS Status; + + // + // Request access to the PHY + // + SetupMsg.RequestType = USB_REQ_TYPE_VENDOR + | USB_TARGET_DEVICE; + SetupMsg.Request = CMD_PHY_ACCESS_SOFTWARE; + SetupMsg.Value = 0; + SetupMsg.Index = 0; + SetupMsg.Length = 0; + Status = Ax88772UsbCommand ( pNicDevice, + &SetupMsg, + NULL ); + if ( !EFI_ERROR ( Status )) { + // + // Write the PHY register + // + SetupMsg.RequestType = USB_REQ_TYPE_VENDOR + | USB_TARGET_DEVICE; + SetupMsg.Request = CMD_PHY_REG_WRITE; + SetupMsg.Value = pNicDevice->PhyId; + SetupMsg.Index = RegisterAddress; + SetupMsg.Length = sizeof ( PhyData ); + Status = Ax88772UsbCommand ( pNicDevice, + &SetupMsg, + &PhyData ); + if ( !EFI_ERROR ( Status )) { + + // + // Release the PHY to the hardware + // + SetupMsg.RequestType = USB_REQ_TYPE_VENDOR + | USB_TARGET_DEVICE; + SetupMsg.Request = CMD_PHY_ACCESS_HARDWARE; + SetupMsg.Value = 0; + SetupMsg.Index = 0; + SetupMsg.Length = 0; + Status = Ax88772UsbCommand ( pNicDevice, + &SetupMsg, + NULL ); + } + } + + // + // Return the operation status. + // + return Status; +} + + +/** + Reset the AX88772 + + This routine uses ::Ax88772UsbCommand to reset the network + adapter. This routine also uses ::Ax88772PhyWrite to reset + the PHY. + + @param [in] pNicDevice Pointer to the NIC_DEVICE structure + + @retval EFI_SUCCESS The MAC address is available. + @retval other The MAC address is not valid. + +**/ +EFI_STATUS +Ax88772Reset ( + IN NIC_DEVICE * pNicDevice + ) +{ + USB_DEVICE_REQUEST SetupMsg; + EFI_STATUS Status; + EFI_USB_IO_PROTOCOL *pUsbIo; + + pUsbIo = pNicDevice->pUsbIo; + + SetupMsg.RequestType = USB_REQ_TYPE_VENDOR + | USB_TARGET_DEVICE; + SetupMsg.Request = CMD_PHY_ACCESS_HARDWARE; + SetupMsg.Value = 0; + SetupMsg.Index = 0; + SetupMsg.Length = 0; + Status = Ax88772UsbCommand ( pNicDevice, + &SetupMsg, + NULL ); + + if (EFI_ERROR(Status)) goto err; + + SetupMsg.RequestType = USB_REQ_TYPE_VENDOR + | USB_TARGET_DEVICE; + SetupMsg.Request = CMD_PHY_SELECT; + SetupMsg.Value = SPHY_PSEL; + SetupMsg.Index = 0; + SetupMsg.Length = 0; + Status = Ax88772UsbCommand ( pNicDevice, + &SetupMsg, + NULL ); + + if (EFI_ERROR(Status)) goto err; + + SetupMsg.RequestType = USB_REQ_TYPE_VENDOR + | USB_TARGET_DEVICE; + SetupMsg.Request = CMD_RESET; + SetupMsg.Value = SRR_IPRL ; + SetupMsg.Index = 0; + SetupMsg.Length = 0; + Status = Ax88772UsbCommand ( pNicDevice, + &SetupMsg, + NULL ); + + if (EFI_ERROR(Status)) goto err; + + SetupMsg.RequestType = USB_REQ_TYPE_VENDOR + | USB_TARGET_DEVICE; + SetupMsg.Request = CMD_RESET; + SetupMsg.Value = SRR_IPPD | SRR_IPRL ; + SetupMsg.Index = 0; + SetupMsg.Length = 0; + Status = Ax88772UsbCommand ( pNicDevice, + &SetupMsg, + NULL ); + + gBS->Stall ( 200000 ); + + if (EFI_ERROR(Status)) goto err; + + SetupMsg.RequestType = USB_REQ_TYPE_VENDOR + | USB_TARGET_DEVICE; + SetupMsg.Request = CMD_RESET; + SetupMsg.Value = SRR_IPRL ; + SetupMsg.Index = 0; + SetupMsg.Length = 0; + Status = Ax88772UsbCommand ( pNicDevice, + &SetupMsg, + NULL ); + + gBS->Stall ( 200000 ); + + if (EFI_ERROR(Status)) goto err; + + SetupMsg.RequestType = USB_REQ_TYPE_VENDOR + | USB_TARGET_DEVICE; + SetupMsg.Request = CMD_RESET; + SetupMsg.Value = 0; + SetupMsg.Index = 0; + SetupMsg.Length = 0; + Status = Ax88772UsbCommand ( pNicDevice, + &SetupMsg, + NULL ); + + if (EFI_ERROR(Status)) goto err; + + SetupMsg.RequestType = USB_REQ_TYPE_VENDOR + | USB_TARGET_DEVICE; + SetupMsg.Request = CMD_PHY_SELECT; + SetupMsg.Value = SPHY_PSEL; + SetupMsg.Index = 0; + SetupMsg.Length = 0; + Status = Ax88772UsbCommand ( pNicDevice, + &SetupMsg, + NULL ); + + if (EFI_ERROR(Status)) goto err; + + SetupMsg.RequestType = USB_REQ_TYPE_VENDOR + | USB_TARGET_DEVICE; + SetupMsg.Request = CMD_RESET; + SetupMsg.Value = SRR_IPRL | SRR_BZ | SRR_BZTYPE; + SetupMsg.Index = 0; + SetupMsg.Length = 0; + Status = Ax88772UsbCommand ( pNicDevice, + &SetupMsg, + NULL ); + + if (EFI_ERROR(Status)) goto err; + + SetupMsg.RequestType = USB_REQ_TYPE_VENDOR + | USB_TARGET_DEVICE; + SetupMsg.Request = CMD_RX_CONTROL_WRITE; + SetupMsg.Value = 0; + SetupMsg.Index = 0; + SetupMsg.Length = 0; + Status = Ax88772UsbCommand ( pNicDevice, + &SetupMsg, + NULL ); + + if (EFI_ERROR(Status)) goto err; + + if (!pNicDevice->Flag772A) { + SetupMsg.RequestType = USB_REQ_TYPE_VENDOR + | USB_TARGET_DEVICE; + SetupMsg.Request = CMD_RXQTC; +#if RXTHOU + /*size cannot exceed 3K*/ + //SetupMsg.Value = 0x0; + //SetupMsg.Index = 0x8001; + /*size cannot exceed 16K*/ + SetupMsg.Value = 0x8300; + SetupMsg.Index = 0x8500; + /*size cannot exceed 32K*/ + //SetupMsg.Value = 0x8784; + //SetupMsg.Index = 0x8A00; + SetupMsg.Length = 0; +#else + SetupMsg.Value = 0x8000; + SetupMsg.Index = 0x8001; +#endif + Status = Ax88772UsbCommand ( pNicDevice, + &SetupMsg, + NULL ); + } +err: + return Status; +} + +/** + Enable or disable the receiver + + This routine calls ::Ax88772UsbCommand to update the + receiver state. This routine also calls ::Ax88772MacAddressSet + to establish the MAC address for the network adapter. + + @param [in] pNicDevice Pointer to the NIC_DEVICE structure + @param [in] RxFilter Simple network RX filter mask value + + @retval EFI_SUCCESS The MAC address was set. + @retval other The MAC address was not set. + +**/ +EFI_STATUS +Ax88772RxControl ( + IN NIC_DEVICE * pNicDevice, + IN UINT32 RxFilter + ) +{ + UINT16 MediumStatus; + UINT16 RxControl; + USB_DEVICE_REQUEST SetupMsg; + EFI_STATUS Status = EFI_SUCCESS; + + // + // Enable the receiver if something is to be received + // + if ( 0 != RxFilter ) { + // + // Enable the receiver + // + SetupMsg.RequestType = USB_ENDPOINT_DIR_IN + | USB_REQ_TYPE_VENDOR + | USB_TARGET_DEVICE; + SetupMsg.Request = CMD_MEDIUM_STATUS_READ; + SetupMsg.Value = 0; + SetupMsg.Index = 0; + SetupMsg.Length = sizeof ( MediumStatus ); + Status = Ax88772UsbCommand ( pNicDevice, + &SetupMsg, + &MediumStatus ); + if ( !EFI_ERROR ( Status )) { + if ( 0 == ( MediumStatus & MS_RE )) { + MediumStatus |= MS_RE | MS_ONE; + + if ( pNicDevice->bFullDuplex ) + MediumStatus |= MS_TFC | MS_RFC | MS_FD; + else + MediumStatus &= ~(MS_TFC | MS_RFC | MS_FD); + + if ( pNicDevice->b100Mbps ) + MediumStatus |= MS_PS; + else + MediumStatus &= ~MS_PS; + + SetupMsg.RequestType = USB_REQ_TYPE_VENDOR + | USB_TARGET_DEVICE; + SetupMsg.Request = CMD_MEDIUM_STATUS_WRITE; + SetupMsg.Value = MediumStatus; + SetupMsg.Index = 0; + SetupMsg.Length = 0; + Status = Ax88772UsbCommand ( pNicDevice, + &SetupMsg, + NULL ); + + if (EFI_ERROR(Status)) + goto EXIT; + } + } else { + goto EXIT; + } + } + RxControl = RXC_SO; + if (!pNicDevice->Flag772A) + RxControl |= RXC_RH1M; + + // + // Enable multicast if requested + // + if ( 0 != ( RxFilter & EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST )) { + RxControl |= RXC_AM; + // + // Update the multicast hash table + // + SetupMsg.RequestType = USB_REQ_TYPE_VENDOR + | USB_TARGET_DEVICE; + SetupMsg.Request = CMD_MULTICAST_HASH_WRITE; + SetupMsg.Value = 0; + SetupMsg.Index = 0; + SetupMsg.Length = sizeof ( pNicDevice ->MulticastHash ); + Status = Ax88772UsbCommand ( pNicDevice, + &SetupMsg, + &pNicDevice->MulticastHash ); + + if (EFI_ERROR(Status)) + goto EXIT; + } + + // + // Enable all multicast if requested + // + if ( 0 != ( RxFilter & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST )) { + RxControl |= RXC_AMALL; + } + + // + // Enable broadcast if requested + // + if ( 0 != ( RxFilter & EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST )) { + RxControl |= RXC_AB; + } + + // + // Enable promiscuous mode if requested + // + if ( 0 != ( RxFilter & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS )) { + RxControl |= RXC_PRO; + } + + // + // Update the receiver control + // + if (pNicDevice->CurRxControl != RxControl) { + SetupMsg.RequestType = USB_REQ_TYPE_VENDOR + | USB_TARGET_DEVICE; + SetupMsg.Request = CMD_RX_CONTROL_WRITE; +#if RXTHOU + if (pNicDevice->Flag772A) + RxControl |= 0x0300; +#endif + if (pNicDevice->Flag772A) + RxControl &= ~(RXC_MFB); + SetupMsg.Value = RxControl; + SetupMsg.Index = 0; + SetupMsg.Length = 0; + Status = Ax88772UsbCommand ( pNicDevice, + &SetupMsg, + NULL ); + if ( !EFI_ERROR ( Status )) + pNicDevice->CurRxControl = RxControl; + } + + // + // Return the operation status + // +EXIT: + return Status; +} + + + +EFI_STATUS +Ax88772ReloadSrom ( + IN NIC_DEVICE * pNicDevice + ) +{ + USB_DEVICE_REQUEST SetupMsg; + EFI_STATUS Status; + + // + // Read a value from the SROM + // + SetupMsg.RequestType = USB_REQ_TYPE_VENDOR + | USB_TARGET_DEVICE; + + SetupMsg.Request = CMD_WRITE_GPIOS; + SetupMsg.Value = 0x80; + SetupMsg.Index = 0; + SetupMsg.Length = 0 ; + Status = Ax88772UsbCommand ( pNicDevice, + &SetupMsg, + NULL ); + + if (EFI_SUCCESS == Status) + gBS->Stall(500000); + + return Status; + +} + + +/** + Read an SROM location + + This routine calls ::Ax88772UsbCommand to read data from the + SROM. + + @param [in] pNicDevice Pointer to the NIC_DEVICE structure + @param [in] Address SROM address + @param [out] pData Buffer to receive the data + + @retval EFI_SUCCESS The read was successful + @retval other The read failed + +**/ +EFI_STATUS +Ax88772SromRead ( + IN NIC_DEVICE * pNicDevice, + IN UINT32 Address, + OUT UINT16 * pData + ) +{ + + USB_DEVICE_REQUEST SetupMsg; + EFI_STATUS Status; + + // + // Read a value from the SROM + // + SetupMsg.RequestType = USB_ENDPOINT_DIR_IN + | USB_REQ_TYPE_VENDOR + | USB_TARGET_DEVICE; + SetupMsg.Request = CMD_SROM_READ; + SetupMsg.Value = (UINT16) Address; + SetupMsg.Index = 0; + SetupMsg.Length = sizeof ( *pData ); + Status = Ax88772UsbCommand ( pNicDevice, + &SetupMsg, + pData ); + + // + // Return the operation status + // + return Status; +} + +EFI_STATUS +Ax88772EnableSromWrite ( + IN NIC_DEVICE * pNicDevice + ) +{ + USB_DEVICE_REQUEST SetupMsg; + EFI_STATUS Status; + + // + // Read a value from the SROM + // + SetupMsg.RequestType = USB_REQ_TYPE_VENDOR + | USB_TARGET_DEVICE; + + SetupMsg.Request = CMD_SROM_WRITE_EN; + SetupMsg.Value = 0; + SetupMsg.Index = 0; + SetupMsg.Length = 0 ; + Status = Ax88772UsbCommand ( pNicDevice, + &SetupMsg, + NULL ); + + if (EFI_SUCCESS == Status) + gBS->Stall(500000); + + return Status; + +} + + +EFI_STATUS +Ax88772DisableSromWrite ( + IN NIC_DEVICE * pNicDevice + ) +{ + USB_DEVICE_REQUEST SetupMsg; + EFI_STATUS Status; + + // + // Read a value from the SROM + // + SetupMsg.RequestType = USB_REQ_TYPE_VENDOR + | USB_TARGET_DEVICE; + + SetupMsg.Request = CMD_SROM_WRITE_DIS; + SetupMsg.Value = 0; + SetupMsg.Index = 0; + SetupMsg.Length = 0; + Status = Ax88772UsbCommand ( pNicDevice, + &SetupMsg, + NULL ); + + if (EFI_SUCCESS == Status) + gBS->Stall(500000); + + return Status; + +} + +/** + Write an SROM location + + This routine calls ::Ax88772UsbCommand to write data from the + SROM. + + @param [in] pNicDevice Pointer to the NIC_DEVICE structure + @param [in] Address SROM address + @param [out] pData Buffer of data to write + + @retval EFI_SUCCESS The write was successful + @retval other The write failed + +**/ +EFI_STATUS +Ax88772SromWrite ( + IN NIC_DEVICE * pNicDevice, + IN UINT32 Address, + IN UINT16 * pData + ) +{ + + USB_DEVICE_REQUEST SetupMsg; + EFI_STATUS Status; + + SetupMsg.RequestType = USB_REQ_TYPE_VENDOR + | USB_TARGET_DEVICE; + + SetupMsg.Request = CMD_SROM_WRITE; + SetupMsg.Value = (UINT16) Address; + SetupMsg.Index = (UINT16) (*pData); + SetupMsg.Length = 0; + + Status = Ax88772UsbCommand ( pNicDevice, + &SetupMsg, + NULL ); + + // + // Return the operation status + // + return Status; +} + +/** + Send a command to the USB device. + + @param [in] pNicDevice Pointer to the NIC_DEVICE structure + @param [in] pRequest Pointer to the request structure + @param [in, out] pBuffer Data buffer address + + @retval EFI_SUCCESS The USB transfer was successful + @retval other The USB transfer failed + +**/ +EFI_STATUS +Ax88772UsbCommand ( + IN NIC_DEVICE * pNicDevice, + IN USB_DEVICE_REQUEST * pRequest, + IN OUT VOID * pBuffer + ) +{ + UINT32 CmdStatus; + EFI_USB_DATA_DIRECTION Direction; + EFI_USB_IO_PROTOCOL * pUsbIo; + EFI_STATUS Status; + + // + // Determine the transfer direction + // + Direction = EfiUsbNoData; + if ( 0 != pRequest->Length ) { + Direction = ( 0 != ( pRequest->RequestType & USB_ENDPOINT_DIR_IN )) + ? EfiUsbDataIn : EfiUsbDataOut; + } + + // + // Issue the command + // + pUsbIo = pNicDevice->pUsbIo; + Status = pUsbIo->UsbControlTransfer ( pUsbIo, + pRequest, + Direction, + USB_BUS_TIMEOUT, + pBuffer, + pRequest->Length, + &CmdStatus ); + + // + // Determine the operation status + // + if ( !EFI_ERROR ( Status )) { + Status = CmdStatus; + } else { + // + // Only use status values associated with the Simple Network protocol + // + if ( EFI_TIMEOUT == Status ) { + Status = EFI_DEVICE_ERROR; + } + } + + // + // Return the operation status + // + return Status; +} + +BOOLEAN +Ax88772GetLinkStatus ( + IN NIC_DEVICE * pNicDevice +) +{ + UINT32 CmdStatus; + EFI_USB_IO_PROTOCOL * pUsbIo; + UINT64 IntData = 0; + UINTN IntDataLeng = 8; + EFI_STATUS Status; + + // + // Issue the command + // + pUsbIo = pNicDevice->pUsbIo; + Status = pUsbIo->UsbSyncInterruptTransfer( pUsbIo, + USB_ENDPOINT_DIR_IN | INTERRUPT_ENDPOINT, + &IntData, + &IntDataLeng, + USB_BUS_TIMEOUT, + &CmdStatus ); + + if ( EFI_ERROR(Status) || EFI_ERROR(CmdStatus) || 0 == IntDataLeng) { + return FALSE; + } + return (IntData & 0x800000)? FALSE : TRUE; + +} + +#if RXTHOU +EFI_STATUS +Ax88772BulkIn( + IN NIC_DEVICE * pNicDevice +) +{ + int i; + UINTN LengthInBytes = 0; + UINTN TMP_LENG = AX88772_MAX_BULKIN_SIZE; + UINTN ORI_TMP_LENG = 0; + EFI_STATUS Status = EFI_DEVICE_ERROR; + EFI_USB_IO_PROTOCOL *pUsbIo; + UINT32 TransferStatus = 0; + UINT16 tmpPktCnt = 0; + UINT16 * tmpHdr = (UINT16 *)pNicDevice->pBulkInbuf; + USB_DEVICE_REQUEST SetupMsg; + + pUsbIo = pNicDevice->pUsbIo; + for ( i = 0 ; i < (AX88772_MAX_BULKIN_SIZE / 512) && pUsbIo != NULL; i++) { + VOID* tmpAddr = 0; + + tmpPktCnt = 0; + tmpAddr = (VOID*) &pNicDevice->pBulkInbuf[LengthInBytes]; + ORI_TMP_LENG = TMP_LENG; + Status = pUsbIo->UsbBulkTransfer ( pUsbIo, + USB_ENDPOINT_DIR_IN | BULK_IN_ENDPOINT, + tmpAddr, + &TMP_LENG, + BULKIN_TIMEOUT, + &TransferStatus ); + + if (ORI_TMP_LENG == TMP_LENG) { + Status = EFI_NOT_READY; + goto no_pkt; + } + + if (( !EFI_ERROR ( Status )) && + ( !EFI_ERROR ( TransferStatus )) && + TMP_LENG != 0) { + LengthInBytes += TMP_LENG; + if ((TMP_LENG % 512) != 0) { + goto done; + } + } else if (( !EFI_ERROR ( Status )) && + ( !EFI_ERROR ( TransferStatus )) && + (TMP_LENG == 0)) { + Status = EFI_NOT_READY; + goto done; + } else if (EFI_TIMEOUT == Status && EFI_USB_ERR_TIMEOUT == TransferStatus) { + SetupMsg.RequestType = USB_REQ_TYPE_STANDARD | 0x02; + SetupMsg.Request = 0x01; + SetupMsg.Value = 0; + SetupMsg.Index = 0x82; + SetupMsg.Length = 0; + Status = Ax88772UsbCommand ( pNicDevice, + &SetupMsg, + NULL ); + Status = EFI_NOT_READY; + goto done; + } else { + Status = EFI_DEVICE_ERROR; + goto done; + } + } +done: + if (LengthInBytes != 0) { + UINT16 tmpLen; + UINT16 tmpLenBar; + UINT16 tmpTotalLen = 0; + UINTN TotalLen = LengthInBytes; + + do { + tmpLen = (*tmpHdr) & 0x7FF; + tmpLenBar = *(tmpHdr + 1); + tmpTotalLen = ((tmpLen + 4 + 1) & 0xfffe); + + if ((tmpLen & 0x7FF) + (tmpLenBar & 0x7FF) == 0x7FF) { + tmpPktCnt++; + } else { + if ( tmpPktCnt != 0) { + break; + } + Status = EFI_NOT_READY; + goto no_pkt; + } + tmpHdr += (tmpTotalLen / 2); + TotalLen -= tmpTotalLen; + } while (TotalLen > 0); + + if (LengthInBytes >= 1000 && tmpPktCnt != 0) { + if ((pNicDevice->rxburst) == 1) { + SetupMsg.RequestType = USB_REQ_TYPE_VENDOR + | USB_TARGET_DEVICE; + SetupMsg.Request = CMD_RESET; + SetupMsg.Value = SRR_IPRL; + SetupMsg.Index = 0; + SetupMsg.Length = 0; + Ax88772UsbCommand ( pNicDevice, + &SetupMsg, + NULL ); + } + + if (pNicDevice->rxburst < 2) + pNicDevice->rxburst++; + + } else { + if (pNicDevice->rxburst >= 2) { + SetupMsg.RequestType = USB_REQ_TYPE_VENDOR + | USB_TARGET_DEVICE; + SetupMsg.Request = CMD_RESET; + SetupMsg.Value = SRR_IPRL| SRR_BZ | SRR_BZTYPE; + SetupMsg.Index = 0; + SetupMsg.Length = 0; + Ax88772UsbCommand ( pNicDevice, + &SetupMsg, + NULL ); + } + pNicDevice->rxburst = 0; + } + } + + if (tmpPktCnt != 0) { + pNicDevice->PktCnt = tmpPktCnt; + pNicDevice->pCurPktHdrOff = pNicDevice->pBulkInbuf; + pNicDevice->pCurPktOff = pNicDevice->pBulkInbuf + 4; + Status = EFI_SUCCESS; + } + +no_pkt: + return Status; +} +#else +EFI_STATUS +Ax88772BulkIn( + IN NIC_DEVICE * pNicDevice +) +{ + int i; + UINTN LengthInBytes = 0; + UINTN TMP_LENG = AX88772_MAX_BULKIN_SIZE; + UINTN ORI_TMP_LENG = 0; + UINTN CURBufSize = AX88772_MAX_BULKIN_SIZE; + EFI_STATUS Status = EFI_DEVICE_ERROR; + EFI_USB_IO_PROTOCOL *pUsbIo; + UINT32 TransferStatus = 0; + UINT16 tmpPktCnt = 0; + UINT16 * tmpHdr = (UINT16 *)pNicDevice->pBulkInbuf; + + pUsbIo = pNicDevice->pUsbIo; + for ( i = 0 ; i < (AX88772_MAX_BULKIN_SIZE / 512) && pUsbIo != NULL; i++) { + VOID* tmpAddr = 0; + + tmpPktCnt = 0; + tmpAddr = (VOID*) &pNicDevice->pBulkInbuf[LengthInBytes]; + ORI_TMP_LENG = TMP_LENG; + Status = pUsbIo->UsbBulkTransfer ( pUsbIo, + USB_ENDPOINT_DIR_IN | BULK_IN_ENDPOINT, + tmpAddr, + &TMP_LENG, + BULKIN_TIMEOUT, + &TransferStatus ); + + if (ORI_TMP_LENG == TMP_LENG) { + Status = EFI_NOT_READY; + goto no_pkt; + } + + if (( !EFI_ERROR ( Status )) && + ( !EFI_ERROR ( TransferStatus )) && + TMP_LENG != 0) { + UINT16 tmpLen; + UINT16 tmpLenBar; + UINT16 tmpTotalLen = 0; + + LengthInBytes += TMP_LENG; + CURBufSize = CURBufSize - TMP_LENG; + TMP_LENG = CURBufSize; + do { + tmpLen = *tmpHdr; + tmpLenBar = *(tmpHdr + 1); + tmpTotalLen += ((tmpLen + 4 + 1) & 0xfffe); + + if (((tmpLen ^ tmpLenBar) == 0xffff)) { + if (tmpTotalLen == LengthInBytes) { + tmpPktCnt++; + Status = EFI_SUCCESS; + goto done; + } else if (tmpTotalLen > LengthInBytes) { + break; + } + } else if (((tmpLen ^ tmpLenBar) != 0xffff)) { + if ( tmpPktCnt != 0) { + Status = EFI_SUCCESS; + goto done; + } + Status = EFI_NOT_READY; + goto no_pkt; + } + tmpHdr += (tmpTotalLen / 2); + tmpPktCnt++; + }while (tmpTotalLen < LengthInBytes); + } else if (( !EFI_ERROR ( Status )) && + ( !EFI_ERROR ( TransferStatus )) && + (TMP_LENG == 0)) { + if ( tmpPktCnt != 0) { + Status = EFI_SUCCESS; + goto done; + } + Status = EFI_NOT_READY; + goto no_pkt; + } else if (EFI_TIMEOUT == Status && EFI_USB_ERR_TIMEOUT == TransferStatus) { + if ( tmpPktCnt != 0) { + Status = EFI_SUCCESS; + goto done; + } + Status = EFI_NOT_READY; + goto no_pkt; + } else { + if ( tmpPktCnt != 0) { + Status = EFI_SUCCESS; + goto done; + } + Status = EFI_DEVICE_ERROR; + goto no_pkt; + } + } +done: + pNicDevice->PktCnt = tmpPktCnt; + pNicDevice->pCurPktHdrOff = pNicDevice->pBulkInbuf; + pNicDevice->pCurPktOff = pNicDevice->pBulkInbuf + 4; +no_pkt: + return Status; +} +#endif diff --git a/Silicon/ASIX/Drivers/Bus/Usb/UsbNetworking/Ax88772c/ComponentName.c b/Silicon/ASIX/Drivers/Bus/Usb/UsbNetworking/Ax88772c/ComponentName.c new file mode 100644 index 000000000000..8e2ba86f945e --- /dev/null +++ b/Silicon/ASIX/Drivers/Bus/Usb/UsbNetworking/Ax88772c/ComponentName.c @@ -0,0 +1,246 @@ +/** @file + UEFI Component Name(2) protocol implementation. + + Copyright (c) 2011, Intel Corporation. All rights reserved. + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "Ax88772.h" + +/** + EFI Component Name Protocol declaration +**/ +GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gComponentName = { + GetDriverName, + GetControllerName, + "eng" +}; + +/** + EFI Component Name 2 Protocol declaration +**/ +GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gComponentName2 = { + (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) GetDriverName, + (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) GetControllerName, + "en" +}; + + +/** + Driver name table declaration +**/ +GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE +mDriverNameTable[] = { + {"eng;en", L"ASIX AX88772B Ethernet Driver 2.8.0"}, + {NULL, NULL} +}; + + +/** + Controller name table declaration +**/ +GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE +mControllerNameTable[] = { + {"eng;en", L"ASIX AX88772B USB Fast Ethernet Controller"}, + {NULL, NULL} +}; + +/** + Retrieves a Unicode string that is the user readable name of the driver. + + This function retrieves the user readable name of a driver in the form of a + Unicode string. If the driver specified by This has a user readable name in + the language specified by Language, then a pointer to the driver name is + returned in DriverName, and EFI_SUCCESS is returned. If the driver specified + by This does not support the language specified by Language, + then EFI_UNSUPPORTED is returned. + + @param [in] pThis A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or + EFI_COMPONENT_NAME_PROTOCOL instance. + @param [in] pLanguage A pointer to a Null-terminated ASCII string + array indicating the language. This is the + language of the driver name that the caller is + requesting, and it must match one of the + languages specified in SupportedLanguages. The + number of languages supported by a driver is up + to the driver writer. Language is specified + in RFC 3066 or ISO 639-2 language code format. + @param [out] ppDriverName A pointer to the Unicode string to return. + This Unicode string is the name of the + driver specified by This in the language + specified by Language. + + @retval EFI_SUCCESS The Unicode string for the Driver specified by + This and the language specified by Language was + returned in DriverName. + @retval EFI_INVALID_PARAMETER Language is NULL. + @retval EFI_INVALID_PARAMETER DriverName is NULL. + @retval EFI_UNSUPPORTED The driver specified by This does not support + the language specified by Language. + +**/ +EFI_STATUS +EFIAPI +GetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL * pThis, + IN CHAR8 * pLanguage, + OUT CHAR16 ** ppDriverName + ) +{ + EFI_STATUS Status; + + Status = LookupUnicodeString2 ( + pLanguage, + pThis->SupportedLanguages, + mDriverNameTable, + ppDriverName, + (BOOLEAN)(pThis == &gComponentName) + ); + + return Status; +} + +/** + Retrieves a Unicode string that is the user readable name of the controller + that is being managed by a driver. + + This function retrieves the user readable name of the controller specified by + ControllerHandle and ChildHandle in the form of a Unicode string. If the + driver specified by This has a user readable name in the language specified by + Language, then a pointer to the controller name is returned in ControllerName, + and EFI_SUCCESS is returned. If the driver specified by This is not currently + managing the controller specified by ControllerHandle and ChildHandle, + then EFI_UNSUPPORTED is returned. If the driver specified by This does not + support the language specified by Language, then EFI_UNSUPPORTED is returned. + + @param [in] pThis A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or + EFI_COMPONENT_NAME_PROTOCOL instance. + @param [in] ControllerHandle The handle of a controller that the driver + specified by This is managing. This handle + specifies the controller whose name is to be + returned. + @param [in] ChildHandle The handle of the child controller to retrieve + the name of. This is an optional parameter that + may be NULL. It will be NULL for device + drivers. It will also be NULL for a bus drivers + that wish to retrieve the name of the bus + controller. It will not be NULL for a bus + driver that wishes to retrieve the name of a + child controller. + @param [in] pLanguage A pointer to a Null-terminated ASCII string + array indicating the language. This is the + language of the driver name that the caller is + requesting, and it must match one of the + languages specified in SupportedLanguages. The + number of languages supported by a driver is up + to the driver writer. Language is specified in + RFC 3066 or ISO 639-2 language code format. + @param [out] ppControllerName A pointer to the Unicode string to return. + This Unicode string is the name of the + controller specified by ControllerHandle and + ChildHandle in the language specified by + Language from the point of view of the driver + specified by This. + + @retval EFI_SUCCESS The Unicode string for the user readable name in + the language specified by Language for the + driver specified by This was returned in + DriverName. + @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE. + @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid + EFI_HANDLE. + @retval EFI_INVALID_PARAMETER Language is NULL. + @retval EFI_INVALID_PARAMETER ControllerName is NULL. + @retval EFI_UNSUPPORTED The driver specified by This is not currently + managing the controller specified by + ControllerHandle and ChildHandle. + @retval EFI_UNSUPPORTED The driver specified by This does not support + the language specified by Language. + +**/ + + +#if PASS_SCT +EFI_STATUS +EFIAPI +GetControllerName ( + IN EFI_COMPONENT_NAME_PROTOCOL * pThis, + IN EFI_HANDLE ControllerHandle, + IN OPTIONAL EFI_HANDLE ChildHandle, + IN CHAR8 * pLanguage, + OUT CHAR16 ** ppControllerName + ) +{ + + EFI_STATUS Status; + EFI_USB_IO_PROTOCOL *UsbIoProtocol; + + // + // This is a device driver, so ChildHandle must be NULL. + // + if (ChildHandle != NULL) { + return EFI_UNSUPPORTED; + } + // + // Check Controller's handle + // + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiUsbIoProtocolGuid, + (VOID **) &UsbIoProtocol, + gDriverBinding.DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (!EFI_ERROR (Status)) { + gBS->CloseProtocol ( + ControllerHandle, + &gEfiUsbIoProtocolGuid, + gDriverBinding.DriverBindingHandle, + ControllerHandle + ); + return EFI_UNSUPPORTED; + } + + if (Status != EFI_ALREADY_STARTED) { + return EFI_UNSUPPORTED; + } + + Status = LookupUnicodeString2 ( + pLanguage, + pThis->SupportedLanguages, + mControllerNameTable, + ppControllerName, + (BOOLEAN)(pThis == &gComponentName) + ); + + return Status; +} +#else +EFI_STATUS +EFIAPI +GetControllerName ( + IN EFI_COMPONENT_NAME_PROTOCOL * pThis, + IN EFI_HANDLE ControllerHandle, + IN OPTIONAL EFI_HANDLE ChildHandle, + IN CHAR8 * pLanguage, + OUT CHAR16 ** ppControllerName + ) +{ + EFI_STATUS Status; + + // + // Set the controller name + // + *ppControllerName = L"ASIX AX88772B USB Fast Ethernet Controller"; + Status = EFI_SUCCESS; + + // + // Return the operation status + // + + return Status; +} + +#endif diff --git a/Silicon/ASIX/Drivers/Bus/Usb/UsbNetworking/Ax88772c/DriverBinding.c b/Silicon/ASIX/Drivers/Bus/Usb/UsbNetworking/Ax88772c/DriverBinding.c new file mode 100644 index 000000000000..5edb7cbb2630 --- /dev/null +++ b/Silicon/ASIX/Drivers/Bus/Usb/UsbNetworking/Ax88772c/DriverBinding.c @@ -0,0 +1,637 @@ +/** @file + Implement the driver binding protocol for Asix AX88772 Ethernet driver. + + Copyright (c) 2011-2013, Intel Corporation. All rights reserved. + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "Ax88772.h" +#include +/** + Verify the controller type + + @param [in] pThis Protocol instance pointer. + @param [in] Controller Handle of device to test. + @param [in] pRemainingDevicePath Not used. + + @retval EFI_SUCCESS This driver supports this device. + @retval other This driver does not support this device. + +**/ +EFI_STATUS +EFIAPI +DriverSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL * pThis, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL * pRemainingDevicePath + ) +{ + EFI_USB_DEVICE_DESCRIPTOR Device; + EFI_USB_IO_PROTOCOL * pUsbIo; + EFI_STATUS Status; + + // + // Connect to the USB stack + // + Status = gBS->OpenProtocol ( + Controller, + &gEfiUsbIoProtocolGuid, + (VOID **) &pUsbIo, + pThis->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (!EFI_ERROR ( Status )) { + // + // Get the interface descriptor to check the USB class and find a transport + // protocol handler. + // + Status = pUsbIo->UsbGetDeviceDescriptor ( pUsbIo, &Device ); + if (EFI_ERROR ( Status )) { + Status = EFI_UNSUPPORTED; + } else { + // + // Validate the adapter + // + if ( VENDOR_ID == Device.IdVendor ) { + if (PRODUCT_AX88772B_ID != Device.IdProduct) { + } else if (PRODUCT_AX88772B_ASUS_ID == Device.IdProduct) { + } else if (PRODUCT_AX88772A_ID == Device.IdProduct) { + } else if (PRODUCT_ID == Device.IdProduct) { + } else { + Status = EFI_UNSUPPORTED; + } + } else if ( VENDOR_AX88772B_LENOVO_ID == Device.IdVendor ) { + if (PRODUCT_AX88772B_LENOVO_ID != Device.IdProduct) { + Status = EFI_UNSUPPORTED; + } + } else { + Status = EFI_UNSUPPORTED; + } + } + + // + // Done with the USB stack + // + gBS->CloseProtocol ( + Controller, + &gEfiUsbIoProtocolGuid, + pThis->DriverBindingHandle, + Controller + ); + } + + // + // Return the device supported status + // + return Status; +} + + +/** + Start this driver on Controller by opening UsbIo and DevicePath protocols. + Initialize PXE structures, create a copy of the Controller Device Path with the + NIC's MAC address appended to it, install the NetworkInterfaceIdentifier protocol + on the newly created Device Path. + + @param [in] pThis Protocol instance pointer. + @param [in] Controller Handle of device to work with. + @param [in] pRemainingDevicePath Not used, always produce all possible children. + + @retval EFI_SUCCESS This driver is added to Controller. + @retval other This driver does not support this device. + +**/ +EFI_STATUS +EFIAPI +DriverStart ( + IN EFI_DRIVER_BINDING_PROTOCOL * pThis, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL * pRemainingDevicePath + ) +{ + EFI_STATUS Status; + NIC_DEVICE *pNicDevice; + UINTN LengthInBytes; + EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath = NULL; + MAC_ADDR_DEVICE_PATH MacDeviceNode; + EFI_USB_DEVICE_DESCRIPTOR Device; + + // + // Allocate the device structure + // + LengthInBytes = sizeof ( *pNicDevice ); + Status = gBS->AllocatePool ( + EfiRuntimeServicesData, + LengthInBytes, + (VOID **) &pNicDevice + ); + + if (EFI_ERROR (Status)) { + goto ERR; + } + + // + // Set the structure signature + // + ZeroMem ( pNicDevice, LengthInBytes ); + pNicDevice->Signature = DEV_SIGNATURE; + + Status = gBS->OpenProtocol ( + Controller, + &gEfiUsbIoProtocolGuid, + (VOID **) &pNicDevice->pUsbIo, + pThis->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + + if (EFI_ERROR (Status)) { + goto ERR; + } + + pNicDevice->Flag772A = FALSE; + pNicDevice->pUsbIo->UsbGetDeviceDescriptor ( pNicDevice->pUsbIo, &Device ); + if ((PRODUCT_AX88772A_ID == Device.IdProduct) || + (PRODUCT_ID == Device.IdProduct)) + pNicDevice->Flag772A = TRUE; + // + // Initialize the simple network protocol + // + Status = SN_Setup ( pNicDevice ); + + if (EFI_ERROR(Status)){ + gBS->CloseProtocol ( + Controller, + &gEfiUsbIoProtocolGuid, + pThis->DriverBindingHandle, + Controller + ); + goto ERR; + } + + // + // Set Device Path + // + + Status = gBS->OpenProtocol ( + Controller, + &gEfiDevicePathProtocolGuid, + (VOID **) &ParentDevicePath, + pThis->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR(Status)) { + gBS->CloseProtocol ( + Controller, + &gEfiUsbIoProtocolGuid, + pThis->DriverBindingHandle, + Controller + ); + goto ERR; + } + + ZeroMem (&MacDeviceNode, sizeof (MAC_ADDR_DEVICE_PATH)); + MacDeviceNode.Header.Type = MESSAGING_DEVICE_PATH; + MacDeviceNode.Header.SubType = MSG_MAC_ADDR_DP; + + SetDevicePathNodeLength (&MacDeviceNode.Header, sizeof (MAC_ADDR_DEVICE_PATH)); + + CopyMem (&MacDeviceNode.MacAddress, + &pNicDevice->SimpleNetworkData.CurrentAddress, + PXE_HWADDR_LEN_ETHER); + + MacDeviceNode.IfType = pNicDevice->SimpleNetworkData.IfType; + + pNicDevice->MyDevPath = AppendDevicePathNode ( + ParentDevicePath, + (EFI_DEVICE_PATH_PROTOCOL *) &MacDeviceNode + ); + + pNicDevice->Controller = NULL; + + // + // Install both the simple network and device path protocols. + // + Status = gBS->InstallMultipleProtocolInterfaces ( + &pNicDevice->Controller, + &gEfiCallerIdGuid, + pNicDevice, + &gEfiSimpleNetworkProtocolGuid, + &pNicDevice->SimpleNetwork, + &gEfiDevicePathProtocolGuid, + pNicDevice->MyDevPath, + NULL + ); + + if (EFI_ERROR(Status)){ + gBS->CloseProtocol ( + Controller, + &gEfiDevicePathProtocolGuid, + pThis->DriverBindingHandle, + Controller); + gBS->CloseProtocol ( + Controller, + &gEfiUsbIoProtocolGuid, + pThis->DriverBindingHandle, + Controller + ); + goto ERR; + } + + // + // Open For Child Device + // + Status = gBS->OpenProtocol ( + Controller, + &gEfiUsbIoProtocolGuid, + (VOID **) &pNicDevice->pUsbIo, + pThis->DriverBindingHandle, + pNicDevice->Controller, + EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER + ); + + if (EFI_ERROR(Status)){ + gBS->UninstallMultipleProtocolInterfaces ( + &pNicDevice->Controller, + &gEfiCallerIdGuid, + pNicDevice, + &gEfiSimpleNetworkProtocolGuid, + &pNicDevice->SimpleNetwork, + &gEfiDevicePathProtocolGuid, + pNicDevice->MyDevPath, + NULL + ); + gBS->CloseProtocol ( + Controller, + &gEfiDevicePathProtocolGuid, + pThis->DriverBindingHandle, + Controller); + gBS->CloseProtocol ( + Controller, + &gEfiUsbIoProtocolGuid, + pThis->DriverBindingHandle, + Controller + ); + goto ERR; + } + + return Status; +ERR: + if ( NULL != pNicDevice->pBulkInbuf) + gBS->FreePool (pNicDevice->pBulkInbuf); + if ( NULL != pNicDevice->pTxTest) + gBS->FreePool (pNicDevice->pTxTest); + if ( NULL != pNicDevice->MyDevPath) + gBS->FreePool (pNicDevice->MyDevPath); + if (NULL != pNicDevice) + gBS->FreePool ( pNicDevice ); + return Status; +} + +/** + Stop this driver on Controller by removing NetworkInterfaceIdentifier protocol and + closing the DevicePath and PciIo protocols on Controller. + + @param [in] pThis Protocol instance pointer. + @param [in] Controller Handle of device to stop driver on. + @param [in] NumberOfChildren How many children need to be stopped. + @param [in] pChildHandleBuffer Not used. + + @retval EFI_SUCCESS This driver is removed Controller. + @retval EFI_DEVICE_ERROR The device could not be stopped due to a device error. + @retval other This driver was not removed from this device. + +**/ +EFI_STATUS +EFIAPI +DriverStop ( + IN EFI_DRIVER_BINDING_PROTOCOL * pThis, + IN EFI_HANDLE Controller, + IN UINTN NumberOfChildren, + IN EFI_HANDLE * ChildHandleBuffer + ) +{ + BOOLEAN AllChildrenStopped; + UINTN Index; + EFI_SIMPLE_NETWORK_PROTOCOL *SimpleNetwork; + EFI_STATUS Status = EFI_SUCCESS; + NIC_DEVICE *pNicDevice; + + // + // Complete all outstanding transactions to Controller. + // Don't allow any new transaction to Controller to be started. + // + if (NumberOfChildren == 0) { + Status = gBS->OpenProtocol ( + Controller, + &gEfiSimpleNetworkProtocolGuid, + (VOID **) &SimpleNetwork, + pThis->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + + if (EFI_ERROR(Status)) { + // + // This is a 2nd type handle(multi-lun root), it needs to close devicepath + // and usbio protocol. + // + gBS->CloseProtocol ( + Controller, + &gEfiDevicePathProtocolGuid, + pThis->DriverBindingHandle, + Controller + ); + gBS->CloseProtocol ( + Controller, + &gEfiUsbIoProtocolGuid, + pThis->DriverBindingHandle, + Controller + ); + return EFI_SUCCESS; + } + + pNicDevice = DEV_FROM_SIMPLE_NETWORK ( SimpleNetwork ); + + Status = gBS->UninstallMultipleProtocolInterfaces ( + Controller, + &gEfiCallerIdGuid, + pNicDevice, + &gEfiSimpleNetworkProtocolGuid, + &pNicDevice->SimpleNetwork, + &gEfiDevicePathProtocolGuid, + pNicDevice->MyDevPath, + NULL + ); + + if (EFI_ERROR (Status)) { + return Status; + } + // + // Close the bus driver + // + Status = gBS->CloseProtocol ( + Controller, + &gEfiDevicePathProtocolGuid, + pThis->DriverBindingHandle, + Controller + ); + + if (EFI_ERROR(Status)){ } + + Status = gBS->CloseProtocol ( + Controller, + &gEfiUsbIoProtocolGuid, + pThis->DriverBindingHandle, + Controller + ); + + if (EFI_ERROR(Status)){ } + + return EFI_SUCCESS; + } + + AllChildrenStopped = TRUE; + + for (Index = 0; Index < NumberOfChildren; Index++) { + Status = gBS->OpenProtocol ( + ChildHandleBuffer[Index], + &gEfiSimpleNetworkProtocolGuid, + (VOID **) &SimpleNetwork, + pThis->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + + if (EFI_ERROR (Status)) { + AllChildrenStopped = FALSE; + continue; + } + + pNicDevice = DEV_FROM_SIMPLE_NETWORK ( SimpleNetwork ); + + gBS->CloseProtocol ( + Controller, + &gEfiUsbIoProtocolGuid, + pThis->DriverBindingHandle, + ChildHandleBuffer[Index] + ); + + Status = gBS->UninstallMultipleProtocolInterfaces ( + ChildHandleBuffer[Index], + &gEfiCallerIdGuid, + pNicDevice, + &gEfiSimpleNetworkProtocolGuid, + &pNicDevice->SimpleNetwork, + &gEfiDevicePathProtocolGuid, + pNicDevice->MyDevPath, + NULL + ); + + if (EFI_ERROR (Status)) { + Status = gBS->OpenProtocol ( + Controller, + &gEfiUsbIoProtocolGuid, + (VOID **) &pNicDevice->pUsbIo, + pThis->DriverBindingHandle, + ChildHandleBuffer[Index], + EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER + ); + } else { + if ( NULL != pNicDevice->pBulkInbuf) + gBS->FreePool (pNicDevice->pBulkInbuf); + if ( NULL != pNicDevice->pTxTest) + gBS->FreePool (pNicDevice->pTxTest); + if ( NULL != pNicDevice->MyDevPath) + gBS->FreePool (pNicDevice->MyDevPath); + if ( NULL != pNicDevice) + gBS->FreePool (pNicDevice); + } + } + + if (!AllChildrenStopped) { + return EFI_DEVICE_ERROR; + } + + return EFI_SUCCESS; +} + + +/** + Driver binding protocol declaration +**/ +EFI_DRIVER_BINDING_PROTOCOL gDriverBinding = { + DriverSupported, + DriverStart, + DriverStop, + 0xa, + NULL, + NULL +}; + + +/** + Ax88772 driver unload routine. + + @param [in] ImageHandle Handle for the image. + + @retval EFI_SUCCESS Image may be unloaded + +**/ +EFI_STATUS +EFIAPI +DriverUnload ( + IN EFI_HANDLE ImageHandle + ) +{ + UINTN BufferSize; + UINTN Index; + UINTN Max; + EFI_HANDLE * pHandle; + EFI_STATUS Status; + + + // + // Determine which devices are using this driver + // + BufferSize = 0; + pHandle = NULL; + Status = gBS->LocateHandle ( + ByProtocol, + &gEfiCallerIdGuid, + NULL, + &BufferSize, + NULL ); + if ( EFI_BUFFER_TOO_SMALL == Status ) { + for ( ; ; ) { + // + // One or more block IO devices are present + // + Status = gBS->AllocatePool ( + EfiRuntimeServicesData, + BufferSize, + (VOID **) &pHandle + ); + if ( EFI_ERROR ( Status )) { + + break; + } + + // + // Locate the block IO devices + // + Status = gBS->LocateHandle ( + ByProtocol, + &gEfiCallerIdGuid, + NULL, + &BufferSize, + pHandle ); + if ( EFI_ERROR ( Status )) { + // + // Error getting handles + // + break; + } + + // + // Remove any use of the driver + // + Max = BufferSize / sizeof ( pHandle[ 0 ]); + for ( Index = 0; Max > Index; Index++ ) { + Status = DriverStop ( &gDriverBinding, + pHandle[ Index ], + 0, + NULL ); + if ( EFI_ERROR ( Status )) { + break; + } + } + break; + } + } else { + if ( EFI_NOT_FOUND == Status ) { + // + // No devices were found + // + Status = EFI_SUCCESS; + } + } + + // + // Free the handle array + // + if ( NULL != pHandle ) { + gBS->FreePool ( pHandle ); + } + + // + // Remove the protocols installed by the EntryPoint routine. + // + if ( !EFI_ERROR ( Status )) { + gBS->UninstallMultipleProtocolInterfaces ( + ImageHandle, + &gEfiDriverBindingProtocolGuid, + &gDriverBinding, + &gEfiComponentNameProtocolGuid, + &gComponentName, + &gEfiComponentName2ProtocolGuid, + &gComponentName2, + NULL + ); + } + + // + // Return the unload status + // + return Status; +} + + +/** +Ax88772 driver entry point. + +@param [in] ImageHandle Handle for the image. +@param [in] pSystemTable Address of the system table. + +@retval EFI_SUCCESS Image successfully loaded. + +**/ +EFI_STATUS +EFIAPI +EntryPoint ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE * pSystemTable + ) +{ + EFI_LOADED_IMAGE_PROTOCOL * pLoadedImage; + EFI_STATUS Status; + + // + // Enable unload support + // + Status = gBS->HandleProtocol ( + gImageHandle, + &gEfiLoadedImageProtocolGuid, + (VOID **)&pLoadedImage + ); + if (!EFI_ERROR (Status)) { + pLoadedImage->Unload = DriverUnload; + } + + // + // Add the driver to the list of drivers + // + Status = EfiLibInstallDriverBindingComponentName2 ( + ImageHandle, + pSystemTable, + &gDriverBinding, + ImageHandle, + &gComponentName, + &gComponentName2 + ); + if ( !EFI_ERROR ( Status )) { } + return Status; +} diff --git a/Silicon/ASIX/Drivers/Bus/Usb/UsbNetworking/Ax88772c/SimpleNetwork.c b/Silicon/ASIX/Drivers/Bus/Usb/UsbNetworking/Ax88772c/SimpleNetwork.c new file mode 100644 index 000000000000..b4627092a676 --- /dev/null +++ b/Silicon/ASIX/Drivers/Bus/Usb/UsbNetworking/Ax88772c/SimpleNetwork.c @@ -0,0 +1,1612 @@ +/** @file + Provides the Simple Network functions. + + Copyright (c) 2011 - 2016, Intel Corporation. All rights reserved. + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "Ax88772.h" +#include +/** + This function updates the filtering on the receiver. + + This support routine calls ::Ax88772MacAddressSet to update + the MAC address. This routine then rebuilds the multicast + hash by calling ::Ax88772MulticastClear and ::Ax88772MulticastSet. + Finally this routine enables the receiver by calling + ::Ax88772RxControl. + + @param [in] pSimpleNetwork Simple network mode pointer + + @retval EFI_SUCCESS This operation was successful. + @retval EFI_NOT_STARTED The network interface was not started. + @retval EFI_INVALID_PARAMETER pSimpleNetwork parameter was NULL or did not point to a valid + EFI_SIMPLE_NETWORK_PROTOCOL structure. + @retval EFI_DEVICE_ERROR The command could not be sent to the network interface. + @retval EFI_UNSUPPORTED The increased buffer size feature is not supported. + +**/ +EFI_STATUS +ReceiveFilterUpdate ( + IN EFI_SIMPLE_NETWORK_PROTOCOL * pSimpleNetwork + ) +{ + EFI_SIMPLE_NETWORK_MODE * pMode; + NIC_DEVICE * pNicDevice; + EFI_STATUS Status; + UINT32 Index; + + // + // Set the MAC address + // + pNicDevice = DEV_FROM_SIMPLE_NETWORK ( pSimpleNetwork ); + pMode = pSimpleNetwork->Mode; + + // + // Clear the multicast hash table + // + Ax88772MulticastClear ( pNicDevice ); + + // + // Load the multicast hash table + // + if ( 0 != ( pMode->ReceiveFilterSetting & EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST )) { + for ( Index = 0; Index < pMode->MCastFilterCount; Index++ ) { + // + // Enable the next multicast address + // + Ax88772MulticastSet ( pNicDevice, + &pMode->MCastFilter[ Index ].Addr[0]); + } + } + + Status = Ax88772RxControl ( pNicDevice, pMode->ReceiveFilterSetting ); + + // + // Return the operation status + // + return Status; +} + + +/** + This function updates the SNP driver status. + + This function gets the current interrupt and recycled transmit + buffer status from the network interface. The interrupt status + and the media status are returned as a bit mask in InterruptStatus. + If InterruptStatus is NULL, the interrupt status will not be read. + Upon successful return of the media status, the MediaPresent field + of EFI_SIMPLE_NETWORK_MODE will be updated to reflect any change + of media status. If TxBuf is not NULL, a recycled transmit buffer + address will be retrived. If a recycled transmit buffer address + is returned in TxBuf, then the buffer has been successfully + transmitted, and the status for that buffer is cleared. + + This function calls ::Ax88772Rx to update the media status and + queue any receive packets. + + @param [in] pSimpleNetwork Protocol instance pointer + @param [in] pInterruptStatus A pointer to the bit mask of the current active interrupts. + If this is NULL, the interrupt status will not be read from + the device. If this is not NULL, the interrupt status will + be read from teh device. When the interrupt status is read, + it will also be cleared. Clearing the transmit interrupt + does not empty the recycled transmit buffer array. + @param [out] ppTxBuf Recycled transmit buffer address. The network interface will + not transmit if its internal recycled transmit buffer array is + full. Reading the transmit buffer does not clear the transmit + interrupt. If this is NULL, then the transmit buffer status + will not be read. If there are not transmit buffers to recycle + and TxBuf is not NULL, *TxBuf will be set to NULL. + + @retval EFI_SUCCESS This operation was successful. + @retval EFI_NOT_STARTED The network interface was not started. + @retval EFI_INVALID_PARAMETER pSimpleNetwork parameter was NULL or did not point to a valid + EFI_SIMPLE_NETWORK_PROTOCOL structure. + @retval EFI_DEVICE_ERROR The command could not be sent to the network interface. + +**/ + +EFI_STATUS +EFIAPI +SN_GetStatus ( + IN EFI_SIMPLE_NETWORK_PROTOCOL * pSimpleNetwork, + OUT UINT32 * pInterruptStatus, + OUT VOID ** ppTxBuf + ) +{ + EFI_SIMPLE_NETWORK_MODE * pMode; + NIC_DEVICE * pNicDevice = NULL; + EFI_STATUS Status = EFI_SUCCESS; + EFI_TPL TplPrevious; + + TplPrevious = gBS->RaiseTPL(TPL_CALLBACK); + + // + // Verify the parameters + // + if (( NULL != pSimpleNetwork ) && ( NULL != pSimpleNetwork->Mode )) { + // + // Return the transmit buffer + // + pNicDevice = DEV_FROM_SIMPLE_NETWORK ( pSimpleNetwork ); + + if (( NULL != ppTxBuf ) && + ( NULL != pNicDevice->pTxBuffer )) { + *ppTxBuf = pNicDevice->pTxBuffer; + pNicDevice->pTxBuffer = NULL; + } + + pMode = pSimpleNetwork->Mode; + if (EfiSimpleNetworkInitialized == pMode->State) { + if (NULL == ppTxBuf && NULL == pInterruptStatus) { + Status = EFI_INVALID_PARAMETER; + goto EXIT; + } + +#if REPORTLINK +#else + if (!pNicDevice->bLinkUp || !pNicDevice->bComplete) { +#endif + Status = Ax88772NegotiateLinkComplete ( pNicDevice, + &pNicDevice->PollCount, + &pNicDevice->bComplete, + &pNicDevice->bLinkUp, + &pNicDevice->b100Mbps, + &pNicDevice->bFullDuplex ); + if (EFI_ERROR(Status)) + goto EXIT; +#if REPORTLINK + if (pNicDevice->bLinkUp && pNicDevice->bComplete) { + pMode->MediaPresent = TRUE; + Status = ReceiveFilterUpdate ( pSimpleNetwork ); + } else { + pMode->MediaPresent = FALSE; + } +#else + if (pNicDevice->bLinkUp && pNicDevice->bComplete) { + pMode->MediaPresent = TRUE; + pMode->MediaPresentSupported = FALSE; + Status = ReceiveFilterUpdate ( pSimpleNetwork ); + } + } +#endif + } else { + if (EfiSimpleNetworkStarted == pMode->State) { + Status = EFI_DEVICE_ERROR; + } else { + Status = EFI_NOT_STARTED ; + } + } + } else { + Status = EFI_INVALID_PARAMETER; + } + if ( NULL != pInterruptStatus ) { + *pInterruptStatus = 0; + } +EXIT: + gBS->RestoreTPL(TplPrevious) ; + + return Status; +} + +/** + This function performs read and write operations on the NVRAM device + attached to a network interface. + + @param [in] pSimpleNetwork Protocol instance pointer + @param [in] ReadWrite TRUE for read operations, FALSE for write operations. + @param [in] Offset Byte offset in the NVRAM device at which to start the + read or write operation. This must be a multiple of + NvRamAccessSize and less than NvRamSize. + @param [in] BufferSize The number of bytes to read or write from the NVRAM device. + This must also be a multiple of NvramAccessSize. + @param [in, out] pBuffer A pointer to the data buffer. + + @retval EFI_SUCCESS This operation was successful. + @retval EFI_NOT_STARTED The network interface was not started. + @retval EFI_INVALID_PARAMETER pSimpleNetwork parameter was NULL or did not point to a valid + EFI_SIMPLE_NETWORK_PROTOCOL structure. + @retval EFI_DEVICE_ERROR The command could not be sent to the network interface. + @retval EFI_UNSUPPORTED The increased buffer size feature is not supported. + +**/ +EFI_STATUS +EFIAPI +SN_NvData ( + IN EFI_SIMPLE_NETWORK_PROTOCOL * pSimpleNetwork, + IN BOOLEAN ReadWrite, + IN UINTN Offset, + IN UINTN BufferSize, + IN OUT VOID * pBuffer + ) +{ + EFI_STATUS Status = EFI_INVALID_PARAMETER; + EFI_TPL TplPrevious; + EFI_SIMPLE_NETWORK_MODE * pMode; + NIC_DEVICE * pNicDevice; + + + TplPrevious = gBS->RaiseTPL(TPL_CALLBACK); + + if (( NULL == pSimpleNetwork ) || ( NULL == pSimpleNetwork->Mode )) { + Status = EFI_INVALID_PARAMETER; + goto EXIT; + } + + pNicDevice = DEV_FROM_SIMPLE_NETWORK ( pSimpleNetwork ); + pMode = pSimpleNetwork->Mode; + +#if PASS_SCT + if (EfiSimpleNetworkInitialized != pMode->State) { + Status = EFI_NOT_STARTED; + goto EXIT; + } +#endif + + if ( 0 != Offset ) { + if ((0 != (Offset % pMode->NvRamAccessSize) ) || + (Offset >= pMode->NvRamSize)) { + Status = EFI_INVALID_PARAMETER; + goto EXIT; + } + } + // + // Offset must be a multiple of NvRamAccessSize and less than NvRamSize. + // + if (0 != (BufferSize % pMode->NvRamAccessSize)) { + Status = EFI_INVALID_PARAMETER; + goto EXIT; + } + + if (BufferSize + Offset > pMode->NvRamSize) { + Status = EFI_INVALID_PARAMETER; + goto EXIT; + } + + if (NULL == pBuffer) { + Status = EFI_INVALID_PARAMETER; + goto EXIT; + } + + // + // ReadWrite: TRUE FOR READ FALSE FOR WRITE + // + if (ReadWrite){ + UINTN i; + + for (i = 0; i < BufferSize / 2; i++) { + Status = Ax88772SromRead ( pNicDevice, + (UINT32)(Offset/2 + i), + (((UINT16*)pBuffer) + i)); + } + } else { + UINTN i; + + Status = Ax88772EnableSromWrite(pNicDevice); + if (EFI_ERROR(Status)) + goto EXIT; + + for (i = 0; i < BufferSize / 2; i++){ + Status = Ax88772SromWrite ( pNicDevice, + (UINT32)(Offset/2 + i), + (((UINT16*)pBuffer) + i)); + } + + Status = Ax88772DisableSromWrite(pNicDevice); + + if (BufferSize == 272) + Status = Ax88772ReloadSrom(pNicDevice); + } + + // + // Return the operation status + // +EXIT: + gBS->RestoreTPL (TplPrevious); + return Status; +} + + + +/** + Resets the network adapter and allocates the transmit and receive buffers + required by the network interface; optionally, also requests allocation of + additional transmit and receive buffers. This routine must be called before + any other routine in the Simple Network protocol is called. + + @param [in] pSimpleNetwork Protocol instance pointer + @param [in] ExtraRxBufferSize Size in bytes to add to the receive buffer allocation + @param [in] ExtraTxBufferSize Size in bytes to add to the transmit buffer allocation + + @retval EFI_SUCCESS This operation was successful. + @retval EFI_NOT_STARTED The network interface was not started. + @retval EFI_OUT_OF_RESOURCES There was not enough memory for the transmit and receive buffers + @retval EFI_INVALID_PARAMETER pSimpleNetwork parameter was NULL or did not point to a valid + EFI_SIMPLE_NETWORK_PROTOCOL structure. + @retval EFI_DEVICE_ERROR The command could not be sent to the network interface. + @retval EFI_UNSUPPORTED The increased buffer size feature is not supported. + +**/ +EFI_STATUS +EFIAPI +SN_Initialize ( + IN EFI_SIMPLE_NETWORK_PROTOCOL * pSimpleNetwork, + IN UINTN ExtraRxBufferSize, + IN UINTN ExtraTxBufferSize + ) +{ + EFI_SIMPLE_NETWORK_MODE * pMode; + EFI_STATUS Status; + UINT32 TmpState; + EFI_TPL TplPrevious; + NIC_DEVICE * pNicDevice; + + TplPrevious = gBS->RaiseTPL (TPL_CALLBACK); + + // + // Verify the parameters + // + if (( NULL != pSimpleNetwork ) && ( NULL != pSimpleNetwork->Mode )) { + // + // Determine if the interface is already started + // + pMode = pSimpleNetwork->Mode; + if ( EfiSimpleNetworkStarted == pMode->State ) { + if (( 0 == ExtraRxBufferSize ) && ( 0 == ExtraTxBufferSize )) { + // + // Start the adapter + // + TmpState = pMode->State; + pMode->State = EfiSimpleNetworkInitialized; + Status = SN_Reset ( pSimpleNetwork, FALSE ); + if ( EFI_ERROR ( Status )) { + // + // Update the network state + // + pMode->State = TmpState ; // EfiSimpleNetworkInitialized; + } else { + pMode->MediaPresentSupported = TRUE; + pNicDevice = DEV_FROM_SIMPLE_NETWORK ( pSimpleNetwork ); + pMode->MediaPresent = Ax88772GetLinkStatus (pNicDevice); + } + } else { + Status = EFI_UNSUPPORTED; + } + } else { + Status = EFI_NOT_STARTED; + } + } else { + Status = EFI_INVALID_PARAMETER; + } + + // + // Return the operation status + // + gBS->RestoreTPL (TplPrevious); + return Status; +} + + +/** + This function converts a multicast IP address to a multicast HW MAC address + for all packet transactions. + + @param [in] pSimpleNetwork Protocol instance pointer + @param [in] bIPv6 Set to TRUE if the multicast IP address is IPv6 [RFC2460]. + Set to FALSE if the multicast IP address is IPv4 [RFC 791]. + @param [in] pIP The multicast IP address that is to be converted to a + multicast HW MAC address. + @param [in] pMAC The multicast HW MAC address that is to be generated from IP. + + @retval EFI_SUCCESS This operation was successful. + @retval EFI_NOT_STARTED The network interface was not started. + @retval EFI_INVALID_PARAMETER pSimpleNetwork parameter was NULL or did not point to a valid + EFI_SIMPLE_NETWORK_PROTOCOL structure. + @retval EFI_DEVICE_ERROR The command could not be sent to the network interface. + @retval EFI_UNSUPPORTED The increased buffer size feature is not supported. + +**/ +EFI_STATUS +EFIAPI +SN_MCastIPtoMAC ( + IN EFI_SIMPLE_NETWORK_PROTOCOL * pSimpleNetwork, + IN BOOLEAN bIPv6, + IN EFI_IP_ADDRESS * pIP, + IN EFI_MAC_ADDRESS * pMAC + ) +{ + EFI_STATUS Status; + EFI_TPL TplPrevious; + EFI_SIMPLE_NETWORK_MODE * pMode; + + TplPrevious = gBS->RaiseTPL(TPL_CALLBACK); + + if (( NULL != pSimpleNetwork ) && ( NULL != pSimpleNetwork->Mode )) { + // + // The interface must be running + // + pMode = pSimpleNetwork->Mode; + if ( EfiSimpleNetworkInitialized == pMode->State ) { + if (pIP == NULL || pMAC == NULL) { + Status = EFI_INVALID_PARAMETER; + goto EXIT; + } + + if (bIPv6) { + Status = EFI_UNSUPPORTED; + goto EXIT; + } else { + // + // check if the ip given is a mcast IP + // + if ((pIP->v4.Addr[0] & 0xF0) != 0xE0) { + Status = EFI_INVALID_PARAMETER; + goto EXIT; + } else { + pMAC->Addr[0] = 0x01; + pMAC->Addr[1] = 0x00; + pMAC->Addr[2] = 0x5e; + pMAC->Addr[3] = (UINT8) (pIP->v4.Addr[1] & 0x7f); + pMAC->Addr[4] = (UINT8) pIP->v4.Addr[2]; + pMAC->Addr[5] = (UINT8) pIP->v4.Addr[3]; + Status = EFI_SUCCESS; + } + } + } else { + if (EfiSimpleNetworkStarted == pMode->State) { + Status = EFI_DEVICE_ERROR; + } else { + Status = EFI_NOT_STARTED ; + } + } + } else { + Status = EFI_INVALID_PARAMETER; + } + +EXIT: + gBS->RestoreTPL(TplPrevious); + return Status; +} + +EFI_STATUS +EFIAPI +SN_Receive ( + IN EFI_SIMPLE_NETWORK_PROTOCOL * pSimpleNetwork, + OUT UINTN * pHeaderSize, + OUT UINTN * pBufferSize, + OUT VOID * pBuffer, + OUT EFI_MAC_ADDRESS * pSrcAddr, + OUT EFI_MAC_ADDRESS * pDestAddr, + OUT UINT16 * pProtocol + ) +{ + ETHERNET_HEADER * pHeader; + EFI_SIMPLE_NETWORK_MODE * pMode; + NIC_DEVICE * pNicDevice = NULL; + EFI_STATUS Status; + EFI_TPL TplPrevious; + UINT16 Type; + UINT16 CurrentPktLen; + + + TplPrevious = gBS->RaiseTPL (TPL_CALLBACK); + + // + // Verify the parameters + // + if (( NULL != pSimpleNetwork ) && ( NULL != pSimpleNetwork->Mode )) { + // + // The interface must be running + // + pMode = pSimpleNetwork->Mode; + if ( EfiSimpleNetworkInitialized == pMode->State ) { + + if ((pBufferSize == NULL) || (pBuffer == NULL)) { + Status = EFI_INVALID_PARAMETER; + gBS->RestoreTPL (TplPrevious); + return Status; + } + + // + // Update the link status + // + pNicDevice = DEV_FROM_SIMPLE_NETWORK ( pSimpleNetwork ); + + if ( pNicDevice->bLinkUp && pNicDevice->bComplete) { + if ((NULL != pHeaderSize) && (7720 == *pHeaderSize)) { + pNicDevice->Grub_f = TRUE; + } + + if ((pNicDevice->Grub_f) && (7720 != *pHeaderSize)) { + gBS->RestoreTPL (TplPrevious); + return EFI_NOT_READY; + } + + // + // Attempt to receive a packet + // + if (0 == pNicDevice->PktCnt) { + Status = Ax88772BulkIn(pNicDevice); + if (EFI_ERROR(Status)) { + goto no_pkt; + } + } + + CurrentPktLen = *((UINT16*) (pNicDevice->pCurPktHdrOff)); + CurrentPktLen &= 0x7ff; + + if (( 60 <= CurrentPktLen ) && + ( CurrentPktLen - 14 <= MAX_ETHERNET_PKT_SIZE)) { + if (*pBufferSize < (UINTN)CurrentPktLen) { + gBS->RestoreTPL (TplPrevious); + return EFI_BUFFER_TOO_SMALL; + } + + *pBufferSize = CurrentPktLen; + CopyMem ( pBuffer, pNicDevice->pCurPktOff, CurrentPktLen ); + pHeader = (ETHERNET_HEADER *) pNicDevice->pCurPktOff; + + if ( NULL != pHeaderSize && (7720 != *pHeaderSize)) { + *pHeaderSize = sizeof ( *pHeader ); + } + if ( NULL != pDestAddr ) { + CopyMem ( pDestAddr, &pHeader->dest_addr, PXE_HWADDR_LEN_ETHER ); + } + if ( NULL != pSrcAddr ) { + CopyMem ( pSrcAddr, &pHeader->src_addr, PXE_HWADDR_LEN_ETHER ); + } + if ( NULL != pProtocol ) { + Type = pHeader->type; + Type = (UINT16)(( Type >> 8 ) | ( Type << 8 )); + *pProtocol = Type; + } + pNicDevice->PktCnt--; + pNicDevice->pCurPktHdrOff += (CurrentPktLen + 4 + 1) & 0xfffe; + pNicDevice->pCurPktOff = pNicDevice->pCurPktHdrOff + 4; + Status = EFI_SUCCESS; + } else { + pNicDevice->PktCnt = 0; + Status = EFI_DEVICE_ERROR; + } + } else { + // + // Link no up + // + Status = EFI_NOT_READY; + } + } else { + if (EfiSimpleNetworkStarted == pMode->State) { + Status = EFI_DEVICE_ERROR; + } else { + Status = EFI_NOT_STARTED; + } + } + } else { + Status = EFI_INVALID_PARAMETER; + } + + // + // Return the operation status + // +no_pkt: + gBS->RestoreTPL (TplPrevious); + return Status; +} + +/** + This function is used to enable and disable the hardware and software receive + filters for the underlying network device. + + The receive filter change is broken down into three steps: + + 1. The filter mask bits that are set (ON) in the Enable parameter + are added to the current receive filter settings. + + 2. The filter mask bits that are set (ON) in the Disable parameter + are subtracted from the updated receive filter settins. + + 3. If the resulting filter settigns is not supported by the hardware + a more liberal setting is selected. + + If the same bits are set in the Enable and Disable parameters, then the bits + in the Disable parameter takes precedence. + + If the ResetMCastFilter parameter is TRUE, then the multicast address list + filter is disabled (irregardless of what other multicast bits are set in + the enable and Disable parameters). The SNP->Mode->MCastFilterCount field + is set to zero. The SNP->Mode->MCastFilter contents are undefined. + + After enableing or disabling receive filter settings, software should + verify the new settings by checking the SNP->Mode->ReceeiveFilterSettings, + SNP->Mode->MCastFilterCount and SNP->Mode->MCastFilter fields. + + Note: Some network drivers and/or devices will automatically promote + receive filter settings if the requested setting can not be honored. + For example, if a request for four multicast addresses is made and + the underlying hardware only supports two multicast addresses the + driver might set the promiscuous or promiscuous multicast receive filters + instead. The receiving software is responsible for discarding any extra + packets that get through the hardware receive filters. + + If ResetMCastFilter is TRUE, then the multicast receive filter list + on the network interface will be reset to the default multicast receive + filter list. If ResetMCastFilter is FALSE, and this network interface + allows the multicast receive filter list to be modified, then the + MCastFilterCnt and MCastFilter are used to update the current multicast + receive filter list. The modified receive filter list settings can be + found in the MCastFilter field of EFI_SIMPLE_NETWORK_MODE. + + This routine calls ::ReceiveFilterUpdate to update the receive + state in the network adapter. + + @param [in] pSimpleNetwork Protocol instance pointer + @param [in] Enable A bit mask of receive filters to enable on the network interface. + @param [in] Disable A bit mask of receive filters to disable on the network interface. + For backward compatibility with EFI 1.1 platforms, the + EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST bit must be set + when the ResetMCastFilter parameter is TRUE. + @param [in] bResetMCastFilter Set to TRUE to reset the contents of the multicast receive + filters on the network interface to their default values. + @param [in] MCastFilterCnt Number of multicast HW MAC address in the new MCastFilter list. + This value must be less than or equal to the MaxMCastFilterCnt + field of EFI_SIMPLE_NETWORK_MODE. This field is optional if + ResetMCastFilter is TRUE. + @param [in] pMCastFilter A pointer to a list of new multicast receive filter HW MAC + addresses. This list will replace any existing multicast + HW MAC address list. This field is optional if ResetMCastFilter + is TRUE. + + @retval EFI_SUCCESS This operation was successful. + @retval EFI_NOT_STARTED The network interface was not started. + @retval EFI_INVALID_PARAMETER pSimpleNetwork parameter was NULL or did not point to a valid + EFI_SIMPLE_NETWORK_PROTOCOL structure. + @retval EFI_DEVICE_ERROR The command could not be sent to the network interface. + @retval EFI_UNSUPPORTED The increased buffer size feature is not supported. + +**/ +EFI_STATUS +EFIAPI +SN_ReceiveFilters ( + IN EFI_SIMPLE_NETWORK_PROTOCOL * pSimpleNetwork, + IN UINT32 Enable, + IN UINT32 Disable, +/* +#define EFI_SIMPLE_NETWORK_RECEIVE_UNICAST 0x01 +#define EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST 0x02 +#define EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST 0x04 +#define EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS 0x08 +#define EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST 0x10 +*/ + IN BOOLEAN bResetMCastFilter, + IN UINTN MCastFilterCnt, + IN EFI_MAC_ADDRESS * pMCastFilter + ) +{ + EFI_SIMPLE_NETWORK_MODE * pMode; + + EFI_STATUS Status = EFI_SUCCESS; + EFI_TPL TplPrevious; + + + NIC_DEVICE * pNicDevice; + TplPrevious = gBS->RaiseTPL(TPL_CALLBACK); + + pNicDevice = DEV_FROM_SIMPLE_NETWORK ( pSimpleNetwork ); + pMode = pSimpleNetwork->Mode; + + + if (pSimpleNetwork == NULL) { + gBS->RestoreTPL(TplPrevious); + return EFI_INVALID_PARAMETER; + } + + + switch (pMode->State) { + case EfiSimpleNetworkInitialized: + break; + + case EfiSimpleNetworkStopped: + Status = EFI_NOT_STARTED; + gBS->RestoreTPL(TplPrevious); + return Status; + + default: + Status = EFI_DEVICE_ERROR; + gBS->RestoreTPL(TplPrevious); + return Status; + } + + // + // check if we are asked to enable or disable something that the UNDI + // does not even support! + // + if (((Enable &~pMode->ReceiveFilterMask) != 0) || + ((Disable &~pMode->ReceiveFilterMask) != 0)) { + Status = EFI_INVALID_PARAMETER; + gBS->RestoreTPL(TplPrevious); + return Status; + } + + if (bResetMCastFilter) { + if ( (0 == (pMode->ReceiveFilterSetting & EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST)) && + Enable == 0 && + Disable == 2) { + gBS->RestoreTPL(TplPrevious); + return EFI_SUCCESS; + } + pMode->MCastFilterCount = 0; + SetMem ( &pMode->MCastFilter[0], + sizeof(EFI_MAC_ADDRESS) * MAX_MCAST_FILTER_CNT, + 0); + } else { + if (MCastFilterCnt != 0) { + UINTN i; + EFI_MAC_ADDRESS * pMulticastAddress; + pMulticastAddress = pMCastFilter; + + if ((MCastFilterCnt > pMode->MaxMCastFilterCount) || + (pMCastFilter == NULL)) { + Status = EFI_INVALID_PARAMETER; + gBS->RestoreTPL(TplPrevious); + return Status; + } + + for ( i = 0 ; i < MCastFilterCnt ; i++ ) { + UINT8 tmp; + tmp = pMulticastAddress->Addr[0]; + if ( (tmp & 0x01) != 0x01 ) { + gBS->RestoreTPL(TplPrevious); + return EFI_INVALID_PARAMETER; + } + pMulticastAddress++; + } + + pMode->MCastFilterCount = (UINT32)MCastFilterCnt; + CopyMem (&pMode->MCastFilter[0], + pMCastFilter, + MCastFilterCnt * sizeof ( EFI_MAC_ADDRESS )); + } + } + + if (Enable == 0 && Disable == 0 && !bResetMCastFilter && MCastFilterCnt == 0) { + Status = EFI_SUCCESS; + gBS->RestoreTPL(TplPrevious); + return Status; + } + + if ((Enable & EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST) != 0 && MCastFilterCnt == 0) { + Status = EFI_INVALID_PARAMETER; + gBS->RestoreTPL(TplPrevious); + return Status; + } + + pMode->ReceiveFilterSetting |= Enable; + pMode->ReceiveFilterSetting &= ~Disable; + + Status = ReceiveFilterUpdate (pSimpleNetwork); + + if (EFI_DEVICE_ERROR == Status || EFI_INVALID_PARAMETER == Status) + Status = EFI_SUCCESS; + + + gBS->RestoreTPL(TplPrevious); + + return Status; +} + +/** + Reset the network adapter. + + Resets a network adapter and reinitializes it with the parameters that + were provided in the previous call to Initialize (). The transmit and + receive queues are cleared. Receive filters, the station address, the + statistics, and the multicast-IP-to-HW MAC addresses are not reset by + this call. + + This routine calls ::Ax88772Reset to perform the adapter specific + reset operation. This routine also starts the link negotiation + by calling ::Ax88772NegotiateLinkStart. + + @param [in] pSimpleNetwork Protocol instance pointer + @param [in] bExtendedVerification Indicates that the driver may perform a more + exhaustive verification operation of the device + during reset. + + @retval EFI_SUCCESS This operation was successful. + @retval EFI_NOT_STARTED The network interface was not started. + @retval EFI_INVALID_PARAMETER pSimpleNetwork parameter was NULL or did not point to a valid + EFI_SIMPLE_NETWORK_PROTOCOL structure. + @retval EFI_DEVICE_ERROR The command could not be sent to the network interface. + @retval EFI_UNSUPPORTED The increased buffer size feature is not supported. + +**/ +EFI_STATUS +EFIAPI +SN_Reset ( + IN EFI_SIMPLE_NETWORK_PROTOCOL * pSimpleNetwork, + IN BOOLEAN bExtendedVerification + ) +{ + EFI_SIMPLE_NETWORK_MODE * pMode; + NIC_DEVICE * pNicDevice; + EFI_STATUS Status; + + EFI_TPL TplPrevious; + + TplPrevious = gBS->RaiseTPL(TPL_CALLBACK); + + // + // Verify the parameters + // + if (( NULL != pSimpleNetwork ) && ( NULL != pSimpleNetwork->Mode )) { + pMode = pSimpleNetwork->Mode; + if ( EfiSimpleNetworkInitialized == pMode->State ) { + // + // Update the device state + // + pNicDevice = DEV_FROM_SIMPLE_NETWORK ( pSimpleNetwork ); + + // + // Reset the device + // + if (!pNicDevice->bFirstRst) { + Status = EFI_SUCCESS; + } else { + Status = Ax88772Reset ( pNicDevice ); + if ( !EFI_ERROR ( Status )) { + Status = ReceiveFilterUpdate ( pSimpleNetwork ); + if ( !EFI_ERROR ( Status ) && !pNicDevice->bLinkUp && pNicDevice->bFirstRst) { + Status = Ax88772NegotiateLinkStart ( pNicDevice ); + pNicDevice->bFirstRst = FALSE; + } + } + } + } else { + Status = EFI_NOT_STARTED; + } + } else { + Status = EFI_INVALID_PARAMETER; + } + // + // Return the operation status + // + gBS->RestoreTPL(TplPrevious); + + return Status; +} + +/** + Initialize the simple network protocol. + + This routine calls ::Ax88772MacAddressGet to obtain the + MAC address. + + @param [in] pNicDevice NIC_DEVICE_INSTANCE pointer + + @retval EFI_SUCCESS Setup was successful + +**/ +EFI_STATUS +SN_Setup ( + IN NIC_DEVICE * pNicDevice + ) +{ + + + EFI_SIMPLE_NETWORK_MODE * pMode; + EFI_SIMPLE_NETWORK_PROTOCOL * pSimpleNetwork; + EFI_STATUS Status; + + // + // Initialize the simple network protocol + // + pSimpleNetwork = &pNicDevice->SimpleNetwork; + pSimpleNetwork->Revision = EFI_SIMPLE_NETWORK_PROTOCOL_REVISION; + pSimpleNetwork->Start = (EFI_SIMPLE_NETWORK_START)SN_Start; + pSimpleNetwork->Stop = (EFI_SIMPLE_NETWORK_STOP)SN_Stop; + pSimpleNetwork->Initialize = (EFI_SIMPLE_NETWORK_INITIALIZE)SN_Initialize; + pSimpleNetwork->Reset = (EFI_SIMPLE_NETWORK_RESET)SN_Reset; + pSimpleNetwork->Shutdown = (EFI_SIMPLE_NETWORK_SHUTDOWN)SN_Shutdown; + pSimpleNetwork->ReceiveFilters = (EFI_SIMPLE_NETWORK_RECEIVE_FILTERS)SN_ReceiveFilters; + pSimpleNetwork->StationAddress = (EFI_SIMPLE_NETWORK_STATION_ADDRESS)SN_StationAddress; + pSimpleNetwork->Statistics = (EFI_SIMPLE_NETWORK_STATISTICS)SN_Statistics; + pSimpleNetwork->MCastIpToMac = (EFI_SIMPLE_NETWORK_MCAST_IP_TO_MAC)SN_MCastIPtoMAC; + pSimpleNetwork->NvData = (EFI_SIMPLE_NETWORK_NVDATA)SN_NvData; + pSimpleNetwork->GetStatus = (EFI_SIMPLE_NETWORK_GET_STATUS)SN_GetStatus; + pSimpleNetwork->Transmit = (EFI_SIMPLE_NETWORK_TRANSMIT)SN_Transmit; + pSimpleNetwork->Receive = (EFI_SIMPLE_NETWORK_RECEIVE)SN_Receive; + pSimpleNetwork->WaitForPacket = NULL; + pMode = &pNicDevice->SimpleNetworkData; + pSimpleNetwork->Mode = pMode; + pMode->State = EfiSimpleNetworkStopped; + pMode->HwAddressSize = PXE_HWADDR_LEN_ETHER; + pMode->MediaHeaderSize = sizeof ( ETHERNET_HEADER ); + pMode->MaxPacketSize = MAX_ETHERNET_PKT_SIZE; + pMode->ReceiveFilterMask = EFI_SIMPLE_NETWORK_RECEIVE_UNICAST + | EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST + | EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST + | EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS + | EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST; + pMode->ReceiveFilterSetting = EFI_SIMPLE_NETWORK_RECEIVE_UNICAST + | EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST; + pMode->MaxMCastFilterCount = ASIX_MCAST_FILTER_CNT; + pMode->MCastFilterCount = 0; + pMode->NvRamSize = 512; + pMode->NvRamAccessSize = 2; + SetMem ( &pMode->BroadcastAddress, + PXE_HWADDR_LEN_ETHER, + 0xff ); + + SetMem ( &pMode->MCastFilter[0], + sizeof(EFI_MAC_ADDRESS) * MAX_MCAST_FILTER_CNT, + 0); + + pMode->IfType = EfiNetworkInterfaceUndi; + pMode->MacAddressChangeable = TRUE; + pMode->MultipleTxSupported = FALSE; + pMode->MediaPresentSupported = TRUE; + pMode->MediaPresent = FALSE; + + // + // Read the MAC address + // + pNicDevice->PhyId = PHY_ID_INTERNAL; + pNicDevice->b100Mbps = TRUE; + pNicDevice->bFullDuplex = TRUE; + pNicDevice->bComplete = FALSE; + pNicDevice->bLinkUp = FALSE; + pNicDevice->Grub_f = FALSE; + pNicDevice->bFirstRst = TRUE; + pNicDevice->PktCnt = 0; + + Status = Ax88772MacAddressGet ( + pNicDevice, + &pMode->PermanentAddress.Addr[0]); + + if ( !EFI_ERROR ( Status )) { + + // + // Use the hardware address as the current address + // + + CopyMem ( &pMode->CurrentAddress, + &pMode->PermanentAddress, + PXE_HWADDR_LEN_ETHER ); + + CopyMem ( &pNicDevice->MAC, + &pMode->PermanentAddress, + PXE_HWADDR_LEN_ETHER ); + + + if (EFI_ERROR(Status)) { + return Status; + } + } else { + return Status; + } + + Status = gBS->AllocatePool ( EfiRuntimeServicesData, + AX88772_MAX_BULKIN_SIZE, + (VOID **) &pNicDevice->pBulkInbuf ); + + if (EFI_ERROR (Status)) { + return Status; + } + + Status = gBS->AllocatePool ( EfiRuntimeServicesData, + sizeof ( RX_TX_PACKET ), + (VOID **) &pNicDevice->pTxTest ); + + if (EFI_ERROR (Status)) { + gBS->FreePool (pNicDevice->pBulkInbuf); + return Status; + } + + // + // Return the setup status + // + return Status; +} + + +/** + This routine starts the network interface. + + @param [in] pSimpleNetwork Protocol instance pointer + + @retval EFI_SUCCESS This operation was successful. + @retval EFI_ALREADY_STARTED The network interface was already started. + @retval EFI_INVALID_PARAMETER pSimpleNetwork parameter was NULL or did not point to a valid + EFI_SIMPLE_NETWORK_PROTOCOL structure. + @retval EFI_DEVICE_ERROR The command could not be sent to the network interface. + @retval EFI_UNSUPPORTED The increased buffer size feature is not supported. + +**/ +EFI_STATUS +EFIAPI +SN_Start ( + IN EFI_SIMPLE_NETWORK_PROTOCOL * pSimpleNetwork + ) +{ + NIC_DEVICE * pNicDevice; + EFI_SIMPLE_NETWORK_MODE * pMode; + EFI_STATUS Status; + + EFI_TPL TplPrevious; + + + TplPrevious = gBS->RaiseTPL(TPL_CALLBACK); + + // + // Verify the parameters + // + Status = EFI_INVALID_PARAMETER; + if (( NULL != pSimpleNetwork ) && ( NULL != pSimpleNetwork->Mode )) { + pMode = pSimpleNetwork->Mode; + if ( EfiSimpleNetworkStopped == pMode->State ) { + // + // Initialize the mode structure + // NVRAM access is not supported + // + ZeroMem ( pMode, sizeof ( *pMode )); + + pMode->State = EfiSimpleNetworkStarted; + pMode->HwAddressSize = PXE_HWADDR_LEN_ETHER; + pMode->MediaHeaderSize = sizeof ( ETHERNET_HEADER ); + pMode->MaxPacketSize = MAX_ETHERNET_PKT_SIZE; + pMode->ReceiveFilterMask = EFI_SIMPLE_NETWORK_RECEIVE_UNICAST + | EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST + | EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST + | EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS + | EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST; + pMode->ReceiveFilterSetting = EFI_SIMPLE_NETWORK_RECEIVE_UNICAST; + pMode->MaxMCastFilterCount = ASIX_MCAST_FILTER_CNT; + pMode->MCastFilterCount = 0; + + SetMem ( &pMode->MCastFilter[0], + sizeof(EFI_MAC_ADDRESS) * MAX_MCAST_FILTER_CNT, + 0); + + pMode->NvRamSize = 512; + pMode->NvRamAccessSize = 2; + pNicDevice = DEV_FROM_SIMPLE_NETWORK ( pSimpleNetwork ); + Status = Ax88772MacAddressGet ( pNicDevice, &pMode->PermanentAddress.Addr[0]); + CopyMem ( &pMode->CurrentAddress, + &pMode->PermanentAddress, + sizeof ( pMode->CurrentAddress )); + SetMem(&pMode->BroadcastAddress, PXE_HWADDR_LEN_ETHER, 0xff); + pMode->IfType = EfiNetworkInterfaceUndi; + pMode->MacAddressChangeable = TRUE; + pMode->MultipleTxSupported = FALSE; + + pMode->MediaPresentSupported = TRUE; + pMode->MediaPresent = FALSE; + + } else { + Status = EFI_ALREADY_STARTED; + } + } + + // + // Return the operation status + // + gBS->RestoreTPL(TplPrevious); + return Status; +} + + +/** + Set the MAC address. + + This function modifies or resets the current station address of a + network interface. If Reset is TRUE, then the current station address + is set ot the network interface's permanent address. If Reset if FALSE + then the current station address is changed to the address specified by + pNew. + + This routine calls ::Ax88772MacAddressSet to update the MAC address + in the network adapter. + + @param [in] pSimpleNetwork Protocol instance pointer + @param [in] bReset Flag used to reset the station address to the + network interface's permanent address. + @param [in] pNew New station address to be used for the network + interface. + + @retval EFI_SUCCESS This operation was successful. + @retval EFI_NOT_STARTED The network interface was not started. + @retval EFI_INVALID_PARAMETER pSimpleNetwork parameter was NULL or did not point to a valid + EFI_SIMPLE_NETWORK_PROTOCOL structure. + @retval EFI_DEVICE_ERROR The command could not be sent to the network interface. + @retval EFI_UNSUPPORTED The increased buffer size feature is not supported. + +**/ +EFI_STATUS +EFIAPI +SN_StationAddress ( + IN EFI_SIMPLE_NETWORK_PROTOCOL * pSimpleNetwork, + IN BOOLEAN bReset, + IN EFI_MAC_ADDRESS * pNew + ) +{ + NIC_DEVICE * pNicDevice; + EFI_SIMPLE_NETWORK_MODE * pMode; + EFI_STATUS Status; + + EFI_TPL TplPrevious; + + + TplPrevious = gBS->RaiseTPL(TPL_CALLBACK); + + // + // Verify the parameters + // + if (( NULL != pSimpleNetwork ) && + ( NULL != pSimpleNetwork->Mode ) && + (( !bReset ) || ( bReset && ( NULL != pNew )))) { + // + // Verify that the adapter is already started + // + pNicDevice = DEV_FROM_SIMPLE_NETWORK ( pSimpleNetwork ); + pMode = pSimpleNetwork->Mode; + if ( EfiSimpleNetworkInitialized == pMode->State ) { + // + // Determine the adapter MAC address + // + if ( bReset ) { + // + // Use the permanent address + // + CopyMem ( &pMode->CurrentAddress, + &pMode->PermanentAddress, + sizeof ( pMode->CurrentAddress )); + } else { + // + // Use the specified address + // + CopyMem ( &pMode->CurrentAddress, + pNew, + sizeof ( pMode->CurrentAddress )); + } + + // + // Update the address on the adapter + // + Status = Ax88772MacAddressSet ( pNicDevice, &pMode->CurrentAddress.Addr[0]); + } else { + if (EfiSimpleNetworkStarted == pMode->State) { + Status = EFI_DEVICE_ERROR; ; + } else { + Status = EFI_NOT_STARTED ; + } + } + } else { + Status = EFI_INVALID_PARAMETER; + } + + // + // Return the operation status + // + gBS->RestoreTPL(TplPrevious); + + return Status; +} + + +/** + This function resets or collects the statistics on a network interface. + If the size of the statistics table specified by StatisticsSize is not + big enough for all of the statistics that are collected by the network + interface, then a partial buffer of statistics is returned in + StatisticsTable. + + @param [in] pSimpleNetwork Protocol instance pointer + @param [in] bReset Set to TRUE to reset the statistics for the network interface. + @param [in, out] pStatisticsSize On input the size, in bytes, of StatisticsTable. On output + the size, in bytes, of the resulting table of statistics. + @param [out] pStatisticsTable A pointer to the EFI_NETWORK_STATISTICS structure that + conains the statistics. + + @retval EFI_SUCCESS This operation was successful. + @retval EFI_NOT_STARTED The network interface was not started. + @retval EFI_BUFFER_TOO_SMALL The pStatisticsTable is NULL or the buffer is too small. + @retval EFI_INVALID_PARAMETER pSimpleNetwork parameter was NULL or did not point to a valid + EFI_SIMPLE_NETWORK_PROTOCOL structure. + @retval EFI_DEVICE_ERROR The command could not be sent to the network interface. + @retval EFI_UNSUPPORTED The increased buffer size feature is not supported. + + typedef struct { + UINT64 RxTotalFrames; + UINT64 RxGoodFrames; + UINT64 RxUndersizeFrames; + UINT64 RxOversizeFrames; + UINT64 RxDroppedFrames; + UINT64 RxUnicastFrames; + UINT64 RxBroadcastFrames; + UINT64 RxMulticastFrames; + UINT64 RxCrcErrorFrames; + UINT64 RxTotalBytes; + UINT64 TxTotalFrames; + UINT64 TxGoodFrames; + UINT64 TxUndersizeFrames; + UINT64 TxOversizeFrames; + UINT64 TxDroppedFrames; + UINT64 TxUnicastFrames; + UINT64 TxBroadcastFrames; + UINT64 TxMulticastFrames; + UINT64 TxCrcErrorFrames; + UINT64 TxTotalBytes; + UINT64 Collisions; + UINT64 UnsupportedProtocol; + } EFI_NETWORK_STATISTICS; +**/ +EFI_STATUS +EFIAPI +SN_Statistics ( + IN EFI_SIMPLE_NETWORK_PROTOCOL * pSimpleNetwork, + IN BOOLEAN bReset, + IN OUT UINTN * pStatisticsSize, + OUT EFI_NETWORK_STATISTICS * pStatisticsTable + ) +{ + EFI_STATUS Status; + EFI_TPL TplPrevious; + EFI_SIMPLE_NETWORK_MODE * pMode; + + + + TplPrevious = gBS->RaiseTPL(TPL_CALLBACK); + + pMode = pSimpleNetwork->Mode; + + if ( EfiSimpleNetworkInitialized == pMode->State ) { + if (NULL != pStatisticsSize && 0 == *pStatisticsSize) { + Status = EFI_BUFFER_TOO_SMALL; + goto EXIT; + } + if(bReset) { + Status = EFI_SUCCESS; + } else { + Status = EFI_SUCCESS; + } + } else { + if (EfiSimpleNetworkStarted == pMode->State) { + Status = EFI_DEVICE_ERROR; ; + } else { + Status = EFI_NOT_STARTED ; + } + } + // + // This is not currently supported + // + +EXIT: + gBS->RestoreTPL(TplPrevious); + return Status; +} + + +/** + This function stops a network interface. This call is only valid + if the network interface is in the started state. + + @param [in] pSimpleNetwork Protocol instance pointer + + @retval EFI_SUCCESS This operation was successful. + @retval EFI_NOT_STARTED The network interface was not started. + @retval EFI_INVALID_PARAMETER pSimpleNetwork parameter was NULL or did not point to a valid + EFI_SIMPLE_NETWORK_PROTOCOL structure. + @retval EFI_DEVICE_ERROR The command could not be sent to the network interface. + @retval EFI_UNSUPPORTED The increased buffer size feature is not supported. + +**/ +EFI_STATUS +EFIAPI +SN_Stop ( + IN EFI_SIMPLE_NETWORK_PROTOCOL * pSimpleNetwork + ) +{ + EFI_SIMPLE_NETWORK_MODE * pMode; + EFI_STATUS Status; + + EFI_TPL TplPrevious; + + TplPrevious = gBS->RaiseTPL(TPL_CALLBACK); + + // + // Verify the parameters + // + if (( NULL != pSimpleNetwork ) && ( NULL != pSimpleNetwork->Mode )) { + // + // Determine if the interface is started + // + pMode = pSimpleNetwork->Mode; + + if ( EfiSimpleNetworkStarted == pMode->State ) { + pMode->State = EfiSimpleNetworkStopped; + Status = EFI_SUCCESS; + } else { + Status = EFI_NOT_STARTED; + } + } else { + Status = EFI_INVALID_PARAMETER; + } + + // + // Return the operation status + // + gBS->RestoreTPL(TplPrevious); + return Status; +} + + +/** + This function releases the memory buffers assigned in the Initialize() call. + Pending transmits and receives are lost, and interrupts are cleared and disabled. + After this call, only Initialize() and Stop() calls may be used. + + @param [in] pSimpleNetwork Protocol instance pointer + + @retval EFI_SUCCESS This operation was successful. + @retval EFI_NOT_STARTED The network interface was not started. + @retval EFI_INVALID_PARAMETER pSimpleNetwork parameter was NULL or did not point to a valid + EFI_SIMPLE_NETWORK_PROTOCOL structure. + @retval EFI_DEVICE_ERROR The command could not be sent to the network interface. + @retval EFI_UNSUPPORTED The increased buffer size feature is not supported. + +**/ +EFI_STATUS +EFIAPI +SN_Shutdown ( + IN EFI_SIMPLE_NETWORK_PROTOCOL * pSimpleNetwork + ) +{ + EFI_SIMPLE_NETWORK_MODE * pMode; + UINT32 RxFilter; + EFI_STATUS Status; + + EFI_TPL TplPrevious; + + TplPrevious = gBS->RaiseTPL(TPL_CALLBACK); + + // + // Verify the parameters + // + if (( NULL != pSimpleNetwork ) && ( NULL != pSimpleNetwork->Mode )) { + // + // Determine if the interface is already started + // + pMode = pSimpleNetwork->Mode; + if ( EfiSimpleNetworkInitialized == pMode->State ) { + // + // Stop the adapter + // + RxFilter = pMode->ReceiveFilterSetting; + pMode->ReceiveFilterSetting = 0; + Status = SN_Reset ( pSimpleNetwork, FALSE ); + pMode->ReceiveFilterSetting = RxFilter; + if ( !EFI_ERROR ( Status )) { + // + // Update the network state + // + pMode->State = EfiSimpleNetworkStarted; + } else if ( EFI_DEVICE_ERROR == Status ) { + pMode->State = EfiSimpleNetworkStopped; + } + + } else { + Status = EFI_NOT_STARTED; + } + } else { + Status = EFI_INVALID_PARAMETER; + } + + // + // Return the operation status + // + gBS->RestoreTPL(TplPrevious ); + return Status; +} + + +/** + Send a packet over the network. + + This function places the packet specified by Header and Buffer on + the transmit queue. This function performs a non-blocking transmit + operation. When the transmit is complete, the buffer is returned + via the GetStatus() call. + + This routine calls ::Ax88772Rx to empty the network adapter of + receive packets. The routine then passes the transmit packet + to the network adapter. + + @param [in] pSimpleNetwork Protocol instance pointer + @param [in] HeaderSize The size, in bytes, of the media header to be filled in by + the Transmit() function. If HeaderSize is non-zero, then + it must be equal to SimpleNetwork->Mode->MediaHeaderSize + and DestAddr and Protocol parameters must not be NULL. + @param [in] BufferSize The size, in bytes, of the entire packet (media header and + data) to be transmitted through the network interface. + @param [in] pBuffer A pointer to the packet (media header followed by data) to + to be transmitted. This parameter can not be NULL. If + HeaderSize is zero, then the media header is Buffer must + already be filled in by the caller. If HeaderSize is nonzero, + then the media header will be filled in by the Transmit() + function. + @param [in] pSrcAddr The source HW MAC address. If HeaderSize is zero, then + this parameter is ignored. If HeaderSize is nonzero and + SrcAddr is NULL, then SimpleNetwork->Mode->CurrentAddress + is used for the source HW MAC address. + @param [in] pDestAddr The destination HW MAC address. If HeaderSize is zero, then + this parameter is ignored. + @param [in] pProtocol The type of header to build. If HeaderSize is zero, then + this parameter is ignored. + + @retval EFI_SUCCESS This operation was successful. + @retval EFI_NOT_STARTED The network interface was not started. + @retval EFI_NOT_READY The network interface is too busy to accept this transmit request. + @retval EFI_BUFFER_TOO_SMALL The BufferSize parameter is too small. + @retval EFI_INVALID_PARAMETER pSimpleNetwork parameter was NULL or did not point to a valid + EFI_SIMPLE_NETWORK_PROTOCOL structure. + @retval EFI_DEVICE_ERROR The command could not be sent to the network interface. + +**/ +EFI_STATUS +EFIAPI +SN_Transmit ( + IN EFI_SIMPLE_NETWORK_PROTOCOL * pSimpleNetwork, + IN UINTN HeaderSize, + IN UINTN BufferSize, + IN VOID * pBuffer, + IN EFI_MAC_ADDRESS * pSrcAddr, + IN EFI_MAC_ADDRESS * pDestAddr, + IN UINT16 * pProtocol + ) +{ + ETHERNET_HEADER * pHeader; + EFI_SIMPLE_NETWORK_MODE * pMode; + NIC_DEVICE * pNicDevice; + EFI_USB_IO_PROTOCOL * pUsbIo; + EFI_STATUS Status; + UINTN TransferLength; + UINT32 TransferStatus; + UINT16 Type; + EFI_TPL TplPrevious; + TplPrevious = gBS->RaiseTPL(TPL_CALLBACK); + + // Verify the parameters + // + if (( NULL != pSimpleNetwork ) && ( NULL != pSimpleNetwork->Mode )) { + // + // The interface must be running + // + pMode = pSimpleNetwork->Mode; + if ( EfiSimpleNetworkInitialized == pMode->State ) { + // + // Update the link status + // + pNicDevice = DEV_FROM_SIMPLE_NETWORK ( pSimpleNetwork ); + + // + // Release the synchronization with Ax88772Timer + // + if ( pNicDevice->bLinkUp && pNicDevice->bComplete) { + // + // Copy the packet into the USB buffer + // + + if (0 != HeaderSize && pMode->MediaHeaderSize != HeaderSize) { + Status = EFI_INVALID_PARAMETER; + goto EXIT; + } + if (BufferSize < pMode->MediaHeaderSize) { + Status = EFI_INVALID_PARAMETER; + goto EXIT; + } + if (NULL == pBuffer) { + Status = EFI_INVALID_PARAMETER; + goto EXIT; + } + if (0 != HeaderSize && NULL == pDestAddr) { + Status = EFI_INVALID_PARAMETER; + goto EXIT; + } + if (0 != HeaderSize && NULL == pProtocol) { + Status = EFI_INVALID_PARAMETER; + goto EXIT; + } + + CopyMem ( &pNicDevice->pTxTest->Data[0], pBuffer, BufferSize ); + pNicDevice->pTxTest->Length = (UINT16) BufferSize; + + // + // Transmit the packet + // + pHeader = (ETHERNET_HEADER *) &pNicDevice->pTxTest->Data[0]; + if ( 0 != HeaderSize ) { + if ( NULL != pDestAddr ) { + CopyMem ( &pHeader->dest_addr, pDestAddr, PXE_HWADDR_LEN_ETHER ); + } + if ( NULL != pSrcAddr ) { + CopyMem ( &pHeader->src_addr, pSrcAddr, PXE_HWADDR_LEN_ETHER ); + } + else { + CopyMem ( &pHeader->src_addr, &pMode->CurrentAddress.Addr[0], PXE_HWADDR_LEN_ETHER ); + } + if ( NULL != pProtocol ) { + Type = *pProtocol; + } else { + Type = pNicDevice->pTxTest->Length; + } + Type = (UINT16)(( Type >> 8 ) | ( Type << 8 )); + pHeader->type = Type; + } + + + if ( pNicDevice->pTxTest->Length < MIN_ETHERNET_PKT_SIZE ) { + pNicDevice->pTxTest->Length = MIN_ETHERNET_PKT_SIZE; + ZeroMem ( &pNicDevice->pTxTest->Data[ BufferSize], + pNicDevice->pTxTest->Length - BufferSize ); + } + + pNicDevice->pTxTest->LengthBar = ~(pNicDevice->pTxTest->Length); + TransferLength = sizeof ( pNicDevice->pTxTest->Length ) + + sizeof ( pNicDevice->pTxTest->LengthBar ) + + pNicDevice->pTxTest->Length; + + if (TransferLength % 512 == 0 || TransferLength % 1024 == 0) + TransferLength +=4; +#if RXTHOU + if (pNicDevice->rxburst == 1) + pNicDevice->rxburst--; +#endif + // + // Work around USB bus driver bug where a timeout set by receive + // succeeds but the timeout expires immediately after, causing the + // transmit operation to timeout. + // + pUsbIo = pNicDevice->pUsbIo; + Status = pUsbIo->UsbBulkTransfer ( pUsbIo, + BULK_OUT_ENDPOINT, + &pNicDevice->pTxTest->Length, + &TransferLength, + 0xfffffffe, + &TransferStatus ); + if ( EFI_SUCCESS == Status) { + Status = TransferStatus; + } + if ( EFI_SUCCESS == Status && EFI_SUCCESS == TransferStatus) { + pNicDevice->pTxBuffer = pBuffer; + } else { + if ( EFI_DEVICE_ERROR == Status ) { + SN_Reset ( pSimpleNetwork, FALSE ); + } + Status = EFI_NOT_READY; + } + } else { + // + // No packets available. + // + + Status = EFI_NOT_READY; + } + } else { + if (EfiSimpleNetworkStarted == pMode->State) { + Status = EFI_DEVICE_ERROR; ; + } else { + Status = EFI_NOT_STARTED ; + } + } + } else { + Status = EFI_INVALID_PARAMETER; + } + +EXIT: + gBS->RestoreTPL (TplPrevious); + + return Status; +} -- 2.17.1