• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
Ax88772Crc(IN UINT8 * pMacAddress)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
Ax88772MacAddressGet(IN NIC_DEVICE * pNicDevice,OUT UINT8 * pMacAddress)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
Ax88772MacAddressSet(IN NIC_DEVICE * pNicDevice,IN UINT8 * pMacAddress)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
Ax88772MulticastClear(IN NIC_DEVICE * pNicDevice)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
Ax88772MulticastSet(IN NIC_DEVICE * pNicDevice,IN UINT8 * pMacAddress)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
Ax88772NegotiateLinkStart(IN NIC_DEVICE * pNicDevice)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
Ax88772NegotiateLinkComplete(IN NIC_DEVICE * pNicDevice,IN OUT UINTN * pPollCount,OUT BOOLEAN * pbComplete,OUT BOOLEAN * pbLinkUp,OUT BOOLEAN * pbHiSpeed,OUT BOOLEAN * pbFullDuplex)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
Ax88772PhyRead(IN NIC_DEVICE * pNicDevice,IN UINT8 RegisterAddress,IN OUT UINT16 * pPhyData)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
Ax88772PhyWrite(IN NIC_DEVICE * pNicDevice,IN UINT8 RegisterAddress,IN UINT16 PhyData)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
Ax88772Reset(IN NIC_DEVICE * pNicDevice)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
Ax88772RxControl(IN NIC_DEVICE * pNicDevice,IN UINT32 RxFilter)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
Ax88772SromRead(IN NIC_DEVICE * pNicDevice,IN UINT32 Address,OUT UINT16 * pData)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
Ax88772UsbCommand(IN NIC_DEVICE * pNicDevice,IN USB_DEVICE_REQUEST * pRequest,IN OUT VOID * pBuffer)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