Home | History | Annotate | Download | only in Ax88772b
      1 /** @file
      2   Implement the interface to the AX88772 Ethernet controller.
      3 
      4   This module implements the interface to the ASIX AX88772
      5   USB to Ethernet MAC with integrated 10/100 PHY.  Note that this implementation
      6   only supports the integrated PHY since no other test cases were available.
      7 
      8   Copyright (c) 2011, Intel Corporation
      9   All rights reserved. This program and the accompanying materials
     10   are licensed and made available under the terms and conditions of the BSD License
     11   which accompanies this distribution.  The full text of the license may be found at
     12   http://opensource.org/licenses/bsd-license.php
     13 
     14   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     15   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     16 
     17 **/
     18 
     19 #include "Ax88772.h"
     20 
     21 
     22 /**
     23   Compute the CRC
     24 
     25   @param [in] pMacAddress      Address of a six byte buffer to containing the MAC address.
     26 
     27   @returns The CRC-32 value associated with this MAC address
     28 
     29 **/
     30 UINT32
     31 Ax88772Crc (
     32   IN UINT8 * pMacAddress
     33   )
     34 {
     35   UINT32 BitNumber;
     36   INT32 Carry;
     37   INT32 Crc;
     38   UINT32 Data;
     39   UINT8 * pEnd;
     40 
     41   //
     42   //  Walk the MAC address
     43   //
     44   Crc = -1;
     45   pEnd = &pMacAddress[ PXE_HWADDR_LEN_ETHER ];
     46   while ( pEnd > pMacAddress ) {
     47     Data = *pMacAddress++;
     48     //
     49     //  CRC32: x32 + x26 + x23 + x22 + x16 + x12 + x11 + x10 + x8 + x7 + x5 + x4 + x2 + x + 1
     50     //
     51     //          1 0000 0100 1100 0001 0001 1101 1011 0111
     52     //
     53     for ( BitNumber = 0; 8 > BitNumber; BitNumber++ ) {
     54       Carry = (( Crc >> 31 ) & 1 ) ^ ( Data & 1 );
     55       Crc <<= 1;
     56       if ( 0 != Carry ) {
     57         Crc ^= 0x04c11db7;
     58       }
     59       Data >>= 1;
     60     }
     61   }
     62   //
     63   //  Return the CRC value
     64   //
     65   return (UINT32) Crc;
     66 }
     67 
     68 
     69 /**
     70   Get the MAC address
     71 
     72   This routine calls ::Ax88772UsbCommand to request the MAC
     73   address from the network adapter.
     74 
     75   @param [in] pNicDevice       Pointer to the NIC_DEVICE structure
     76   @param [out] pMacAddress      Address of a six byte buffer to receive the MAC address.
     77 
     78   @retval EFI_SUCCESS          The MAC address is available.
     79   @retval other                The MAC address is not valid.
     80 
     81 **/
     82 EFI_STATUS
     83 Ax88772MacAddressGet (
     84   IN NIC_DEVICE * pNicDevice,
     85   OUT UINT8 * pMacAddress
     86   )
     87 {
     88   USB_DEVICE_REQUEST SetupMsg;
     89   EFI_STATUS Status;
     90 
     91   //
     92   //  Set the register address.
     93   //
     94   SetupMsg.RequestType = USB_ENDPOINT_DIR_IN
     95                        | USB_REQ_TYPE_VENDOR
     96                        | USB_TARGET_DEVICE;
     97   SetupMsg.Request = CMD_MAC_ADDRESS_READ;
     98   SetupMsg.Value = 0;
     99   SetupMsg.Index = 0;
    100   SetupMsg.Length = PXE_HWADDR_LEN_ETHER;
    101 
    102   //
    103   //  Read the PHY register
    104   //
    105   Status = Ax88772UsbCommand ( pNicDevice,
    106                                &SetupMsg,
    107                                pMacAddress );
    108   return Status;
    109 }
    110 
    111 
    112 /**
    113   Set the MAC address
    114 
    115   This routine calls ::Ax88772UsbCommand to set the MAC address
    116   in the network adapter.
    117 
    118   @param [in] pNicDevice       Pointer to the NIC_DEVICE structure
    119   @param [in] pMacAddress      Address of a six byte buffer to containing the new MAC address.
    120 
    121   @retval EFI_SUCCESS          The MAC address was set.
    122   @retval other                The MAC address was not set.
    123 
    124 **/
    125 EFI_STATUS
    126 Ax88772MacAddressSet (
    127   IN NIC_DEVICE * pNicDevice,
    128   IN UINT8 * pMacAddress
    129   )
    130 {
    131   USB_DEVICE_REQUEST SetupMsg;
    132   EFI_STATUS Status;
    133 
    134   //
    135   //  Set the register address.
    136   //
    137   SetupMsg.RequestType = USB_REQ_TYPE_VENDOR
    138                        | USB_TARGET_DEVICE;
    139   SetupMsg.Request = CMD_MAC_ADDRESS_WRITE;
    140   SetupMsg.Value = 0;
    141   SetupMsg.Index = 0;
    142   SetupMsg.Length = PXE_HWADDR_LEN_ETHER;
    143 
    144   //
    145   //  Read the PHY register
    146   //
    147   Status = Ax88772UsbCommand ( pNicDevice,
    148                                &SetupMsg,
    149                                pMacAddress );
    150   return Status;
    151 }
    152 
    153 /**
    154   Clear the multicast hash table
    155 
    156   @param [in] pNicDevice       Pointer to the NIC_DEVICE structure
    157 
    158 **/
    159 VOID
    160 Ax88772MulticastClear (
    161   IN NIC_DEVICE * pNicDevice
    162   )
    163 {
    164   int i = 0;
    165   //
    166   // Clear the multicast hash table
    167   //
    168   for ( i = 0 ; i < 8 ; i ++ )
    169      pNicDevice->MulticastHash[0] = 0;
    170 }
    171 
    172 /**
    173   Enable a multicast address in the multicast hash table
    174 
    175   This routine calls ::Ax88772Crc to compute the hash bit for
    176   this MAC address.
    177 
    178   @param [in] pNicDevice       Pointer to the NIC_DEVICE structure
    179   @param [in] pMacAddress      Address of a six byte buffer to containing the MAC address.
    180 
    181 **/
    182 VOID
    183 Ax88772MulticastSet (
    184   IN NIC_DEVICE * pNicDevice,
    185   IN UINT8 * pMacAddress
    186   )
    187 {
    188   UINT32 Crc;
    189 
    190   //
    191   //  Compute the CRC on the destination address
    192   //
    193   Crc = Ax88772Crc ( pMacAddress ) >> 26;
    194 
    195   //
    196   //  Set the bit corresponding to the destination address
    197   //
    198    pNicDevice->MulticastHash [ Crc >> 3 ] |= ( 1<< (Crc& 7));
    199 }
    200 
    201 /**
    202   Start the link negotiation
    203 
    204   This routine calls ::Ax88772PhyWrite to start the PHY's link
    205   negotiation.
    206 
    207   @param [in] pNicDevice       Pointer to the NIC_DEVICE structure
    208 
    209   @retval EFI_SUCCESS          The link negotiation was started.
    210   @retval other                Failed to start the link negotiation.
    211 
    212 **/
    213 EFI_STATUS
    214 Ax88772NegotiateLinkStart (
    215   IN NIC_DEVICE * pNicDevice
    216   )
    217 {
    218   UINT16 Control;
    219   EFI_STATUS Status;
    220   int i;
    221   //
    222   // Set the supported capabilities.
    223   //
    224   Status = Ax88772PhyWrite ( pNicDevice,
    225                              PHY_ANAR,
    226                              AN_CSMA_CD
    227                              | AN_TX_FDX | AN_TX_HDX
    228                              | AN_10_FDX | AN_10_HDX );
    229   if ( !EFI_ERROR ( Status )) {
    230     //
    231     // Set the link speed and duplex
    232     //
    233     Control = BMCR_AUTONEGOTIATION_ENABLE
    234             | BMCR_RESTART_AUTONEGOTIATION;
    235     if ( pNicDevice->b100Mbps ) {
    236       Control |= BMCR_100MBPS;
    237     }
    238     if ( pNicDevice->bFullDuplex ) {
    239       Control |= BMCR_FULL_DUPLEX;
    240     }
    241     Status = Ax88772PhyWrite ( pNicDevice, PHY_BMCR, Control );
    242   }
    243 
    244   if (!EFI_ERROR(Status)) {
    245     i = 0;
    246     do {
    247 
    248         if (pNicDevice->bComplete && pNicDevice->bLinkUp) {
    249             pNicDevice->SimpleNetwork.Mode->MediaPresent
    250                = pNicDevice->bLinkUp & pNicDevice->bComplete;
    251            break;
    252        }
    253        else {
    254             gBS->Stall(AUTONEG_DELAY);
    255             Status = Ax88772NegotiateLinkComplete ( pNicDevice,
    256                                             &pNicDevice->PollCount,
    257                                             &pNicDevice->bComplete,
    258                                             &pNicDevice->bLinkUp,
    259                                             &pNicDevice->b100Mbps,
    260                                             &pNicDevice->bFullDuplex );
    261             i++;
    262         }
    263     }while(!pNicDevice->bLinkUp && i < AUTONEG_POLLCNT);
    264   }
    265   return Status;
    266 }
    267 
    268 
    269 /**
    270   Complete the negotiation of the PHY link
    271 
    272   This routine calls ::Ax88772PhyRead to determine if the
    273   link negotiation is complete.
    274 
    275   @param [in] pNicDevice       Pointer to the NIC_DEVICE structure
    276   @param [in, out] pPollCount  Address of number of times this routine was polled
    277   @param [out] pbComplete      Address of boolean to receive complate status.
    278   @param [out] pbLinkUp        Address of boolean to receive link status, TRUE=up.
    279   @param [out] pbHiSpeed       Address of boolean to receive link speed, TRUE=100Mbps.
    280   @param [out] pbFullDuplex    Address of boolean to receive link duplex, TRUE=full.
    281 
    282   @retval EFI_SUCCESS          The MAC address is available.
    283   @retval other                The MAC address is not valid.
    284 
    285 **/
    286 EFI_STATUS
    287 Ax88772NegotiateLinkComplete (
    288   IN NIC_DEVICE * pNicDevice,
    289   IN OUT UINTN * pPollCount,
    290   OUT BOOLEAN * pbComplete,
    291   OUT BOOLEAN * pbLinkUp,
    292   OUT BOOLEAN * pbHiSpeed,
    293   OUT BOOLEAN * pbFullDuplex
    294   )
    295 {
    296   UINT16 Mask;
    297   UINT16 PhyData;
    298   EFI_STATUS  Status;
    299 
    300   //
    301   //  Determine if the link is up.
    302   //
    303   *pbComplete = FALSE;
    304 
    305   //
    306   //  Get the link status
    307   //
    308   Status = Ax88772PhyRead ( pNicDevice,
    309                             PHY_BMSR,
    310                             &PhyData );
    311 
    312   if ( !EFI_ERROR ( Status )) {
    313       *pbLinkUp = (BOOLEAN)( 0 != ( PhyData & BMSR_LINKST ));
    314       if ( 0 == *pbLinkUp ) {
    315         DEBUG (( EFI_D_INFO, "Link Down\n" ));
    316       }
    317       else {
    318          *pbComplete = (BOOLEAN)( 0 != ( PhyData & 0x20 ));
    319          if ( 0 == *pbComplete ) {
    320               DEBUG (( EFI_D_INFO, "Autoneg is not yet Complete\n" ));
    321         }
    322         else {
    323           Status = Ax88772PhyRead ( pNicDevice,
    324                                 PHY_ANLPAR,
    325                                 &PhyData );
    326           if ( !EFI_ERROR ( Status )) {
    327             //
    328             //  Autonegotiation is complete
    329             //  Determine the link speed.
    330             //
    331             *pbHiSpeed = (BOOLEAN)( 0 != ( PhyData & ( AN_TX_FDX | AN_TX_HDX )));
    332 
    333             //
    334             //  Determine the link duplex.
    335             //
    336             Mask = ( *pbHiSpeed ) ? AN_TX_FDX : AN_10_FDX;
    337             *pbFullDuplex = (BOOLEAN)( 0 != ( PhyData & Mask ));
    338           }
    339         }
    340       }
    341   }
    342   else {
    343       DEBUG (( EFI_D_ERROR, "Failed to read BMCR\n" ));
    344   }
    345   return Status;
    346 }
    347 
    348 
    349 /**
    350   Read a register from the PHY
    351 
    352   This routine calls ::Ax88772UsbCommand to read a PHY register.
    353 
    354   @param [in] pNicDevice       Pointer to the NIC_DEVICE structure
    355   @param [in] RegisterAddress  Number of the register to read.
    356   @param [in, out] pPhyData    Address of a buffer to receive the PHY register value
    357 
    358   @retval EFI_SUCCESS          The PHY data is available.
    359   @retval other                The PHY data is not valid.
    360 
    361 **/
    362 EFI_STATUS
    363 Ax88772PhyRead (
    364   IN NIC_DEVICE * pNicDevice,
    365   IN UINT8 RegisterAddress,
    366   IN OUT UINT16 * pPhyData
    367   )
    368 {
    369   USB_DEVICE_REQUEST SetupMsg;
    370   EFI_STATUS Status;
    371 
    372   //
    373   //  Request access to the PHY
    374   //
    375   SetupMsg.RequestType = USB_REQ_TYPE_VENDOR
    376                        | USB_TARGET_DEVICE;
    377   SetupMsg.Request = CMD_PHY_ACCESS_SOFTWARE;
    378   SetupMsg.Value = 0;
    379   SetupMsg.Index = 0;
    380   SetupMsg.Length = 0;
    381   Status = Ax88772UsbCommand ( pNicDevice,
    382                                &SetupMsg,
    383                                NULL );
    384   if ( !EFI_ERROR ( Status )) {
    385     //
    386     //  Read the PHY register address.
    387     //
    388     SetupMsg.RequestType = USB_ENDPOINT_DIR_IN
    389                          | USB_REQ_TYPE_VENDOR
    390                          | USB_TARGET_DEVICE;
    391     SetupMsg.Request = CMD_PHY_REG_READ;
    392     SetupMsg.Value = pNicDevice->PhyId;
    393     SetupMsg.Index = RegisterAddress;
    394     SetupMsg.Length = sizeof ( *pPhyData );
    395     Status = Ax88772UsbCommand ( pNicDevice,
    396                                  &SetupMsg,
    397                                  pPhyData );
    398     if ( !EFI_ERROR ( Status )) {
    399 
    400       //
    401       //  Release the PHY to the hardware
    402       //
    403       SetupMsg.RequestType = USB_REQ_TYPE_VENDOR
    404                            | USB_TARGET_DEVICE;
    405       SetupMsg.Request = CMD_PHY_ACCESS_HARDWARE;
    406       SetupMsg.Value = 0;
    407       SetupMsg.Index = 0;
    408       SetupMsg.Length = 0;
    409       Status = Ax88772UsbCommand ( pNicDevice,
    410                                    &SetupMsg,
    411                                    NULL );
    412     }
    413   }
    414   return Status;
    415 }
    416 
    417 
    418 /**
    419   Write to a PHY register
    420 
    421   This routine calls ::Ax88772UsbCommand to write a PHY register.
    422 
    423   @param [in] pNicDevice       Pointer to the NIC_DEVICE structure
    424   @param [in] RegisterAddress  Number of the register to read.
    425   @param [in] PhyData          Address of a buffer to receive the PHY register value
    426 
    427   @retval EFI_SUCCESS          The PHY data was written.
    428   @retval other                Failed to wwrite the PHY register.
    429 
    430 **/
    431 EFI_STATUS
    432 Ax88772PhyWrite (
    433   IN NIC_DEVICE * pNicDevice,
    434   IN UINT8 RegisterAddress,
    435   IN UINT16 PhyData
    436   )
    437 {
    438   USB_DEVICE_REQUEST SetupMsg;
    439   EFI_STATUS Status;
    440 
    441   //
    442   //  Request access to the PHY
    443   //
    444   SetupMsg.RequestType = USB_REQ_TYPE_VENDOR
    445                        | USB_TARGET_DEVICE;
    446   SetupMsg.Request = CMD_PHY_ACCESS_SOFTWARE;
    447   SetupMsg.Value = 0;
    448   SetupMsg.Index = 0;
    449   SetupMsg.Length = 0;
    450   Status = Ax88772UsbCommand ( pNicDevice,
    451                                &SetupMsg,
    452                                NULL );
    453   if ( !EFI_ERROR ( Status )) {
    454     //
    455     //  Write the PHY register
    456     //
    457     SetupMsg.RequestType = USB_REQ_TYPE_VENDOR
    458                          | USB_TARGET_DEVICE;
    459     SetupMsg.Request = CMD_PHY_REG_WRITE;
    460     SetupMsg.Value = pNicDevice->PhyId;
    461     SetupMsg.Index = RegisterAddress;
    462     SetupMsg.Length = sizeof ( PhyData );
    463     Status = Ax88772UsbCommand ( pNicDevice,
    464                                  &SetupMsg,
    465                                  &PhyData );
    466     if ( !EFI_ERROR ( Status )) {
    467 
    468       //
    469       //  Release the PHY to the hardware
    470       //
    471       SetupMsg.RequestType = USB_REQ_TYPE_VENDOR
    472                            | USB_TARGET_DEVICE;
    473       SetupMsg.Request = CMD_PHY_ACCESS_HARDWARE;
    474       SetupMsg.Value = 0;
    475       SetupMsg.Index = 0;
    476       SetupMsg.Length = 0;
    477       Status = Ax88772UsbCommand ( pNicDevice,
    478                                    &SetupMsg,
    479                                    NULL );
    480     }
    481   }
    482 
    483   return Status;
    484 }
    485 
    486 
    487 /**
    488   Reset the AX88772
    489 
    490   This routine uses ::Ax88772UsbCommand to reset the network
    491   adapter.  This routine also uses ::Ax88772PhyWrite to reset
    492   the PHY.
    493 
    494   @param [in] pNicDevice       Pointer to the NIC_DEVICE structure
    495 
    496   @retval EFI_SUCCESS          The MAC address is available.
    497   @retval other                The MAC address is not valid.
    498 
    499 **/
    500 EFI_STATUS
    501 Ax88772Reset (
    502   IN NIC_DEVICE * pNicDevice
    503   )
    504 {
    505   USB_DEVICE_REQUEST SetupMsg;
    506   EFI_STATUS Status;
    507 
    508   EFI_USB_IO_PROTOCOL *pUsbIo;
    509   EFI_USB_DEVICE_DESCRIPTOR Device;
    510 
    511   pUsbIo = pNicDevice->pUsbIo;
    512   Status = pUsbIo->UsbGetDeviceDescriptor ( pUsbIo, &Device );
    513 
    514 	if (EFI_ERROR(Status)) goto err;
    515 
    516   SetupMsg.RequestType = USB_REQ_TYPE_VENDOR
    517                            | USB_TARGET_DEVICE;
    518   SetupMsg.Request = CMD_PHY_ACCESS_HARDWARE;
    519   SetupMsg.Value = 0;
    520   SetupMsg.Index = 0;
    521   SetupMsg.Length = 0;
    522   Status = Ax88772UsbCommand ( pNicDevice,
    523                                 &SetupMsg,
    524                                 NULL );
    525 
    526   if (EFI_ERROR(Status)) goto err;
    527 
    528   SetupMsg.RequestType = USB_REQ_TYPE_VENDOR
    529                           | USB_TARGET_DEVICE;
    530       SetupMsg.Request = CMD_PHY_SELECT;
    531       SetupMsg.Value = SPHY_PSEL;
    532       SetupMsg.Index = 0;
    533       SetupMsg.Length = 0;
    534       Status = Ax88772UsbCommand ( pNicDevice,
    535                                     &SetupMsg,
    536                                     NULL );
    537 
    538   if (EFI_ERROR(Status)) goto err;
    539 
    540   SetupMsg.RequestType = USB_REQ_TYPE_VENDOR
    541                           | USB_TARGET_DEVICE;
    542   SetupMsg.Request = CMD_RESET;
    543       SetupMsg.Value = SRR_IPRL ;
    544       SetupMsg.Index = 0;
    545       SetupMsg.Length = 0;
    546       Status = Ax88772UsbCommand ( pNicDevice,
    547                                    &SetupMsg,
    548                                    NULL );
    549 
    550   if (EFI_ERROR(Status)) goto err;
    551 
    552   SetupMsg.RequestType = USB_REQ_TYPE_VENDOR
    553                           | USB_TARGET_DEVICE;
    554   SetupMsg.Request = CMD_RESET;
    555         SetupMsg.Value = SRR_IPPD | SRR_IPRL ;
    556         SetupMsg.Index = 0;
    557         SetupMsg.Length = 0;
    558         Status = Ax88772UsbCommand ( pNicDevice,
    559                                     &SetupMsg,
    560                                     NULL );
    561 
    562   gBS->Stall ( 200000 );
    563 
    564   if (EFI_ERROR(Status)) goto err;
    565 
    566   SetupMsg.RequestType = USB_REQ_TYPE_VENDOR
    567                           | USB_TARGET_DEVICE;
    568   SetupMsg.Request = CMD_RESET;
    569   SetupMsg.Value =  SRR_IPRL  ;
    570   SetupMsg.Index = 0;
    571   SetupMsg.Length = 0;
    572   Status = Ax88772UsbCommand ( pNicDevice,
    573                                 &SetupMsg,
    574                                 NULL );
    575 
    576   gBS->Stall ( 200000 );
    577 
    578   if (EFI_ERROR(Status)) goto err;
    579 
    580   SetupMsg.RequestType = USB_REQ_TYPE_VENDOR
    581                           | USB_TARGET_DEVICE;
    582   SetupMsg.Request = CMD_RESET;
    583   SetupMsg.Value = 0;
    584   SetupMsg.Index = 0;
    585   SetupMsg.Length = 0;
    586   Status = Ax88772UsbCommand ( pNicDevice,
    587                                     &SetupMsg,
    588                                     NULL );
    589 
    590   if (EFI_ERROR(Status)) goto err;
    591 
    592   SetupMsg.RequestType = USB_REQ_TYPE_VENDOR
    593                           | USB_TARGET_DEVICE;
    594   SetupMsg.Request = CMD_PHY_SELECT;
    595   SetupMsg.Value = SPHY_PSEL;
    596   SetupMsg.Index = 0;
    597   SetupMsg.Length = 0;
    598   Status = Ax88772UsbCommand ( pNicDevice,
    599                                     &SetupMsg,
    600                                     NULL );
    601 
    602   if (EFI_ERROR(Status)) goto err;
    603 
    604   SetupMsg.RequestType = USB_REQ_TYPE_VENDOR
    605                           | USB_TARGET_DEVICE;
    606   SetupMsg.Request = CMD_RESET;
    607   SetupMsg.Value =  SRR_IPRL | SRR_BZ | SRR_BZTYPE;
    608   SetupMsg.Index = 0;
    609   SetupMsg.Length = 0;
    610   Status = Ax88772UsbCommand ( pNicDevice,
    611                                     &SetupMsg,
    612                                     NULL );
    613 
    614   if (EFI_ERROR(Status)) goto err;
    615 
    616   SetupMsg.RequestType = USB_REQ_TYPE_VENDOR
    617                         | USB_TARGET_DEVICE;
    618   SetupMsg.Request = CMD_RX_CONTROL_WRITE;
    619   SetupMsg.Value = 0;
    620   SetupMsg.Index = 0;
    621   SetupMsg.Length = 0;
    622   Status = Ax88772UsbCommand ( pNicDevice,
    623                                   &SetupMsg,
    624                                   NULL );
    625 
    626   if (EFI_ERROR(Status)) goto err;
    627 
    628   if (pNicDevice->Flags != FLAG_TYPE_AX88772) {
    629         SetupMsg.RequestType = USB_REQ_TYPE_VENDOR
    630                         | USB_TARGET_DEVICE;
    631         SetupMsg.Request = CMD_RXQTC;
    632         SetupMsg.Value = 0x8000;
    633         SetupMsg.Index = 0x8001;
    634         SetupMsg.Length = 0;
    635         Status = Ax88772UsbCommand ( pNicDevice,
    636                                   &SetupMsg,
    637                                   NULL );
    638   }
    639 
    640 err:
    641   return Status;
    642 }
    643 
    644 /**
    645   Enable or disable the receiver
    646 
    647   This routine calls ::Ax88772UsbCommand to update the
    648   receiver state.  This routine also calls ::Ax88772MacAddressSet
    649   to establish the MAC address for the network adapter.
    650 
    651   @param [in] pNicDevice       Pointer to the NIC_DEVICE structure
    652   @param [in] RxFilter         Simple network RX filter mask value
    653 
    654   @retval EFI_SUCCESS          The MAC address was set.
    655   @retval other                The MAC address was not set.
    656 
    657 **/
    658 EFI_STATUS
    659 Ax88772RxControl (
    660   IN NIC_DEVICE * pNicDevice,
    661   IN UINT32 RxFilter
    662   )
    663 {
    664   UINT16 MediumStatus;
    665   UINT16 RxControl;
    666   USB_DEVICE_REQUEST SetupMsg;
    667   EFI_STATUS Status;
    668   EFI_USB_IO_PROTOCOL *pUsbIo;
    669   EFI_USB_DEVICE_DESCRIPTOR Device;
    670 
    671   pUsbIo = pNicDevice->pUsbIo;
    672   Status = pUsbIo->UsbGetDeviceDescriptor ( pUsbIo, &Device );
    673 
    674   if (EFI_ERROR(Status)) {
    675     DEBUG (( EFI_D_ERROR, "Failed to get device descriptor\n" ));
    676     return Status;
    677   }
    678 
    679   //
    680   // Enable the receiver if something is to be received
    681   //
    682 
    683   if ( 0 != RxFilter ) {
    684     //
    685     //  Enable the receiver
    686     //
    687     SetupMsg.RequestType = USB_ENDPOINT_DIR_IN
    688                          | USB_REQ_TYPE_VENDOR
    689                          | USB_TARGET_DEVICE;
    690     SetupMsg.Request = CMD_MEDIUM_STATUS_READ;
    691     SetupMsg.Value = 0;
    692     SetupMsg.Index = 0;
    693     SetupMsg.Length = sizeof ( MediumStatus );
    694     Status = Ax88772UsbCommand ( pNicDevice,
    695                                  &SetupMsg,
    696                                  &MediumStatus );
    697     if ( !EFI_ERROR ( Status )) {
    698       if ( 0 == ( MediumStatus & MS_RE )) {
    699         MediumStatus |= MS_RE | MS_ONE;
    700 
    701         if ( pNicDevice->bFullDuplex )
    702           MediumStatus |= MS_TFC | MS_RFC | MS_FD;
    703         else
    704           MediumStatus &= ~(MS_TFC | MS_RFC | MS_FD);
    705 
    706         if ( pNicDevice->b100Mbps )
    707           MediumStatus |= MS_PS;
    708         else
    709           MediumStatus &= ~MS_PS;
    710 
    711         SetupMsg.RequestType = USB_REQ_TYPE_VENDOR
    712                              | USB_TARGET_DEVICE;
    713         SetupMsg.Request = CMD_MEDIUM_STATUS_WRITE;
    714         SetupMsg.Value = MediumStatus;
    715         SetupMsg.Index = 0;
    716         SetupMsg.Length = 0;
    717         Status = Ax88772UsbCommand ( pNicDevice,
    718                                      &SetupMsg,
    719                                      NULL );
    720         if ( EFI_ERROR ( Status )) {
    721             DEBUG (( EFI_D_ERROR, "Failed to enable receiver, Status: %r\r\n",
    722               Status ));
    723         }
    724       }
    725     }
    726     else {
    727         DEBUG (( EFI_D_ERROR, "Failed to read receiver status, Status: %r\r\n",
    728               Status ));
    729     }
    730   }
    731 
    732   RxControl = RXC_SO | RXC_RH1M;
    733   //
    734   //  Enable multicast if requested
    735   //
    736   if ( 0 != ( RxFilter & EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST )) {
    737       RxControl |= RXC_AM;
    738       //
    739       //  Update the multicast hash table
    740       //
    741       SetupMsg.RequestType = USB_REQ_TYPE_VENDOR
    742                            | USB_TARGET_DEVICE;
    743       SetupMsg.Request = CMD_MULTICAST_HASH_WRITE;
    744       SetupMsg.Value = 0;
    745       SetupMsg.Index = 0;
    746       SetupMsg.Length = sizeof ( pNicDevice ->MulticastHash );
    747       Status = Ax88772UsbCommand ( pNicDevice,
    748                                    &SetupMsg,
    749                                    &pNicDevice->MulticastHash );
    750   }
    751   //
    752   //  Enable all multicast if requested
    753   //
    754   if ( 0 != ( RxFilter & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST )) {
    755       RxControl |= RXC_AMALL;
    756   }
    757 
    758   //
    759   //  Enable broadcast if requested
    760   //
    761   if ( 0 != ( RxFilter & EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST )) {
    762       RxControl |= RXC_AB;
    763   }
    764 
    765   //
    766   //  Enable promiscuous mode if requested
    767   //
    768   if ( 0 != ( RxFilter & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS )) {
    769       RxControl |= RXC_PRO;
    770   }
    771 
    772   //
    773   //  Update the receiver control
    774   //
    775   if (pNicDevice->CurRxControl != RxControl) {
    776     SetupMsg.RequestType = USB_REQ_TYPE_VENDOR
    777                          | USB_TARGET_DEVICE;
    778     SetupMsg.Request = CMD_RX_CONTROL_WRITE;
    779     SetupMsg.Value = RxControl;
    780     SetupMsg.Index = 0;
    781     SetupMsg.Length = 0;
    782     Status = Ax88772UsbCommand ( pNicDevice,
    783                                  &SetupMsg,
    784                                  NULL );
    785     if ( !EFI_ERROR ( Status )) {
    786       pNicDevice->CurRxControl = RxControl;
    787 
    788     }
    789     else {
    790         DEBUG (( EFI_D_ERROR, "ERROR - Failed to set receiver control, Status: %r\r\n",
    791             Status ));
    792     }
    793   }
    794   return Status;
    795 }
    796 
    797 
    798 /**
    799   Read an SROM location
    800 
    801   This routine calls ::Ax88772UsbCommand to read data from the
    802   SROM.
    803 
    804   @param [in] pNicDevice       Pointer to the NIC_DEVICE structure
    805   @param [in] Address          SROM address
    806   @param [out] pData           Buffer to receive the data
    807 
    808   @retval EFI_SUCCESS          The read was successful
    809   @retval other                The read failed
    810 
    811 **/
    812 EFI_STATUS
    813 Ax88772SromRead (
    814   IN NIC_DEVICE * pNicDevice,
    815   IN UINT32 Address,
    816   OUT UINT16 * pData
    817   )
    818 {
    819   return EFI_UNSUPPORTED;
    820 }
    821 
    822 /**
    823   Send a command to the USB device.
    824 
    825   @param [in] pNicDevice       Pointer to the NIC_DEVICE structure
    826   @param [in] pRequest         Pointer to the request structure
    827   @param [in, out] pBuffer     Data buffer address
    828 
    829   @retval EFI_SUCCESS          The USB transfer was successful
    830   @retval other                The USB transfer failed
    831 
    832 **/
    833 EFI_STATUS
    834 Ax88772UsbCommand (
    835   IN NIC_DEVICE * pNicDevice,
    836   IN USB_DEVICE_REQUEST * pRequest,
    837   IN OUT VOID * pBuffer
    838   )
    839 {
    840   UINT32 CmdStatus;
    841   EFI_USB_DATA_DIRECTION Direction;
    842   EFI_USB_IO_PROTOCOL * pUsbIo;
    843   EFI_STATUS Status;
    844 
    845   //
    846   // Determine the transfer direction
    847   //
    848   Direction = EfiUsbNoData;
    849   if ( 0 != pRequest->Length ) {
    850     Direction = ( 0 != ( pRequest->RequestType & USB_ENDPOINT_DIR_IN ))
    851               ? EfiUsbDataIn : EfiUsbDataOut;
    852   }
    853 
    854   //
    855   // Issue the command
    856   //
    857   pUsbIo = pNicDevice->pUsbIo;
    858   Status = pUsbIo->UsbControlTransfer ( pUsbIo,
    859                                         pRequest,
    860                                         Direction,
    861                                         USB_BUS_TIMEOUT,
    862                                         pBuffer,
    863                                         pRequest->Length,
    864                                         &CmdStatus );
    865   //
    866   // Determine the operation status
    867   //
    868   if ( !EFI_ERROR ( Status )) {
    869     Status = CmdStatus;
    870   }
    871   else {
    872     //
    873     // Only use status values associated with the Simple Network protocol
    874     //
    875     if ( EFI_TIMEOUT == Status ) {
    876       Status = EFI_DEVICE_ERROR;
    877     }
    878   }
    879   return Status;
    880 }
    881 
    882