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**/
30UINT32
31Ax88772Crc (
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**/
82EFI_STATUS
83Ax88772MacAddressGet (
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**/
125EFI_STATUS
126Ax88772MacAddressSet (
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**/
159VOID
160Ax88772MulticastClear (
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**/
182VOID
183Ax88772MulticastSet (
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**/
213EFI_STATUS
214Ax88772NegotiateLinkStart (
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**/
286EFI_STATUS
287Ax88772NegotiateLinkComplete (
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**/
362EFI_STATUS
363Ax88772PhyRead (
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**/
431EFI_STATUS
432Ax88772PhyWrite (
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**/
500EFI_STATUS
501Ax88772Reset (
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
640err:
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**/
658EFI_STATUS
659Ax88772RxControl (
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**/
812EFI_STATUS
813Ax88772SromRead (
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**/
833EFI_STATUS
834Ax88772UsbCommand (
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