]> git.proxmox.com Git - mirror_edk2.git/blame - EdkModulePkg/Bus/Pci/Uhci/Dxe/uhchlp.c
git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@1459 6f19259b...
[mirror_edk2.git] / EdkModulePkg / Bus / Pci / Uhci / Dxe / uhchlp.c
CommitLineData
878ddf1f 1/*++\r
2\r
3Copyright (c) 2006, Intel Corporation \r
4All rights reserved. This program and the accompanying materials \r
5are licensed and made available under the terms and conditions of the BSD License \r
6which accompanies this distribution. The full text of the license may be found at \r
7http://opensource.org/licenses/bsd-license.php \r
8 \r
9THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
10WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. \r
11\r
12Module Name:\r
13\r
14 UhcHlp.c\r
15 \r
16Abstract: \r
17 \r
18\r
19Revision History\r
20--*/\r
21\r
22#include "uhci.h"\r
23\r
24EFI_STATUS\r
25USBReadPortW (\r
26 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
27 IN UINT32 PortOffset,\r
28 IN OUT UINT16 *Data\r
29 )\r
30/*++\r
31\r
32Routine Description:\r
33\r
34 USBReadPort Word\r
35\r
36Arguments:\r
37\r
38 PciIo - EFI_PCI_IO_PROTOCOL\r
39 PortOffset - Port offset\r
40 Data - Data to reutrn\r
41\r
42Returns:\r
43\r
44 EFI_SUCCESS\r
45\r
46--*/\r
47{\r
48 //\r
49 // Perform 16bit Read in PCI IO Space\r
50 //\r
51 return PciIo->Io.Read (\r
562d2849 52 PciIo,\r
53 EfiPciIoWidthUint16,\r
54 USB_BAR_INDEX,\r
55 (UINT64) PortOffset,\r
56 1,\r
57 Data\r
58 );\r
878ddf1f 59}\r
60\r
61EFI_STATUS\r
62USBReadPortDW (\r
63 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
64 IN UINT32 PortOffset,\r
65 IN OUT UINT32 *Data\r
66 )\r
67/*++\r
68\r
69Routine Description:\r
70\r
71 USBReadPort DWord\r
72\r
73Arguments:\r
74\r
75 PciIo - EFI_PCI_IO_PROTOCOL\r
76 PortOffset - Port offset\r
77 Data - Data to reutrn\r
78\r
79Returns:\r
80\r
81 EFI_SUCCESS\r
82\r
83--*/\r
84{\r
85 //\r
86 // Perform 32bit Read in PCI IO Space\r
87 //\r
88 return PciIo->Io.Read (\r
562d2849 89 PciIo,\r
90 EfiPciIoWidthUint32,\r
91 USB_BAR_INDEX,\r
92 (UINT64) PortOffset,\r
93 1,\r
94 Data\r
95 );\r
878ddf1f 96}\r
97\r
98EFI_STATUS\r
99USBWritePortW (\r
100 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
101 IN UINT32 PortOffset,\r
102 IN UINT16 Data\r
103 )\r
104/*++\r
105\r
106Routine Description:\r
107\r
108 USB Write Port Word\r
109\r
110Arguments:\r
111\r
112 PciIo - EFI_PCI_IO_PROTOCOL\r
113 PortOffset - Port offset\r
114 Data - Data to write\r
115\r
116Returns:\r
117\r
118 EFI_SUCCESS\r
119\r
120--*/\r
121{\r
122 //\r
123 // Perform 16bit Write in PCI IO Space\r
124 //\r
125 return PciIo->Io.Write (\r
562d2849 126 PciIo,\r
127 EfiPciIoWidthUint16,\r
128 USB_BAR_INDEX,\r
129 (UINT64) PortOffset,\r
130 1,\r
131 &Data\r
132 );\r
878ddf1f 133}\r
134\r
135EFI_STATUS\r
136USBWritePortDW (\r
137 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
138 IN UINT32 PortOffset,\r
139 IN UINT32 Data\r
140 )\r
141/*++\r
142\r
143Routine Description:\r
144\r
145 USB Write Port DWord\r
146\r
147Arguments:\r
148\r
149 PciIo - EFI_PCI_IO_PROTOCOL\r
150 PortOffset - Port offset\r
151 Data - Data to write\r
152\r
153Returns:\r
154\r
155 EFI_SUCCESS\r
156\r
157--*/\r
158{\r
159 //\r
160 // Perform 32bit Write in PCI IO Space\r
161 //\r
162 return PciIo->Io.Write (\r
562d2849 163 PciIo,\r
164 EfiPciIoWidthUint32,\r
165 USB_BAR_INDEX,\r
166 (UINT64) PortOffset,\r
167 1,\r
168 &Data\r
169 );\r
878ddf1f 170}\r
171//\r
172// USB register-base helper functions\r
173//\r
174EFI_STATUS\r
175WriteUHCCommandReg (\r
176 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
177 IN UINT32 CmdAddrOffset,\r
178 IN UINT16 UsbCmd\r
179 )\r
180/*++\r
181\r
182Routine Description:\r
183\r
184 Write UHCI Command Register\r
185\r
186Arguments:\r
187\r
188 PciIo - EFI_PCI_IO_PROTOCOL\r
189 CmdAddrOffset - Command address offset\r
190 UsbCmd - Data to write\r
191\r
192Returns:\r
193\r
194 EFI_SUCCESS\r
195\r
196--*/\r
197{\r
198 //\r
199 // Write to UHC's Command Register\r
200 //\r
201 return USBWritePortW (PciIo, CmdAddrOffset, UsbCmd);\r
202}\r
203\r
204EFI_STATUS\r
205ReadUHCCommandReg (\r
206 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
207 IN UINT32 CmdAddrOffset,\r
208 IN OUT UINT16 *Data\r
209 )\r
210/*++\r
211\r
212Routine Description:\r
213\r
214 Read UHCI Command Register\r
215\r
216Arguments:\r
217\r
218 PciIo - EFI_PCI_IO_PROTOCOL\r
219 CmdAddrOffset - Command address offset\r
220 Data - Data to return\r
221\r
222Returns:\r
223\r
224 EFI_SUCCESS\r
225\r
226--*/\r
227{\r
228 //\r
229 // Read from UHC's Command Register\r
230 //\r
231 return USBReadPortW (PciIo, CmdAddrOffset, Data);\r
232}\r
233\r
234EFI_STATUS\r
235WriteUHCStatusReg (\r
236 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
237 IN UINT32 StatusAddrOffset,\r
238 IN UINT16 UsbSts\r
239 )\r
240/*++\r
241\r
242Routine Description:\r
243\r
244 Write UHCI Staus Register\r
245\r
246Arguments:\r
247\r
248 PciIo - EFI_PCI_IO_PROTOCOL\r
249 StatusAddrOffset - Status address offset\r
250 UsbSts - Data to write\r
251\r
252Returns:\r
253\r
254 EFI_SUCCESS\r
255\r
256--*/\r
257{\r
258 //\r
259 // Write to UHC's Status Register\r
260 //\r
261 return USBWritePortW (PciIo, StatusAddrOffset, UsbSts);\r
262}\r
263\r
264EFI_STATUS\r
265ReadUHCStatusReg (\r
266 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
267 IN UINT32 StatusAddrOffset,\r
268 IN OUT UINT16 *Data\r
269 )\r
270/*++\r
271\r
272Routine Description:\r
273\r
274 Read UHCI Staus Register\r
275\r
276Arguments:\r
277\r
278 PciIo - EFI_PCI_IO_PROTOCOL\r
279 StatusAddrOffset - Status address offset\r
280 UsbSts - Data to return\r
281\r
282Returns:\r
283\r
284 EFI_SUCCESS\r
285\r
286--*/\r
287{\r
288 //\r
289 // Read from UHC's Status Register\r
290 //\r
291 return USBReadPortW (PciIo, StatusAddrOffset, Data);\r
292}\r
293\r
294\r
295EFI_STATUS\r
296ClearStatusReg (\r
297 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
298 IN UINT32 StatusAddrOffset\r
299 )\r
300/*++\r
301\r
302Routine Description:\r
303\r
304 Clear the content of UHC's Status Register\r
305\r
306Arguments:\r
307\r
308 PciIo - EFI_PCI_IO_PROTOCOL\r
309 StatusAddrOffset - Status address offset\r
310 \r
311Returns:\r
312\r
313 EFI_SUCCESS\r
314\r
315--*/\r
316{\r
317 \r
318 return WriteUHCStatusReg (PciIo, StatusAddrOffset, 0x003F);\r
319}\r
320\r
321EFI_STATUS\r
322ReadUHCFrameNumberReg (\r
323 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
324 IN UINT32 FrameNumAddrOffset,\r
325 IN OUT UINT16 *Data\r
326 )\r
327/*++\r
328\r
329Routine Description:\r
330\r
331 Read from UHC's Frame Number Register\r
332\r
333Arguments:\r
334\r
335 PciIo - EFI_PCI_IO_PROTOCOL\r
336 FrameNumAddrOffset - Frame number register offset\r
337 Data - Data to return \r
338Returns:\r
339\r
340 EFI_SUCCESS\r
341\r
342--*/\r
343{\r
344 \r
345 return USBReadPortW (PciIo, FrameNumAddrOffset, Data);\r
346}\r
347\r
348EFI_STATUS\r
349WriteUHCFrameListBaseReg (\r
350 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
351 IN UINT32 FlBaseAddrOffset,\r
352 IN UINT32 UsbFrameListBaseAddr\r
353 )\r
354/*++\r
355\r
356Routine Description:\r
357\r
358 Write to UHC's Frame List Base Register\r
359\r
360Arguments:\r
361\r
362 PciIo - EFI_PCI_IO_PROTOCOL\r
363 FlBaseAddrOffset - Frame Base address register\r
364 UsbFrameListBaseAddr - Address to write\r
365\r
366Returns:\r
367\r
368 EFI_SUCCESS\r
369\r
370--*/\r
371{\r
372 \r
373 return USBWritePortDW (PciIo, FlBaseAddrOffset, UsbFrameListBaseAddr);\r
374}\r
375\r
376EFI_STATUS\r
377ReadRootPortReg (\r
378 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
379 IN UINT32 PortAddrOffset,\r
380 IN OUT UINT16 *Data\r
381 )\r
382/*++\r
383\r
384Routine Description:\r
385\r
386 Read from UHC's Root Port Register\r
387\r
388Arguments:\r
389\r
390 PciIo - EFI_PCI_IO_PROTOCOL\r
391 PortAddrOffset - Port Addrress Offset,\r
392 Data - Data to return\r
393Returns:\r
394\r
395 EFI_SUCCESS\r
396\r
397--*/\r
398{\r
399 \r
400 return USBReadPortW (PciIo, PortAddrOffset, Data);\r
401}\r
402\r
403EFI_STATUS\r
404WriteRootPortReg (\r
405 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
406 IN UINT32 PortAddrOffset,\r
407 IN UINT16 ControlBits\r
408 )\r
409/*++\r
410\r
411Routine Description:\r
412\r
413 Write to UHC's Root Port Register\r
414\r
415Arguments:\r
416\r
417 PciIo - EFI_PCI_IO_PROTOCOL\r
418 PortAddrOffset - Port Addrress Offset,\r
419 ControlBits - Data to write\r
420Returns:\r
421\r
422 EFI_SUCCESS\r
423\r
424--*/\r
425{\r
426 \r
427 return USBWritePortW (PciIo, PortAddrOffset, ControlBits);\r
428}\r
429\r
430\r
431\r
432EFI_STATUS\r
433WaitForUHCHalt (\r
434 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
435 IN UINT32 StatusRegAddr,\r
436 IN UINTN Timeout\r
437 )\r
438/*++\r
439\r
440Routine Description:\r
441\r
442 Wait until UHCI halt or timeout\r
443\r
444Arguments:\r
445\r
446 PciIo - EFI_PCI_IO_PROTOCOL\r
447 StatusRegAddr - Status Register Address\r
448 Timeout - Time out value in us\r
449\r
450Returns:\r
451\r
452 EFI_DEVICE_ERROR - Unable to read the status register\r
453 EFI_TIMEOUT - Time out\r
454 EFI_SUCCESS - Success\r
455\r
456--*/\r
457{\r
458 UINTN Delay;\r
459 EFI_STATUS Status;\r
460 UINT16 HcStatus;\r
461\r
462 //\r
463 // Timeout is in us unit\r
464 //\r
465 Delay = (Timeout / 50) + 1;\r
466 do {\r
467 Status = ReadUHCStatusReg (PciIo, StatusRegAddr, &HcStatus);\r
468 if (EFI_ERROR (Status)) {\r
469 return EFI_DEVICE_ERROR;\r
470 }\r
471\r
472 if ((HcStatus & USBSTS_HCH) == USBSTS_HCH) {\r
473 break;\r
474 }\r
475 //\r
476 // Stall for 50 us\r
477 //\r
478 gBS->Stall (50);\r
479\r
480 } while (Delay--);\r
481\r
482 if (Delay == 0) {\r
483 return EFI_TIMEOUT;\r
484 }\r
485\r
486 return EFI_SUCCESS;\r
487}\r
488\r
489BOOLEAN\r
490IsStatusOK (\r
491 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
492 IN UINT32 StatusRegAddr\r
493 )\r
494/*++\r
495\r
496Routine Description:\r
497\r
498 Judge whether the host controller operates well\r
499\r
500Arguments:\r
501\r
502 PciIo - EFI_PCI_IO_PROTOCOL\r
503 StatusRegAddr - Status register address\r
504\r
505Returns:\r
506\r
507 TRUE - Status is good\r
508 FALSE - Status is bad\r
509\r
510--*/\r
511{\r
512 EFI_STATUS Status;\r
513 UINT16 HcStatus;\r
514 //\r
515 // Detect whether the interrupt is caused by fatal error.\r
516 // see "UHCI Design Guid".\r
517 //\r
518 Status = ReadUHCStatusReg (PciIo, StatusRegAddr, &HcStatus);\r
519 if (EFI_ERROR (Status)) {\r
520 return FALSE;\r
521 }\r
522\r
523 if (HcStatus & (USBSTS_HCPE | USBSTS_HSE | USBSTS_HCH)) {\r
524 return FALSE;\r
525 } else {\r
526 return TRUE;\r
527 }\r
528\r
529}\r
530\r
531\r
532BOOLEAN \r
533IsHostSysOrProcessErr (\r
534 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
535 IN UINT32 StatusRegAddr\r
536 )\r
537/*++\r
538\r
539Routine Description:\r
540\r
541 Judge the status is HostSys,ProcessErr error or good\r
542\r
543Arguments:\r
544\r
545 PciIo - EFI_PCI_IO_PROTOCOL\r
546 StatusRegAddr - Status register address\r
547\r
548Returns:\r
549\r
550 TRUE - Status is good\r
551 FALSE - Status is bad\r
552\r
553--*/\r
554{\r
555 EFI_STATUS Status;\r
556 UINT16 HcStatus;\r
557 //\r
558 // Detect whether the interrupt is caused by serious error.\r
559 // see "UHCI Design Guid".\r
560 //\r
561 Status = ReadUHCStatusReg (PciIo, StatusRegAddr, &HcStatus);\r
562 if (EFI_ERROR (Status)) {\r
563 return FALSE;\r
564 }\r
565\r
566 if (HcStatus & (USBSTS_HSE | USBSTS_HCPE)) {\r
567 return TRUE;\r
568 } else {\r
569 return FALSE;\r
570 }\r
571}\r
572\r
573\r
574UINT16\r
575GetCurrentFrameNumber (\r
576 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
577 IN UINT32 FrameNumAddrOffset\r
578 )\r
579/*++\r
580\r
581Routine Description:\r
582\r
583 Get Current Frame Number\r
584\r
585Arguments:\r
586\r
587 PciIo - EFI_PCI_IO_PROTOCOL\r
588 FrameNumAddrOffset - FrameNum register AddrOffset\r
589\r
590Returns:\r
591\r
592 Frame number \r
593\r
594--*/\r
595{\r
596 //\r
597 // Gets value in the USB frame number register.\r
598 //\r
599 UINT16 FrameNumber;\r
600\r
601 ReadUHCFrameNumberReg (PciIo, FrameNumAddrOffset, &FrameNumber);\r
602\r
603 return (UINT16) (FrameNumber & 0x03FF);\r
604}\r
605\r
606EFI_STATUS\r
607SetFrameListBaseAddress (\r
608 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
609 IN UINT32 FlBaseAddrReg,\r
610 IN UINT32 Addr\r
611 )\r
612/*++\r
613\r
614Routine Description:\r
615\r
616 Set FrameListBase Address\r
617\r
618Arguments:\r
619\r
620 PciIo - EFI_PCI_IO_PROTOCOL\r
621 FlBaseAddrReg - FrameListBase register\r
622 Addr - Address to set\r
623\r
624Returns:\r
625\r
626 EFI_SUCCESS\r
627\r
628--*/\r
629{\r
630 //\r
631 // Sets value in the USB Frame List Base Address register.\r
632 //\r
633 return WriteUHCFrameListBaseReg (PciIo, FlBaseAddrReg, (UINT32) (Addr & 0xFFFFF000));\r
634}\r
635\r
636VOID\r
637EnableMaxPacketSize (\r
638 IN USB_HC_DEV *HcDev\r
639 )\r
640/*++\r
641\r
642Routine Description:\r
643\r
644 Enable Max Packet Size\r
645\r
646Arguments:\r
647\r
648 HcDev - USB_HC_DEV\r
649\r
650Returns:\r
651\r
652 VOID\r
653\r
654--*/\r
655{\r
656 UINT16 CommandContent;\r
657 EFI_STATUS Status;\r
658\r
659 Status = ReadUHCCommandReg (\r
562d2849 660 HcDev->PciIo,\r
661 (UINT32) (USBCMD),\r
662 &CommandContent\r
663 );\r
878ddf1f 664\r
665 if ((CommandContent & USBCMD_MAXP) != USBCMD_MAXP) {\r
666 CommandContent |= USBCMD_MAXP;\r
667 WriteUHCCommandReg (\r
668 HcDev->PciIo,\r
669 (UINT32) (USBCMD),\r
670 CommandContent\r
671 );\r
672 }\r
673\r
674 return ;\r
675}\r
676\r
677EFI_STATUS\r
678CreateFrameList (\r
679 IN USB_HC_DEV *HcDev,\r
680 IN UINT32 FlBaseAddrReg\r
681 )\r
682/*++\r
683\r
684Routine Description:\r
685\r
686 CreateFrameList\r
687\r
688Arguments:\r
689\r
690 HcDev - USB_HC_DEV\r
691 FlBaseAddrReg - Frame List register\r
692\r
693Returns:\r
694\r
695 EFI_OUT_OF_RESOURCES - Can't allocate memory resources\r
696 EFI_UNSUPPORTED - Map memory fail\r
697 EFI_SUCCESS - Success\r
698\r
699--*/\r
700{\r
701 EFI_STATUS Status;\r
702 VOID *CommonBuffer;\r
703 EFI_PHYSICAL_ADDRESS MappedAddress;\r
704 VOID *Mapping;\r
705 UINTN BufferSizeInPages;\r
706 UINTN BufferSizeInBytes;\r
707\r
708 //\r
709 // The Frame List is a common buffer that will be\r
710 // accessed by both the cpu and the usb bus master\r
711 // at the same time.\r
712 // The Frame List ocupies 4K bytes,\r
713 // and must be aligned on 4-Kbyte boundaries.\r
714 //\r
715 BufferSizeInBytes = 4096;\r
716 BufferSizeInPages = EFI_SIZE_TO_PAGES (BufferSizeInBytes);\r
717 Status = HcDev->PciIo->AllocateBuffer (\r
562d2849 718 HcDev->PciIo,\r
719 AllocateAnyPages,\r
720 EfiBootServicesData,\r
721 BufferSizeInPages,\r
722 &CommonBuffer,\r
723 0\r
724 );\r
878ddf1f 725 if (EFI_ERROR (Status)) {\r
726 return EFI_OUT_OF_RESOURCES;\r
727 }\r
728\r
729 Status = HcDev->PciIo->Map (\r
562d2849 730 HcDev->PciIo,\r
731 EfiPciIoOperationBusMasterCommonBuffer,\r
732 CommonBuffer,\r
733 &BufferSizeInBytes,\r
734 &MappedAddress,\r
735 &Mapping\r
736 );\r
878ddf1f 737 if (EFI_ERROR (Status) || (BufferSizeInBytes != 4096)) {\r
738 HcDev->PciIo->FreeBuffer (HcDev->PciIo, BufferSizeInPages, CommonBuffer);\r
739 return EFI_UNSUPPORTED;\r
740 }\r
741\r
742 HcDev->FrameListEntry = (FRAMELIST_ENTRY *) ((UINTN) MappedAddress);\r
743\r
744 HcDev->FrameListMapping = Mapping;\r
745\r
746 InitFrameList (HcDev);\r
747\r
748 //\r
749 // Tell the Host Controller where the Frame List lies,\r
750 // by set the Frame List Base Address Register.\r
751 //\r
752 SetFrameListBaseAddress (\r
753 HcDev->PciIo,\r
754 FlBaseAddrReg,\r
755 (UINT32) ((UINTN) HcDev->FrameListEntry)\r
756 );\r
757\r
758 return EFI_SUCCESS;\r
759}\r
760\r
761EFI_STATUS\r
762FreeFrameListEntry (\r
763 IN USB_HC_DEV *HcDev\r
764 )\r
765/*++\r
766\r
767Routine Description:\r
768\r
769 Free FrameList buffer\r
770\r
771Arguments:\r
772\r
773 HcDev - USB_HC_DEV\r
774\r
775Returns:\r
776\r
777 EFI_SUCCESS - success\r
778\r
779--*/\r
780{\r
781 //\r
782 // Unmap the common buffer for framelist entry,\r
783 // and free the common buffer.\r
784 // Uhci's frame list occupy 4k memory.\r
785 //\r
786 HcDev->PciIo->Unmap (HcDev->PciIo, HcDev->FrameListMapping);\r
787 HcDev->PciIo->FreeBuffer (\r
788 HcDev->PciIo,\r
789 EFI_SIZE_TO_PAGES (4096),\r
790 (VOID *) (HcDev->FrameListEntry)\r
791 );\r
792 return EFI_SUCCESS;\r
793}\r
794\r
795VOID\r
796InitFrameList (\r
797 IN USB_HC_DEV *HcDev\r
798 )\r
799/*++\r
800\r
801Routine Description:\r
802\r
803 Initialize FrameList\r
804\r
805Arguments:\r
806\r
807 HcDev - USB_HC_DEV\r
808\r
809Returns:\r
810 VOID\r
811\r
812--*/ \r
813{\r
814 FRAMELIST_ENTRY *FrameListPtr;\r
815 UINTN Index;\r
816\r
817 //\r
818 // Validate each Frame List Entry\r
819 //\r
820 FrameListPtr = HcDev->FrameListEntry;\r
821 for (Index = 0; Index < 1024; Index++) {\r
822 FrameListPtr->FrameListPtrTerminate = 1;\r
823 FrameListPtr->FrameListPtr = 0;\r
824 FrameListPtr->FrameListPtrQSelect = 0;\r
825 FrameListPtr->FrameListRsvd = 0;\r
826 FrameListPtr++;\r
827 }\r
828}\r
829//\r
830// //////////////////////////////////////////////////////////////\r
831//\r
832// QH TD related Helper Functions\r
833//\r
834////////////////////////////////////////////////////////////////\r
835//\r
836// functions for QH\r
837//\r
838EFI_STATUS\r
839AllocateQHStruct (\r
840 IN USB_HC_DEV *HcDev,\r
841 OUT QH_STRUCT **ppQHStruct\r
842 )\r
843/*++\r
844\r
845Routine Description:\r
846\r
847 Allocate QH Struct\r
848\r
849Arguments:\r
850\r
851 HcDev - USB_HC_DEV\r
852 ppQHStruct - QH_STRUCT content to return\r
853Returns:\r
854\r
855 EFI_SUCCESS\r
856\r
857--*/\r
858{\r
859 *ppQHStruct = NULL;\r
860\r
861 //\r
862 // QH must align on 16 bytes alignment,\r
863 // since the memory allocated by UhciAllocatePool ()\r
864 // is aligned on 32 bytes, it is no need to adjust\r
865 // the allocated memory returned.\r
866 //\r
867 return UhciAllocatePool (HcDev, (UINT8 **) ppQHStruct, sizeof (QH_STRUCT));\r
868}\r
869\r
870\r
871EFI_STATUS\r
872CreateQH (\r
873 IN USB_HC_DEV *HcDev,\r
874 OUT QH_STRUCT **pptrQH\r
875 )\r
876/*++\r
877\r
878Routine Description:\r
879\r
880 CreateQH\r
881\r
882Arguments:\r
883\r
884 HcDev - USB_HC_DEV\r
885 ppQHStruct - QH_STRUCT content to return\r
886Returns:\r
887\r
888 EFI_SUCCESS - Success\r
889 EFI_OUT_OF_RESOURCES - Can't allocate memory\r
890--*/\r
891{\r
892 EFI_STATUS Status;\r
893\r
894 //\r
895 // allocate align memory for QH_STRUCT\r
896 //\r
897 Status = AllocateQHStruct (HcDev, pptrQH);\r
898 if (EFI_ERROR (Status)) {\r
899 return EFI_OUT_OF_RESOURCES;\r
900 }\r
901 //\r
902 // init each field of the QH_STRUCT\r
903 //\r
904 //\r
905 // Make QH ready\r
906 //\r
907 SetQHHorizontalValidorInvalid (*pptrQH, FALSE);\r
908 SetQHVerticalValidorInvalid (*pptrQH, FALSE);\r
909\r
910 return EFI_SUCCESS;\r
911}\r
912\r
913VOID\r
914SetQHHorizontalLinkPtr (\r
915 IN QH_STRUCT *PtrQH,\r
916 IN VOID *ptrNext\r
917 )\r
918/*++\r
919\r
920Routine Description:\r
921\r
922 Set QH Horizontal Link Pointer\r
923\r
924Arguments:\r
925\r
926 PtrQH - QH_STRUCT\r
927 ptrNext - Data to write \r
928\r
929Returns:\r
930\r
931 VOID\r
932\r
933--*/\r
934{\r
935 //\r
936 // Since the QH_STRUCT is aligned on 16-byte boundaries,\r
937 // Only the highest 28bit of the address is valid\r
938 // (take 32bit address as an example).\r
939 //\r
940 PtrQH->QH.QHHorizontalPtr = (UINT32) ((UINTN) ptrNext >> 4);\r
941}\r
942\r
943VOID *\r
944GetQHHorizontalLinkPtr (\r
945 IN QH_STRUCT *PtrQH\r
946 )\r
947/*++\r
948\r
949Routine Description:\r
950\r
951 Get QH Horizontal Link Pointer\r
952\r
953Arguments:\r
954\r
955 PtrQH - QH_STRUCT\r
956 \r
957\r
958Returns:\r
959\r
960 Data to return \r
961\r
962--*/\r
963{\r
964 //\r
965 // Restore the 28bit address to 32bit address\r
966 // (take 32bit address as an example)\r
967 //\r
968 return (VOID *) ((UINTN) (PtrQH->QH.QHHorizontalPtr << 4));\r
969}\r
970\r
971VOID\r
972SetQHHorizontalQHorTDSelect (\r
973 IN QH_STRUCT *PtrQH,\r
974 IN BOOLEAN bQH\r
975 )\r
976/*++\r
977\r
978Routine Description:\r
979\r
980 Set QH Horizontal QH or TD \r
981\r
982Arguments:\r
983\r
984 PtrQH - QH_STRUCT\r
985 bQH - TRUE is QH FALSE is TD\r
986\r
987Returns:\r
988 VOID\r
989\r
990--*/\r
991{\r
992 //\r
993 // if QH is connected, the specified bit is set,\r
994 // if TD is connected, the specified bit is cleared.\r
995 //\r
996 PtrQH->QH.QHHorizontalQSelect = bQH ? 1 : 0;\r
997}\r
998\r
999\r
1000VOID\r
1001SetQHHorizontalValidorInvalid (\r
1002 IN QH_STRUCT *PtrQH,\r
1003 IN BOOLEAN bValid\r
1004 )\r
1005/*++\r
1006\r
1007Routine Description:\r
1008\r
1009 Set QH Horizontal Valid or Invalid\r
1010\r
1011Arguments:\r
1012\r
1013 PtrQH - QH_STRUCT\r
1014 bValid - TRUE is Valid FALSE is Invalid\r
1015\r
1016Returns:\r
1017 VOID\r
1018\r
1019--*/\r
1020{\r
1021 //\r
1022 // Valid means the horizontal link pointer is valid,\r
1023 // else, it's invalid.\r
1024 //\r
1025 PtrQH->QH.QHHorizontalTerminate = bValid ? 0 : 1;\r
1026}\r
1027\r
1028VOID\r
1029SetQHVerticalLinkPtr (\r
1030 IN QH_STRUCT *PtrQH,\r
1031 IN VOID *ptrNext\r
1032 )\r
1033/*++\r
1034\r
1035Routine Description:\r
1036\r
1037 Set QH Vertical Link Pointer\r
1038 \r
1039Arguments:\r
1040\r
1041 PtrQH - QH_STRUCT\r
1042 ptrNext - Data to write\r
1043Returns:\r
1044\r
1045 VOID\r
1046\r
1047--*/\r
1048{\r
1049 //\r
1050 // Since the QH_STRUCT is aligned on 16-byte boundaries,\r
1051 // Only the highest 28bit of the address is valid\r
1052 // (take 32bit address as an example).\r
1053 //\r
1054 PtrQH->QH.QHVerticalPtr = (UINT32) ((UINTN) ptrNext >> 4);\r
1055}\r
1056\r
1057VOID *\r
1058GetQHVerticalLinkPtr (\r
1059 IN QH_STRUCT *PtrQH\r
1060 )\r
1061/*++\r
1062\r
1063Routine Description:\r
1064\r
1065 Get QH Vertical Link Pointer\r
1066 \r
1067Arguments:\r
1068\r
1069 PtrQH - QH_STRUCT\r
1070 \r
1071Returns:\r
1072\r
1073 Data to return\r
1074\r
1075--*/\r
1076{\r
1077 //\r
1078 // Restore the 28bit address to 32bit address\r
1079 // (take 32bit address as an example)\r
1080 //\r
1081 return (VOID *) ((UINTN) (PtrQH->QH.QHVerticalPtr << 4));\r
1082}\r
1083\r
1084VOID\r
1085SetQHVerticalQHorTDSelect (\r
1086 IN QH_STRUCT *PtrQH,\r
1087 IN BOOLEAN bQH\r
1088 )\r
1089/*++\r
1090\r
1091Routine Description:\r
1092\r
1093 Set QH Vertical QH or TD\r
1094\r
1095Arguments:\r
1096\r
1097 PtrQH - QH_STRUCT\r
1098 bQH - TRUE is QH FALSE is TD\r
1099\r
1100Returns:\r
1101\r
1102 VOID\r
1103\r
1104--*/\r
1105{\r
1106 //\r
1107 // Set the specified bit if the Vertical Link Pointer pointing to a QH,\r
1108 // Clear the specified bit if the Vertical Link Pointer pointing to a TD.\r
1109 //\r
1110 PtrQH->QH.QHVerticalQSelect = bQH ? 1 : 0;\r
1111}\r
1112\r
1113BOOLEAN\r
1114IsQHHorizontalQHSelect (\r
1115 IN QH_STRUCT *PtrQH\r
1116 )\r
1117/*++\r
1118\r
1119Routine Description:\r
1120\r
1121 Is QH Horizontal QH Select\r
1122\r
1123Arguments:\r
1124\r
1125 PtrQH - QH_STRUCT\r
1126 \r
1127Returns:\r
1128\r
1129 TRUE - QH\r
1130 FALSE - TD\r
1131\r
1132--*/\r
1133{\r
1134 //\r
1135 // Retrieve the information about whether the Horizontal Link Pointer\r
1136 // pointing to a QH or TD.\r
1137 //\r
1138 return (BOOLEAN) (PtrQH->QH.QHHorizontalQSelect ? TRUE : FALSE);\r
1139}\r
1140\r
1141VOID\r
1142SetQHVerticalValidorInvalid (\r
1143 IN QH_STRUCT *PtrQH,\r
1144 IN BOOLEAN IsValid\r
1145 )\r
1146/*++\r
1147\r
1148Routine Description:\r
1149\r
1150 Set QH Vertical Valid or Invalid\r
1151\r
1152Arguments:\r
1153\r
1154 PtrQH - QH_STRUCT\r
1155 IsValid - TRUE is valid FALSE is invalid\r
1156\r
1157Returns:\r
1158\r
1159 VOID\r
1160\r
1161--*/\r
1162{\r
1163 //\r
1164 // If TRUE, indicates the Vertical Link Pointer field is valid,\r
1165 // else, the field is invalid.\r
1166 //\r
1167 PtrQH->QH.QHVerticalTerminate = IsValid ? 0 : 1;\r
1168}\r
1169\r
1170\r
1171BOOLEAN\r
1172GetQHVerticalValidorInvalid (\r
1173 IN QH_STRUCT *PtrQH\r
1174 )\r
1175/*++\r
1176\r
1177Routine Description:\r
1178\r
1179 Get QH Vertical Valid or Invalid\r
1180\r
1181Arguments:\r
1182\r
1183 PtrQH - QH_STRUCT\r
1184\r
1185Returns:\r
1186\r
1187 TRUE - Valid\r
1188 FALSE - Invalid\r
1189\r
1190--*/\r
1191{\r
1192 //\r
1193 // If TRUE, indicates the Vertical Link Pointer field is valid,\r
1194 // else, the field is invalid.\r
1195 //\r
1196 return (BOOLEAN) (!(PtrQH->QH.QHVerticalTerminate));\r
1197}\r
1198\r
1199BOOLEAN\r
1200GetQHHorizontalValidorInvalid (\r
1201 IN QH_STRUCT *PtrQH\r
1202 )\r
1203/*++\r
1204\r
1205Routine Description:\r
1206\r
1207 Get QH Horizontal Valid or Invalid\r
1208\r
1209Arguments:\r
1210\r
1211 PtrQH - QH_STRUCT\r
1212\r
1213Returns:\r
1214\r
1215 TRUE - Valid\r
1216 FALSE - Invalid\r
1217\r
1218--*/\r
1219{\r
1220 //\r
1221 // If TRUE, meaning the Horizontal Link Pointer field is valid,\r
1222 // else, the field is invalid.\r
1223 //\r
1224 return (BOOLEAN) (!(PtrQH->QH.QHHorizontalTerminate));\r
1225}\r
1226//\r
1227// functions for TD\r
1228//\r
1229EFI_STATUS\r
1230AllocateTDStruct (\r
1231 IN USB_HC_DEV *HcDev,\r
1232 OUT TD_STRUCT **ppTDStruct\r
1233 )\r
1234/*++\r
1235\r
1236Routine Description:\r
1237\r
1238 Allocate TD Struct\r
1239\r
1240Arguments:\r
1241\r
1242 HcDev - USB_HC_DEV\r
1243 ppTDStruct - place to store TD_STRUCT pointer\r
1244Returns:\r
1245\r
1246 EFI_SUCCESS\r
1247\r
1248--*/\r
1249{\r
1250 *ppTDStruct = NULL;\r
1251\r
1252 //\r
1253 // TD must align on 16 bytes alignment,\r
1254 // since the memory allocated by UhciAllocatePool ()\r
1255 // is aligned on 32 bytes, it is no need to adjust\r
1256 // the allocated memory returned.\r
1257 //\r
1258 return UhciAllocatePool (\r
1259 HcDev,\r
1260 (UINT8 **) ppTDStruct,\r
1261 sizeof (TD_STRUCT)\r
1262 );\r
1263}\r
1264\r
1265EFI_STATUS\r
1266CreateTD (\r
1267 IN USB_HC_DEV *HcDev,\r
1268 OUT TD_STRUCT **pptrTD\r
1269 )\r
1270/*++\r
1271\r
1272Routine Description:\r
1273\r
1274 Create TD\r
1275\r
1276Arguments:\r
1277\r
1278 HcDev - USB_HC_DEV\r
1279 pptrTD - TD_STRUCT pointer to store\r
1280\r
1281Returns:\r
1282\r
1283 EFI_OUT_OF_RESOURCES - Can't allocate resources\r
1284 EFI_SUCCESS - Success\r
1285\r
1286--*/\r
1287{\r
1288 EFI_STATUS Status;\r
1289 //\r
1290 // create memory for TD_STRUCT, and align the memory.\r
1291 //\r
1292 Status = AllocateTDStruct (HcDev, pptrTD);\r
1293 if (EFI_ERROR (Status)) {\r
1294 return EFI_OUT_OF_RESOURCES;\r
1295 }\r
1296\r
1297 //\r
1298 // Make TD ready.\r
1299 //\r
1300 SetTDLinkPtrValidorInvalid (*pptrTD, FALSE);\r
1301\r
1302\r
1303 return EFI_SUCCESS;\r
1304}\r
1305\r
1306EFI_STATUS\r
1307GenSetupStageTD (\r
1308 IN USB_HC_DEV *HcDev,\r
1309 IN UINT8 DevAddr,\r
1310 IN UINT8 Endpoint,\r
1311 IN BOOLEAN bSlow,\r
1312 IN UINT8 *pDevReq,\r
1313 IN UINT8 RequestLen,\r
1314 OUT TD_STRUCT **ppTD\r
1315 )\r
1316/*++\r
1317\r
1318Routine Description:\r
1319\r
1320 Generate Setup Stage TD\r
1321\r
1322Arguments:\r
1323\r
1324 HcDev - USB_HC_DEV\r
1325 DevAddr - Device address\r
1326 Endpoint - Endpoint number \r
1327 bSlow - Full speed or low speed\r
1328 pDevReq - Device request\r
1329 RequestLen - Request length\r
1330 ppTD - TD_STRUCT to return\r
1331Returns:\r
1332\r
1333 EFI_OUT_OF_RESOURCES - Can't allocate memory\r
1334 EFI_SUCCESS - Success\r
1335\r
1336--*/\r
1337{\r
1338 EFI_STATUS Status;\r
1339 TD_STRUCT *pTDStruct;\r
1340\r
1341 Status = CreateTD (HcDev, &pTDStruct);\r
1342 if (EFI_ERROR (Status)) {\r
1343 return EFI_OUT_OF_RESOURCES;\r
1344 }\r
1345\r
1346 SetTDLinkPtr (pTDStruct, NULL);\r
1347\r
1348 //\r
1349 // Depth first fashion\r
1350 //\r
1351 SetTDLinkPtrDepthorBreadth (pTDStruct, TRUE);\r
1352\r
1353 //\r
1354 // initialize as the last TD in the QH context,\r
1355 // this field will be updated in the TD linkage process.\r
1356 //\r
1357 SetTDLinkPtrValidorInvalid (pTDStruct, FALSE);\r
1358\r
1359 //\r
1360 // Disable Short Packet Detection by default\r
1361 //\r
1362 EnableorDisableTDShortPacket (pTDStruct, FALSE);\r
1363\r
1364 //\r
1365 // Max error counter is 3, retry 3 times when error encountered.\r
1366 //\r
1367 SetTDControlErrorCounter (pTDStruct, 3);\r
1368\r
1369 //\r
1370 // set device speed attribute\r
1371 // (TRUE - Slow Device; FALSE - Full Speed Device)\r
1372 //\r
1373 SetTDLoworFullSpeedDevice (pTDStruct, bSlow);\r
1374\r
1375 //\r
1376 // Non isochronous transfer TD\r
1377 //\r
1378 SetTDControlIsochronousorNot (pTDStruct, FALSE);\r
1379\r
1380 //\r
1381 // Interrupt On Complete bit be set to zero,\r
1382 // Disable IOC interrupt.\r
1383 //\r
1384 SetorClearTDControlIOC (pTDStruct, FALSE);\r
1385\r
1386 //\r
1387 // Set TD Active bit\r
1388 //\r
1389 SetTDStatusActiveorInactive (pTDStruct, TRUE);\r
1390\r
1391 SetTDTokenMaxLength (pTDStruct, RequestLen);\r
1392\r
1393 SetTDTokenDataToggle0 (pTDStruct);\r
1394\r
1395 SetTDTokenEndPoint (pTDStruct, Endpoint);\r
1396\r
1397 SetTDTokenDeviceAddress (pTDStruct, DevAddr);\r
1398\r
1399 SetTDTokenPacketID (pTDStruct, SETUP_PACKET_ID);\r
1400\r
1401 pTDStruct->pTDBuffer = (UINT8 *) pDevReq;\r
1402 pTDStruct->TDBufferLength = RequestLen;\r
1403 SetTDDataBuffer (pTDStruct);\r
1404\r
1405 *ppTD = pTDStruct;\r
1406\r
1407 return EFI_SUCCESS;\r
1408}\r
1409\r
1410EFI_STATUS\r
1411GenDataTD (\r
1412 IN USB_HC_DEV *HcDev,\r
1413 IN UINT8 DevAddr,\r
1414 IN UINT8 Endpoint,\r
1415 IN UINT8 *pData,\r
1416 IN UINT8 Len,\r
1417 IN UINT8 PktID,\r
1418 IN UINT8 Toggle,\r
1419 IN BOOLEAN bSlow,\r
1420 OUT TD_STRUCT **ppTD\r
1421 )\r
1422/*++\r
1423\r
1424Routine Description:\r
1425\r
1426 Generate Data Stage TD\r
1427\r
1428Arguments:\r
1429\r
1430 HcDev - USB_HC_DEV\r
1431 DevAddr - Device address\r
1432 Endpoint - Endpoint number \r
1433 pData - Data buffer \r
1434 Len - Data length\r
1435 PktID - Packet ID\r
1436 Toggle - Data toggle value\r
1437 bSlow - Full speed or low speed\r
1438 ppTD - TD_STRUCT to return\r
1439Returns:\r
1440\r
1441 EFI_OUT_OF_RESOURCES - Can't allocate memory\r
1442 EFI_SUCCESS - Success\r
1443\r
1444--*/\r
1445{\r
1446 TD_STRUCT *pTDStruct;\r
1447 EFI_STATUS Status;\r
1448\r
1449 Status = CreateTD (HcDev, &pTDStruct);\r
1450 if (EFI_ERROR (Status)) {\r
1451 return EFI_OUT_OF_RESOURCES;\r
1452 }\r
1453\r
1454 SetTDLinkPtr (pTDStruct, NULL);\r
1455\r
1456 //\r
1457 // Depth first fashion\r
1458 //\r
1459 SetTDLinkPtrDepthorBreadth (pTDStruct, TRUE);\r
1460\r
1461 //\r
1462 // Link pointer pointing to TD struct\r
1463 //\r
1464 SetTDLinkPtrQHorTDSelect (pTDStruct, FALSE);\r
1465\r
1466 //\r
1467 // initialize as the last TD in the QH context,\r
1468 // this field will be updated in the TD linkage process.\r
1469 //\r
1470 SetTDLinkPtrValidorInvalid (pTDStruct, FALSE);\r
1471\r
1472 //\r
1473 // Disable short packet detect\r
1474 //\r
1475 EnableorDisableTDShortPacket (pTDStruct, FALSE);\r
1476 //\r
1477 // Max error counter is 3\r
1478 //\r
1479 SetTDControlErrorCounter (pTDStruct, 3);\r
1480\r
1481 //\r
1482 // set device speed attribute\r
1483 // (TRUE - Slow Device; FALSE - Full Speed Device)\r
1484 //\r
1485 SetTDLoworFullSpeedDevice (pTDStruct, bSlow);\r
1486\r
1487 //\r
1488 // Non isochronous transfer TD\r
1489 //\r
1490 SetTDControlIsochronousorNot (pTDStruct, FALSE);\r
1491\r
1492 //\r
1493 // Disable Interrupt On Complete\r
1494 // Disable IOC interrupt.\r
1495 //\r
1496 SetorClearTDControlIOC (pTDStruct, FALSE);\r
1497\r
1498 //\r
1499 // Set Active bit\r
1500 //\r
1501 SetTDStatusActiveorInactive (pTDStruct, TRUE);\r
1502\r
1503 SetTDTokenMaxLength (pTDStruct, Len);\r
1504\r
1505 if (Toggle) {\r
1506 SetTDTokenDataToggle1 (pTDStruct);\r
1507 } else {\r
1508 SetTDTokenDataToggle0 (pTDStruct);\r
1509 }\r
1510\r
1511 SetTDTokenEndPoint (pTDStruct, Endpoint);\r
1512\r
1513 SetTDTokenDeviceAddress (pTDStruct, DevAddr);\r
1514\r
1515 SetTDTokenPacketID (pTDStruct, PktID);\r
1516\r
1517 pTDStruct->pTDBuffer = (UINT8 *) pData;\r
1518 pTDStruct->TDBufferLength = Len;\r
1519 SetTDDataBuffer (pTDStruct);\r
1520 *ppTD = pTDStruct;\r
1521\r
1522 return EFI_SUCCESS;\r
1523}\r
1524\r
1525\r
1526EFI_STATUS\r
1527CreateStatusTD (\r
1528 IN USB_HC_DEV *HcDev,\r
1529 IN UINT8 DevAddr,\r
1530 IN UINT8 Endpoint,\r
1531 IN UINT8 PktID,\r
1532 IN BOOLEAN bSlow,\r
1533 OUT TD_STRUCT **ppTD\r
1534 )\r
1535/*++\r
1536\r
1537Routine Description:\r
1538\r
1539 Generate Status Stage TD\r
1540\r
1541Arguments:\r
1542\r
1543 HcDev - USB_HC_DEV\r
1544 DevAddr - Device address\r
1545 Endpoint - Endpoint number \r
1546 PktID - Packet ID\r
1547 bSlow - Full speed or low speed\r
1548 ppTD - TD_STRUCT to return\r
1549Returns:\r
1550\r
1551 EFI_OUT_OF_RESOURCES - Can't allocate memory\r
1552 EFI_SUCCESS - Success\r
1553\r
1554--*/\r
1555{\r
1556 TD_STRUCT *ptrTDStruct;\r
1557 EFI_STATUS Status;\r
1558\r
1559 Status = CreateTD (HcDev, &ptrTDStruct);\r
1560 if (EFI_ERROR (Status)) {\r
1561 return EFI_OUT_OF_RESOURCES;\r
1562 }\r
1563\r
1564 SetTDLinkPtr (ptrTDStruct, NULL);\r
1565\r
1566 //\r
1567 // Depth first fashion\r
1568 //\r
1569 SetTDLinkPtrDepthorBreadth (ptrTDStruct, TRUE);\r
1570\r
1571 //\r
1572 // initialize as the last TD in the QH context,\r
1573 // this field will be updated in the TD linkage process.\r
1574 //\r
1575 SetTDLinkPtrValidorInvalid (ptrTDStruct, FALSE);\r
1576\r
1577 //\r
1578 // Disable short packet detect\r
1579 //\r
1580 EnableorDisableTDShortPacket (ptrTDStruct, FALSE);\r
1581\r
1582 //\r
1583 // Max error counter is 3\r
1584 //\r
1585 SetTDControlErrorCounter (ptrTDStruct, 3);\r
1586\r
1587 //\r
1588 // set device speed attribute\r
1589 // (TRUE - Slow Device; FALSE - Full Speed Device)\r
1590 //\r
1591 SetTDLoworFullSpeedDevice (ptrTDStruct, bSlow);\r
1592\r
1593 //\r
1594 // Non isochronous transfer TD\r
1595 //\r
1596 SetTDControlIsochronousorNot (ptrTDStruct, FALSE);\r
1597\r
1598 //\r
1599 // Disable Interrupt On Complete\r
1600 // Disable IOC interrupt.\r
1601 //\r
1602 SetorClearTDControlIOC (ptrTDStruct, FALSE);\r
1603\r
1604 //\r
1605 // Set TD Active bit\r
1606 //\r
1607 SetTDStatusActiveorInactive (ptrTDStruct, TRUE);\r
1608\r
1609 SetTDTokenMaxLength (ptrTDStruct, 0);\r
1610\r
1611 SetTDTokenDataToggle1 (ptrTDStruct);\r
1612\r
1613 SetTDTokenEndPoint (ptrTDStruct, Endpoint);\r
1614\r
1615 SetTDTokenDeviceAddress (ptrTDStruct, DevAddr);\r
1616\r
1617 SetTDTokenPacketID (ptrTDStruct, PktID);\r
1618\r
1619 ptrTDStruct->pTDBuffer = NULL;\r
1620 ptrTDStruct->TDBufferLength = 0;\r
1621 SetTDDataBuffer (ptrTDStruct);\r
1622\r
1623 *ppTD = ptrTDStruct;\r
1624\r
1625 return EFI_SUCCESS;\r
1626}\r
1627\r
1628\r
1629VOID\r
1630SetTDLinkPtrValidorInvalid (\r
1631 IN TD_STRUCT *ptrTDStruct,\r
1632 IN BOOLEAN bValid\r
1633 )\r
1634/*++\r
1635\r
1636Routine Description:\r
1637\r
1638 Set TD Link Pointer Valid or Invalid\r
1639\r
1640Arguments:\r
1641\r
1642 ptrTDStruct - TD_STRUCT\r
1643 bValid - TRUE is valid FALSE is invalid\r
1644\r
1645Returns:\r
1646\r
1647 VOID\r
1648\r
1649--*/\r
1650{\r
1651 //\r
1652 // Valid means the link pointer is valid,\r
1653 // else, it's invalid.\r
1654 //\r
1655 ptrTDStruct->TDData.TDLinkPtrTerminate = (bValid ? 0 : 1);\r
1656}\r
1657\r
1658VOID\r
1659SetTDLinkPtrQHorTDSelect (\r
1660 IN TD_STRUCT *ptrTDStruct,\r
1661 IN BOOLEAN bQH\r
1662 )\r
1663/*++\r
1664\r
1665Routine Description:\r
1666\r
1667 Set TD Link Pointer QH or TD Select\r
1668\r
1669Arguments:\r
1670\r
1671 ptrTDStruct - TD_STRUCT\r
1672 bQH - TRUE is QH FALSE is TD\r
1673 \r
1674Returns:\r
1675\r
1676 VOID\r
1677\r
1678--*/\r
1679{\r
1680 //\r
1681 // Indicate whether the Link Pointer pointing to a QH or TD\r
1682 //\r
1683 ptrTDStruct->TDData.TDLinkPtrQSelect = (bQH ? 1 : 0);\r
1684}\r
1685\r
1686VOID\r
1687SetTDLinkPtrDepthorBreadth (\r
1688 IN TD_STRUCT *ptrTDStruct,\r
1689 IN BOOLEAN bDepth\r
1690 )\r
1691/*++\r
1692\r
1693Routine Description:\r
1694\r
1695 Set TD Link Pointer depth or bread priority\r
1696\r
1697Arguments:\r
1698\r
1699 ptrTDStruct - TD_STRUCT\r
1700 bDepth - TRUE is Depth FALSE is Breadth\r
1701 \r
1702Returns:\r
1703\r
1704 VOID\r
1705\r
1706--*/\r
1707{\r
1708 //\r
1709 // If TRUE, indicating the host controller should process in depth first\r
1710 // fashion,\r
1711 // else, the host controller should process in breadth first fashion\r
1712 //\r
1713 ptrTDStruct->TDData.TDLinkPtrDepthSelect = (bDepth ? 1 : 0);\r
1714}\r
1715\r
1716VOID\r
1717SetTDLinkPtr (\r
1718 IN TD_STRUCT *ptrTDStruct,\r
1719 IN VOID *ptrNext\r
1720 )\r
1721/*++\r
1722\r
1723Routine Description:\r
1724\r
1725 Set TD Link Pointer\r
1726\r
1727Arguments:\r
1728\r
1729 ptrTDStruct - TD_STRUCT\r
1730 ptrNext - Pointer to set\r
1731 \r
1732Returns:\r
1733\r
1734 VOID\r
1735\r
1736--*/\r
1737{\r
1738 //\r
1739 // Set TD Link Pointer. Since QH,TD align on 16-byte boundaries,\r
1740 // only the highest 28 bits are valid. (if take 32bit address as an example)\r
1741 //\r
1742 ptrTDStruct->TDData.TDLinkPtr = (UINT32) ((UINTN) ptrNext >> 4);\r
1743}\r
1744\r
1745VOID *\r
1746GetTDLinkPtr (\r
1747 IN TD_STRUCT *ptrTDStruct\r
1748 )\r
1749/*++\r
1750\r
1751Routine Description:\r
1752\r
1753 Get TD Link Pointer\r
1754\r
1755Arguments:\r
1756\r
1757 ptrTDStruct - TD_STRUCT\r
1758 \r
1759Returns:\r
1760\r
1761 Pointer to get\r
1762\r
1763--*/\r
1764{\r
1765 //\r
1766 // Get TD Link Pointer. Restore it back to 32bit\r
1767 // (if take 32bit address as an example)\r
1768 //\r
1769 return (VOID *) ((UINTN) (ptrTDStruct->TDData.TDLinkPtr << 4));\r
1770}\r
1771\r
1772BOOLEAN\r
1773IsTDLinkPtrQHOrTD (\r
1774 IN TD_STRUCT *ptrTDStruct\r
1775 )\r
1776/*++\r
1777\r
1778Routine Description:\r
1779\r
1780 Is TD Link Pointer is QH Or TD\r
1781\r
1782Arguments:\r
1783\r
1784 ptrTDStruct - TODO: add argument description\r
1785\r
1786Returns:\r
1787\r
1788 TRUE - QH\r
1789 FALSE - TD \r
1790\r
1791--*/\r
1792{\r
1793 //\r
1794 // Get the information about whether the Link Pointer field pointing to\r
1795 // a QH or a TD.\r
1796 //\r
1797 return (BOOLEAN) (ptrTDStruct->TDData.TDLinkPtrQSelect);\r
1798}\r
1799\r
1800VOID\r
1801EnableorDisableTDShortPacket (\r
1802 IN TD_STRUCT *ptrTDStruct,\r
1803 IN BOOLEAN bEnable\r
1804 )\r
1805/*++\r
1806\r
1807Routine Description:\r
1808\r
1809 Enable or Disable TD ShortPacket\r
1810\r
1811Arguments:\r
1812\r
1813 ptrTDStruct - TD_STRUCT\r
1814 bEnable - TRUE is Enanble FALSE is Disable\r
1815\r
1816Returns:\r
1817\r
1818 VOID\r
1819\r
1820--*/\r
1821{\r
1822 //\r
1823 // TRUE means enable short packet detection mechanism.\r
1824 //\r
1825 ptrTDStruct->TDData.TDStatusSPD = (bEnable ? 1 : 0);\r
1826}\r
1827\r
1828VOID\r
1829SetTDControlErrorCounter (\r
1830 IN TD_STRUCT *ptrTDStruct,\r
1831 IN UINT8 nMaxErrors\r
1832 )\r
1833/*++\r
1834\r
1835Routine Description:\r
1836\r
1837 Set TD Control ErrorCounter\r
1838\r
1839Arguments:\r
1840\r
1841 ptrTDStruct - TD_STRUCT\r
1842 nMaxErrors - Error counter number\r
1843 \r
1844Returns:\r
1845\r
1846 VOID\r
1847\r
1848--*/\r
1849{\r
1850 //\r
1851 // valid value of nMaxErrors is 0,1,2,3\r
1852 //\r
1853 if (nMaxErrors > 3) {\r
1854 nMaxErrors = 3;\r
1855 }\r
1856\r
1857 ptrTDStruct->TDData.TDStatusErr = nMaxErrors;\r
1858}\r
1859\r
1860\r
1861VOID\r
1862SetTDLoworFullSpeedDevice (\r
1863 IN TD_STRUCT *ptrTDStruct,\r
1864 IN BOOLEAN bLowSpeedDevice\r
1865 )\r
1866{\r
1867 //\r
1868 // TRUE means the TD is targeting at a Low-speed device\r
1869 //\r
1870 ptrTDStruct->TDData.TDStatusLS = (bLowSpeedDevice ? 1 : 0);\r
1871}\r
1872\r
1873VOID\r
1874SetTDControlIsochronousorNot (\r
1875 IN TD_STRUCT *ptrTDStruct,\r
1876 IN BOOLEAN IsIsochronous\r
1877 )\r
1878{\r
1879 //\r
1880 // TRUE means the TD belongs to Isochronous transfer type.\r
1881 //\r
1882 ptrTDStruct->TDData.TDStatusIOS = (IsIsochronous ? 1 : 0);\r
1883}\r
1884\r
1885VOID\r
1886SetorClearTDControlIOC (\r
1887 IN TD_STRUCT *ptrTDStruct,\r
1888 IN BOOLEAN IsSet\r
1889 )\r
1890{\r
1891 //\r
1892 // If this bit is set, it indicates that the host controller should issue\r
1893 // an interrupt on completion of the frame in which this TD is executed.\r
1894 //\r
1895 ptrTDStruct->TDData.TDStatusIOC = IsSet ? 1 : 0;\r
1896}\r
1897\r
1898VOID\r
1899SetTDStatusActiveorInactive (\r
1900 IN TD_STRUCT *ptrTDStruct,\r
1901 IN BOOLEAN IsActive\r
1902 )\r
1903{\r
1904 //\r
1905 // If this bit is set, it indicates that the TD is active and can be\r
1906 // executed.\r
1907 //\r
1908 if (IsActive) {\r
1909 ptrTDStruct->TDData.TDStatus |= 0x80;\r
1910 } else {\r
1911 ptrTDStruct->TDData.TDStatus &= 0x7F;\r
1912 }\r
1913}\r
1914\r
1915UINT16\r
1916SetTDTokenMaxLength (\r
1917 IN TD_STRUCT *ptrTDStruct,\r
1918 IN UINT16 MaximumLength\r
1919 )\r
1920{\r
1921 //\r
1922 // Specifies the maximum number of data bytes allowed for the transfer.\r
1923 // the legal value extent is 0 ~ 0x500.\r
1924 //\r
1925 if (MaximumLength > 0x500) {\r
1926 MaximumLength = 0x500;\r
1927 }\r
1928 ptrTDStruct->TDData.TDTokenMaxLen = MaximumLength - 1;\r
1929\r
1930 return MaximumLength;\r
1931}\r
1932\r
1933VOID\r
1934SetTDTokenDataToggle1 (\r
1935 IN TD_STRUCT *ptrTDStruct\r
1936 )\r
1937{\r
1938 //\r
1939 // Set the data toggle bit to DATA1\r
1940 //\r
1941 ptrTDStruct->TDData.TDTokenDataToggle = 1;\r
1942}\r
1943\r
1944VOID\r
1945SetTDTokenDataToggle0 (\r
1946 IN TD_STRUCT *ptrTDStruct\r
1947 )\r
1948{\r
1949 //\r
1950 // Set the data toggle bit to DATA0\r
1951 //\r
1952 ptrTDStruct->TDData.TDTokenDataToggle = 0;\r
1953}\r
1954\r
1955UINT8\r
1956GetTDTokenDataToggle (\r
1957 IN TD_STRUCT *ptrTDStruct\r
1958 )\r
1959{\r
1960 //\r
1961 // Get the data toggle value.\r
1962 //\r
1963 return (UINT8) (ptrTDStruct->TDData.TDTokenDataToggle);\r
1964}\r
1965\r
1966VOID\r
1967SetTDTokenEndPoint (\r
1968 IN TD_STRUCT *ptrTDStruct,\r
1969 IN UINTN EndPoint\r
1970 )\r
1971{\r
1972 //\r
1973 // Set EndPoint Number the TD is targeting at.\r
1974 //\r
1975 ptrTDStruct->TDData.TDTokenEndPt = (UINT8) EndPoint;\r
1976}\r
1977\r
1978VOID\r
1979SetTDTokenDeviceAddress (\r
1980 IN TD_STRUCT *ptrTDStruct,\r
1981 IN UINTN DeviceAddress\r
1982 )\r
1983{\r
1984 //\r
1985 // Set Device Address the TD is targeting at.\r
1986 //\r
1987 ptrTDStruct->TDData.TDTokenDevAddr = (UINT8) DeviceAddress;\r
1988}\r
1989\r
1990VOID\r
1991SetTDTokenPacketID (\r
1992 IN TD_STRUCT *ptrTDStruct,\r
1993 IN UINT8 PID\r
1994 )\r
1995{\r
1996 //\r
1997 // Set the Packet Identification to be used for this transaction.\r
1998 //\r
1999 ptrTDStruct->TDData.TDTokenPID = PID;\r
2000}\r
2001\r
2002VOID\r
2003SetTDDataBuffer (\r
2004 IN TD_STRUCT *ptrTDStruct\r
2005 )\r
2006{\r
2007 //\r
2008 // Set the beginning address of the data buffer that will be used\r
2009 // during the transaction.\r
2010 //\r
2011 ptrTDStruct->TDData.TDBufferPtr = (UINT32) ((UINTN) (ptrTDStruct->pTDBuffer));\r
2012}\r
2013\r
2014BOOLEAN\r
2015IsTDStatusActive (\r
2016 IN TD_STRUCT *ptrTDStruct\r
2017 )\r
2018{\r
2019 UINT8 TDStatus;\r
2020\r
2021 //\r
2022 // Detect whether the TD is active.\r
2023 //\r
2024 TDStatus = (UINT8) (ptrTDStruct->TDData.TDStatus);\r
2025 return (BOOLEAN) (TDStatus & 0x80);\r
2026}\r
2027\r
2028BOOLEAN\r
2029IsTDStatusStalled (\r
2030 IN TD_STRUCT *ptrTDStruct\r
2031 )\r
2032{\r
2033 UINT8 TDStatus;\r
2034\r
2035 //\r
2036 // Detect whether the device/endpoint addressed by this TD is stalled.\r
2037 //\r
2038 TDStatus = (UINT8) (ptrTDStruct->TDData.TDStatus);\r
2039 return (BOOLEAN) (TDStatus & 0x40);\r
2040}\r
2041\r
2042BOOLEAN\r
2043IsTDStatusBufferError (\r
2044 IN TD_STRUCT *ptrTDStruct\r
2045 )\r
2046{\r
2047 UINT8 TDStatus;\r
2048 //\r
2049 // Detect whether Data Buffer Error is happened.\r
2050 //\r
2051 TDStatus = (UINT8) (ptrTDStruct->TDData.TDStatus);\r
2052 return (BOOLEAN) (TDStatus & 0x20);\r
2053}\r
2054\r
2055BOOLEAN\r
2056IsTDStatusBabbleError (\r
2057 IN TD_STRUCT *ptrTDStruct\r
2058 )\r
2059{\r
2060 UINT8 TDStatus;\r
2061\r
2062 //\r
2063 // Detect whether Babble Error is happened.\r
2064 //\r
2065 TDStatus = (UINT8) (ptrTDStruct->TDData.TDStatus);\r
2066 return (BOOLEAN) (TDStatus & 0x10);\r
2067}\r
2068\r
2069BOOLEAN\r
2070IsTDStatusNAKReceived (\r
2071 IN TD_STRUCT *ptrTDStruct\r
2072 )\r
2073{\r
2074 UINT8 TDStatus;\r
2075\r
2076 //\r
2077 // Detect whether NAK is received.\r
2078 //\r
2079 TDStatus = (UINT8) (ptrTDStruct->TDData.TDStatus);\r
2080 return (BOOLEAN) (TDStatus & 0x08);\r
2081}\r
2082\r
2083BOOLEAN\r
2084IsTDStatusCRCTimeOutError (\r
2085 IN TD_STRUCT *ptrTDStruct\r
2086 )\r
2087{\r
2088 UINT8 TDStatus;\r
2089\r
2090 //\r
2091 // Detect whether CRC/Time Out Error is encountered.\r
2092 //\r
2093 TDStatus = (UINT8) (ptrTDStruct->TDData.TDStatus);\r
2094 return (BOOLEAN) (TDStatus & 0x04);\r
2095}\r
2096\r
2097BOOLEAN\r
2098IsTDStatusBitStuffError (\r
2099 IN TD_STRUCT *ptrTDStruct\r
2100 )\r
2101{\r
2102 UINT8 TDStatus;\r
2103\r
2104 //\r
2105 // Detect whether Bitstuff Error is received.\r
2106 //\r
2107 TDStatus = (UINT8) (ptrTDStruct->TDData.TDStatus);\r
2108 return (BOOLEAN) (TDStatus & 0x02);\r
2109}\r
2110\r
2111UINT16\r
2112GetTDStatusActualLength (\r
2113 IN TD_STRUCT *ptrTDStruct\r
2114 )\r
2115{\r
2116 //\r
2117 // Retrieve the actual number of bytes that were tansferred.\r
2118 // the value is encoded as n-1. so return the decoded value.\r
2119 //\r
2120 return (UINT16) ((ptrTDStruct->TDData.TDStatusActualLength) + 1);\r
2121}\r
2122\r
2123UINT16\r
2124GetTDTokenMaxLength (\r
2125 IN TD_STRUCT *ptrTDStruct\r
2126 )\r
2127{\r
2128 //\r
2129 // Retrieve the maximum number of data bytes allowed for the trnasfer.\r
2130 //\r
2131 return (UINT16) ((ptrTDStruct->TDData.TDTokenMaxLen) + 1);\r
2132}\r
2133\r
2134UINT8\r
2135GetTDTokenEndPoint (\r
2136 IN TD_STRUCT *ptrTDStruct\r
2137 )\r
2138{\r
2139 //\r
2140 // Retrieve the endpoint number the transaction is targeting at.\r
2141 //\r
2142 return (UINT8) (ptrTDStruct->TDData.TDTokenEndPt);\r
2143}\r
2144\r
2145UINT8\r
2146GetTDTokenDeviceAddress (\r
2147 IN TD_STRUCT *ptrTDStruct\r
2148 )\r
2149{\r
2150 //\r
2151 // Retrieve the device address the transaction is targeting at.\r
2152 //\r
2153 return (UINT8) (ptrTDStruct->TDData.TDTokenDevAddr);\r
2154}\r
2155\r
2156UINT8\r
2157GetTDTokenPacketID (\r
2158 IN TD_STRUCT *ptrTDStruct\r
2159 )\r
2160{\r
2161 //\r
2162 // Retrieve the Packet Identification information.\r
2163 //\r
2164 return (UINT8) (ptrTDStruct->TDData.TDTokenPID);\r
2165}\r
2166\r
2167UINT8 *\r
2168GetTDDataBuffer (\r
2169 IN TD_STRUCT *ptrTDStruct\r
2170 )\r
2171{\r
2172 //\r
2173 // Retrieve the beginning address of the data buffer\r
2174 // that involved in this transaction.\r
2175 //\r
2176 return ptrTDStruct->pTDBuffer;\r
2177}\r
2178\r
2179BOOLEAN\r
2180GetTDLinkPtrValidorInvalid (\r
2181 IN TD_STRUCT *ptrTDStruct\r
2182 )\r
2183{\r
2184 //\r
2185 // Retrieve the information of whether the Link Pointer field\r
2186 // is valid or not.\r
2187 //\r
2188 if (ptrTDStruct->TDData.TDLinkPtrTerminate) {\r
2189 return FALSE;\r
2190 } else {\r
2191 return TRUE;\r
2192 }\r
2193\r
2194}\r
2195\r
2196UINTN\r
2197CountTDsNumber (\r
2198 IN TD_STRUCT *PtrFirstTD\r
2199 )\r
2200{\r
2201 UINTN Number;\r
2202 TD_STRUCT *ptr;\r
2203 //\r
2204 // Count the queued TDs number.\r
2205 //\r
2206 Number = 0;\r
2207 ptr = PtrFirstTD;\r
2208 while (ptr) {\r
2209 ptr = (TD_STRUCT *) ptr->ptrNextTD;\r
2210 Number++;\r
2211 }\r
2212\r
2213 return Number;\r
2214}\r
2215\r
2216\r
2217\r
2218VOID\r
2219LinkTDToQH (\r
2220 IN QH_STRUCT *PtrQH,\r
2221 IN TD_STRUCT *PtrTD\r
2222 )\r
2223/*++\r
2224\r
2225Routine Description:\r
2226\r
2227 Link TD To QH\r
2228\r
2229Arguments:\r
2230\r
2231 PtrQH - QH_STRUCT\r
2232 PtrTD - TD_STRUCT\r
2233Returns:\r
2234\r
2235 VOID\r
2236\r
2237--*/\r
2238{\r
2239 if (PtrQH == NULL || PtrTD == NULL) {\r
2240 return ;\r
2241 }\r
2242 //\r
2243 // Validate QH Vertical Ptr field\r
2244 //\r
2245 SetQHVerticalValidorInvalid (PtrQH, TRUE);\r
2246\r
2247 //\r
2248 // Vertical Ptr pointing to TD structure\r
2249 //\r
2250 SetQHVerticalQHorTDSelect (PtrQH, FALSE);\r
2251\r
2252 SetQHVerticalLinkPtr (PtrQH, (VOID *) PtrTD);\r
2253\r
2254 PtrQH->ptrDown = (VOID *) PtrTD;\r
2255}\r
2256\r
2257VOID\r
2258LinkTDToTD (\r
2259 IN TD_STRUCT *ptrPreTD,\r
2260 IN TD_STRUCT *PtrTD\r
2261 )\r
2262/*++\r
2263\r
2264Routine Description:\r
2265\r
2266 Link TD To TD\r
2267\r
2268Arguments:\r
2269\r
2270 ptrPreTD - Previous TD_STRUCT to be linked\r
2271 PtrTD - TD_STRUCT to link\r
2272Returns:\r
2273\r
2274 VOID\r
2275\r
2276--*/\r
2277{\r
2278 if (ptrPreTD == NULL || PtrTD == NULL) {\r
2279 return ;\r
2280 }\r
2281 //\r
2282 // Depth first fashion\r
2283 //\r
2284 SetTDLinkPtrDepthorBreadth (ptrPreTD, TRUE);\r
2285\r
2286 //\r
2287 // Link pointer pointing to TD struct\r
2288 //\r
2289 SetTDLinkPtrQHorTDSelect (ptrPreTD, FALSE);\r
2290\r
2291 //\r
2292 // Validate the link pointer valid bit\r
2293 //\r
2294 SetTDLinkPtrValidorInvalid (ptrPreTD, TRUE);\r
2295\r
2296 SetTDLinkPtr (ptrPreTD, PtrTD);\r
2297\r
2298 ptrPreTD->ptrNextTD = (VOID *) PtrTD;\r
2299}\r
2300//\r
2301// Transfer Schedule related Helper Functions\r
2302//\r
2303VOID\r
2304SetorClearCurFrameListTerminate (\r
2305 IN FRAMELIST_ENTRY *pCurEntry,\r
2306 IN BOOLEAN IsSet\r
2307 )\r
2308{\r
2309 //\r
2310 // If TRUE, empty the frame. If FALSE, indicate the Pointer field is valid.\r
2311 //\r
2312 pCurEntry->FrameListPtrTerminate = (IsSet ? 1 : 0);\r
2313}\r
2314\r
2315VOID\r
2316SetCurFrameListQHorTD (\r
2317 IN FRAMELIST_ENTRY *pCurEntry,\r
2318 IN BOOLEAN IsQH\r
2319 )\r
2320{\r
2321 //\r
2322 // This bit indicates to the hardware whether the item referenced by the\r
2323 // link pointer is a TD or a QH.\r
2324 //\r
2325 pCurEntry->FrameListPtrQSelect = (IsQH ? 1 : 0);\r
2326}\r
2327\r
2328BOOLEAN\r
2329IsCurFrameListQHorTD (\r
2330 IN FRAMELIST_ENTRY *pCurEntry\r
2331 )\r
2332{\r
2333 //\r
2334 // TRUE is QH\r
2335 // FALSE is TD\r
2336 //\r
2337 return (BOOLEAN) (pCurEntry->FrameListPtrQSelect);\r
2338}\r
2339\r
2340BOOLEAN\r
2341GetCurFrameListTerminate (\r
2342 IN FRAMELIST_ENTRY *pCurEntry\r
2343 )\r
2344{\r
2345 //\r
2346 // TRUE means the frame is empty,\r
2347 // FALSE means the link pointer field is valid.\r
2348 //\r
2349 return (BOOLEAN) (pCurEntry->FrameListPtrTerminate);\r
2350}\r
2351\r
2352VOID\r
2353SetCurFrameListPointer (\r
2354 IN FRAMELIST_ENTRY *pCurEntry,\r
2355 IN UINT8 *ptr\r
2356 )\r
2357{\r
2358 //\r
2359 // Set the pointer field of the frame.\r
2360 //\r
2361 pCurEntry->FrameListPtr = (UINT32) ((UINTN) ptr >> 4);\r
2362}\r
2363\r
2364VOID *\r
2365GetCurFrameListPointer (\r
2366 IN FRAMELIST_ENTRY *pCurEntry\r
2367 )\r
2368{\r
2369 //\r
2370 // Get the link pointer of the frame.\r
2371 //\r
2372 return (VOID *) ((UINTN) (pCurEntry->FrameListPtr << 4));\r
2373\r
2374}\r
2375\r
2376VOID\r
2377LinkQHToFrameList (\r
2378 IN FRAMELIST_ENTRY *pEntry,\r
2379 IN UINT16 FrameListIndex,\r
2380 IN QH_STRUCT *PtrQH\r
2381 )\r
2382/*++\r
2383\r
2384Routine Description:\r
2385\r
2386 Link QH To Frame List\r
2387\r
2388Arguments:\r
2389\r
2390 pEntry - FRAMELIST_ENTRY\r
2391 FrameListIndex - Frame List Index\r
2392 PtrQH - QH to link \r
2393Returns:\r
2394\r
2395 VOID\r
2396\r
2397--*/\r
2398{\r
2399 FRAMELIST_ENTRY *pCurFrame;\r
2400 QH_STRUCT *TempQH;\r
2401 QH_STRUCT *NextTempQH;\r
2402 TD_STRUCT *TempTD;\r
2403 BOOLEAN LINK;\r
2404\r
2405 //\r
2406 // Get frame list entry that the link process will begin from.\r
2407 //\r
2408 pCurFrame = pEntry + FrameListIndex;\r
2409\r
2410 //\r
2411 // if current frame is empty\r
2412 // then link the specified QH directly to the Frame List.\r
2413 //\r
2414 if (GetCurFrameListTerminate (pCurFrame)) {\r
2415 \r
2416 //\r
2417 // Link new QH to the frame list entry.\r
2418 //\r
2419 SetCurFrameListQHorTD (pCurFrame, TRUE);\r
2420\r
2421 SetCurFrameListPointer (pCurFrame, (UINT8 *) PtrQH);\r
2422\r
2423 //\r
2424 // clear T bit in the Frame List, indicating that the frame list entry\r
2425 // is no longer empty.\r
2426 //\r
2427 SetorClearCurFrameListTerminate (pCurFrame, FALSE);\r
2428\r
2429 return ;\r
2430\r
2431 } else {\r
2432 //\r
2433 // current frame list has link pointer\r
2434 //\r
2435 if (!IsCurFrameListQHorTD (pCurFrame)) {\r
2436 //\r
2437 // a TD is linked to the framelist entry\r
2438 //\r
2439 TempTD = (TD_STRUCT *) GetCurFrameListPointer (pCurFrame);\r
2440\r
2441 while (GetTDLinkPtrValidorInvalid (TempTD)) {\r
2442\r
2443 if (IsTDLinkPtrQHOrTD (TempTD)) {\r
2444 //\r
2445 // QH linked next to the TD\r
2446 //\r
2447 break;\r
2448 }\r
2449\r
2450 TempTD = (TD_STRUCT *) GetTDLinkPtr (TempTD);\r
2451 }\r
2452 \r
2453 //\r
2454 // either no ptr linked next to the TD or QH is linked next to the TD\r
2455 //\r
2456 if (!GetTDLinkPtrValidorInvalid (TempTD)) {\r
2457 \r
2458 //\r
2459 // no ptr linked next to the TD\r
2460 //\r
2461 TempTD->ptrNextQH = PtrQH;\r
2462 SetTDLinkPtrQHorTDSelect (TempTD, TRUE);\r
2463 SetTDLinkPtr (TempTD, PtrQH);\r
2464 SetTDLinkPtrValidorInvalid (TempTD, TRUE);\r
2465 return ;\r
2466\r
2467 } else {\r
2468 //\r
2469 // QH is linked next to the TD\r
2470 //\r
2471 TempQH = (QH_STRUCT *) GetTDLinkPtr (TempTD);\r
2472 }\r
2473 } else {\r
2474 //\r
2475 // a QH is linked to the framelist entry\r
2476 //\r
2477 TempQH = (QH_STRUCT *) GetCurFrameListPointer (pCurFrame);\r
2478 }\r
2479 \r
2480 //\r
2481 // Set up Flag\r
2482 //\r
2483 LINK = TRUE;\r
2484\r
2485 //\r
2486 // Avoid the same qh repeated linking in one frame entry\r
2487 //\r
2488 if (TempQH == PtrQH) {\r
2489 LINK = FALSE;\r
2490 return ;\r
2491 }\r
2492 //\r
2493 // if current QH has next QH connected\r
2494 //\r
2495 while (GetQHHorizontalValidorInvalid (TempQH)) {\r
2496 //\r
2497 // Get next QH pointer\r
2498 //\r
2499 NextTempQH = (QH_STRUCT *) GetQHHorizontalLinkPtr (TempQH);\r
2500\r
2501 //\r
2502 // Bulk transfer qh may be self-linked,\r
2503 // so, the code below is to aVOID dead-loop when meeting self-linked qh\r
2504 //\r
2505 if (NextTempQH == TempQH) {\r
2506 LINK = FALSE;\r
2507 break;\r
2508 }\r
2509\r
2510 TempQH = NextTempQH;\r
2511\r
2512 //\r
2513 // Avoid the same qh repeated linking in one frame entry\r
2514 //\r
2515 if (TempQH == PtrQH) {\r
2516 LINK = FALSE;\r
2517 }\r
2518 }\r
2519\r
2520 if (LINK) {\r
2521 TempQH->ptrNext = PtrQH;\r
2522 SetQHHorizontalQHorTDSelect (TempQH, TRUE);\r
2523 SetQHHorizontalLinkPtr (TempQH, PtrQH);\r
2524 SetQHHorizontalValidorInvalid (TempQH, TRUE);\r
2525 }\r
2526\r
2527 return ;\r
2528 }\r
2529}\r
2530\r
2531EFI_STATUS\r
2532ExecuteControlTransfer (\r
2533 IN USB_HC_DEV *HcDev,\r
2534 IN TD_STRUCT *PtrTD,\r
2535 IN UINT32 wIndex,\r
2536 OUT UINTN *ActualLen,\r
2537 IN UINTN TimeOut,\r
2538 OUT UINT32 *TransferResult\r
2539 )\r
2540/*++\r
2541\r
2542Routine Description:\r
2543\r
2544 Execute Control Transfer\r
2545\r
2546Arguments:\r
2547\r
2548 HcDev - USB_HC_DEV\r
2549 PtrTD - TD_STRUCT\r
2550 wIndex - No use\r
2551 ActualLen - Actual transfered Len \r
2552 TimeOut - TimeOut value in milliseconds\r
2553 TransferResult - Transfer result\r
2554Returns:\r
2555\r
2556 EFI_SUCCESS - Sucess\r
2557 EFI_DEVICE_ERROR - Error\r
2558 \r
2559\r
2560--*/\r
2561{\r
2562 UINTN ErrTDPos;\r
2563 UINTN Delay;\r
2564 UINTN RequiredLen;\r
2565 BOOLEAN TransferFinished;\r
2566\r
2567 ErrTDPos = 0;\r
2568 *TransferResult = EFI_USB_NOERROR;\r
2569 RequiredLen = *ActualLen;\r
2570 *ActualLen = 0;\r
2571\r
2572 Delay = (TimeOut * STALL_1_MILLI_SECOND / 50) + 1;\r
2573\r
2574 do {\r
2575 TransferFinished = CheckTDsResults (\r
2576 PtrTD,\r
2577 RequiredLen,\r
2578 TransferResult,\r
2579 &ErrTDPos,\r
2580 ActualLen\r
2581 );\r
2582\r
2583 if (TransferFinished) {\r
2584 break;\r
2585 }\r
2586 \r
2587 //\r
2588 // TD is inactive, which means the control transfer is end.\r
2589 //\r
2590 if ((*TransferResult & EFI_USB_ERR_NOTEXECUTE) != EFI_USB_ERR_NOTEXECUTE) {\r
2591 break;\r
2592 } \r
2593\r
2594 gBS->Stall (50);\r
2595\r
2596 } while (Delay--);\r
2597\r
2598 if (*TransferResult != EFI_USB_NOERROR) {\r
2599 return EFI_DEVICE_ERROR;\r
2600 }\r
2601\r
2602 return EFI_SUCCESS;\r
2603}\r
2604\r
2605EFI_STATUS\r
2606ExecBulkorSyncInterruptTransfer (\r
2607 IN USB_HC_DEV *HcDev,\r
2608 IN TD_STRUCT *PtrTD,\r
2609 IN UINT32 wIndex,\r
2610 OUT UINTN *ActualLen,\r
2611 OUT UINT8 *DataToggle,\r
2612 IN UINTN TimeOut,\r
2613 OUT UINT32 *TransferResult\r
2614 )\r
2615/*++\r
2616\r
2617Routine Description:\r
2618\r
2619 Execute Bulk or SyncInterrupt Transfer\r
2620\r
2621Arguments:\r
2622\r
2623 HcDev - USB_HC_DEV\r
2624 PtrTD - TD_STRUCT\r
2625 wIndex - No use\r
2626 ActualLen - Actual transfered Len \r
2627 DataToggle - Data Toggle\r
2628 TimeOut - TimeOut value in milliseconds\r
2629 TransferResult - Transfer result\r
2630Returns:\r
2631\r
2632 EFI_SUCCESS - Sucess\r
2633 EFI_DEVICE_ERROR - Error\r
2634--*/\r
2635{\r
2636 UINTN ErrTDPos;\r
2637 UINTN ScrollNum;\r
2638 UINTN Delay;\r
2639 UINTN RequiredLen;\r
2640 BOOLEAN TransferFinished;\r
2641\r
2642 ErrTDPos = 0;\r
2643 *TransferResult = EFI_USB_NOERROR;\r
2644 RequiredLen = *ActualLen;\r
2645 *ActualLen = 0;\r
2646\r
2647 Delay = (TimeOut * STALL_1_MILLI_SECOND / 50) + 1;\r
2648\r
2649 do {\r
2650\r
2651 TransferFinished = CheckTDsResults (\r
2652 PtrTD,\r
2653 RequiredLen,\r
2654 TransferResult,\r
2655 &ErrTDPos,\r
2656 ActualLen\r
2657 );\r
2658 \r
2659 if (TransferFinished) {\r
2660 break;\r
2661 }\r
2662 \r
2663 //\r
2664 // TD is inactive, which means bulk or interrupt transfer's end.\r
2665 // \r
2666 if ((*TransferResult & EFI_USB_ERR_NOTEXECUTE) != EFI_USB_ERR_NOTEXECUTE) {\r
2667 break;\r
2668 }\r
2669\r
2670 gBS->Stall (50);\r
2671\r
2672 } while (Delay--);\r
2673\r
2674 //\r
2675 // has error\r
2676 //\r
2677 if (*TransferResult != EFI_USB_NOERROR) {\r
2678 \r
2679 //\r
2680 // scroll the Data Toggle back to the last success TD\r
2681 //\r
2682 ScrollNum = CountTDsNumber (PtrTD) - ErrTDPos;\r
2683 if (ScrollNum & 0x1) {\r
2684 *DataToggle ^= 1;\r
2685 }\r
2686\r
2687 return EFI_DEVICE_ERROR;\r
2688 }\r
2689\r
2690 return EFI_SUCCESS;\r
2691}\r
2692\r
2693VOID\r
2694DelLinkSingleQH (\r
2695 IN USB_HC_DEV *HcDev,\r
2696 IN QH_STRUCT *PtrQH,\r
2697 IN UINT16 FrameListIndex,\r
2698 IN BOOLEAN SearchOther,\r
2699 IN BOOLEAN Delete\r
2700 )\r
2701/*++\r
2702\r
2703Routine Description:\r
2704\r
2705 Unlink from frame list and delete single QH\r
2706Arguments:\r
2707\r
2708 HcDev - USB_HC_DEV\r
2709 PtrQH - QH_STRUCT\r
2710 FrameListIndex - Frame List Index\r
2711 SearchOther - Search Other QH\r
2712 Delete - TRUE is to delete the QH\r
2713Returns:\r
2714 VOID\r
2715--*/\r
2716{\r
2717 FRAMELIST_ENTRY *pCurFrame;\r
2718 UINTN Index;\r
2719 UINTN BeginFrame;\r
2720 UINTN EndFrame;\r
2721 QH_STRUCT *CurrentQH;\r
2722 QH_STRUCT *NextQH;\r
2723 TD_STRUCT *CurrentTD;\r
2724 VOID *PtrPreQH;\r
2725 BOOLEAN Found;\r
2726\r
2727 NextQH = NULL;\r
2728 PtrPreQH = NULL;\r
2729 Found = FALSE;\r
2730\r
2731 if (PtrQH == NULL) {\r
2732 return ;\r
2733 }\r
2734\r
2735 if (SearchOther) {\r
2736 BeginFrame = 0;\r
2737 EndFrame = 1024;\r
2738 } else {\r
2739 BeginFrame = FrameListIndex;\r
2740 EndFrame = FrameListIndex + 1;\r
2741 }\r
2742\r
2743 for (Index = BeginFrame; Index < EndFrame; Index++) {\r
2744\r
2745 pCurFrame = HcDev->FrameListEntry + (Index & 0x3FF);\r
2746\r
2747 if (GetCurFrameListTerminate (pCurFrame)) {\r
2748 //\r
2749 // current frame list is empty,search next frame list entry\r
2750 //\r
2751 continue;\r
2752 }\r
2753\r
2754 if (!IsCurFrameListQHorTD (pCurFrame)) {\r
2755 //\r
2756 // TD linked to current framelist\r
2757 //\r
2758 CurrentTD = (TD_STRUCT *) GetCurFrameListPointer (pCurFrame);\r
2759\r
2760 while (GetTDLinkPtrValidorInvalid (CurrentTD)) {\r
2761\r
2762 if (IsTDLinkPtrQHOrTD (CurrentTD)) {\r
2763 //\r
2764 // QH linked next to the TD,break while ()\r
2765 //\r
2766 break;\r
2767 }\r
2768\r
2769 CurrentTD = (TD_STRUCT *) GetTDLinkPtr (CurrentTD);\r
2770 }\r
2771\r
2772 if (!GetTDLinkPtrValidorInvalid (CurrentTD)) {\r
2773 //\r
2774 // no QH linked next to the last TD,\r
2775 // search next frame list\r
2776 //\r
2777 continue;\r
2778 }\r
2779 \r
2780 //\r
2781 // a QH linked next to the last TD\r
2782 //\r
2783 CurrentQH = (QH_STRUCT *) GetTDLinkPtr (CurrentTD);\r
2784\r
2785 PtrPreQH = CurrentTD;\r
2786\r
2787 } else {\r
2788 //\r
2789 // a QH linked to current framelist\r
2790 //\r
2791 CurrentQH = (QH_STRUCT *) GetCurFrameListPointer (pCurFrame);\r
2792\r
2793 PtrPreQH = NULL;\r
2794 }\r
2795\r
2796 if (CurrentQH == PtrQH) {\r
2797\r
2798 if (GetQHHorizontalValidorInvalid (PtrQH)) {\r
2799 //\r
2800 // there is QH connected after the QH found\r
2801 //\r
2802 //\r
2803 // retrieve nex qh pointer of the qh found.\r
2804 //\r
2805 NextQH = GetQHHorizontalLinkPtr (PtrQH);\r
2806 } else {\r
2807 NextQH = NULL;\r
2808 }\r
2809\r
2810 if (PtrPreQH) {\r
2811 //\r
2812 // QH linked to a TD struct\r
2813 //\r
2814 CurrentTD = (TD_STRUCT *) PtrPreQH;\r
2815\r
2816 SetTDLinkPtrValidorInvalid (CurrentTD, (BOOLEAN) ((NextQH == NULL) ? FALSE : TRUE));\r
2817 SetTDLinkPtr (CurrentTD, NextQH);\r
2818 CurrentTD->ptrNextQH = NextQH;\r
2819\r
2820 } else {\r
2821 //\r
2822 // QH linked directly to current framelist entry\r
2823 //\r
2824 SetorClearCurFrameListTerminate (pCurFrame, (BOOLEAN) ((NextQH == NULL) ? TRUE : FALSE));\r
2825 SetCurFrameListPointer (pCurFrame, (UINT8 *) NextQH);\r
2826 }\r
2827\r
2828 Found = TRUE;\r
2829 //\r
2830 // search next framelist entry\r
2831 //\r
2832 continue;\r
2833 }\r
2834\r
2835 while (GetQHHorizontalValidorInvalid (CurrentQH)) {\r
2836\r
2837 PtrPreQH = CurrentQH;\r
2838 //\r
2839 // Get next horizontal linked QH\r
2840 //\r
2841 CurrentQH = (QH_STRUCT *) GetQHHorizontalLinkPtr (CurrentQH);\r
2842 //\r
2843 // the qh is found\r
2844 //\r
2845 if (CurrentQH == PtrQH) {\r
2846 break;\r
2847 }\r
2848 }\r
2849 \r
2850 //\r
2851 // search next frame list entry\r
2852 //\r
2853 if (CurrentQH != PtrQH) {\r
2854 //\r
2855 // Not find the QH\r
2856 //\r
2857 continue;\r
2858 }\r
2859 //\r
2860 // find the specified qh, then delink it from\r
2861 // the horizontal QH list in the frame entry.\r
2862 //\r
2863 \r
2864 if (GetQHHorizontalValidorInvalid (PtrQH)) {\r
2865 //\r
2866 // there is QH connected after the QH found\r
2867 //\r
2868 //\r
2869 // retrieve nex qh pointer of the qh found.\r
2870 //\r
2871 NextQH = GetQHHorizontalLinkPtr (PtrQH);\r
2872\r
2873 } else {\r
2874 //\r
2875 // NO QH connected after the QH found\r
2876 //\r
2877 NextQH = NULL;\r
2878 //\r
2879 // NULL the previous QH's link ptr and set Terminate field.\r
2880 //\r
2881 SetQHHorizontalValidorInvalid ((QH_STRUCT *) PtrPreQH, FALSE);\r
2882 }\r
2883\r
2884 SetQHHorizontalLinkPtr ((QH_STRUCT *) PtrPreQH, NextQH);\r
2885 ((QH_STRUCT *) PtrPreQH)->ptrNext = NextQH;\r
2886\r
2887 Found = TRUE;\r
2888 }\r
2889\r
2890 if (Found && Delete) {\r
2891 //\r
2892 // free memory once used by the specific QH\r
2893 //\r
2894 UhciFreePool (HcDev, (UINT8 *) PtrQH, sizeof (QH_STRUCT));\r
2895 }\r
2896\r
2897 return ;\r
2898}\r
2899\r
2900\r
2901VOID\r
2902DeleteQueuedTDs (\r
2903 IN USB_HC_DEV *HcDev,\r
2904 IN TD_STRUCT *PtrFirstTD\r
2905 )\r
2906/*++\r
2907Routine Description:\r
2908\r
2909 Delete Queued TDs\r
2910Arguments:\r
2911\r
2912 HcDev - USB_HC_DEV\r
2913 PtrFirstTD - TD link list head\r
2914\r
2915Returns:\r
2916 VOID\r
2917\r
2918--*/\r
2919{\r
2920 TD_STRUCT *Tptr1;\r
2921 TD_STRUCT *Tptr2;\r
2922\r
2923 Tptr1 = PtrFirstTD;\r
2924 //\r
2925 // Delete all the TDs in a queue.\r
2926 //\r
2927 while (Tptr1) {\r
2928\r
2929 Tptr2 = Tptr1;\r
2930\r
2931 if (!GetTDLinkPtrValidorInvalid (Tptr2)) {\r
2932 Tptr1 = NULL;\r
2933 } else {\r
2934\r
2935 Tptr1 = GetTDLinkPtr (Tptr2);\r
2936\r
2937 //\r
2938 // TD link to itself\r
2939 //\r
2940 if (Tptr1 == Tptr2) {\r
2941 Tptr1 = NULL;\r
2942 }\r
2943 }\r
2944\r
2945 UhciFreePool (HcDev, (UINT8 *) Tptr2, sizeof (TD_STRUCT));\r
2946 }\r
2947\r
2948 return ;\r
2949}\r
2950\r
2951VOID\r
2952InsertQHTDToINTList (\r
2953 IN USB_HC_DEV *HcDev,\r
2954 IN QH_STRUCT *PtrQH,\r
2955 IN TD_STRUCT *PtrFirstTD,\r
2956 IN UINT8 DeviceAddress,\r
2957 IN UINT8 EndPointAddress,\r
2958 IN UINT8 DataToggle,\r
2959 IN UINTN DataLength,\r
2960 IN UINTN PollingInterval,\r
2961 IN VOID *Mapping,\r
2962 IN UINT8 *DataBuffer,\r
2963 IN EFI_ASYNC_USB_TRANSFER_CALLBACK CallBackFunction,\r
2964 IN VOID *Context\r
2965 )\r
2966/*++\r
2967Routine Description:\r
2968 Insert QH and TD To Interrupt List\r
2969Arguments:\r
2970\r
2971 HcDev - USB_HC_DEV\r
2972 PtrQH - QH_STRUCT\r
2973 PtrFirstTD - First TD_STRUCT\r
2974 DeviceAddress - Device Address\r
2975 EndPointAddress - EndPoint Address\r
2976 DataToggle - Data Toggle\r
2977 DataLength - Data length \r
2978 PollingInterval - Polling Interval when inserted to frame list\r
2979 Mapping - Mapping alue \r
2980 DataBuffer - Data buffer\r
2981 CallBackFunction- CallBackFunction after interrupt transfeer\r
2982 Context - CallBackFunction Context passed as function parameter\r
2983Returns:\r
2984 EFI_SUCCESS - Sucess\r
2985 EFI_INVALID_PARAMETER - Paremeter is error \r
2986\r
2987--*/\r
2988{\r
2989 INTERRUPT_LIST *Node;\r
2990\r
2991 Node = AllocatePool (sizeof (INTERRUPT_LIST));\r
2992 if (Node == NULL) {\r
2993 return ;\r
2994 }\r
2995 \r
2996 //\r
2997 // Fill Node field\r
2998 //\r
2999 Node->Signature = INTERRUPT_LIST_SIGNATURE;\r
3000 Node->DevAddr = DeviceAddress;\r
3001 Node->EndPoint = EndPointAddress;\r
3002 Node->PtrQH = PtrQH;\r
3003 Node->PtrFirstTD = PtrFirstTD;\r
3004 Node->DataToggle = DataToggle;\r
3005 Node->DataLen = DataLength;\r
3006 Node->PollInterval = PollingInterval;\r
3007 Node->Mapping = Mapping;\r
3008 //\r
3009 // DataBuffer is allocated host memory, not mapped memory\r
3010 //\r
3011 Node->DataBuffer = DataBuffer;\r
3012 Node->InterruptCallBack = CallBackFunction;\r
3013 Node->InterruptContext = Context;\r
3014\r
3015 //\r
3016 // insert the new interrupt transfer to the head of the list.\r
3017 // The interrupt transfer's monitor function scans the whole list from head\r
3018 // to tail. The new interrupt transfer MUST be added to the head of the list\r
3019 // for the sake of error recovery.\r
3020 //\r
3021 InsertHeadList (&(HcDev->InterruptListHead), &(Node->Link));\r
3022\r
3023 return ;\r
3024}\r
3025\r
3026\r
3027EFI_STATUS\r
3028DeleteAsyncINTQHTDs (\r
3029 IN USB_HC_DEV *HcDev,\r
3030 IN UINT8 DeviceAddress,\r
3031 IN UINT8 EndPointAddress,\r
3032 OUT UINT8 *DataToggle\r
3033 )\r
3034/*++\r
3035Routine Description:\r
3036\r
3037 Delete Async INT QH and TDs\r
3038Arguments:\r
3039\r
3040 HcDev - USB_HC_DEV\r
3041 DeviceAddress - Device Address\r
3042 EndPointAddress - EndPoint Address\r
3043 DataToggle - Data Toggle\r
3044\r
3045Returns:\r
3046 EFI_SUCCESS - Sucess\r
3047 EFI_INVALID_PARAMETER - Paremeter is error \r
3048\r
3049--*/\r
3050{\r
3051 QH_STRUCT *MatchQH;\r
3052 QH_STRUCT *ptrNextQH;\r
3053 TD_STRUCT *MatchTD;\r
3054 LIST_ENTRY *Link;\r
3055 INTERRUPT_LIST *MatchList;\r
3056 INTERRUPT_LIST *PtrList;\r
3057 BOOLEAN Found;\r
3058\r
3059 UINT32 Result;\r
3060 UINTN ErrTDPos;\r
3061 UINTN ActualLen;\r
3062\r
3063 MatchQH = NULL;\r
3064 MatchTD = NULL;\r
3065 MatchList = NULL;\r
3066\r
3067 //\r
3068 // no interrupt transaction exists\r
3069 //\r
3070 if (IsListEmpty (&(HcDev->InterruptListHead))) {\r
3071 return EFI_INVALID_PARAMETER;\r
3072 }\r
3073 //\r
3074 // find the correct QH-TD that need to delete\r
3075 // (by matching Device address and EndPoint number to match QH-TD )\r
3076 //\r
3077 Found = FALSE;\r
3078 Link = &(HcDev->InterruptListHead);\r
3079 do {\r
3080\r
3081 Link = Link->ForwardLink;\r
3082 PtrList = INTERRUPT_LIST_FROM_LINK (Link);\r
3083\r
3084 if ((PtrList->DevAddr == DeviceAddress) && ((PtrList->EndPoint & 0x0f) == (EndPointAddress & 0x0f))) {\r
3085 MatchList = PtrList;\r
3086\r
3087 Found = TRUE;\r
3088 break;\r
3089 }\r
3090\r
3091 } while (Link->ForwardLink != &(HcDev->InterruptListHead));\r
3092\r
3093 if (!Found) {\r
3094 return EFI_INVALID_PARAMETER;\r
3095 }\r
3096 //\r
3097 // get current endpoint's data toggle bit and save.\r
3098 //\r
3099 ExecuteAsyncINTTDs (HcDev, MatchList, &Result, &ErrTDPos, &ActualLen);\r
3100 UpdateAsyncINTQHTDs (MatchList, Result, (UINT32) ErrTDPos);\r
3101 *DataToggle = MatchList->DataToggle;\r
3102\r
3103 MatchTD = MatchList->PtrFirstTD;\r
3104 MatchQH = MatchList->PtrQH;\r
3105 //\r
3106 // find the first matching QH position in the FrameList\r
3107 //\r
3108 while (MatchQH) {\r
3109\r
3110 ptrNextQH = MatchQH->ptrNextIntQH;\r
3111\r
3112 //\r
3113 // Search all the entries\r
3114 //\r
3115 DelLinkSingleQH (HcDev, MatchQH, 0, TRUE, TRUE);\r
3116\r
3117 MatchQH = ptrNextQH;\r
3118 }\r
3119 \r
3120 //\r
3121 // Call PciIo->Unmap() to unmap the busmaster read/write\r
3122 //\r
3123 HcDev->PciIo->Unmap (HcDev->PciIo, MatchList->Mapping);\r
3124\r
3125 //\r
3126 // free host data buffer allocated,\r
3127 // mapped data buffer is freed by Unmap\r
3128 //\r
3129 if (MatchList->DataBuffer != NULL) {\r
3130 gBS->FreePool (MatchList->DataBuffer);\r
3131 }\r
3132 \r
3133 //\r
3134 // at last delete the TDs, to aVOID problems\r
3135 //\r
3136 DeleteQueuedTDs (HcDev, MatchTD);\r
3137\r
3138 //\r
3139 // remove Match node from interrupt list\r
3140 //\r
3141 RemoveEntryList (&(MatchList->Link));\r
3142 gBS->FreePool (MatchList);\r
3143 return EFI_SUCCESS;\r
3144}\r
3145\r
3146BOOLEAN\r
3147CheckTDsResults (\r
3148 IN TD_STRUCT *PtrTD,\r
3149 IN UINTN RequiredLen,\r
3150 OUT UINT32 *Result,\r
3151 OUT UINTN *ErrTDPos,\r
3152 OUT UINTN *ActualTransferSize\r
3153 )\r
3154/*++\r
3155\r
3156Routine Description:\r
3157\r
3158 Check TDs Results\r
3159\r
3160Arguments:\r
3161\r
3162 PtrTD - TD_STRUCT to check\r
3163 RequiredLen - Required Len\r
3164 Result - Transfer result\r
3165 ErrTDPos - Error TD Position\r
3166 ActualTransferSize - Actual Transfer Size\r
3167\r
3168Returns:\r
3169\r
3170 TRUE - Sucess\r
3171 FALSE - Fail\r
3172\r
3173--*/\r
3174{\r
3175 UINTN Len;\r
3176\r
3177 *Result = EFI_USB_NOERROR;\r
3178 *ErrTDPos = 0;\r
3179\r
3180 //\r
3181 // Init to zero.\r
3182 //\r
3183 *ActualTransferSize = 0;\r
3184\r
3185 while (PtrTD) {\r
3186\r
3187 if (IsTDStatusActive (PtrTD)) {\r
3188 *Result |= EFI_USB_ERR_NOTEXECUTE;\r
3189 }\r
3190\r
3191 if (IsTDStatusStalled (PtrTD)) {\r
3192 *Result |= EFI_USB_ERR_STALL;\r
3193 }\r
3194\r
3195 if (IsTDStatusBufferError (PtrTD)) {\r
3196 *Result |= EFI_USB_ERR_BUFFER;\r
3197 }\r
3198\r
3199 if (IsTDStatusBabbleError (PtrTD)) {\r
3200 *Result |= EFI_USB_ERR_BABBLE;\r
3201 }\r
3202\r
3203 if (IsTDStatusNAKReceived (PtrTD)) {\r
3204 *Result |= EFI_USB_ERR_NAK;\r
3205 }\r
3206\r
3207 if (IsTDStatusCRCTimeOutError (PtrTD)) {\r
3208 *Result |= EFI_USB_ERR_TIMEOUT;\r
3209 }\r
3210\r
3211 if (IsTDStatusBitStuffError (PtrTD)) {\r
3212 *Result |= EFI_USB_ERR_BITSTUFF;\r
3213 }\r
3214 \r
3215 //\r
3216 // if any error encountered, stop processing the left TDs.\r
3217 //\r
3218 if (*Result) {\r
3219 return FALSE;\r
3220 }\r
3221\r
3222 Len = GetTDStatusActualLength (PtrTD) & 0x7FF;\r
3223 *ActualTransferSize += Len;\r
3224\r
3225 if (*ActualTransferSize <= RequiredLen && Len < PtrTD->TDData.TDTokenMaxLen) {\r
3226 //\r
3227 // transter finished and actural length less than required length\r
3228 //\r
3229 goto Done;\r
3230 }\r
3231 //\r
3232 // Accumulate actual transferred data length in each TD.\r
3233 //\r
3234 PtrTD = (TD_STRUCT *) (PtrTD->ptrNextTD);\r
3235 //\r
3236 // Record the first Error TD's position in the queue,\r
3237 // this value is zero-based.\r
3238 //\r
3239 (*ErrTDPos)++;\r
3240 }\r
3241\r
3242Done:\r
3243 return TRUE;\r
3244}\r
3245\r
3246\r
3247VOID\r
3248ExecuteAsyncINTTDs (\r
3249 IN USB_HC_DEV *HcDev,\r
3250 IN INTERRUPT_LIST *PtrList,\r
3251 OUT UINT32 *Result,\r
3252 OUT UINTN *ErrTDPos,\r
3253 OUT UINTN *ActualLen\r
3254 )\r
3255/*++\r
3256\r
3257Routine Description:\r
3258\r
3259 Execute Async Interrupt TDs\r
3260\r
3261Arguments:\r
3262\r
3263 HcDev - USB_HC_DEV\r
3264 PtrList - INTERRUPT_LIST\r
3265 Result - Transfer result\r
3266 ErrTDPos - Error TD Position\r
3267 ActualTransferSize - Actual Transfer Size\r
3268 \r
3269Returns:\r
3270\r
3271 VOID\r
3272\r
3273--*/\r
3274{\r
3275 //\r
3276 // *ErrTDPos is zero-based value, indicating the first error TD's position\r
3277 // in the TDs' sequence.\r
3278 // *ErrTDPos value is only valid when *Result is not equal NOERROR.\r
3279 //\r
3280 UINTN RequiredLen;\r
3281\r
3282 RequiredLen = *ActualLen;\r
3283 CheckTDsResults (PtrList->PtrFirstTD, RequiredLen, Result, ErrTDPos, ActualLen);\r
3284\r
3285 return ;\r
3286}\r
3287\r
3288\r
3289VOID\r
3290UpdateAsyncINTQHTDs (\r
3291 IN INTERRUPT_LIST *PtrList,\r
3292 IN UINT32 Result,\r
3293 IN UINT32 ErrTDPos\r
3294 )\r
3295/*++\r
3296\r
3297Routine Description:\r
3298\r
3299 Update Async Interrupt QH and TDs\r
3300\r
3301Arguments:\r
3302\r
3303 PtrList - INTERRUPT_LIST\r
3304 Result - Transfer reslut\r
3305 ErrTDPos - Error TD Position\r
3306\r
3307Returns:\r
3308\r
3309 VOID\r
3310\r
3311--*/\r
3312{\r
3313 QH_STRUCT *PtrFirstQH;\r
3314 QH_STRUCT *PtrQH;\r
3315 TD_STRUCT *PtrFirstTD;\r
3316 TD_STRUCT *PtrTD;\r
3317 UINT8 DataToggle;\r
3318 UINT32 Index;\r
3319\r
3320 PtrFirstQH = PtrList->PtrQH;\r
3321 PtrFirstTD = PtrList->PtrFirstTD;\r
3322\r
3323 DataToggle = 0;\r
3324\r
3325 if (Result == EFI_USB_NOERROR) {\r
3326\r
3327 PtrTD = PtrFirstTD;\r
3328 while (PtrTD) {\r
3329 DataToggle = GetTDTokenDataToggle (PtrTD);\r
3330 PtrTD = PtrTD->ptrNextTD;\r
3331 }\r
3332 \r
3333 //\r
3334 // save current DataToggle value to interrupt list.\r
3335 // this value is used for tracing the interrupt endpoint DataToggle.\r
3336 // when this interrupt transfer is deleted, the last DataToggle is saved\r
3337 //\r
3338 PtrList->DataToggle = DataToggle;\r
3339\r
3340 PtrTD = PtrFirstTD;\r
3341\r
3342 //\r
3343 // Since DataToggle bit should toggle after each success transaction,\r
3344 // the First TD's DataToggle bit will be updated to XOR of Last TD's\r
3345 // DataToggle bit. If the First TD's DataToggle bit is not equal Last\r
3346 // TD's DataToggle bit, that means it already be the XOR of Last TD's,\r
3347 // so no update is needed.\r
3348 //\r
3349 if (DataToggle == GetTDTokenDataToggle (PtrFirstTD)) {\r
3350 PtrTD = PtrFirstTD;\r
3351 while (PtrTD) {\r
3352\r
3353 DataToggle ^= 1;\r
3354 if (DataToggle) {\r
3355 SetTDTokenDataToggle1 (PtrTD);\r
3356 } else {\r
3357 SetTDTokenDataToggle0 (PtrTD);\r
3358 }\r
3359\r
3360 PtrTD = PtrTD->ptrNextTD;\r
3361 }\r
3362 }\r
3363 //\r
3364 // restore Link Pointer of QH to First TD\r
3365 // (because QH's Link Pointer will change during TD execution)\r
3366 //\r
3367 PtrQH = PtrFirstQH;\r
3368 while (PtrQH) {\r
3369\r
3370 LinkTDToQH (PtrQH, PtrFirstTD);\r
3371 PtrQH = PtrQH->ptrNextIntQH;\r
3372 }\r
3373 \r
3374 //\r
3375 // set all the TDs active\r
3376 //\r
3377 PtrTD = PtrFirstTD;\r
3378 while (PtrTD) {\r
3379 SetTDStatusActiveorInactive (PtrTD, TRUE);\r
3380 PtrTD = PtrTD->ptrNextTD;\r
3381 }\r
3382\r
3383 } else if (((Result & EFI_USB_ERR_NOTEXECUTE) == EFI_USB_ERR_NOTEXECUTE) ||\r
3384 ((Result & EFI_USB_ERR_NAK) == EFI_USB_ERR_NAK)\r
3385 ) {\r
3386 //\r
3387 // no update\r
3388 //\r
3389 } else {\r
3390 //\r
3391 // Have Errors\r
3392 //\r
3393 PtrTD = PtrFirstTD;\r
3394 //\r
3395 // not first TD error\r
3396 //\r
3397 if (ErrTDPos != 0) {\r
3398 //\r
3399 // get the last success TD\r
3400 //\r
3401 for (Index = 1; Index < ErrTDPos; Index++) {\r
3402 PtrTD = PtrTD->ptrNextTD;\r
3403 }\r
3404 //\r
3405 // update Data Toggle in the interrupt list node\r
3406 //\r
3407 PtrList->DataToggle = GetTDTokenDataToggle (PtrTD);\r
3408\r
3409 //\r
3410 // get the error TD\r
3411 //\r
3412 PtrTD = PtrTD->ptrNextTD;\r
3413\r
3414 } else {\r
3415 PtrList->DataToggle = GetTDTokenDataToggle (PtrTD);\r
3416 }\r
3417 //\r
3418 // do not restore the QH's vertical link pointer,\r
3419 // let the callback function do the rest of error handling.\r
3420 //\r
3421 }\r
3422\r
3423 return ;\r
3424}\r
3425\r
3426VOID\r
3427ReleaseInterruptList (\r
3428 IN USB_HC_DEV *HcDev,\r
3429 IN LIST_ENTRY *ListHead\r
3430 )\r
3431/*++\r
3432\r
3433Routine Description:\r
3434\r
3435 Release Interrupt List\r
3436Arguments:\r
3437\r
3438 HcDev - USB_HC_DEV\r
3439 ListHead - List head\r
3440\r
3441Returns:\r
3442\r
3443 VOID\r
3444\r
3445--*/\r
3446{\r
3447 LIST_ENTRY *Link;\r
3448 LIST_ENTRY *SavedLink;\r
3449 INTERRUPT_LIST *pNode;\r
3450 TD_STRUCT *PtrTD;\r
3451 TD_STRUCT *ptrNextTD;\r
3452 QH_STRUCT *PtrQH;\r
3453 QH_STRUCT *SavedQH;\r
3454\r
3455 if (ListHead == NULL) {\r
3456 return ;\r
3457 }\r
3458\r
3459 Link = ListHead;\r
3460\r
3461 //\r
3462 // Free all the resources in the interrupt list\r
3463 //\r
3464 SavedLink = Link->ForwardLink;\r
3465 while (!IsListEmpty (ListHead)) {\r
3466\r
3467 Link = SavedLink;\r
3468\r
3469 SavedLink = Link->ForwardLink;\r
3470\r
3471 pNode = INTERRUPT_LIST_FROM_LINK (Link);\r
3472\r
3473 RemoveEntryList (&pNode->Link);\r
3474\r
3475 SavedQH = pNode->PtrQH;\r
3476 for (PtrQH = SavedQH; PtrQH != NULL; PtrQH = SavedQH) {\r
3477 SavedQH = PtrQH->ptrNextIntQH;\r
3478 UhciFreePool (HcDev, (UINT8 *) PtrQH, sizeof (QH_STRUCT));\r
3479 }\r
3480\r
3481 PtrTD = pNode->PtrFirstTD;\r
3482 while (PtrTD != NULL) {\r
3483\r
3484 ptrNextTD = PtrTD->ptrNextTD;\r
3485 UhciFreePool (HcDev, (UINT8 *) PtrTD, sizeof (TD_STRUCT));\r
3486 PtrTD = ptrNextTD;\r
3487 }\r
3488\r
3489 gBS->FreePool (pNode);\r
3490 }\r
3491}\r
3492\r
3493\r
3494EFI_STATUS\r
3495InitializeMemoryManagement (\r
3496 IN USB_HC_DEV *HcDev\r
3497 )\r
3498/*++\r
3499\r
3500Routine Description:\r
3501\r
3502 Initialize Memory Management\r
3503\r
3504Arguments:\r
3505\r
3506 HcDev - USB_HC_DEV\r
3507\r
3508Returns:\r
3509\r
3510 EFI_SUCCESS - Success\r
3511--*/\r
3512{\r
3513 MEMORY_MANAGE_HEADER *MemoryHeader;\r
3514 EFI_STATUS Status;\r
3515 UINTN MemPages;\r
3516\r
3517 MemPages = NORMAL_MEMORY_BLOCK_UNIT_IN_PAGES;\r
3518 Status = CreateMemoryBlock (HcDev, &MemoryHeader, MemPages);\r
3519 if (EFI_ERROR (Status)) {\r
3520 return Status;\r
3521 }\r
3522\r
3523 HcDev->MemoryHeader = MemoryHeader;\r
3524\r
3525 return EFI_SUCCESS;\r
3526}\r
3527\r
3528EFI_STATUS\r
3529CreateMemoryBlock (\r
3530 IN USB_HC_DEV *HcDev,\r
3531 OUT MEMORY_MANAGE_HEADER **MemoryHeader,\r
3532 IN UINTN MemoryBlockSizeInPages\r
3533 )\r
3534/*++\r
3535\r
3536Routine Description:\r
3537\r
3538 Use PciIo->AllocateBuffer to allocate common buffer for the memory block,\r
3539 and use PciIo->Map to map the common buffer for Bus Master Read/Write.\r
3540\r
3541\r
3542Arguments:\r
3543\r
3544 HcDev - USB_HC_DEV\r
3545 MemoryHeader - MEMORY_MANAGE_HEADER to output\r
3546 MemoryBlockSizeInPages - MemoryBlockSizeInPages\r
3547Returns:\r
3548\r
3549 EFI_SUCCESS - Success\r
3550--*/\r
3551{\r
3552 EFI_STATUS Status;\r
3553 VOID *CommonBuffer;\r
3554 EFI_PHYSICAL_ADDRESS MappedAddress;\r
3555 UINTN MemoryBlockSizeInBytes;\r
3556 VOID *Mapping;\r
3557\r
3558 //\r
3559 // Allocate memory for MemoryHeader\r
3560 //\r
3561 *MemoryHeader = AllocateZeroPool (sizeof (MEMORY_MANAGE_HEADER));\r
3562 if (*MemoryHeader == NULL) {\r
3563 return EFI_OUT_OF_RESOURCES;\r
3564 }\r
3565\r
3566 (*MemoryHeader)->Next = NULL;\r
3567\r
3568 //\r
3569 // set Memory block size\r
3570 //\r
3571 (*MemoryHeader)->MemoryBlockSizeInBytes = EFI_PAGES_TO_SIZE (MemoryBlockSizeInPages);\r
3572\r
3573 //\r
3574 // each bit in Bit Array will manage 32 bytes memory in memory block\r
3575 //\r
3576 (*MemoryHeader)->BitArraySizeInBytes = ((*MemoryHeader)->MemoryBlockSizeInBytes / 32) / 8;\r
3577\r
3578 //\r
3579 // Allocate memory for BitArray\r
3580 //\r
3581 (*MemoryHeader)->BitArrayPtr = AllocateZeroPool ((*MemoryHeader)->BitArraySizeInBytes);\r
3582 if ((*MemoryHeader)->BitArrayPtr == NULL) {\r
3583 gBS->FreePool (*MemoryHeader);\r
3584 return EFI_OUT_OF_RESOURCES;\r
3585 }\r
3586 \r
3587 //\r
3588 // Memory Block uses MemoryBlockSizeInPages pages,\r
3589 // and it is allocated as common buffer use.\r
3590 //\r
3591 Status = HcDev->PciIo->AllocateBuffer (\r
562d2849 3592 HcDev->PciIo,\r
3593 AllocateAnyPages,\r
3594 EfiBootServicesData,\r
3595 MemoryBlockSizeInPages,\r
3596 &CommonBuffer,\r
3597 0\r
3598 );\r
878ddf1f 3599 if (EFI_ERROR (Status)) {\r
3600 gBS->FreePool ((*MemoryHeader)->BitArrayPtr);\r
3601 gBS->FreePool (*MemoryHeader);\r
3602 return Status;\r
3603 }\r
3604\r
3605 MemoryBlockSizeInBytes = EFI_PAGES_TO_SIZE (MemoryBlockSizeInPages);\r
3606 Status = HcDev->PciIo->Map (\r
562d2849 3607 HcDev->PciIo,\r
3608 EfiPciIoOperationBusMasterCommonBuffer,\r
3609 CommonBuffer,\r
3610 &MemoryBlockSizeInBytes,\r
3611 &MappedAddress,\r
3612 &Mapping\r
3613 );\r
878ddf1f 3614 //\r
3615 // if returned Mapped size is less than the size we request,do not support.\r
3616 //\r
3617 if (EFI_ERROR (Status) || (MemoryBlockSizeInBytes != EFI_PAGES_TO_SIZE (MemoryBlockSizeInPages))) {\r
3618 HcDev->PciIo->FreeBuffer (HcDev->PciIo, MemoryBlockSizeInPages, CommonBuffer);\r
3619 gBS->FreePool ((*MemoryHeader)->BitArrayPtr);\r
3620 gBS->FreePool (*MemoryHeader);\r
3621 return EFI_UNSUPPORTED;\r
3622 }\r
3623 //\r
3624 // Set Memory block initial address\r
3625 //\r
3626 (*MemoryHeader)->MemoryBlockPtr = (UINT8 *) ((UINTN) MappedAddress);\r
3627 (*MemoryHeader)->Mapping = Mapping;\r
3628\r
3629 ZeroMem (\r
3630 (*MemoryHeader)->MemoryBlockPtr,\r
3631 EFI_PAGES_TO_SIZE (MemoryBlockSizeInPages)\r
3632 );\r
3633\r
3634 return EFI_SUCCESS;\r
3635}\r
3636\r
3637EFI_STATUS\r
3638FreeMemoryHeader (\r
3639 IN USB_HC_DEV *HcDev,\r
3640 IN MEMORY_MANAGE_HEADER *MemoryHeader\r
3641 )\r
3642/*++\r
3643\r
3644Routine Description:\r
3645\r
3646 Free Memory Header\r
3647\r
3648Arguments:\r
3649\r
3650 HcDev - USB_HC_DEV\r
3651 MemoryHeader - MemoryHeader to be freed\r
3652\r
3653Returns:\r
3654\r
3655 EFI_INVALID_PARAMETER - Parameter is error\r
3656 EFI_SUCCESS - Success\r
3657\r
3658--*/\r
3659{\r
3660 if ((MemoryHeader == NULL) || (HcDev == NULL)) {\r
3661 return EFI_INVALID_PARAMETER;\r
3662 }\r
3663 //\r
3664 // unmap the common buffer used by the memory block\r
3665 //\r
3666 HcDev->PciIo->Unmap (HcDev->PciIo, MemoryHeader->Mapping);\r
3667\r
3668 //\r
3669 // free common buffer\r
3670 //\r
3671 HcDev->PciIo->FreeBuffer (\r
3672 HcDev->PciIo,\r
3673 EFI_SIZE_TO_PAGES (MemoryHeader->MemoryBlockSizeInBytes),\r
3674 MemoryHeader->MemoryBlockPtr\r
3675 );\r
3676 //\r
3677 // free bit array\r
3678 //\r
3679 gBS->FreePool (MemoryHeader->BitArrayPtr);\r
3680 //\r
3681 // free memory header\r
3682 //\r
3683 gBS->FreePool (MemoryHeader);\r
3684\r
3685 return EFI_SUCCESS;\r
3686}\r
3687\r
3688EFI_STATUS\r
3689UhciAllocatePool (\r
3690 IN USB_HC_DEV *HcDev,\r
3691 OUT UINT8 **Pool,\r
3692 IN UINTN AllocSize\r
3693 )\r
3694/*++\r
3695\r
3696Routine Description:\r
3697\r
3698 Uhci Allocate Pool\r
3699\r
3700Arguments:\r
3701\r
3702 HcDev - USB_HC_DEV\r
3703 Pool - Place to store pointer to the memory buffer\r
3704 AllocSize - Alloc Size\r
3705\r
3706Returns:\r
3707\r
3708 EFI_SUCCESS - Success\r
3709\r
3710--*/\r
3711{\r
3712 MEMORY_MANAGE_HEADER *MemoryHeader;\r
3713 MEMORY_MANAGE_HEADER *TempHeaderPtr;\r
3714 MEMORY_MANAGE_HEADER *NewMemoryHeader;\r
3715 UINTN RealAllocSize;\r
3716 UINTN MemoryBlockSizeInPages;\r
3717 EFI_STATUS Status;\r
3718\r
3719 *Pool = NULL;\r
3720\r
3721 MemoryHeader = HcDev->MemoryHeader;\r
3722 ASSERT (MemoryHeader != NULL);\r
3723\r
3724 //\r
3725 // allocate unit is 32 bytes (align on 32 byte)\r
3726 //\r
3727 if (AllocSize & 0x1F) {\r
3728 RealAllocSize = (AllocSize / 32 + 1) * 32;\r
3729 } else {\r
3730 RealAllocSize = AllocSize;\r
3731 }\r
3732 \r
3733 //\r
3734 // There may be linked MemoryHeaders.\r
3735 // To allocate a free pool in Memory blocks,\r
3736 // must search in the MemoryHeader link list\r
3737 // until enough free pool is found.\r
3738 //\r
3739 Status = EFI_NOT_FOUND;\r
3740 for (TempHeaderPtr = MemoryHeader; TempHeaderPtr != NULL;\r
3741 TempHeaderPtr = TempHeaderPtr->Next) {\r
3742\r
3743 Status = AllocMemInMemoryBlock (\r
562d2849 3744 TempHeaderPtr,\r
3745 (VOID **) Pool,\r
3746 RealAllocSize / 32\r
3747 );\r
878ddf1f 3748 if (!EFI_ERROR (Status)) {\r
3749 ZeroMem (*Pool, AllocSize);\r
3750 return EFI_SUCCESS;\r
3751 }\r
3752 }\r
3753 \r
3754 //\r
3755 // There is no enough memory,\r
3756 // Create a new Memory Block\r
3757 //\r
3758 \r
3759 //\r
3760 // if pool size is larger than NORMAL_MEMORY_BLOCK_UNIT_IN_PAGES,\r
3761 // just allocate a large enough memory block.\r
3762 //\r
3763 if (RealAllocSize > EFI_PAGES_TO_SIZE (NORMAL_MEMORY_BLOCK_UNIT_IN_PAGES)) {\r
3764 MemoryBlockSizeInPages = EFI_SIZE_TO_PAGES (RealAllocSize) + 1;\r
3765 } else {\r
3766 MemoryBlockSizeInPages = NORMAL_MEMORY_BLOCK_UNIT_IN_PAGES;\r
3767 }\r
3768\r
3769 Status = CreateMemoryBlock (HcDev, &NewMemoryHeader, MemoryBlockSizeInPages);\r
3770 if (EFI_ERROR (Status)) {\r
3771 return Status;\r
3772 }\r
3773 \r
3774 //\r
3775 // Link the new Memory Block to the Memory Header list\r
3776 //\r
3777 InsertMemoryHeaderToList (MemoryHeader, NewMemoryHeader);\r
3778\r
3779 Status = AllocMemInMemoryBlock (\r
562d2849 3780 NewMemoryHeader,\r
3781 (VOID **) Pool,\r
3782 RealAllocSize / 32\r
3783 );\r
878ddf1f 3784\r
3785 if (!EFI_ERROR (Status)) {\r
3786 ZeroMem (*Pool, AllocSize);\r
3787 }\r
3788\r
3789 return Status;\r
3790}\r
3791\r
3792VOID\r
3793UhciFreePool (\r
3794 IN USB_HC_DEV *HcDev,\r
3795 IN UINT8 *Pool,\r
3796 IN UINTN AllocSize\r
3797 )\r
3798/*++\r
3799\r
3800Routine Description:\r
3801\r
3802 Uhci Free Pool\r
3803\r
3804Arguments:\r
3805\r
3806 HcDev - USB_HC_DEV\r
3807 Pool - Pool to free\r
3808 AllocSize - Pool size\r
3809\r
3810Returns:\r
3811\r
3812 VOID\r
3813\r
3814--*/\r
3815{\r
3816 MEMORY_MANAGE_HEADER *MemoryHeader;\r
3817 MEMORY_MANAGE_HEADER *TempHeaderPtr;\r
3818 UINTN StartBytePos;\r
3819 UINTN Index;\r
3820 UINT8 StartBitPos;\r
3821 UINT8 Index2;\r
3822 UINTN Count;\r
3823 UINTN RealAllocSize;\r
3824\r
3825 MemoryHeader = HcDev->MemoryHeader;\r
3826\r
3827 //\r
3828 // allocate unit is 32 byte (align on 32 byte)\r
3829 //\r
3830 if (AllocSize & 0x1F) {\r
3831 RealAllocSize = (AllocSize / 32 + 1) * 32;\r
3832 } else {\r
3833 RealAllocSize = AllocSize;\r
3834 }\r
3835 //\r
3836 // scan the memory header linked list for\r
3837 // the asigned memory to free.\r
3838 //\r
3839 for (TempHeaderPtr = MemoryHeader;TempHeaderPtr != NULL;\r
3840 TempHeaderPtr = TempHeaderPtr->Next) {\r
3841\r
3842 if ((Pool >= TempHeaderPtr->MemoryBlockPtr) &&\r
3843 ((Pool + RealAllocSize) <= (TempHeaderPtr->MemoryBlockPtr + TempHeaderPtr->MemoryBlockSizeInBytes))\r
3844 ) {\r
3845 //\r
3846 // Pool is in the Memory Block area,\r
3847 // find the start byte and bit in the bit array\r
3848 //\r
3849 StartBytePos = ((Pool - TempHeaderPtr->MemoryBlockPtr) / 32) / 8;\r
3850 StartBitPos = (UINT8) (((Pool - TempHeaderPtr->MemoryBlockPtr) / 32) & 0x7);\r
3851\r
3852 //\r
3853 // reset associated bits in bit arry\r
3854 //\r
3855 for (Index = StartBytePos, Index2 = StartBitPos, Count = 0; Count < (RealAllocSize / 32); Count++) {\r
3856\r
3857 TempHeaderPtr->BitArrayPtr[Index] ^= (UINT8) (bit (Index2));\r
3858 Index2++;\r
3859 if (Index2 == 8) {\r
3860 Index += 1;\r
3861 Index2 = 0;\r
3862 }\r
3863 }\r
3864 //\r
3865 // break the loop\r
3866 //\r
3867 break;\r
3868 }\r
3869 }\r
3870 \r
3871 //\r
3872 // Release emptied memory blocks (only if the memory block is not\r
3873 // the first one in the memory header list\r
3874 //\r
3875 for (TempHeaderPtr = MemoryHeader->Next; TempHeaderPtr != NULL;) {\r
3876 //\r
3877 // Debug\r
3878 //\r
3879 ASSERT (MemoryHeader->Next != NULL);\r
3880\r
3881 if (IsMemoryBlockEmptied (TempHeaderPtr)) {\r
3882\r
3883 DelinkMemoryBlock (MemoryHeader, TempHeaderPtr);\r
3884 //\r
3885 // when the TempHeaderPtr is freed in FreeMemoryHeader(),\r
3886 // the TempHeaderPtr is pointing to nonsense content.\r
3887 //\r
3888 FreeMemoryHeader (HcDev, TempHeaderPtr);\r
3889 //\r
3890 // reset the TempHeaderPtr, continue search for\r
3891 // another empty memory block.\r
3892 //\r
3893 TempHeaderPtr = MemoryHeader->Next;\r
3894 continue;\r
3895 }\r
3896\r
3897 TempHeaderPtr = TempHeaderPtr->Next;\r
3898 }\r
3899}\r
3900\r
3901VOID\r
3902InsertMemoryHeaderToList (\r
3903 IN MEMORY_MANAGE_HEADER *MemoryHeader,\r
3904 IN MEMORY_MANAGE_HEADER *NewMemoryHeader\r
3905 )\r
3906/*++\r
3907\r
3908Routine Description:\r
3909\r
3910 Insert Memory Header To List\r
3911\r
3912Arguments:\r
3913\r
3914 MemoryHeader - MEMORY_MANAGE_HEADER\r
3915 NewMemoryHeader - MEMORY_MANAGE_HEADER\r
3916\r
3917Returns:\r
3918\r
3919 VOID\r
3920\r
3921--*/\r
3922{\r
3923 MEMORY_MANAGE_HEADER *TempHeaderPtr;\r
3924\r
3925 for (TempHeaderPtr = MemoryHeader; TempHeaderPtr != NULL;\r
3926 TempHeaderPtr = TempHeaderPtr->Next) {\r
3927 if (TempHeaderPtr->Next == NULL) {\r
3928 TempHeaderPtr->Next = NewMemoryHeader;\r
3929 break;\r
3930 }\r
3931 }\r
3932}\r
3933\r
3934EFI_STATUS\r
3935AllocMemInMemoryBlock (\r
3936 IN MEMORY_MANAGE_HEADER *MemoryHeader,\r
3937 OUT VOID **Pool,\r
3938 IN UINTN NumberOfMemoryUnit\r
3939 )\r
3940/*++\r
3941\r
3942Routine Description:\r
3943\r
3944 Alloc Memory In MemoryBlock\r
3945\r
3946Arguments:\r
3947\r
3948 MemoryHeader - MEMORY_MANAGE_HEADER\r
3949 Pool - Place to store pointer to memory\r
3950 NumberOfMemoryUnit - Number Of Memory Unit\r
3951\r
3952Returns:\r
3953\r
3954 EFI_NOT_FOUND - Can't find the free memory \r
3955 EFI_SUCCESS - Success\r
3956\r
3957--*/\r
3958{\r
3959 UINTN TempBytePos;\r
3960 UINTN FoundBytePos;\r
3961 UINT8 Index;\r
3962 UINT8 FoundBitPos;\r
3963 UINT8 ByteValue;\r
3964 UINT8 BitValue;\r
3965 UINTN NumberOfZeros;\r
3966 UINTN Count;\r
3967\r
3968 FoundBytePos = 0;\r
3969 FoundBitPos = 0;\r
3970 ByteValue = MemoryHeader->BitArrayPtr[0];\r
3971 NumberOfZeros = 0;\r
3972 Index = 0;\r
3973\r
3974 for (TempBytePos = 0; TempBytePos < MemoryHeader->BitArraySizeInBytes;) {\r
3975 \r
3976 //\r
3977 // Pop out BitValue from a byte in TempBytePos.\r
3978 //\r
3979 BitValue = (UINT8) (ByteValue & 0x1);\r
3980 //\r
3981 // right shift the byte\r
3982 //\r
3983 ByteValue /= 2;\r
3984\r
3985 if (BitValue == 0) {\r
3986 //\r
3987 // Found a free bit, the NumberOfZeros only record the number\r
3988 // of those consecutive zeros\r
3989 //\r
3990 NumberOfZeros++;\r
3991 //\r
3992 // Found enough consecutive free space, break the loop\r
3993 //\r
3994 if (NumberOfZeros >= NumberOfMemoryUnit) {\r
3995 break;\r
3996 }\r
3997 } else {\r
3998 //\r
3999 // Encountering a '1', meant the bit is ocupied.\r
4000 //\r
4001 if (NumberOfZeros >= NumberOfMemoryUnit) {\r
4002 //\r
4003 // Found enough consecutive free space,break the loop\r
4004 //\r
4005 break;\r
4006 } else {\r
4007 //\r
4008 // the NumberOfZeros only record the number of those consecutive zeros,\r
4009 // so reset the NumberOfZeros to 0 when encountering '1' before finding\r
4010 // enough consecutive '0's\r
4011 //\r
4012 NumberOfZeros = 0;\r
4013 //\r
4014 // reset the (FoundBytePos,FoundBitPos) to the position of '1'\r
4015 //\r
4016 FoundBytePos = TempBytePos;\r
4017 FoundBitPos = Index;\r
4018 }\r
4019 }\r
4020 //\r
4021 // step forward a bit\r
4022 //\r
4023 Index++;\r
4024 if (Index == 8) {\r
4025 //\r
4026 // step forward a byte, getting the byte value,\r
4027 // and reset the bit pos.\r
4028 //\r
4029 TempBytePos += 1;\r
4030 ByteValue = MemoryHeader->BitArrayPtr[TempBytePos];\r
4031 Index = 0;\r
4032 }\r
4033 }\r
4034\r
4035 if (NumberOfZeros < NumberOfMemoryUnit) {\r
4036 return EFI_NOT_FOUND;\r
4037 }\r
4038 \r
4039 //\r
4040 // Found enough free space.\r
4041 //\r
4042 \r
4043 //\r
4044 // The values recorded in (FoundBytePos,FoundBitPos) have two conditions:\r
4045 // 1)(FoundBytePos,FoundBitPos) record the position\r
4046 // of the last '1' before the consecutive '0's, it must\r
4047 // be adjusted to the start position of the consecutive '0's.\r
4048 // 2)the start address of the consecutive '0's is just the start of\r
4049 // the bitarray. so no need to adjust the values of\r
4050 // (FoundBytePos,FoundBitPos).\r
4051 //\r
4052 if ((MemoryHeader->BitArrayPtr[0] & bit (0)) != 0) {\r
4053 FoundBitPos += 1;\r
4054 }\r
4055 \r
4056 //\r
4057 // Have the (FoundBytePos,FoundBitPos) make sense.\r
4058 //\r
4059 if (FoundBitPos > 7) {\r
4060 FoundBytePos += 1;\r
4061 FoundBitPos -= 8;\r
4062 }\r
4063 \r
4064 //\r
4065 // Set the memory as allocated\r
4066 //\r
4067 for (TempBytePos = FoundBytePos, Index = FoundBitPos,Count = 0;\r
4068 Count < NumberOfMemoryUnit; Count ++) {\r
4069\r
4070 MemoryHeader->BitArrayPtr[TempBytePos] |= bit (Index);\r
4071 Index++;\r
4072 if (Index == 8) {\r
4073 TempBytePos += 1;\r
4074 Index = 0;\r
4075 }\r
4076 }\r
4077\r
4078 *Pool = MemoryHeader->MemoryBlockPtr + (FoundBytePos * 8 + FoundBitPos) * 32;\r
4079\r
4080 return EFI_SUCCESS;\r
4081}\r
4082\r
4083BOOLEAN\r
4084IsMemoryBlockEmptied (\r
4085 IN MEMORY_MANAGE_HEADER *MemoryHeaderPtr\r
4086 )\r
4087/*++\r
4088\r
4089Routine Description:\r
4090\r
4091 Is Memory Block Emptied\r
4092\r
4093Arguments:\r
4094\r
4095 MemoryHeaderPtr - MEMORY_MANAGE_HEADER\r
4096\r
4097Returns:\r
4098\r
4099 TRUE - Empty\r
4100 FALSE - Not Empty \r
4101\r
4102--*/\r
4103{\r
4104 UINTN Index;\r
4105\r
4106 for (Index = 0; Index < MemoryHeaderPtr->BitArraySizeInBytes; Index++) {\r
4107 if (MemoryHeaderPtr->BitArrayPtr[Index] != 0) {\r
4108 return FALSE;\r
4109 }\r
4110 }\r
4111\r
4112 return TRUE;\r
4113}\r
4114\r
4115VOID\r
4116DelinkMemoryBlock (\r
4117 IN MEMORY_MANAGE_HEADER *FirstMemoryHeader,\r
4118 IN MEMORY_MANAGE_HEADER *NeedFreeMemoryHeader\r
4119 )\r
4120/*++\r
4121\r
4122Routine Description:\r
4123\r
4124 Delink Memory Block\r
4125\r
4126Arguments:\r
4127\r
4128 FirstMemoryHeader - MEMORY_MANAGE_HEADER\r
4129 NeedFreeMemoryHeader - MEMORY_MANAGE_HEADER\r
4130\r
4131Returns:\r
4132\r
4133 VOID\r
4134\r
4135--*/\r
4136{\r
4137 MEMORY_MANAGE_HEADER *TempHeaderPtr;\r
4138\r
4139 if ((FirstMemoryHeader == NULL) || (NeedFreeMemoryHeader == NULL)) {\r
4140 return ;\r
4141 }\r
4142 for (TempHeaderPtr = FirstMemoryHeader; TempHeaderPtr != NULL;\r
4143 TempHeaderPtr = TempHeaderPtr->Next) {\r
4144\r
4145 if (TempHeaderPtr->Next == NeedFreeMemoryHeader) {\r
4146 //\r
4147 // Link the before and after\r
4148 //\r
4149 TempHeaderPtr->Next = NeedFreeMemoryHeader->Next;\r
4150 break;\r
4151 }\r
4152 }\r
4153}\r
4154\r
4155EFI_STATUS\r
4156DelMemoryManagement (\r
4157 IN USB_HC_DEV *HcDev\r
4158 )\r
4159/*++\r
4160\r
4161Routine Description:\r
4162\r
4163 Delete Memory Management\r
4164\r
4165Arguments:\r
4166\r
4167 HcDev - USB_HC_DEV\r
4168\r
4169Returns:\r
4170\r
4171 EFI_SUCCESS - Success\r
4172\r
4173--*/\r
4174{\r
4175 MEMORY_MANAGE_HEADER *TempHeaderPtr;\r
4176\r
4177 for (TempHeaderPtr = HcDev->MemoryHeader->Next; TempHeaderPtr != NULL;) {\r
4178\r
4179 DelinkMemoryBlock (HcDev->MemoryHeader, TempHeaderPtr);\r
4180 //\r
4181 // when the TempHeaderPtr is freed in FreeMemoryHeader(),\r
4182 // the TempHeaderPtr is pointing to nonsense content.\r
4183 //\r
4184 FreeMemoryHeader (HcDev, TempHeaderPtr);\r
4185 //\r
4186 // reset the TempHeaderPtr,continue free another memory block.\r
4187 //\r
4188 TempHeaderPtr = HcDev->MemoryHeader->Next;\r
4189 }\r
4190\r
4191 FreeMemoryHeader (HcDev, HcDev->MemoryHeader);\r
4192\r
4193 return EFI_SUCCESS;\r
4194}\r
4195\r
4196\r
4197VOID\r
4198CleanUsbTransactions (\r
4199 IN USB_HC_DEV *HcDev\r
4200 )\r
4201{\r
4202 //\r
4203 // only asynchronous interrupt transfers are always alive on the bus\r
4204 //\r
4205 ReleaseInterruptList (HcDev, &(HcDev->InterruptListHead));\r
4206}\r
4207\r
4208VOID\r
4209TurnOffUSBEmulation (\r
4210 IN EFI_PCI_IO_PROTOCOL *PciIo\r
4211 )\r
4212/*++\r
4213 \r
4214 Routine Description:\r
4215 Disable USB Emulation\r
4216 Arguments:\r
4217 PciIo - EFI_PCI_IO_PROTOCOL\r
4218 Returns:\r
4219 VOID\r
4220--*/\r
4221{\r
4222 UINT16 Command;\r
4223\r
4224 //\r
4225 // Disable USB Emulation\r
4226 //\r
4227 Command = 0;\r
4228 PciIo->Pci.Write (\r
562d2849 4229 PciIo,\r
4230 EfiPciIoWidthUint16,\r
4231 USB_EMULATION,\r
4232 1,\r
4233 &Command\r
4234 );\r
878ddf1f 4235\r
4236 return ;\r
4237}\r