blob: 9604179b0ce689116f1aceae9b2baa1908a6c9a2 [file] [log] [blame]
/** @file
Implement the interface to the AX88772 Ethernet controller.
This module implements the interface to the ASIX AX88772
USB to Ethernet MAC with integrated 10/100 PHY. Note that this implementation
only supports the integrated PHY since no other test cases were available.
Copyright (c) 2011, Intel Corporation
All rights reserved. This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#include "Ax88772.h"
/**
Compute the CRC
@param [in] pMacAddress Address of a six byte buffer to containing the MAC address.
@returns The CRC-32 value associated with this MAC address
**/
UINT32
Ax88772Crc (
IN UINT8 * pMacAddress
)
{
UINT32 BitNumber;
INT32 Carry;
INT32 Crc;
UINT32 Data;
UINT8 * pEnd;
//
// 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
)
{
EFI_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 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 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[0] = 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;
int i;
//
// Set the supported capabilities.
//
Status = Ax88772PhyWrite ( pNicDevice,
PHY_ANAR,
AN_CSMA_CD
| AN_TX_FDX | AN_TX_HDX
| AN_10_FDX | AN_10_HDX );
if ( !EFI_ERROR ( Status )) {
//
// Set the link speed and duplex
//
Control = BMCR_AUTONEGOTIATION_ENABLE
| BMCR_RESTART_AUTONEGOTIATION;
if ( pNicDevice->b100Mbps ) {
Control |= BMCR_100MBPS;
}
if ( pNicDevice->bFullDuplex ) {
Control |= BMCR_FULL_DUPLEX;
}
Status = Ax88772PhyWrite ( pNicDevice, PHY_BMCR, Control );
}
if (!EFI_ERROR(Status)) {
i = 0;
do {
if (pNicDevice->bComplete && pNicDevice->bLinkUp) {
pNicDevice->SimpleNetwork.Mode->MediaPresent
= pNicDevice->bLinkUp & pNicDevice->bComplete;
break;
}
else {
gBS->Stall(AUTONEG_DELAY);
Status = Ax88772NegotiateLinkComplete ( pNicDevice,
&pNicDevice->PollCount,
&pNicDevice->bComplete,
&pNicDevice->bLinkUp,
&pNicDevice->b100Mbps,
&pNicDevice->bFullDuplex );
i++;
}
}while(!pNicDevice->bLinkUp && i < AUTONEG_POLLCNT);
}
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 ) {
DEBUG (D_INFO, L"Link Down\n" );
}
else {
*pbComplete = (BOOLEAN)( 0 != ( PhyData & 0x20 ));
if ( 0 == *pbComplete ) {
DEBUG (EFI_D_INFO, L"Autoneg is not yet Complete\n");
}
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 {
DEBUG ( EFI_D_ERROR, L"Failed to read BMCR\n" );
}
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 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 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;
EFI_USB_DEVICE_DESCRIPTOR Device;
pUsbIo = pNicDevice->pUsbIo;
Status = pUsbIo->UsbGetDeviceDescriptor ( pUsbIo, &Device );
if (EFI_ERROR(Status)) goto err;
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->Flags != FLAG_TYPE_AX88772) {
SetupMsg.RequestType = USB_REQ_TYPE_VENDOR
| USB_TARGET_DEVICE;
SetupMsg.Request = CMD_RXQTC;
SetupMsg.Value = 0x8000;
SetupMsg.Index = 0x8001;
SetupMsg.Length = 0;
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_USB_IO_PROTOCOL *pUsbIo;
EFI_USB_DEVICE_DESCRIPTOR Device;
pUsbIo = pNicDevice->pUsbIo;
Status = pUsbIo->UsbGetDeviceDescriptor ( pUsbIo, &Device );
if (EFI_ERROR(Status)) {
DEBUG ( EFI_D_ERROR, L"Failed to get device descriptor\n" );
return Status;
}
//
// 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 )) {
DEBUG ( EFI_D_ERROR, L"Failed to enable receiver, Status: %r\r\n",
Status );
}
}
}
else {
DEBUG ( EFI_D_ERROR, L"Failed to read receiver status, Status: %r\r\n",
Status );
}
}
RxControl = RXC_SO | 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 );
}
//
// 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;
SetupMsg.Value = RxControl;
SetupMsg.Index = 0;
SetupMsg.Length = 0;
Status = Ax88772UsbCommand ( pNicDevice,
&SetupMsg,
NULL );
if ( !EFI_ERROR ( Status )) {
pNicDevice->CurRxControl = RxControl;
}
else {
DEBUG ( EFI_D_ERROR, L"ERROR - Failed to set receiver control, Status: %r\r\n",
Status );
}
}
return Status;
}
/**
Read an SROM location
This routine calls ::Ax88772UsbCommand to read data from the
SROM.
@param [in] pNicDevice Pointer to the NIC_DEVICE structure
@param [in] Address SROM address
@param [out] pData Buffer to receive the data
@retval EFI_SUCCESS The read was successful
@retval other The read failed
**/
EFI_STATUS
Ax88772SromRead (
IN NIC_DEVICE * pNicDevice,
IN UINT32 Address,
OUT UINT16 * pData
)
{
return EFI_UNSUPPORTED;
}
/**
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 Status;
}