/** @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. Copyright (c) 2020, ARM Limited. All rights reserved. SPDX-License-Identifier: BSD-2-Clause-Patent **/ #include "Ax88772.h" /** Compute the CRC @param [in] MacAddress 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 *MacAddress ) { UINT32 BitNumber; INT32 Carry; INT32 Crc; UINT32 Data; UINT8 *End; // // Walk the MAC address // Crc = -1; End = &MacAddress[PXE_HWADDR_LEN_ETHER]; while (End > MacAddress) { Data = *MacAddress++; // // 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 (Carry != 0) { 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] NicDevice Pointer to the NIC_DEVICE structure @param [out] MacAddress 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 *NicDevice, OUT UINT8 *MacAddress ) { 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 (NicDevice, &SetupMsg, MacAddress); // // 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] NicDevice Pointer to the NIC_DEVICE structure @param [in] MacAddress 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 *NicDevice, IN UINT8 *MacAddress ) { 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 (NicDevice, &SetupMsg, MacAddress); // // Return the operation status // return Status; } /** Clear the multicast hash table @param [in] NicDevice Pointer to the NIC_DEVICE structure **/ VOID Ax88772MulticastClear ( IN NIC_DEVICE *NicDevice ) { int Index = 0; // // Clear the multicast hash table // for (Index = 0 ; Index < 8 ; Index ++) NicDevice->MulticastHash[Index] = 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] NicDevice Pointer to the NIC_DEVICE structure @param [in] MacAddress Address of a six byte buffer to containing the MAC address. **/ VOID Ax88772MulticastSet ( IN NIC_DEVICE *NicDevice, IN UINT8 *MacAddress ) { UINT32 Crc; // // Compute the CRC on the destination address // Crc = Ax88772Crc (MacAddress) >> 26; // // Set the bit corresponding to the destination address // NicDevice->MulticastHash [Crc >> 3] |= (1 << (Crc & 7)); } /** Start the link negotiation This routine calls ::Ax88772PhyWrite to start the PHY's link negotiation. @param [in] NicDevice 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 *NicDevice ) { UINT16 Control; EFI_STATUS Status; // // Set the supported capabilities. // Status = Ax88772PhyWrite (NicDevice, 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 (NicDevice->LinkSpeed100Mbps) { Control |= BMCR_100MBPS; } if (NicDevice->FullDuplex) { Control |= BMCR_FULL_DUPLEX; } Status = Ax88772PhyWrite (NicDevice, 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] NicDevice Pointer to the NIC_DEVICE structure @param [in, out] PollCount Address of number of times this routine was polled @param [out] Complete Address of boolean to receive complate status. @param [out] LinkUp Address of boolean to receive link status, TRUE=up. @param [out] HiSpeed Address of boolean to receive link speed, TRUE=100Mbps. @param [out] FullDuplex 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 *NicDevice, IN OUT UINTN *PollCount, OUT BOOLEAN *Complete, OUT BOOLEAN *LinkUp, OUT BOOLEAN *HiSpeed, OUT BOOLEAN *FullDuplex ) { UINT16 Mask; UINT16 PhyData; EFI_STATUS Status; // // Determine if the link is up. // *Complete = FALSE; // // Get the link status // Status = Ax88772PhyRead (NicDevice, PHY_BMSR, &PhyData); if (EFI_ERROR (Status)) { return Status; } *LinkUp = ((PhyData & BMSR_LINKST) != 0); if (0 == *LinkUp) { } else { *Complete = ((PhyData & 0x20) != 0); if (0 == *Complete) { } else { Status = Ax88772PhyRead (NicDevice, PHY_ANLPAR, &PhyData); if (!EFI_ERROR (Status)) { // // Autonegotiation is complete // Determine the link speed. // *HiSpeed = ((PhyData & (AN_TX_FDX | AN_TX_HDX))!= 0); // // Determine the link duplex. // Mask = (*HiSpeed) ? AN_TX_FDX : AN_10_FDX; *FullDuplex = (BOOLEAN)((PhyData & Mask) != 0); } } } return Status; } /** Read a register from the PHY This routine calls ::Ax88772UsbCommand to read a PHY register. @param [in] NicDevice Pointer to the NIC_DEVICE structure @param [in] RegisterAddress Number of the register to read. @param [in, out] PhyData 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 *NicDevice, IN UINT8 RegisterAddress, IN OUT 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 (NicDevice, &SetupMsg, NULL); if (EFI_ERROR (Status)) { return 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 = NicDevice->PhyId; SetupMsg.Index = RegisterAddress; SetupMsg.Length = sizeof(*PhyData); Status = Ax88772UsbCommand(NicDevice, &SetupMsg, PhyData); if (EFI_ERROR (Status)) { return 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(NicDevice, &SetupMsg, NULL); // // Return the operation status. // return Status; } /** Write to a PHY register This routine calls ::Ax88772UsbCommand to write a PHY register. @param [in] NicDevice 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 *NicDevice, 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 (NicDevice, &SetupMsg, NULL); if (EFI_ERROR (Status)) { return Status; } // // Write the PHY register // SetupMsg.RequestType = USB_REQ_TYPE_VENDOR | USB_TARGET_DEVICE; SetupMsg.Request = CMD_PHY_REG_WRITE; SetupMsg.Value = NicDevice->PhyId; SetupMsg.Index = RegisterAddress; SetupMsg.Length = sizeof (PhyData); Status = Ax88772UsbCommand (NicDevice, &SetupMsg, &PhyData); if (EFI_ERROR (Status)) { return 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 (NicDevice, &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] NicDevice 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 *NicDevice ) { USB_DEVICE_REQUEST SetupMsg; EFI_STATUS Status; 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 (NicDevice, &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 (NicDevice, &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 (NicDevice, &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 (NicDevice, &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 (NicDevice, &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 (NicDevice, &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 (NicDevice, &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 (NicDevice, &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 (NicDevice, &SetupMsg, NULL); if (EFI_ERROR(Status)) goto err; if (!NicDevice->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 (NicDevice, &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] NicDevice 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 *NicDevice, 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 (RxFilter != 0) { // // 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 (NicDevice, &SetupMsg, &MediumStatus); if (!EFI_ERROR (Status)) { if (0 == (MediumStatus & MS_RE)) { MediumStatus |= MS_RE | MS_ONE; if (NicDevice->FullDuplex) MediumStatus |= MS_TFC | MS_RFC | MS_FD; else MediumStatus &= ~(MS_TFC | MS_RFC | MS_FD); if (NicDevice->LinkSpeed100Mbps) 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 (NicDevice, &SetupMsg, NULL); if (EFI_ERROR(Status)) goto EXIT; } } else { goto EXIT; } } RxControl = RXC_SO; if (!NicDevice->Flag772A) RxControl |= RXC_RH1M; // // Enable multicast if requested // if ((RxFilter & EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST) != 0) { 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 (NicDevice ->MulticastHash); Status = Ax88772UsbCommand (NicDevice, &SetupMsg, &NicDevice->MulticastHash); if (EFI_ERROR(Status)) goto EXIT; } // // Enable all multicast if requested // if ((RxFilter & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST) != 0) { RxControl |= RXC_AMALL; } // // Enable broadcast if requested // if ((RxFilter & EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST) != 0) { RxControl |= RXC_AB; } // // Enable promiscuous mode if requested // if ((RxFilter & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS) != 0) { RxControl |= RXC_PRO; } // // Update the receiver control // if (NicDevice->CurRxControl != RxControl) { SetupMsg.RequestType = USB_REQ_TYPE_VENDOR | USB_TARGET_DEVICE; SetupMsg.Request = CMD_RX_CONTROL_WRITE; #if RXTHOU if (NicDevice->Flag772A) RxControl |= 0x0300; #endif if (NicDevice->Flag772A) RxControl &= ~(RXC_MFB); SetupMsg.Value = RxControl; SetupMsg.Index = 0; SetupMsg.Length = 0; Status = Ax88772UsbCommand (NicDevice, &SetupMsg, NULL); if (!EFI_ERROR (Status)) NicDevice->CurRxControl = RxControl; } // // Return the operation status // EXIT: return Status; } EFI_STATUS Ax88772ReloadSrom ( IN NIC_DEVICE *NicDevice ) { 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 (NicDevice, &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] NicDevice Pointer to the NIC_DEVICE structure @param [in] Address SROM address @param [out] Data Buffer to receive the data @retval EFI_SUCCESS The read was successful @retval other The read failed **/ EFI_STATUS Ax88772SromRead ( IN NIC_DEVICE *NicDevice, IN UINT32 Address, OUT UINT16 *Data ) { 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 (*Data); Status = Ax88772UsbCommand (NicDevice, &SetupMsg, Data); // // Return the operation status // return Status; } EFI_STATUS Ax88772EnableSromWrite ( IN NIC_DEVICE * NicDevice ) { 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 (NicDevice, &SetupMsg, NULL); if (EFI_SUCCESS == Status) gBS->Stall(500000); return Status; } EFI_STATUS Ax88772DisableSromWrite ( IN NIC_DEVICE *NicDevice ) { 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 (NicDevice, &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] NicDevice Pointer to the NIC_DEVICE structure @param [in] Address SROM address @param [out] Data Buffer of data to write @retval EFI_SUCCESS The write was successful @retval other The write failed **/ EFI_STATUS Ax88772SromWrite ( IN NIC_DEVICE *NicDevice, IN UINT32 Address, IN UINT16 *Data ) { 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) (*Data); SetupMsg.Length = 0; Status = Ax88772UsbCommand (NicDevice, &SetupMsg, NULL); // // Return the operation status // return Status; } /** Send a command to the USB device. @param [in] NicDevice Pointer to the NIC_DEVICE structure @param [in] Request Pointer to the request structure @param [in, out] Buffer Data buffer address @retval EFI_SUCCESS The USB transfer was successful @retval other The USB transfer failed **/ EFI_STATUS Ax88772UsbCommand ( IN NIC_DEVICE *NicDevice, IN USB_DEVICE_REQUEST *Request, IN OUT VOID *Buffer ) { UINT32 CmdStatus; EFI_USB_DATA_DIRECTION Direction; EFI_USB_IO_PROTOCOL *UsbIo; EFI_STATUS Status; // // Determine the transfer direction // Direction = EfiUsbNoData; if (Request->Length != 0) { Direction = ((Request->RequestType & USB_ENDPOINT_DIR_IN) != 0) ? EfiUsbDataIn : EfiUsbDataOut; } // // Issue the command // UsbIo = NicDevice->UsbIo; Status = UsbIo->UsbControlTransfer (UsbIo, Request, Direction, USB_BUS_TIMEOUT, Buffer, Request->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 *NicDevice ) { UINT32 CmdStatus; EFI_USB_IO_PROTOCOL *UsbIo; UINT64 IntData = 0; UINTN IntDataLeng = 8; EFI_STATUS Status; // // Issue the command // UsbIo = NicDevice->UsbIo; Status = UsbIo->UsbSyncInterruptTransfer(UsbIo, 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 * NicDevice ) { UINTN Index; UINTN LengthInBytes = 0; UINTN TmpLen = AX88772_MAX_BULKIN_SIZE; UINTN OrigTmpLen = 0; UINT16 TmpLen2; UINT16 TmpLenBar; UINT16 TmpTotalLen = 0; UINTN TotalLen = LengthInBytes; EFI_STATUS Status = EFI_DEVICE_ERROR; EFI_USB_IO_PROTOCOL *UsbIo; UINT32 TransferStatus = 0; UINT16 TmpPktCnt = 0; UINT16 *TmpHdr = (UINT16 *)NicDevice->BulkInbuf; USB_DEVICE_REQUEST SetupMsg; UsbIo = NicDevice->UsbIo; for (Index = 0 ; Index < (AX88772_MAX_BULKIN_SIZE / 512) && UsbIo != NULL; Index++) { VOID* TmpAddr = 0; TmpPktCnt = 0; TmpAddr = (VOID*) &NicDevice->BulkInbuf[LengthInBytes]; OrigTmpLen = TmpLen; Status = UsbIo->UsbBulkTransfer (UsbIo, USB_ENDPOINT_DIR_IN | BULK_IN_ENDPOINT, TmpAddr, &TmpLen, BULKIN_TIMEOUT, &TransferStatus); if (OrigTmpLen == TmpLen) { Status = EFI_NOT_READY; goto no_pkt; } if ((!EFI_ERROR (Status)) && (!EFI_ERROR (TransferStatus)) && TmpLen != 0) { LengthInBytes += TmpLen; if ((TmpLen % 512) != 0) { goto done; } } else if ((!EFI_ERROR (Status)) && (!EFI_ERROR (TransferStatus)) && (TmpLen == 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 (NicDevice, &SetupMsg, NULL); Status = EFI_NOT_READY; goto done; } else { Status = EFI_DEVICE_ERROR; goto done; } } done: if (LengthInBytes != 0) { do { TmpLen2 = (*TmpHdr) & 0x7FF; TmpLenBar = *(TmpHdr + 1); TmpTotalLen = ((TmpLen + 4 + 1) & 0xfffe); if ((TmpLen2 & 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 ((NicDevice->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 (NicDevice, &SetupMsg, NULL); } if (NicDevice->RxBurst < 2) NicDevice->RxBurst++; } else { if (NicDevice->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 (NicDevice, &SetupMsg, NULL); } NicDevice->RxBurst = 0; } } if (TmpPktCnt != 0) { NicDevice->PktCnt = TmpPktCnt; NicDevice->CurPktHdrOff = NicDevice->BulkInbuf; NicDevice->CurPktOff = NicDevice->BulkInbuf + 4; Status = EFI_SUCCESS; } no_pkt: return Status; } #else EFI_STATUS Ax88772BulkIn( IN NIC_DEVICE *NicDevice ) { UINTN Index; UINTN LengthInBytes = 0; UINTN TmpLen = AX88772_MAX_BULKIN_SIZE; UINTN OrigTmpLen = 0; UINT16 TmpLen2; UINT16 TmpLenBar; UINT16 TmpTotalLen = 0; UINTN CURBufSize = AX88772_MAX_BULKIN_SIZE; EFI_STATUS Status = EFI_DEVICE_ERROR; EFI_USB_IO_PROTOCOL *UsbIo; UINT32 TransferStatus = 0; UINT16 TmpPktCnt = 0; UINT16 *TmpHdr = (UINT16 *)NicDevice->BulkInbuf; UsbIo = NicDevice->UsbIo; for (Index = 0 ; Index < (AX88772_MAX_BULKIN_SIZE / 512) && UsbIo != NULL; Index++) { VOID *TmpAddr = 0; TmpPktCnt = 0; TmpAddr = (VOID*) &NicDevice->BulkInbuf[LengthInBytes]; OrigTmpLen = TmpLen; Status = UsbIo->UsbBulkTransfer (UsbIo, USB_ENDPOINT_DIR_IN | BULK_IN_ENDPOINT, TmpAddr, &TmpLen, BULKIN_TIMEOUT, &TransferStatus); if (OrigTmpLen == TmpLen) { Status = EFI_NOT_READY; goto no_pkt; } if ((!EFI_ERROR (Status)) && (!EFI_ERROR (TransferStatus)) && TmpLen != 0) { LengthInBytes += TmpLen; CURBufSize = CURBufSize - TmpLen; TmpLen = CURBufSize; do { TmpLen2 = *TmpHdr; TmpLenBar = *(TmpHdr + 1); TmpTotalLen += ((TmpLen2 + 4 + 1) & 0xfffe); if (((TmpLen2 ^ TmpLenBar) == 0xffff)) { if (TmpTotalLen == LengthInBytes) { TmpPktCnt++; Status = EFI_SUCCESS; goto done; } else if (TmpTotalLen > LengthInBytes) { break; } } else if (((TmpLen2 ^ 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)) && (TmpLen == 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: NicDevice->PktCnt = TmpPktCnt; NicDevice->CurPktHdrOff = NicDevice->BulkInbuf; NicDevice->CurPktOff = NicDevice->BulkInbuf + 4; no_pkt: return Status; } #endif