]> git.proxmox.com Git - mirror_edk2.git/blame - OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772/Ax88772.c
update copyright format
[mirror_edk2.git] / OptionRomPkg / Bus / Usb / UsbNetworking / Ax88772 / Ax88772.c
CommitLineData
8dde1f6e 1/** @file\r
2 Implement the interface to the AX88772 Ethernet controller.\r
3\r
4 This module implements the interface to the ASIX AX88772\r
5 USB to Ethernet MAC with integrated 10/100 PHY. Note that this implementation\r
6 only supports the integrated PHY since no other test cases were available.\r
7\r
bce3e2ab
HT
8 Copyright (c) 2011, Intel Corporation. All rights reserved.<BR>\r
9 This program and the accompanying materials\r
8dde1f6e 10 are licensed and made available under the terms and conditions of the BSD License\r
11 which accompanies this distribution. The full text of the license may be found at\r
12 http://opensource.org/licenses/bsd-license.php\r
13\r
14 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
15 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
16\r
17**/\r
18\r
19#include "Ax88772.h"\r
20\r
21\r
22/**\r
23 Compute the CRC\r
24\r
25 @param [in] pMacAddress Address of a six byte buffer to containing the MAC address.\r
26\r
27 @returns The CRC-32 value associated with this MAC address\r
28\r
29**/\r
30UINT32\r
31Ax88772Crc (\r
32 IN UINT8 * pMacAddress\r
33 )\r
34{\r
35 UINT32 BitNumber;\r
36 INT32 Carry;\r
37 INT32 Crc;\r
38 UINT32 Data;\r
39 UINT8 * pEnd;\r
40\r
41 DBG_ENTER ( );\r
42\r
43 //\r
44 // Walk the MAC address\r
45 //\r
46 Crc = -1;\r
47 pEnd = &pMacAddress[ PXE_HWADDR_LEN_ETHER ];\r
48 while ( pEnd > pMacAddress ) {\r
49 Data = *pMacAddress++;\r
50 \r
51 \r
52 //\r
53 // CRC32: x32 + x26 + x23 + x22 + x16 + x12 + x11 + x10 + x8 + x7 + x5 + x4 + x2 + x + 1\r
54 //\r
55 // 1 0000 0100 1100 0001 0001 1101 1011 0111\r
56 //\r
57 for ( BitNumber = 0; 8 > BitNumber; BitNumber++ ) {\r
58 Carry = (( Crc >> 31 ) & 1 ) ^ ( Data & 1 );\r
59 Crc <<= 1;\r
60 if ( 0 != Carry ) {\r
61 Crc ^= 0x04c11db7;\r
62 }\r
63 Data >>= 1;\r
64 }\r
65 }\r
66\r
67 //\r
68 // Return the CRC value\r
69 //\r
70 DBG_EXIT_HEX ( Crc );\r
71 return (UINT32) Crc;\r
72}\r
73\r
74\r
75/**\r
76 Get the MAC address\r
77\r
78 This routine calls ::Ax88772UsbCommand to request the MAC\r
79 address from the network adapter.\r
80\r
81 @param [in] pNicDevice Pointer to the NIC_DEVICE structure\r
82 @param [out] pMacAddress Address of a six byte buffer to receive the MAC address.\r
83\r
84 @retval EFI_SUCCESS The MAC address is available.\r
85 @retval other The MAC address is not valid.\r
86\r
87**/\r
88EFI_STATUS\r
89Ax88772MacAddressGet (\r
90 IN NIC_DEVICE * pNicDevice,\r
91 OUT UINT8 * pMacAddress\r
92 )\r
93{\r
94 USB_DEVICE_REQUEST SetupMsg;\r
95 EFI_STATUS Status;\r
96 \r
97 DBG_ENTER ( );\r
98 \r
99 //\r
100 // Set the register address.\r
101 //\r
102 SetupMsg.RequestType = USB_ENDPOINT_DIR_IN\r
103 | USB_REQ_TYPE_VENDOR\r
104 | USB_TARGET_DEVICE;\r
105 SetupMsg.Request = CMD_MAC_ADDRESS_READ;\r
106 SetupMsg.Value = 0;\r
107 SetupMsg.Index = 0;\r
108 SetupMsg.Length = PXE_HWADDR_LEN_ETHER;\r
109\r
110 //\r
111 // Read the PHY register\r
112 //\r
113 Status = Ax88772UsbCommand ( pNicDevice,\r
114 &SetupMsg,\r
115 pMacAddress );\r
116\r
117 //\r
118 // Return the operation status\r
119 //\r
120 DBG_EXIT_STATUS ( Status );\r
121 return Status;\r
122}\r
123\r
124\r
125/**\r
126 Set the MAC address\r
127\r
128 This routine calls ::Ax88772UsbCommand to set the MAC address\r
129 in the network adapter.\r
130\r
131 @param [in] pNicDevice Pointer to the NIC_DEVICE structure\r
132 @param [in] pMacAddress Address of a six byte buffer to containing the new MAC address.\r
133\r
134 @retval EFI_SUCCESS The MAC address was set.\r
135 @retval other The MAC address was not set.\r
136\r
137**/\r
138EFI_STATUS\r
139Ax88772MacAddressSet (\r
140 IN NIC_DEVICE * pNicDevice,\r
141 IN UINT8 * pMacAddress\r
142 )\r
143{\r
144 USB_DEVICE_REQUEST SetupMsg;\r
145 EFI_STATUS Status;\r
146 \r
147 DBG_ENTER ( );\r
148 \r
149 //\r
150 // Set the register address.\r
151 //\r
152 SetupMsg.RequestType = USB_REQ_TYPE_VENDOR\r
153 | USB_TARGET_DEVICE;\r
154 SetupMsg.Request = CMD_MAC_ADDRESS_WRITE;\r
155 SetupMsg.Value = 0;\r
156 SetupMsg.Index = 0;\r
157 SetupMsg.Length = PXE_HWADDR_LEN_ETHER;\r
158 \r
159 //\r
160 // Read the PHY register\r
161 //\r
162 Status = Ax88772UsbCommand ( pNicDevice,\r
163 &SetupMsg,\r
164 pMacAddress );\r
165 \r
166 //\r
167 // Return the operation status\r
168 //\r
169 DBG_EXIT_STATUS ( Status );\r
170 return Status;\r
171}\r
172\r
173\r
174/**\r
175 Clear the multicast hash table\r
176\r
177 @param [in] pNicDevice Pointer to the NIC_DEVICE structure\r
178\r
179**/\r
180VOID\r
181Ax88772MulticastClear (\r
182 IN NIC_DEVICE * pNicDevice\r
183 )\r
184{\r
185 DBG_ENTER ( );\r
186\r
187 //\r
188 // Clear the multicast hash table\r
189 //\r
190 pNicDevice->MulticastHash[0] = 0;\r
191 pNicDevice->MulticastHash[1] = 0;\r
192\r
193 DBG_EXIT ( );\r
194}\r
195\r
196\r
197/**\r
198 Enable a multicast address in the multicast hash table\r
199\r
200 This routine calls ::Ax88772Crc to compute the hash bit for\r
201 this MAC address.\r
202\r
203 @param [in] pNicDevice Pointer to the NIC_DEVICE structure\r
204 @param [in] pMacAddress Address of a six byte buffer to containing the MAC address.\r
205\r
206**/\r
207VOID\r
208Ax88772MulticastSet (\r
209 IN NIC_DEVICE * pNicDevice,\r
210 IN UINT8 * pMacAddress\r
211 )\r
212{\r
213 UINT32 BitNumber;\r
214 UINT32 Crc;\r
215 UINT32 Mask;\r
216\r
217 DBG_ENTER ( );\r
218\r
219 //\r
220 // Compute the CRC on the destination address\r
221 //\r
222 Crc = Ax88772Crc ( pMacAddress );\r
223\r
224 //\r
225 // Set the bit corresponding to the destination address\r
226 //\r
227 BitNumber = Crc >> 26;\r
228 if ( 32 > BitNumber ) {\r
229 Mask = 1 << BitNumber;\r
230 pNicDevice->MulticastHash[0] |= Mask;\r
231 }\r
232 else {\r
233 Mask = 1 << ( BitNumber - 32 );\r
234 pNicDevice->MulticastHash[1] |= Mask;\r
235 }\r
236\r
237 //\r
238 // Display the multicast address\r
239 //\r
240 DEBUG (( DEBUG_RX_MULTICAST | DEBUG_INFO,\r
241 "Enable multicast: 0x%02x-%02x-%02x-%02x-%02x-%02x, CRC: 0x%08x, Bit number: 0x%02x\r\n",\r
242 pMacAddress[0],\r
243 pMacAddress[1],\r
244 pMacAddress[2],\r
245 pMacAddress[3],\r
246 pMacAddress[4],\r
247 pMacAddress[5],\r
248 Crc,\r
249 BitNumber ));\r
250\r
251 DBG_EXIT ( );\r
252}\r
253\r
254\r
255/**\r
256 Start the link negotiation\r
257\r
258 This routine calls ::Ax88772PhyWrite to start the PHY's link\r
259 negotiation.\r
260\r
261 @param [in] pNicDevice Pointer to the NIC_DEVICE structure\r
262\r
263 @retval EFI_SUCCESS The link negotiation was started.\r
264 @retval other Failed to start the link negotiation.\r
265\r
266**/\r
267EFI_STATUS\r
268Ax88772NegotiateLinkStart (\r
269 IN NIC_DEVICE * pNicDevice\r
270 )\r
271{\r
272 UINT16 Control;\r
273 EFI_STATUS Status;\r
274\r
275 DBG_ENTER ( );\r
276\r
277 //\r
278 // Set the supported capabilities.\r
279 //\r
280 Status = Ax88772PhyWrite ( pNicDevice,\r
281 PHY_ANAR,\r
282 AN_CSMA_CD\r
283 | AN_TX_FDX | AN_TX_HDX\r
284 | AN_10_FDX | AN_10_HDX );\r
285 if ( !EFI_ERROR ( Status )) {\r
286 //\r
287 // Set the link speed and duplex\r
288 //\r
289 Control = BMCR_AUTONEGOTIATION_ENABLE\r
290 | BMCR_RESTART_AUTONEGOTIATION;\r
291 if ( pNicDevice->b100Mbps ) {\r
292 Control |= BMCR_100MBPS;\r
293 }\r
294 if ( pNicDevice->bFullDuplex ) {\r
295 Control |= BMCR_FULL_DUPLEX;\r
296 }\r
297 Status = Ax88772PhyWrite ( pNicDevice, PHY_BMCR, Control );\r
298 }\r
299\r
300 //\r
301 // Return the operation status\r
302 //\r
303 DBG_EXIT_STATUS ( Status );\r
304 return Status;\r
305}\r
306\r
307\r
308/**\r
309 Complete the negotiation of the PHY link\r
310\r
311 This routine calls ::Ax88772PhyRead to determine if the\r
312 link negotiation is complete.\r
313\r
314 @param [in] pNicDevice Pointer to the NIC_DEVICE structure\r
315 @param [in, out] pPollCount Address of number of times this routine was polled\r
316 @param [out] pbComplete Address of boolean to receive complate status.\r
317 @param [out] pbLinkUp Address of boolean to receive link status, TRUE=up.\r
318 @param [out] pbHiSpeed Address of boolean to receive link speed, TRUE=100Mbps.\r
319 @param [out] pbFullDuplex Address of boolean to receive link duplex, TRUE=full.\r
320\r
321 @retval EFI_SUCCESS The MAC address is available.\r
322 @retval other The MAC address is not valid.\r
323\r
324**/\r
325EFI_STATUS\r
326Ax88772NegotiateLinkComplete (\r
327 IN NIC_DEVICE * pNicDevice,\r
328 IN OUT UINTN * pPollCount,\r
329 OUT BOOLEAN * pbComplete,\r
330 OUT BOOLEAN * pbLinkUp,\r
331 OUT BOOLEAN * pbHiSpeed,\r
332 OUT BOOLEAN * pbFullDuplex\r
333 )\r
334{\r
335 UINT16 Mask;\r
336 UINT16 PhyData;\r
337 EFI_STATUS Status;\r
338\r
339 DBG_ENTER ( );\r
340 \r
341 //\r
342 // Determine if the link is up.\r
343 //\r
344 *pbComplete = FALSE;\r
345\r
346 //\r
347 // Get the link status\r
348 //\r
349 Status = Ax88772PhyRead ( pNicDevice,\r
350 PHY_BMSR,\r
351 &PhyData );\r
352 if ( !EFI_ERROR ( Status )) {\r
353 //\r
354 // Determine if the autonegotiation is complete.\r
355 //\r
356 *pbLinkUp = (BOOLEAN)( 0 != ( PhyData & BMSR_LINKST ));\r
357 *pbComplete = *pbLinkUp;\r
358 if ( 0 != *pbComplete ) {\r
359 //\r
360 // Get the partners capabilities.\r
361 //\r
362 Status = Ax88772PhyRead ( pNicDevice,\r
363 PHY_ANLPAR,\r
364 &PhyData );\r
365 if ( !EFI_ERROR ( Status )) {\r
366 //\r
367 // Autonegotiation is complete\r
368 // Determine the link speed.\r
369 //\r
370 *pbHiSpeed = (BOOLEAN)( 0 != ( PhyData & ( AN_TX_FDX | AN_TX_HDX )));\r
371\r
372 //\r
373 // Determine the link duplex.\r
374 //\r
375 Mask = ( *pbHiSpeed ) ? AN_TX_FDX : AN_10_FDX;\r
376 *pbFullDuplex = (BOOLEAN)( 0 != ( PhyData & Mask ));\r
377 }\r
378 }\r
379 }\r
380\r
381 //\r
382 // Return the operation status\r
383 //\r
384 DBG_EXIT_STATUS ( Status );\r
385 return Status;\r
386}\r
387\r
388\r
389/**\r
390 Read a register from the PHY\r
391\r
392 This routine calls ::Ax88772UsbCommand to read a PHY register.\r
393\r
394 @param [in] pNicDevice Pointer to the NIC_DEVICE structure\r
395 @param [in] RegisterAddress Number of the register to read.\r
396 @param [in, out] pPhyData Address of a buffer to receive the PHY register value\r
397\r
398 @retval EFI_SUCCESS The PHY data is available.\r
399 @retval other The PHY data is not valid.\r
400\r
401**/\r
402EFI_STATUS\r
403Ax88772PhyRead (\r
404 IN NIC_DEVICE * pNicDevice,\r
405 IN UINT8 RegisterAddress,\r
406 IN OUT UINT16 * pPhyData\r
407 )\r
408{\r
409 USB_DEVICE_REQUEST SetupMsg;\r
410 EFI_STATUS Status;\r
411\r
412 DBG_ENTER ( );\r
413\r
414 //\r
415 // Request access to the PHY\r
416 //\r
417 SetupMsg.RequestType = USB_REQ_TYPE_VENDOR\r
418 | USB_TARGET_DEVICE;\r
419 SetupMsg.Request = CMD_PHY_ACCESS_SOFTWARE;\r
420 SetupMsg.Value = 0;\r
421 SetupMsg.Index = 0;\r
422 SetupMsg.Length = 0;\r
423 Status = Ax88772UsbCommand ( pNicDevice,\r
424 &SetupMsg,\r
425 NULL );\r
426 if ( !EFI_ERROR ( Status )) {\r
427 //\r
428 // Read the PHY register address.\r
429 //\r
430 SetupMsg.RequestType = USB_ENDPOINT_DIR_IN\r
431 | USB_REQ_TYPE_VENDOR\r
432 | USB_TARGET_DEVICE;\r
433 SetupMsg.Request = CMD_PHY_REG_READ;\r
434 SetupMsg.Value = pNicDevice->PhyId;\r
435 SetupMsg.Index = RegisterAddress;\r
436 SetupMsg.Length = sizeof ( *pPhyData );\r
437 Status = Ax88772UsbCommand ( pNicDevice,\r
438 &SetupMsg,\r
439 pPhyData );\r
440 if ( !EFI_ERROR ( Status )) {\r
441 DEBUG (( DEBUG_PHY | DEBUG_INFO,\r
442 "PHY %d: 0x%02x --> 0x%04x\r\n",\r
443 pNicDevice->PhyId,\r
444 RegisterAddress,\r
445 *pPhyData ));\r
446\r
447 //\r
448 // Release the PHY to the hardware\r
449 //\r
450 SetupMsg.RequestType = USB_REQ_TYPE_VENDOR\r
451 | USB_TARGET_DEVICE;\r
452 SetupMsg.Request = CMD_PHY_ACCESS_HARDWARE;\r
453 SetupMsg.Value = 0;\r
454 SetupMsg.Index = 0;\r
455 SetupMsg.Length = 0;\r
456 Status = Ax88772UsbCommand ( pNicDevice,\r
457 &SetupMsg,\r
458 NULL );\r
459 }\r
460 }\r
461\r
462 //\r
463 // Return the operation status.\r
464 //\r
465 DBG_EXIT_STATUS ( Status );\r
466 return Status;\r
467}\r
468\r
469\r
470/**\r
471 Write to a PHY register\r
472\r
473 This routine calls ::Ax88772UsbCommand to write a PHY register.\r
474\r
475 @param [in] pNicDevice Pointer to the NIC_DEVICE structure\r
476 @param [in] RegisterAddress Number of the register to read.\r
477 @param [in] PhyData Address of a buffer to receive the PHY register value\r
478\r
479 @retval EFI_SUCCESS The PHY data was written.\r
480 @retval other Failed to wwrite the PHY register.\r
481\r
482**/\r
483EFI_STATUS\r
484Ax88772PhyWrite (\r
485 IN NIC_DEVICE * pNicDevice,\r
486 IN UINT8 RegisterAddress,\r
487 IN UINT16 PhyData\r
488 )\r
489{\r
490 USB_DEVICE_REQUEST SetupMsg;\r
491 EFI_STATUS Status;\r
492 \r
493 DBG_ENTER ( );\r
494 \r
495 //\r
496 // Request access to the PHY\r
497 //\r
498 SetupMsg.RequestType = USB_REQ_TYPE_VENDOR\r
499 | USB_TARGET_DEVICE;\r
500 SetupMsg.Request = CMD_PHY_ACCESS_SOFTWARE;\r
501 SetupMsg.Value = 0;\r
502 SetupMsg.Index = 0;\r
503 SetupMsg.Length = 0;\r
504 Status = Ax88772UsbCommand ( pNicDevice,\r
505 &SetupMsg,\r
506 NULL );\r
507 if ( !EFI_ERROR ( Status )) {\r
508 //\r
509 // Write the PHY register\r
510 //\r
511 SetupMsg.RequestType = USB_REQ_TYPE_VENDOR\r
512 | USB_TARGET_DEVICE;\r
513 SetupMsg.Request = CMD_PHY_REG_WRITE;\r
514 SetupMsg.Value = pNicDevice->PhyId;\r
515 SetupMsg.Index = RegisterAddress;\r
516 SetupMsg.Length = sizeof ( PhyData );\r
517 Status = Ax88772UsbCommand ( pNicDevice,\r
518 &SetupMsg,\r
519 &PhyData );\r
520 if ( !EFI_ERROR ( Status )) {\r
521 DEBUG (( DEBUG_PHY | DEBUG_INFO,\r
522 "PHY %d: 0x%02x <-- 0x%04x\r\n",\r
523 pNicDevice->PhyId,\r
524 RegisterAddress,\r
525 PhyData ));\r
526\r
527 //\r
528 // Release the PHY to the hardware\r
529 //\r
530 SetupMsg.RequestType = USB_REQ_TYPE_VENDOR\r
531 | USB_TARGET_DEVICE;\r
532 SetupMsg.Request = CMD_PHY_ACCESS_HARDWARE;\r
533 SetupMsg.Value = 0;\r
534 SetupMsg.Index = 0;\r
535 SetupMsg.Length = 0;\r
536 Status = Ax88772UsbCommand ( pNicDevice,\r
537 &SetupMsg,\r
538 NULL );\r
539 }\r
540 }\r
541\r
542 //\r
543 // Return the operation status.\r
544 //\r
545 DBG_EXIT_STATUS ( Status );\r
546 return Status;\r
547}\r
548\r
549\r
550/**\r
551 Reset the AX88772\r
552\r
553 This routine uses ::Ax88772UsbCommand to reset the network\r
554 adapter. This routine also uses ::Ax88772PhyWrite to reset\r
555 the PHY.\r
556\r
557 @param [in] pNicDevice Pointer to the NIC_DEVICE structure\r
558\r
559 @retval EFI_SUCCESS The MAC address is available.\r
560 @retval other The MAC address is not valid.\r
561\r
562**/\r
563EFI_STATUS\r
564Ax88772Reset (\r
565 IN NIC_DEVICE * pNicDevice\r
566 )\r
567{\r
568 USB_DEVICE_REQUEST SetupMsg;\r
569 EFI_STATUS Status;\r
570 \r
571 DBG_ENTER ( );\r
572\r
573 //\r
574 // Turn off the MAC\r
575 //\r
576 SetupMsg.RequestType = USB_REQ_TYPE_VENDOR\r
577 | USB_TARGET_DEVICE;\r
578 SetupMsg.Request = CMD_RX_CONTROL_WRITE;\r
579 SetupMsg.Value = 0;\r
580 SetupMsg.Index = 0;\r
581 SetupMsg.Length = 0;\r
582 Status = Ax88772UsbCommand ( pNicDevice,\r
583 &SetupMsg,\r
584 NULL );\r
585 if ( !EFI_ERROR ( Status )) {\r
586 DEBUG (( DEBUG_PHY | DEBUG_RX_BROADCAST | DEBUG_RX_MULTICAST\r
587 | DEBUG_RX_UNICAST | DEBUG_TX | DEBUG_INFO,\r
588 "MAC reset\r\n" ));\r
589\r
590 //\r
591 // The link is now idle\r
592 //\r
593 pNicDevice->bLinkIdle = TRUE;\r
594\r
595 //\r
596 // Delay for a bit\r
597 //\r
598 gBS->Stall ( RESET_MSEC );\r
599\r
600 //\r
601 // Select the internal PHY\r
602 //\r
603 SetupMsg.RequestType = USB_REQ_TYPE_VENDOR\r
604 | USB_TARGET_DEVICE;\r
605 SetupMsg.Request = CMD_PHY_SELECT;\r
606 SetupMsg.Value = SPHY_PSEL;\r
607 SetupMsg.Index = 0;\r
608 SetupMsg.Length = 0;\r
609 Status = Ax88772UsbCommand ( pNicDevice,\r
610 &SetupMsg,\r
611 NULL );\r
612 if ( !EFI_ERROR ( Status )) {\r
613 //\r
614 // Delay for a bit\r
615 //\r
616 gBS->Stall ( PHY_RESET_MSEC );\r
617\r
618 //\r
619 // Clear the internal PHY reset\r
620 //\r
621 SetupMsg.Request = CMD_RESET;\r
622 SetupMsg.Value = SRR_IPRL | SRR_PRL;\r
623 Status = Ax88772UsbCommand ( pNicDevice,\r
624 &SetupMsg,\r
625 NULL );\r
626 if ( !EFI_ERROR ( Status )) {\r
627 //\r
628 // Reset the PHY\r
629 //\r
630 Status = Ax88772PhyWrite ( pNicDevice,\r
631 PHY_BMCR,\r
632 BMCR_RESET );\r
633 if ( !EFI_ERROR ( Status )) {\r
634 //\r
635 // Set the gaps\r
636 //\r
637 SetupMsg.RequestType = USB_REQ_TYPE_VENDOR\r
638 | USB_TARGET_DEVICE;\r
639 SetupMsg.Request = CMD_GAPS_WRITE;\r
640 SetupMsg.Value = 0x0c15;\r
641 SetupMsg.Index = 0x0e;\r
642 SetupMsg.Length = 0;\r
643 Status = Ax88772UsbCommand ( pNicDevice,\r
644 &SetupMsg,\r
645 NULL );\r
646 }\r
647 }\r
648 }\r
649 }\r
650\r
651 //\r
652 // Return the operation status.\r
653 //\r
654 DBG_EXIT_STATUS ( Status );\r
655 return Status;\r
656}\r
657\r
658\r
659/**\r
660 Receive a frame from the network.\r
661\r
662 This routine polls the USB receive interface for a packet. If a packet\r
663 is available, this routine adds the receive packet to the list of\r
664 pending receive packets.\r
665\r
666 This routine calls ::Ax88772NegotiateLinkComplete to verify\r
667 that the link is up. This routine also calls ::SN_Reset to\r
668 reset the network adapter when necessary. Finally this\r
669 routine attempts to receive one or more packets from the\r
670 network adapter.\r
671\r
672 @param [in] pNicDevice Pointer to the NIC_DEVICE structure\r
673 @param [in] bUpdateLink TRUE = Update link status\r
674\r
675**/\r
676VOID\r
677Ax88772Rx (\r
678 IN NIC_DEVICE * pNicDevice,\r
679 IN BOOLEAN bUpdateLink\r
680 )\r
681{\r
682 BOOLEAN bFullDuplex;\r
683 BOOLEAN bLinkUp;\r
684 BOOLEAN bRxPacket;\r
685 BOOLEAN bSpeed100;\r
686 UINTN LengthInBytes;\r
687 RX_TX_PACKET Packet;\r
688 RX_TX_PACKET * pRxPacket;\r
689 EFI_USB_IO_PROTOCOL *pUsbIo;\r
690 EFI_STATUS Status;\r
691 EFI_TPL TplPrevious;\r
692 UINT32 TransferStatus;\r
693\r
694 //\r
695 // Synchronize with Ax88772Timer\r
696 //\r
697 VERIFY_TPL ( TPL_AX88772 );\r
698 TplPrevious = gBS->RaiseTPL ( TPL_AX88772 );\r
699 DEBUG (( DEBUG_TPL | DEBUG_INFO,\r
700 "%d: TPL\r\n",\r
701 TPL_AX88772 ));\r
702\r
703 //\r
704 // Get the link status\r
705 //\r
706 if ( bUpdateLink ) {\r
707 bLinkUp = pNicDevice->bLinkUp;\r
708 bSpeed100 = pNicDevice->b100Mbps;\r
709 bFullDuplex = pNicDevice->bFullDuplex;\r
710 Status = Ax88772NegotiateLinkComplete ( pNicDevice,\r
711 &pNicDevice->PollCount,\r
712 &pNicDevice->bComplete,\r
713 &pNicDevice->bLinkUp,\r
714 &pNicDevice->b100Mbps,\r
715 &pNicDevice->bFullDuplex );\r
716\r
717 //\r
718 // Determine if the autonegotiation is complete\r
719 //\r
720 if ( pNicDevice->bComplete ) {\r
721 if ( pNicDevice->bLinkUp ) {\r
722 if (( bSpeed100 && ( !pNicDevice->b100Mbps ))\r
723 || (( !bSpeed100 ) && pNicDevice->b100Mbps )\r
724 || ( bFullDuplex && ( !pNicDevice->bFullDuplex ))\r
725 || (( !bFullDuplex ) && pNicDevice->bFullDuplex )) {\r
726 pNicDevice->PollCount = 0;\r
727 DEBUG (( DEBUG_LINK | DEBUG_INFO,\r
728 "Reset to establish proper link setup: %d Mbps, %s duplex\r\n",\r
729 pNicDevice->b100Mbps ? 100 : 10,\r
730 pNicDevice->bFullDuplex ? L"Full" : L"Half" ));\r
731 Status = SN_Reset ( &pNicDevice->SimpleNetwork, FALSE );\r
732 }\r
733 if (( !bLinkUp ) && pNicDevice->bLinkUp ) {\r
734 //\r
735 // Display the autonegotiation status\r
736 //\r
737 DEBUG (( DEBUG_LINK | DEBUG_INFO,\r
738 "Link: Up, %d Mbps, %s duplex\r\n",\r
739 pNicDevice->b100Mbps ? 100 : 10,\r
740 pNicDevice->bFullDuplex ? L"Full" : L"Half" ));\r
741 }\r
742 }\r
743 }\r
744\r
745 //\r
746 // Update the link status\r
747 //\r
748 if ( bLinkUp && ( !pNicDevice->bLinkUp )) {\r
749 DEBUG (( DEBUG_LINK | DEBUG_INFO, "Link: Down\r\n" ));\r
750 }\r
751 }\r
752\r
753 //\r
754 // Loop until all the packets are emptied from the receiver\r
755 //\r
756 do {\r
757 bRxPacket = FALSE;\r
758\r
759 //\r
760 // Locate a packet for use\r
761 //\r
762 pRxPacket = pNicDevice->pRxFree;\r
763 LengthInBytes = sizeof ( *pRxPacket ) - sizeof ( pRxPacket->pNext );\r
764 if ( NULL == pRxPacket ) {\r
765 Status = gBS->AllocatePool ( EfiRuntimeServicesData,\r
766 LengthInBytes,\r
767 (VOID **) &pRxPacket );\r
768 if ( !EFI_ERROR ( Status )) {\r
769 //\r
770 // Add this packet to the free packet list\r
771 //\r
772 pNicDevice->pRxFree = pRxPacket;\r
773 pRxPacket->pNext = NULL;\r
774 }\r
775 else {\r
776 //\r
777 // Use the discard packet buffer\r
778 //\r
779 pRxPacket = &Packet;\r
780 }\r
781 }\r
782\r
783 //\r
784 // Attempt to receive a packet\r
785 //\r
786 pUsbIo = pNicDevice->pUsbIo;\r
787 Status = pUsbIo->UsbBulkTransfer ( pUsbIo,\r
788 USB_ENDPOINT_DIR_IN | BULK_IN_ENDPOINT,\r
789 &pRxPacket->Length,\r
790 &LengthInBytes,\r
791 2,\r
792 &TransferStatus );\r
793 if (( !EFI_ERROR ( Status ))\r
794 && ( 0 < pRxPacket->Length )\r
795 && ( pRxPacket->Length <= sizeof ( pRxPacket->Data ))) {\r
796\r
797 //\r
798 // Determine if the packet should be received\r
799 //\r
800 bRxPacket = TRUE;\r
801 LengthInBytes = pRxPacket->Length;\r
802 pNicDevice->bLinkIdle = FALSE;\r
803 if ( pNicDevice->pRxFree == pRxPacket ) {\r
804 //\r
805 // Display the received packet\r
806 //\r
807 if ( 0 != ( pRxPacket->Data[0] & 1 )) {\r
808 if (( 0xff == pRxPacket->Data[0])\r
809 && ( 0xff == pRxPacket->Data[1])\r
810 && ( 0xff == pRxPacket->Data[2])\r
811 && ( 0xff == pRxPacket->Data[3])\r
812 && ( 0xff == pRxPacket->Data[4])\r
813 && ( 0xff == pRxPacket->Data[5])) {\r
814 DEBUG (( DEBUG_RX_BROADCAST | DEBUG_INFO,\r
815 "RX: %02x-%02x-%02x-%02x-%02x-%02x %02x-%02x-%02x-%02x-%02x-%02x %02x-%02x %d bytes\r\n",\r
816 pRxPacket->Data[0],\r
817 pRxPacket->Data[1],\r
818 pRxPacket->Data[2],\r
819 pRxPacket->Data[3],\r
820 pRxPacket->Data[4],\r
821 pRxPacket->Data[5],\r
822 pRxPacket->Data[6],\r
823 pRxPacket->Data[7],\r
824 pRxPacket->Data[8],\r
825 pRxPacket->Data[9],\r
826 pRxPacket->Data[10],\r
827 pRxPacket->Data[11],\r
828 pRxPacket->Data[12],\r
829 pRxPacket->Data[13],\r
830 LengthInBytes ));\r
831 }\r
832 else {\r
833 DEBUG (( DEBUG_RX_MULTICAST | DEBUG_INFO,\r
834 "RX: %02x-%02x-%02x-%02x-%02x-%02x %02x-%02x-%02x-%02x-%02x-%02x %02x-%02x %d bytes\r\n",\r
835 pRxPacket->Data[0],\r
836 pRxPacket->Data[1],\r
837 pRxPacket->Data[2],\r
838 pRxPacket->Data[3],\r
839 pRxPacket->Data[4],\r
840 pRxPacket->Data[5],\r
841 pRxPacket->Data[6],\r
842 pRxPacket->Data[7],\r
843 pRxPacket->Data[8],\r
844 pRxPacket->Data[9],\r
845 pRxPacket->Data[10],\r
846 pRxPacket->Data[11],\r
847 pRxPacket->Data[12],\r
848 pRxPacket->Data[13],\r
849 LengthInBytes ));\r
850 }\r
851 }\r
852 else {\r
853 DEBUG (( DEBUG_RX_UNICAST | DEBUG_INFO,\r
854 "RX: %02x-%02x-%02x-%02x-%02x-%02x %02x-%02x-%02x-%02x-%02x-%02x %02x-%02x %d bytes\r\n",\r
855 pRxPacket->Data[0],\r
856 pRxPacket->Data[1],\r
857 pRxPacket->Data[2],\r
858 pRxPacket->Data[3],\r
859 pRxPacket->Data[4],\r
860 pRxPacket->Data[5],\r
861 pRxPacket->Data[6],\r
862 pRxPacket->Data[7],\r
863 pRxPacket->Data[8],\r
864 pRxPacket->Data[9],\r
865 pRxPacket->Data[10],\r
866 pRxPacket->Data[11],\r
867 pRxPacket->Data[12],\r
868 pRxPacket->Data[13],\r
869 LengthInBytes ));\r
870 }\r
871 \r
872 //\r
873 // Remove this packet from the free packet list\r
874 //\r
875 pNicDevice->pRxFree = pRxPacket->pNext;\r
876 pRxPacket->pNext = NULL;\r
877\r
878 //\r
879 // Append this packet to the receive list\r
880 //\r
881 if ( NULL == pNicDevice->pRxTail ) {\r
882 pNicDevice->pRxHead = pRxPacket;\r
883 }\r
884 else {\r
885 pNicDevice->pRxTail->pNext = pRxPacket;\r
886 }\r
887 pNicDevice->pRxTail = pRxPacket;\r
888 }\r
889 else {\r
890 //\r
891 // Error, not enough buffers for this packet, discard packet\r
892 //\r
893 DEBUG (( DEBUG_WARN | DEBUG_INFO,\r
894 "WARNING - No buffer, discarding RX packet: %02x-%02x-%02x-%02x-%02x-%02x %02x-%02x-%02x-%02x-%02x-%02x %02x-%02x %d bytes\r\n",\r
895 pRxPacket->Data[0],\r
896 pRxPacket->Data[1],\r
897 pRxPacket->Data[2],\r
898 pRxPacket->Data[3],\r
899 pRxPacket->Data[4],\r
900 pRxPacket->Data[5],\r
901 pRxPacket->Data[6],\r
902 pRxPacket->Data[7],\r
903 pRxPacket->Data[8],\r
904 pRxPacket->Data[9],\r
905 pRxPacket->Data[10],\r
906 pRxPacket->Data[11],\r
907 pRxPacket->Data[12],\r
908 pRxPacket->Data[13],\r
909 LengthInBytes ));\r
910 }\r
911 }\r
912 }while ( bRxPacket );\r
913\r
914 //\r
915 // Release the synchronization withhe Ax88772Timer\r
916 //\r
917 gBS->RestoreTPL ( TplPrevious );\r
918 DEBUG (( DEBUG_TPL | DEBUG_INFO,\r
919 "%d: TPL\r\n",\r
920 TplPrevious ));\r
921}\r
922\r
923\r
924/**\r
925 Enable or disable the receiver\r
926\r
927 This routine calls ::Ax88772UsbCommand to update the\r
928 receiver state. This routine also calls ::Ax88772MacAddressSet\r
929 to establish the MAC address for the network adapter.\r
930\r
931 @param [in] pNicDevice Pointer to the NIC_DEVICE structure\r
932 @param [in] RxFilter Simple network RX filter mask value\r
933\r
934 @retval EFI_SUCCESS The MAC address was set.\r
935 @retval other The MAC address was not set.\r
936\r
937**/\r
938EFI_STATUS\r
939Ax88772RxControl (\r
940 IN NIC_DEVICE * pNicDevice,\r
941 IN UINT32 RxFilter\r
942 )\r
943{\r
944 UINT16 MediumStatus;\r
945 INT32 MulticastHash[2];\r
946 UINT16 RxControl;\r
947 USB_DEVICE_REQUEST SetupMsg;\r
948 EFI_STATUS Status;\r
949\r
950 DBG_ENTER ( );\r
951\r
952 //\r
953 // Disable all multicast\r
954 //\r
955 MulticastHash[0] = 0;\r
956 MulticastHash[1] = 0;\r
957\r
958 //\r
959 // Enable the receiver if something is to be received\r
960 //\r
961 Status = EFI_SUCCESS;\r
962 RxControl = RXC_SO | RXC_MFB_16384;\r
963 if ( 0 != RxFilter ) {\r
964 //\r
965 // Enable the receiver\r
966 //\r
967 SetupMsg.RequestType = USB_ENDPOINT_DIR_IN\r
968 | USB_REQ_TYPE_VENDOR\r
969 | USB_TARGET_DEVICE;\r
970 SetupMsg.Request = CMD_MEDIUM_STATUS_READ;\r
971 SetupMsg.Value = 0;\r
972 SetupMsg.Index = 0;\r
973 SetupMsg.Length = sizeof ( MediumStatus );\r
974 Status = Ax88772UsbCommand ( pNicDevice,\r
975 &SetupMsg,\r
976 &MediumStatus );\r
977 if ( !EFI_ERROR ( Status )) {\r
978 if ( 0 == ( MediumStatus & MS_RE )) {\r
979 MediumStatus |= MS_RE | MS_ONE;\r
980 if ( pNicDevice->bFullDuplex ) {\r
981 MediumStatus |= MS_TFC | MS_RFC;\r
982 }\r
983 SetupMsg.RequestType = USB_REQ_TYPE_VENDOR\r
984 | USB_TARGET_DEVICE;\r
985 SetupMsg.Request = CMD_MEDIUM_STATUS_WRITE;\r
986 SetupMsg.Value = MediumStatus;\r
987 SetupMsg.Index = 0;\r
988 SetupMsg.Length = 0;\r
989 Status = Ax88772UsbCommand ( pNicDevice,\r
990 &SetupMsg,\r
991 NULL );\r
992 if ( EFI_ERROR ( Status )) {\r
993 DEBUG (( DEBUG_ERROR | DEBUG_INFO,\r
994 "ERROR - Failed to enable receiver, Status: %r\r\n",\r
995 Status ));\r
996 }\r
997 }\r
998 }\r
999 else {\r
1000 DEBUG (( DEBUG_ERROR | DEBUG_INFO,\r
1001 "ERROR - Failed to read receiver status, Status: %r\r\n",\r
1002 Status ));\r
1003 }\r
1004\r
1005 //\r
1006 // Enable multicast if requested\r
1007 //\r
1008 if ( 0 != ( RxFilter & EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST )) {\r
1009 RxControl |= RXC_AM;\r
1010 MulticastHash[0] = pNicDevice->MulticastHash[0];\r
1011 MulticastHash[1] = pNicDevice->MulticastHash[1];\r
1012 }\r
1013\r
1014 //\r
1015 // Enable all multicast if requested\r
1016 //\r
1017 if ( 0 != ( RxFilter & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST )) {\r
1018 RxControl |= RXC_AMALL;\r
1019 MulticastHash[0] = -1;\r
1020 MulticastHash[1] = -1;\r
1021 }\r
1022\r
1023 //\r
1024 // Enable broadcast if requested\r
1025 //\r
1026 if ( 0 != ( RxFilter & EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST )) {\r
1027 RxControl |= RXC_AB;\r
1028 }\r
1029\r
1030 //\r
1031 // Enable promiscuous mode if requested\r
1032 //\r
1033 if ( 0 != ( RxFilter & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS )) {\r
1034 RxControl |= RXC_PRO;\r
1035 MulticastHash[0] = -1;\r
1036 MulticastHash[1] = -1;\r
1037 }\r
1038 }\r
1039\r
1040 //\r
1041 // Update the MAC address\r
1042 //\r
1043 if ( !EFI_ERROR ( Status )) {\r
1044 Status = Ax88772MacAddressSet ( pNicDevice, &pNicDevice->SimpleNetworkData.CurrentAddress.Addr[0]);\r
1045 }\r
1046\r
1047 //\r
1048 // Update the receiver control\r
1049 //\r
1050 if ( !EFI_ERROR ( Status )) {\r
1051 SetupMsg.RequestType = USB_REQ_TYPE_VENDOR\r
1052 | USB_TARGET_DEVICE;\r
1053 SetupMsg.Request = CMD_RX_CONTROL_WRITE;\r
1054 SetupMsg.Value = RxControl;\r
1055 SetupMsg.Index = 0;\r
1056 SetupMsg.Length = 0;\r
1057 Status = Ax88772UsbCommand ( pNicDevice,\r
1058 &SetupMsg,\r
1059 NULL );\r
1060 if ( !EFI_ERROR ( Status )) {\r
1061 DEBUG (( DEBUG_RX_BROADCAST | DEBUG_RX_MULTICAST | DEBUG_RX_UNICAST | DEBUG_INFO,\r
1062 "RxControl: 0x%04x\r\n",\r
1063 RxControl ));\r
1064\r
1065 //\r
1066 // Update the multicast hash table\r
1067 //\r
1068 SetupMsg.RequestType = USB_REQ_TYPE_VENDOR\r
1069 | USB_TARGET_DEVICE;\r
1070 SetupMsg.Request = CMD_MULTICAST_HASH_WRITE;\r
1071 SetupMsg.Value = 0;\r
1072 SetupMsg.Index = 0;\r
1073 SetupMsg.Length = sizeof ( pNicDevice ->MulticastHash );\r
1074 Status = Ax88772UsbCommand ( pNicDevice,\r
1075 &SetupMsg,\r
1076 &pNicDevice->MulticastHash );\r
1077 if ( !EFI_ERROR ( Status )) {\r
1078 DEBUG (( DEBUG_RX_MULTICAST | DEBUG_INFO,\r
1079 "Multicast Hash: 0x%02x %02x %02x %02x %02x %02x %02x %02x\r\n",\r
1080 (UINT8) MulticastHash[0],\r
1081 (UINT8)( MulticastHash[0] >> 8 ),\r
1082 (UINT8)( MulticastHash[0] >> 16 ),\r
1083 (UINT8)( MulticastHash[0] >> 24 ),\r
1084 (UINT8) MulticastHash[1],\r
1085 (UINT8)( MulticastHash[1] >> 8 ),\r
1086 (UINT8)( MulticastHash[1] >> 16 ),\r
1087 (UINT8)( MulticastHash[1] >> 24 )));\r
1088 }\r
1089 else {\r
1090 DEBUG (( DEBUG_ERROR | DEBUG_INFO,\r
1091 "ERROR - Failed to update multicast hash table, Status: %r\r\n",\r
1092 Status ));\r
1093 }\r
1094 }\r
1095 else {\r
1096 DEBUG (( DEBUG_ERROR | DEBUG_INFO,\r
1097 "ERROR - Failed to set receiver control, Status: %r\r\n",\r
1098 Status ));\r
1099 }\r
1100 }\r
1101\r
1102 //\r
1103 // Return the operation status\r
1104 //\r
1105 DBG_EXIT_STATUS ( Status );\r
1106 return Status;\r
1107}\r
1108\r
1109\r
1110/**\r
1111 Read an SROM location\r
1112\r
1113 This routine calls ::Ax88772UsbCommand to read data from the\r
1114 SROM.\r
1115\r
1116 @param [in] pNicDevice Pointer to the NIC_DEVICE structure\r
1117 @param [in] Address SROM address\r
1118 @param [out] pData Buffer to receive the data\r
1119\r
1120 @retval EFI_SUCCESS The read was successful\r
1121 @retval other The read failed\r
1122\r
1123**/\r
1124EFI_STATUS\r
1125Ax88772SromRead (\r
1126 IN NIC_DEVICE * pNicDevice,\r
1127 IN UINT32 Address,\r
1128 OUT UINT16 * pData\r
1129 )\r
1130{\r
1131 USB_DEVICE_REQUEST SetupMsg;\r
1132 EFI_STATUS Status;\r
1133\r
1134 DBG_ENTER ( );\r
1135\r
1136 //\r
1137 // Read a value from the SROM\r
1138 //\r
1139 SetupMsg.RequestType = USB_ENDPOINT_DIR_IN\r
1140 | USB_REQ_TYPE_VENDOR\r
1141 | USB_TARGET_DEVICE;\r
1142 SetupMsg.Request = CMD_SROM_READ;\r
1143 SetupMsg.Value = (UINT16) Address;\r
1144 SetupMsg.Index = 0;\r
1145 SetupMsg.Length = sizeof ( *pData );\r
1146 Status = Ax88772UsbCommand ( pNicDevice,\r
1147 &SetupMsg,\r
1148 pData );\r
1149\r
1150 //\r
1151 // Return the operation status\r
1152 //\r
1153 DBG_EXIT_STATUS ( Status );\r
1154 return Status;\r
1155}\r
1156\r
1157\r
1158/**\r
1159 This routine is called at a regular interval to poll for\r
1160 receive packets.\r
1161\r
1162 This routine polls the link state and gets any receive packets\r
1163 by calling ::Ax88772Rx.\r
1164\r
1165 @param [in] Event Timer event\r
1166 @param [in] pNicDevice Pointer to the NIC_DEVICE structure\r
1167\r
1168**/\r
1169VOID\r
1170Ax88772Timer (\r
1171 IN EFI_EVENT Event,\r
1172 IN NIC_DEVICE * pNicDevice\r
1173 )\r
1174{\r
1175 //\r
1176 // Use explicit DEBUG messages since the output frequency is too\r
1177 // high for DEBUG_INFO to keep up and have spare cycles for the\r
1178 // shell\r
1179 //\r
1180 DEBUG (( DEBUG_TIMER, "Entering Ax88772Timer\r\n" ));\r
1181\r
1182 //\r
1183 // Poll the link state and get any receive packets\r
1184 //\r
1185 Ax88772Rx ( pNicDevice, FALSE );\r
1186\r
1187 DEBUG (( DEBUG_TIMER, "Exiting Ax88772Timer\r\n" ));\r
1188}\r
1189\r
1190\r
1191/**\r
1192 Send a command to the USB device.\r
1193\r
1194 @param [in] pNicDevice Pointer to the NIC_DEVICE structure\r
1195 @param [in] pRequest Pointer to the request structure\r
1196 @param [in, out] pBuffer Data buffer address\r
1197\r
1198 @retval EFI_SUCCESS The USB transfer was successful\r
1199 @retval other The USB transfer failed\r
1200\r
1201**/\r
1202EFI_STATUS\r
1203Ax88772UsbCommand (\r
1204 IN NIC_DEVICE * pNicDevice,\r
1205 IN USB_DEVICE_REQUEST * pRequest,\r
1206 IN OUT VOID * pBuffer\r
1207 )\r
1208{\r
1209 UINT32 CmdStatus;\r
1210 EFI_USB_DATA_DIRECTION Direction;\r
1211 EFI_USB_IO_PROTOCOL * pUsbIo;\r
1212 EFI_STATUS Status;\r
1213\r
1214 DBG_ENTER ( );\r
1215\r
1216 //\r
1217 // Determine the transfer direction\r
1218 //\r
1219 Direction = EfiUsbNoData;\r
1220 if ( 0 != pRequest->Length ) {\r
1221 Direction = ( 0 != ( pRequest->RequestType & USB_ENDPOINT_DIR_IN ))\r
1222 ? EfiUsbDataIn : EfiUsbDataOut;\r
1223 }\r
1224\r
1225 //\r
1226 // Issue the command\r
1227 //\r
1228 pUsbIo = pNicDevice->pUsbIo;\r
1229 Status = pUsbIo->UsbControlTransfer ( pUsbIo,\r
1230 pRequest,\r
1231 Direction,\r
1232 USB_BUS_TIMEOUT,\r
1233 pBuffer,\r
1234 pRequest->Length,\r
1235 &CmdStatus );\r
1236\r
1237 //\r
1238 // Determine the operation status\r
1239 //\r
1240 if ( !EFI_ERROR ( Status )) {\r
1241 Status = CmdStatus;\r
1242 }\r
1243 else {\r
1244 //\r
1245 // Display any errors\r
1246 //\r
1247 DEBUG (( DEBUG_INFO,\r
1248 "Ax88772UsbCommand - Status: %r\n",\r
1249 Status ));\r
1250\r
1251 //\r
1252 // Only use status values associated with the Simple Network protocol\r
1253 //\r
1254 if ( EFI_TIMEOUT == Status ) {\r
1255 Status = EFI_DEVICE_ERROR;\r
1256 }\r
1257 }\r
1258\r
1259 //\r
1260 // Return the operation status\r
1261 //\r
1262 DBG_EXIT_STATUS ( Status );\r
1263 return Status;\r
1264}\r