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