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