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