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
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.
25 InitialPeriodicFrameList (
26 IN USB2_HC_DEV
*HcDev
,
33 Initialize Periodic Schedule Frame List
38 Length - Frame List Length
49 EFI_PHYSICAL_ADDRESS FrameBuffer
;
51 UINTN BufferSizeInPages
;
52 UINTN BufferSizeInBytes
;
54 FRAME_LIST_ENTRY
*FrameEntryPtr
;
57 // The Frame List is a common buffer that will be
58 // accessed by both the cpu and the usb bus master
60 // The Frame List ocupies 4K bytes,
61 // and must be aligned on 4-Kbyte boundaries.
63 if (EHCI_MAX_FRAME_LIST_LENGTH
!= Length
&& IsFrameListProgrammable (HcDev
)) {
64 Status
= SetFrameListLen (HcDev
, Length
);
65 if (EFI_ERROR (Status
)) {
66 Status
= EFI_INVALID_PARAMETER
;
71 BufferSizeInBytes
= EFI_PAGE_SIZE
;
72 BufferSizeInPages
= EFI_SIZE_TO_PAGES (BufferSizeInBytes
);
73 Status
= HcDev
->PciIo
->AllocateBuffer (
81 if (EFI_ERROR (Status
)) {
82 DEBUG ((gEHCErrorLevel
, "PciIo->AllocateBuffer Failed\n"));
83 Status
= EFI_OUT_OF_RESOURCES
;
87 Status
= HcDev
->PciIo
->Map (
89 EfiPciIoOperationBusMasterCommonBuffer
,
95 if (EFI_ERROR (Status
) || (BufferSizeInBytes
!= EFI_PAGE_SIZE
)) {
96 DEBUG ((gEHCErrorLevel
, "PciIo->MapBuffer Failed\n"));
97 Status
= EFI_OUT_OF_RESOURCES
;
102 // Put high 32bit into CtrlDataStructSeg reg
103 // when 64bit addressing range capability
105 if (HcDev
->Is64BitCapable
!= 0) {
106 HcDev
->High32BitAddr
= (UINT32
) GET_32B_TO_63B (FrameBuffer
);
108 Status
= SetCtrlDataStructSeg (HcDev
);
109 if (EFI_ERROR (Status
)) {
110 DEBUG ((gEHCErrorLevel
, "SetCtrlDataStructSeg Failed\n"));
111 Status
= EFI_DEVICE_ERROR
;
117 // Tell the Host Controller where the Frame List lies,
118 // by set the Frame List Base Address Register.
120 Status
= SetFrameListBaseAddr (HcDev
, (UINT32
) FrameBuffer
);
121 if (EFI_ERROR (Status
)) {
122 Status
= EFI_DEVICE_ERROR
;
126 HcDev
->PeriodicFrameListLength
= Length
;
127 HcDev
->PeriodicFrameListBuffer
= (VOID
*) ((UINTN
) FrameBuffer
);
128 HcDev
->PeriodicFrameListMap
= Map
;
131 // Init Frame List Array fields
133 FrameEntryPtr
= (FRAME_LIST_ENTRY
*) HcDev
->PeriodicFrameListBuffer
;
134 for (FrameIndex
= 0; FrameIndex
< HcDev
->PeriodicFrameListLength
; FrameIndex
++) {
135 FrameEntryPtr
->LinkPointer
= 0;
136 FrameEntryPtr
->Rsvd
= 0;
137 FrameEntryPtr
->SelectType
= 0;
138 FrameEntryPtr
->LinkTerminate
= TRUE
;
145 HcDev
->PciIo
->Unmap (HcDev
->PciIo
, Map
);
147 HcDev
->PciIo
->FreeBuffer (HcDev
->PciIo
, BufferSizeInPages
, CommonBuffer
);
153 DeinitialPeriodicFrameList (
154 IN USB2_HC_DEV
*HcDev
160 Deinitialize Periodic Schedule Frame List
172 HcDev
->PciIo
->Unmap (HcDev
->PciIo
, HcDev
->PeriodicFrameListMap
);
173 HcDev
->PciIo
->FreeBuffer (HcDev
->PciIo
, EFI_SIZE_TO_PAGES (EFI_PAGE_SIZE
), HcDev
->PeriodicFrameListBuffer
);
179 IN USB2_HC_DEV
*HcDev
,
180 IN EFI_EVENT_NOTIFY NotifyFunction
186 Create Async Request Polling Timer
191 NotifyFunction - Timer Notify Function
196 EFI_DEVICE_ERROR Fail
200 return gBS
->CreateEvent (
201 EFI_EVENT_TIMER
| EFI_EVENT_NOTIFY_SIGNAL
,
205 &HcDev
->AsyncRequestEvent
210 DestoryPollingTimer (
211 IN USB2_HC_DEV
*HcDev
217 Destory Async Request Polling Timer
226 EFI_DEVICE_ERROR Fail
230 return gBS
->CloseEvent (HcDev
->AsyncRequestEvent
);
235 IN USB2_HC_DEV
*HcDev
241 Start Async Request Polling Timer
250 EFI_DEVICE_ERROR Fail
254 return gBS
->SetTimer (
255 HcDev
->AsyncRequestEvent
,
257 EHCI_ASYNC_REQUEST_POLLING_TIME
263 IN USB2_HC_DEV
*HcDev
269 Stop Async Request Polling Timer
278 EFI_DEVICE_ERROR Fail
282 return gBS
->SetTimer (
283 HcDev
->AsyncRequestEvent
,
285 EHCI_ASYNC_REQUEST_POLLING_TIME
291 IN USB2_HC_DEV
*HcDev
,
294 IN UINT8 DeviceSpeed
,
295 IN UINTN MaxPacketLen
,
296 OUT EHCI_QH_ENTITY
**QhPtrPtr
302 Create Qh Structure and Pre-Initialize
307 DeviceAddr - Address of Device
308 Endpoint - Endpoint Number
309 DeviceSpeed - Device Speed
310 MaxPacketLen - Max Length of one Packet
311 QhPtrPtr - A pointer of pointer to Qh for return
316 EFI_OUT_OF_RESOURCES Cannot allocate resources
329 // Allocate memory for Qh structure
331 Status
= EhciAllocatePool (
334 sizeof (EHCI_QH_ENTITY
)
336 if (EFI_ERROR (Status
)) {
337 Status
= EFI_OUT_OF_RESOURCES
;
343 gBS
->SetMem (*QhPtrPtr
, sizeof (EHCI_QH_ENTITY
), 0);
348 (*QhPtrPtr
)->Next
= NULL
;
349 (*QhPtrPtr
)->Prev
= NULL
;
350 (*QhPtrPtr
)->FirstQtdPtr
= NULL
;
351 (*QhPtrPtr
)->AltQtdPtr
= NULL
;
352 (*QhPtrPtr
)->LastQtdPtr
= NULL
;
357 QhHwPtr
= &((*QhPtrPtr
)->Qh
);
358 QhHwPtr
->QhHorizontalPointer
= 0;
359 QhHwPtr
->SelectType
= 0;
360 QhHwPtr
->MaxPacketLen
= (UINT32
) MaxPacketLen
;
361 QhHwPtr
->EndpointSpeed
= (DeviceSpeed
& 0x3);
362 QhHwPtr
->EndpointNum
= (Endpoint
& 0x0f);
363 QhHwPtr
->DeviceAddr
= (DeviceAddr
& 0x7f);
364 QhHwPtr
->Multiplier
= HIGH_BANDWIDTH_PIPE_MULTIPLIER
;
378 IN USB2_HC_DEV
*HcDev
,
379 IN EHCI_QH_ENTITY
*QhPtr
390 QhPtr - A pointer to Qh
395 EFI_DEVICE_ERROR Fail
402 EhciFreePool (HcDev
, (UINT8
*) QhPtr
, sizeof (EHCI_QH_ENTITY
));
408 IN USB2_HC_DEV
*HcDev
,
410 IN UINT8 DeviceSpeed
,
411 IN UINTN MaxPacketLen
,
412 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR
*Translator
,
413 OUT EHCI_QH_ENTITY
**QhPtrPtr
419 Create Qh for Control Transfer
424 DeviceAddr - Address of Device
425 DeviceSpeed - Device Speed
426 MaxPacketLen - Max Length of one Packet
427 Translator - Translator Transaction for SplitX
428 QhPtrPtr - A pointer of pointer to Qh for return
433 EFI_OUT_OF_RESOURCES Cannot allocate resources
440 // Create and init Control Qh
450 if (EFI_ERROR (Status
)) {
451 Status
= EFI_OUT_OF_RESOURCES
;
457 (*QhPtrPtr
)->Next
= (*QhPtrPtr
);
458 (*QhPtrPtr
)->Prev
= (*QhPtrPtr
);
459 (*QhPtrPtr
)->TransferType
= CONTROL_TRANSFER
;
464 // Control Transfer use DataToggleControl
466 (*QhPtrPtr
)->Qh
.DataToggleControl
= TRUE
;
467 (*QhPtrPtr
)->Qh
.QhHorizontalPointer
= (UINT32
) (GET_0B_TO_31B (&((*QhPtrPtr
)->Qh
)) >> 5);
468 (*QhPtrPtr
)->Qh
.SelectType
= QH_SELECT_TYPE
;
469 (*QhPtrPtr
)->Qh
.QhTerminate
= FALSE
;
470 (*QhPtrPtr
)->Qh
.ControlEndpointFlag
= TRUE
;
471 (*QhPtrPtr
)->Qh
.NakCountReload
= NAK_COUNT_RELOAD
;
472 if (NULL
!= Translator
) {
473 (*QhPtrPtr
)->Qh
.PortNum
= Translator
->TranslatorPortNumber
;
474 (*QhPtrPtr
)->Qh
.HubAddr
= Translator
->TranslatorHubAddress
;
475 (*QhPtrPtr
)->Qh
.Status
|= QTD_STATUS_DO_START_SPLIT
;
484 IN USB2_HC_DEV
*HcDev
,
486 IN UINT8 EndPointAddr
,
487 IN UINT8 DeviceSpeed
,
489 IN UINTN MaxPacketLen
,
490 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR
*Translator
,
491 OUT EHCI_QH_ENTITY
**QhPtrPtr
497 Create Qh for Bulk Transfer
502 DeviceAddr - Address of Device
503 EndPointAddr - Address of Endpoint
504 DeviceSpeed - Device Speed
505 MaxPacketLen - Max Length of one Packet
506 Translator - Translator Transaction for SplitX
507 QhPtrPtr - A pointer of pointer to Qh for return
512 EFI_OUT_OF_RESOURCES Cannot allocate resources
519 // Create and init Bulk Qh
529 if (EFI_ERROR (Status
)) {
530 Status
= EFI_OUT_OF_RESOURCES
;
537 (*QhPtrPtr
)->Next
= (*QhPtrPtr
);
538 (*QhPtrPtr
)->Prev
= (*QhPtrPtr
);
539 (*QhPtrPtr
)->TransferType
= BULK_TRANSFER
;
544 // BulkTransfer don't use DataToggleControl
546 (*QhPtrPtr
)->Qh
.DataToggleControl
= FALSE
;
547 (*QhPtrPtr
)->Qh
.QhHorizontalPointer
= (UINT32
) (GET_0B_TO_31B (&((*QhPtrPtr
)->Qh
)) >> 5);
548 (*QhPtrPtr
)->Qh
.SelectType
= QH_SELECT_TYPE
;
549 (*QhPtrPtr
)->Qh
.QhTerminate
= FALSE
;
550 (*QhPtrPtr
)->Qh
.NakCountReload
= NAK_COUNT_RELOAD
;
551 (*QhPtrPtr
)->Qh
.DataToggle
= DataToggle
;
552 if (NULL
!= Translator
) {
553 (*QhPtrPtr
)->Qh
.PortNum
= Translator
->TranslatorPortNumber
;
554 (*QhPtrPtr
)->Qh
.HubAddr
= Translator
->TranslatorHubAddress
;
555 (*QhPtrPtr
)->Qh
.Status
|= QTD_STATUS_DO_START_SPLIT
;
564 IN USB2_HC_DEV
*HcDev
,
566 IN UINT8 EndPointAddr
,
567 IN UINT8 DeviceSpeed
,
569 IN UINTN MaxPacketLen
,
571 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR
*Translator
,
572 OUT EHCI_QH_ENTITY
**QhPtrPtr
578 Create Qh for Control Transfer
583 DeviceAddr - Address of Device
584 EndPointAddr - Address of Endpoint
585 DeviceSpeed - Device Speed
586 MaxPacketLen - Max Length of one Packet
587 Interval - value of interval
588 Translator - Translator Transaction for SplitX
589 QhPtrPtr - A pointer of pointer to Qh for return
594 EFI_OUT_OF_RESOURCES Cannot allocate resources
601 // Create and init InterruptQh
611 if (EFI_ERROR (Status
)) {
612 Status
= EFI_OUT_OF_RESOURCES
;
620 (*QhPtrPtr
)->TransferType
= SYNC_INTERRUPT_TRANSFER
;
622 (*QhPtrPtr
)->TransferType
= ASYNC_INTERRUPT_TRANSFER
;
624 (*QhPtrPtr
)->Interval
= GetApproxiOfInterval (Interval
);
629 // InterruptTranfer don't use DataToggleControl
631 (*QhPtrPtr
)->Qh
.DataToggleControl
= FALSE
;
632 (*QhPtrPtr
)->Qh
.QhHorizontalPointer
= 0;
633 (*QhPtrPtr
)->Qh
.QhTerminate
= TRUE
;
634 (*QhPtrPtr
)->Qh
.NakCountReload
= 0;
635 (*QhPtrPtr
)->Qh
.InerruptScheduleMask
= MICRO_FRAME_0_CHANNEL
;
636 (*QhPtrPtr
)->Qh
.SplitComletionMask
= (MICRO_FRAME_2_CHANNEL
| MICRO_FRAME_3_CHANNEL
| MICRO_FRAME_4_CHANNEL
);
637 (*QhPtrPtr
)->Qh
.DataToggle
= DataToggle
;
638 if (NULL
!= Translator
) {
639 (*QhPtrPtr
)->Qh
.PortNum
= Translator
->TranslatorPortNumber
;
640 (*QhPtrPtr
)->Qh
.HubAddr
= Translator
->TranslatorHubAddress
;
641 (*QhPtrPtr
)->Qh
.Status
|= QTD_STATUS_DO_START_SPLIT
;
650 IN USB2_HC_DEV
*HcDev
,
656 OUT EHCI_QTD_ENTITY
**QtdPtrPtr
662 Create Qtd Structure and Pre-Initialize it
667 DataPtr - A pointer to user data buffer to transfer
668 DataLen - Length of user data to transfer
669 PktId - Packet Identification of this Qtd
670 Toggle - Data Toggle of this Qtd
671 QtdStatus - Default value of status of this Qtd
672 QtdPtrPtr - A pointer of pointer to Qtd for return
677 EFI_OUT_OF_RESOURCES Cannot allocate resources
682 EHCI_QTD_HW
*QtdHwPtr
;
688 // Create memory for Qtd structure
690 Status
= EhciAllocatePool (
692 (UINT8
**) QtdPtrPtr
,
693 sizeof (EHCI_QTD_ENTITY
)
695 if (EFI_ERROR (Status
)) {
696 Status
= EFI_OUT_OF_RESOURCES
;
700 // Init fields in Qtd
702 gBS
->SetMem (*QtdPtrPtr
, sizeof (EHCI_QTD_ENTITY
), 0);
707 (*QtdPtrPtr
)->TotalBytes
= (UINT32
) DataLen
;
708 (*QtdPtrPtr
)->StaticTotalBytes
= (UINT32
) DataLen
;
709 (*QtdPtrPtr
)->Prev
= NULL
;
710 (*QtdPtrPtr
)->Next
= NULL
;
715 QtdHwPtr
= &((*QtdPtrPtr
)->Qtd
);
716 QtdHwPtr
->NextQtdPointer
= 0;
717 QtdHwPtr
->NextQtdTerminate
= TRUE
;
718 QtdHwPtr
->AltNextQtdPointer
= 0;
719 QtdHwPtr
->AltNextQtdTerminate
= TRUE
;
720 QtdHwPtr
->DataToggle
= Toggle
;
721 QtdHwPtr
->TotalBytes
= (UINT32
) DataLen
;
722 QtdHwPtr
->CurrentPage
= 0;
723 QtdHwPtr
->ErrorCount
= QTD_ERROR_COUNTER
;
724 QtdHwPtr
->Status
= QtdStatus
;
733 // Set PacketID [Setup/Data/Status]
736 case SETUP_PACKET_ID
:
737 QtdHwPtr
->PidCode
= SETUP_PACKET_PID_CODE
;
740 case INPUT_PACKET_ID
:
741 QtdHwPtr
->PidCode
= INPUT_PACKET_PID_CODE
;
744 case OUTPUT_PACKET_ID
:
745 QtdHwPtr
->PidCode
= OUTPUT_PACKET_PID_CODE
;
749 Status
= EFI_INVALID_PARAMETER
;
754 // Set Data Buffer Pointers
756 if (NULL
!= DataPtr
) {
757 SetQtdBufferPointer (
762 (*QtdPtrPtr
)->StaticCurrentOffset
= QtdHwPtr
->CurrentOffset
;
771 IN USB2_HC_DEV
*HcDev
,
773 OUT EHCI_QTD_ENTITY
**QtdPtrPtr
779 Create Qtd Structure for Setup
784 DevReqPtr - A pointer to Device Request Data
785 QtdPtrPtr - A pointer of pointer to Qtd for return
790 EFI_OUT_OF_RESOURCES Cannot allocate resources
797 sizeof (EFI_USB_DEVICE_REQUEST
),
807 IN USB2_HC_DEV
*HcDev
,
812 OUT EHCI_QTD_ENTITY
**QtdPtrPtr
818 Create Qtd Structure for data
823 DataPtr - A pointer to user data buffer to transfer
824 DataLen - Length of user data to transfer
825 PktId - Packet Identification of this Qtd
826 Toggle - Data Toggle of this Qtd
827 QtdPtrPtr - A pointer of pointer to Qtd for return
832 EFI_OUT_OF_RESOURCES Cannot allocate resources
849 IN USB2_HC_DEV
*HcDev
,
851 OUT EHCI_QTD_ENTITY
**QtdPtrPtr
857 Create Qtd Structure for Alternative
862 PktId - Packet Identification of this Qtd
863 QtdPtrPtr - A pointer of pointer to Qtd for return
868 EFI_OUT_OF_RESOURCES Cannot allocate resources
885 IN USB2_HC_DEV
*HcDev
,
887 OUT EHCI_QTD_ENTITY
**QtdPtrPtr
893 Create Qtd Structure for status
898 PktId - Packet Identification of this Qtd
899 QtdPtrPtr - A pointer of pointer to Qtd for return
904 EFI_OUT_OF_RESOURCES Cannot allocate resources
921 IN USB2_HC_DEV
*HcDev
,
923 IN UINT8
*RequestCursor
,
924 IN UINT8
*DataCursor
,
926 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR
*Translator
,
927 OUT EHCI_QTD_ENTITY
**ControlQtdsHead
933 Create Qtds list for Control Transfer
938 DataPktId - Packet Identification of Data Qtds
939 RequestCursor - A pointer to request structure buffer to transfer
940 DataCursor - A pointer to user data buffer to transfer
941 DataLen - Length of user data to transfer
942 ControlQtdsHead - A pointer of pointer to first Qtd for control tranfer for return
947 EFI_OUT_OF_RESOURCES Cannot allocate resources
952 EHCI_QTD_ENTITY
*QtdPtr
;
953 EHCI_QTD_ENTITY
*PreQtdPtr
;
954 EHCI_QTD_ENTITY
*SetupQtdPtr
;
955 EHCI_QTD_ENTITY
*FirstDataQtdPtr
;
956 EHCI_QTD_ENTITY
*LastDataQtdPtr
;
957 EHCI_QTD_ENTITY
*StatusQtdPtr
;
968 FirstDataQtdPtr
= NULL
;
969 LastDataQtdPtr
= NULL
;
974 // Setup Stage of Control Transfer
976 Status
= CreateSetupQtd (
981 if (EFI_ERROR (Status
)) {
982 Status
= EFI_OUT_OF_RESOURCES
;
987 // Data Stage of Control Transfer
993 // Create Qtd structure and link together
995 while (DataCount
> 0) {
997 // PktSize is the data load size that each Qtd.
999 CapacityOfQtd
= GetCapacityOfQtd (DataCursor
);
1000 SizePerQtd
= DataCount
;
1001 if (DataCount
> CapacityOfQtd
) {
1002 SizePerQtd
= CapacityOfQtd
;
1005 Status
= CreateDataQtd (
1013 if (EFI_ERROR (Status
)) {
1014 Status
= EFI_OUT_OF_RESOURCES
;
1015 if (NULL
== FirstDataQtdPtr
) {
1016 goto destory_setup_qtd
;
1022 if (NULL
== FirstDataQtdPtr
) {
1023 FirstDataQtdPtr
= QtdPtr
;
1025 LinkQtdToQtd (PreQtdPtr
, QtdPtr
);
1029 // Reverse Data Toggle or not determined by parity of transactions of one qtd
1031 Xnum
= Translator
? GetNumberOfTransaction (SizePerQtd
, EHCI_BLOCK_SIZE_WITH_TT
) : GetNumberOfTransaction (SizePerQtd
, EHCI_BLOCK_SIZE
);
1032 if (Xnum
% 2 != 0) {
1037 DataCursor
+= SizePerQtd
;
1038 DataCount
-= SizePerQtd
;
1041 LastDataQtdPtr
= QtdPtr
;
1044 // Status Stage of Control Transfer
1046 if (OUTPUT_PACKET_ID
== DataPktId
) {
1047 StatusPktId
= INPUT_PACKET_ID
;
1049 StatusPktId
= OUTPUT_PACKET_ID
;
1052 Status
= CreateStatusQtd (
1057 if (EFI_ERROR (Status
)) {
1058 Status
= EFI_OUT_OF_RESOURCES
;
1063 // Link setup Qtd -> data Qtds -> status Qtd
1065 if (FirstDataQtdPtr
!= NULL
) {
1066 LinkQtdToQtd (SetupQtdPtr
, FirstDataQtdPtr
);
1067 LinkQtdToQtd (LastDataQtdPtr
, StatusQtdPtr
);
1069 LinkQtdToQtd (SetupQtdPtr
, StatusQtdPtr
);
1072 *ControlQtdsHead
= SetupQtdPtr
;
1077 DestoryQtds (HcDev
, FirstDataQtdPtr
);
1079 DestoryQtds (HcDev
, SetupQtdPtr
);
1085 CreateBulkOrInterruptQtds (
1086 IN USB2_HC_DEV
*HcDev
,
1088 IN UINT8
*DataCursor
,
1090 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR
*Translator
,
1091 OUT EHCI_QTD_ENTITY
**QtdsHead
1095 Routine Description:
1097 Create Qtds list for Bulk or Interrupt Transfer
1102 PktId - Packet Identification of Qtds
1103 DataCursor - A pointer to user data buffer to transfer
1104 DataLen - Length of user data to transfer
1105 DataToggle - Data Toggle to start
1106 Translator - Translator Transaction for SplitX
1107 QtdsHead - A pointer of pointer to first Qtd for control tranfer for return
1112 EFI_OUT_OF_RESOURCES Cannot allocate resources
1117 EHCI_QTD_ENTITY
*QtdPtr
;
1118 EHCI_QTD_ENTITY
*PreQtdPtr
;
1119 EHCI_QTD_ENTITY
*FirstQtdPtr
;
1120 EHCI_QTD_ENTITY
*AltQtdPtr
;
1122 UINTN CapacityOfQtd
;
1125 Status
= EFI_SUCCESS
;
1132 DataCount
= DataLen
;
1133 while (DataCount
> 0) {
1135 CapacityOfQtd
= GetCapacityOfQtd (DataCursor
);
1136 SizePerQtd
= DataCount
;
1137 if (DataCount
> CapacityOfQtd
) {
1138 SizePerQtd
= CapacityOfQtd
;
1141 Status
= CreateDataQtd (
1149 if (EFI_ERROR (Status
)) {
1150 Status
= EFI_OUT_OF_RESOURCES
;
1151 if (NULL
== FirstQtdPtr
) {
1158 if (NULL
== FirstQtdPtr
) {
1159 FirstQtdPtr
= QtdPtr
;
1161 LinkQtdToQtd (PreQtdPtr
, QtdPtr
);
1165 DataCursor
+= SizePerQtd
;
1166 DataCount
-= SizePerQtd
;
1170 // Set Alternate Qtd
1172 if (INPUT_PACKET_ID
== PktId
&& 1 < GetNumberOfQtd (FirstQtdPtr
)) {
1173 Status
= CreateAltQtd (
1178 if (EFI_ERROR (Status
)) {
1179 Status
= EFI_OUT_OF_RESOURCES
;
1183 LinkQtdsToAltQtd (FirstQtdPtr
, AltQtdPtr
);
1186 *QtdsHead
= FirstQtdPtr
;
1190 DestoryQtds (HcDev
, FirstQtdPtr
);
1197 IN USB2_HC_DEV
*HcDev
,
1198 IN EHCI_QTD_ENTITY
*FirstQtdPtr
1202 Routine Description:
1204 Destory all Qtds in the list
1209 FirstQtdPtr - A pointer to first Qtd in the list
1217 EHCI_QTD_ENTITY
*PrevQtd
;
1218 EHCI_QTD_ENTITY
*NextQtd
;
1224 PrevQtd
= FirstQtdPtr
;
1227 // Delete all the Qtds.
1230 NextQtd
= PrevQtd
->Next
;
1231 EhciFreePool (HcDev
, (UINT8
*) PrevQtd
, sizeof (EHCI_QTD_ENTITY
));
1233 } while (NULL
!= PrevQtd
);
1241 IN EHCI_QTD_ENTITY
*FirstQtdPtr
1245 Routine Description:
1247 Number of Qtds in the list
1251 FirstQtdPtr - A pointer to first Qtd in the list
1255 Number of Qtds in the list
1260 EHCI_QTD_ENTITY
*QtdPtr
;
1262 QtdPtr
= FirstQtdPtr
;
1266 while (NULL
!= QtdPtr
) {
1268 QtdPtr
= QtdPtr
->Next
;
1275 GetNumberOfTransaction (
1276 IN UINTN SizeOfData
,
1277 IN UINTN SizeOfTransaction
1281 Routine Description:
1283 Number of Transactions in one Qtd
1287 SizeOfData - Size of one Qtd
1288 SizeOfTransaction - Size of one Transaction
1292 Number of Transactions in this Qtd
1297 return ((SizeOfData
& (SizeOfTransaction
- 1)) ? SizeOfData
/ SizeOfTransaction
+ 1 : SizeOfData
/ SizeOfTransaction
);
1303 IN UINT8
*BufferCursor
1307 Routine Description:
1309 Get Size of First Qtd
1313 BufferCursor - BufferCursor of the Qtd
1322 return (EHCI_MAX_QTD_CAPACITY
- (EHCI_BLOCK_SIZE
* GetNumberOfTransaction (EFI_PAGE_MASK
& GET_0B_TO_31B (BufferCursor
), EHCI_BLOCK_SIZE
)));
1327 GetApproxiOfInterval (
1332 Routine Description:
1334 Get the approximate value in the 2 index sequence
1338 Interval - the value of interval
1342 approximate value of interval in the 2 index sequence
1349 Orignate
= Interval
;
1352 while (Orignate
!= 1 && Orignate
!= 0) {
1353 Orignate
= Orignate
>> 1;
1354 Approxi
= Approxi
<< 1;
1357 if (Interval
& (Approxi
>> 1)) {
1358 Approxi
= Approxi
<< 1;
1365 GetQtdAlternateNextPointer (
1366 IN EHCI_QTD_HW
*HwQtdPtr
1370 Routine Description:
1372 Get Qtd alternate next pointer field
1376 HwQtdPtr - A pointer to hardware Qtd structure
1380 A pointer to hardware alternate Qtd
1388 if (!HwQtdPtr
->AltNextQtdTerminate
) {
1389 Value
= (EHCI_QTD_HW
*) (UINTN
) GET_0B_TO_31B (HwQtdPtr
->AltNextQtdPointer
<< 5);
1397 IN EHCI_QTD_HW
*HwQtdPtr
1401 Routine Description:
1403 Get Qtd next pointer field
1407 HwQtdPtr - A pointer to hardware Qtd structure
1411 A pointer to next hardware Qtd structure
1419 if (!HwQtdPtr
->NextQtdTerminate
) {
1420 Value
= (EHCI_QTD_HW
*) (UINTN
) GET_0B_TO_31B (HwQtdPtr
->NextQtdPointer
<< 5);
1427 IN EHCI_QTD_ENTITY
* PreQtdPtr
,
1428 IN EHCI_QTD_ENTITY
* QtdPtr
1432 Routine Description:
1438 PreQtdPtr - A pointer to pre Qtd
1439 QtdPtr - A pointer to next Qtd
1447 EHCI_QTD_HW
*QtdHwPtr
;
1455 PreQtdPtr
->Next
= QtdPtr
;
1456 QtdPtr
->Prev
= PreQtdPtr
;
1461 QtdHwPtr
= &(QtdPtr
->Qtd
);
1462 PreQtdPtr
->Qtd
.NextQtdPointer
= (UINT32
) (GET_0B_TO_31B(QtdHwPtr
) >> 5);
1463 PreQtdPtr
->Qtd
.NextQtdTerminate
= FALSE
;
1469 VOID
LinkQtdsToAltQtd (
1470 IN EHCI_QTD_ENTITY
* FirstQtdPtr
,
1471 IN EHCI_QTD_ENTITY
* AltQtdPtr
1475 Routine Description:
1477 Link AlterQtds together
1481 FirstQtdPtr - A pointer to first Qtd in the list
1482 AltQtdPtr - A pointer to alternative Qtd
1490 EHCI_QTD_ENTITY
*QtdPtr
;
1491 EHCI_QTD_HW
*AltQtdHwPtr
;
1493 ASSERT(FirstQtdPtr
);
1496 AltQtdHwPtr
= &(AltQtdPtr
->Qtd
);
1497 QtdPtr
= FirstQtdPtr
;
1499 while (NULL
!= QtdPtr
) {
1503 QtdPtr
->AltNext
= AltQtdPtr
;
1507 QtdPtr
->Qtd
.AltNextQtdPointer
= (UINT32
) (GET_0B_TO_31B(AltQtdHwPtr
) >> 5);
1508 QtdPtr
->Qtd
.AltNextQtdTerminate
= FALSE
;
1509 QtdPtr
= QtdPtr
->Next
;
1517 IN EHCI_QH_ENTITY
*QhPtr
,
1518 IN EHCI_QTD_ENTITY
*QtdPtr
1522 Routine Description:
1524 Link Qtds list to Qh
1528 QhPtr - A pointer to Qh
1529 QtdPtr - A pointer to first Qtd in the list
1537 EHCI_QTD_ENTITY
*Cursor
;
1538 EHCI_QTD_HW
*QtdHwPtr
;
1543 QhPtr
->FirstQtdPtr
= QtdPtr
;
1544 if (NULL
!= QtdPtr
->AltNext
) {
1545 QhPtr
->AltQtdPtr
= QtdPtr
->AltNext
;
1549 while (NULL
!= Cursor
) {
1550 Cursor
->SelfQh
= QhPtr
;
1551 if (NULL
== Cursor
->Next
) {
1552 QhPtr
->LastQtdPtr
= Cursor
;
1555 Cursor
= Cursor
->Next
;
1558 QtdHwPtr
= &(QtdPtr
->Qtd
);
1559 QhPtr
->Qh
.NextQtdPointer
= (UINT32
) (GET_0B_TO_31B (QtdHwPtr
) >> 5);
1560 QhPtr
->Qh
.NextQtdTerminate
= FALSE
;
1567 IN USB2_HC_DEV
*HcDev
,
1568 IN EHCI_QH_ENTITY
*QhPtr
1572 Routine Description:
1574 Link Qh to Async Schedule List
1579 QhPtr - A pointer to Qh
1584 EFI_DEVICE_ERROR Fail
1593 QhPtr
->Qh
.HeadReclamationFlag
= TRUE
;
1595 Status
= SetAsyncListAddr (HcDev
, QhPtr
);
1596 if (EFI_ERROR (Status
)) {
1597 Status
= EFI_DEVICE_ERROR
;
1601 if (!IsAsyncScheduleEnabled (HcDev
)) {
1603 Status
= EnableAsynchronousSchedule (HcDev
);
1604 if (EFI_ERROR (Status
)) {
1605 Status
= EFI_DEVICE_ERROR
;
1609 Status
= WaitForAsyncScheduleEnable (HcDev
, EHCI_GENERIC_TIMEOUT
);
1610 if (EFI_ERROR (Status
)) {
1611 DEBUG ((gEHCDebugLevel
, "WaitForAsyncScheduleEnable TimeOut"));
1612 Status
= EFI_TIMEOUT
;
1616 if (IsEhcHalted (HcDev
)) {
1617 Status
= StartScheduleExecution (HcDev
);
1618 if (EFI_ERROR (Status
)) {
1619 Status
= EFI_DEVICE_ERROR
;
1630 UnlinkQhFromAsyncList (
1631 IN USB2_HC_DEV
*HcDev
,
1632 IN EHCI_QH_ENTITY
*QhPtr
1636 Routine Description:
1638 Unlink Qh from Async Schedule List
1643 QhPtr - A pointer to Qh
1648 EFI_DEVICE_ERROR Fail
1654 Status
= EFI_SUCCESS
;
1659 if (QhPtr
== QhPtr
->Next
) {
1661 Status
= DisableAsynchronousSchedule (HcDev
);
1662 if (EFI_ERROR (Status
)) {
1663 Status
= EFI_DEVICE_ERROR
;
1667 Status
= WaitForAsyncScheduleDisable (HcDev
, EHCI_GENERIC_TIMEOUT
);
1668 if (EFI_ERROR (Status
)) {
1669 DEBUG ((gEHCErrorLevel
, "WaitForAsyncScheduleDisable TimeOut\n"));
1670 Status
= EFI_TIMEOUT
;
1681 LinkQhToPeriodicList (
1682 IN USB2_HC_DEV
*HcDev
,
1683 IN EHCI_QH_ENTITY
*QhPtr
1687 Routine Description:
1689 Link Qh to Periodic Schedule List
1694 QhPtr - A pointer to Qh
1702 FRAME_LIST_ENTRY
*FrameEntryPtr
;
1703 EHCI_QH_ENTITY
*FindQhPtr
;
1704 EHCI_QH_HW
*FindQhHwPtr
;
1713 FrameEntryPtr
= (FRAME_LIST_ENTRY
*) HcDev
->PeriodicFrameListBuffer
;
1715 QhPtr
->Qh
.HeadReclamationFlag
= FALSE
;
1717 if (QhPtr
->TransferType
== ASYNC_INTERRUPT_TRANSFER
) {
1720 // AsyncInterruptTransfer Qh
1724 // Link to Frame[0] List
1726 if (!FrameEntryPtr
->LinkTerminate
) {
1728 // Not Null FrameList
1730 FindQhHwPtr
= (EHCI_QH_HW
*) (UINTN
) GET_0B_TO_31B (FrameEntryPtr
->LinkPointer
<< 5);
1731 FindQhPtr
= (EHCI_QH_ENTITY
*) GET_QH_ENTITY_ADDR (FindQhHwPtr
);
1733 // FindQh is Left/Right to Qh
1735 while ((NULL
!= FindQhPtr
->Next
) && (FindQhPtr
->Interval
> QhPtr
->Interval
)) {
1736 FindQhPtr
= FindQhPtr
->Next
;
1739 if (FindQhPtr
->Interval
== QhPtr
->Interval
) {
1741 // Link Qh after FindQh
1743 if (NULL
!= FindQhPtr
->Next
) {
1744 FindQhPtr
->Next
->Prev
= QhPtr
;
1745 QhPtr
->Qh
.QhHorizontalPointer
= (UINT32
) GET_0B_TO_31B (((UINTN
) &(FindQhPtr
->Next
->Qh
)) >> 5);
1746 QhPtr
->Qh
.SelectType
= QH_SELECT_TYPE
;
1747 QhPtr
->Qh
.QhTerminate
= FALSE
;
1750 FindQhPtr
->Qh
.QhHorizontalPointer
= (UINT32
) GET_0B_TO_31B (((UINTN
)&(QhPtr
->Qh
)) >> 5);
1751 FindQhPtr
->Qh
.SelectType
= QH_SELECT_TYPE
;
1752 FindQhPtr
->Qh
.QhTerminate
= FALSE
;
1754 QhPtr
->Prev
= FindQhPtr
;
1755 QhPtr
->Next
= FindQhPtr
->Next
;
1756 FindQhPtr
->Next
= QhPtr
;
1757 } else if (FindQhPtr
->Interval
< QhPtr
->Interval
) {
1759 // Link Qh before FindQh
1761 if (NULL
== FindQhPtr
->Prev
) {
1763 // Qh is the First one in Frame[0] List
1765 FrameEntryPtr
->LinkPointer
= (UINT32
) GET_0B_TO_31B (((UINTN
) &(QhPtr
->Qh
)) >> 5);
1766 FrameEntryPtr
->SelectType
= QH_SELECT_TYPE
;
1767 FrameEntryPtr
->LinkTerminate
= FALSE
;
1770 // Qh is not the First one in Frame[0] List
1772 FindQhPtr
->Prev
->Next
= QhPtr
;
1773 FindQhPtr
->Prev
->Qh
.QhHorizontalPointer
= (UINT32
) GET_0B_TO_31B (((UINTN
) &(QhPtr
->Qh
)) >> 5);
1774 FindQhPtr
->Prev
->Qh
.SelectType
= QH_SELECT_TYPE
;
1775 FindQhPtr
->Prev
->Qh
.QhTerminate
= FALSE
;
1778 QhPtr
->Qh
.QhHorizontalPointer
= (UINT32
) GET_0B_TO_31B (((UINTN
) &(FindQhPtr
->Qh
)) >> 5);
1779 QhPtr
->Qh
.SelectType
= QH_SELECT_TYPE
;
1780 QhPtr
->Qh
.QhTerminate
= FALSE
;
1782 QhPtr
->Next
= FindQhPtr
;
1783 QhPtr
->Prev
= FindQhPtr
->Prev
;
1784 FindQhPtr
->Prev
= QhPtr
;
1787 // Link Qh after FindQh, Qh is the Last one
1789 FindQhPtr
->Qh
.QhHorizontalPointer
= (UINT32
) GET_0B_TO_31B (((UINTN
) &(QhPtr
->Qh
)) >> 5);
1790 FindQhPtr
->Prev
->Qh
.SelectType
= QH_SELECT_TYPE
;
1791 FindQhPtr
->Qh
.QhTerminate
= FALSE
;
1793 QhPtr
->Prev
= FindQhPtr
;
1795 FindQhPtr
->Next
= QhPtr
;
1801 FrameEntryPtr
->LinkPointer
= (UINT32
) GET_0B_TO_31B (((UINTN
) &(QhPtr
->Qh
)) >> 5);
1802 FrameEntryPtr
->SelectType
= QH_SELECT_TYPE
;
1803 FrameEntryPtr
->LinkTerminate
= FALSE
;
1808 if (NULL
== QhPtr
->Prev
) {
1810 // Qh is the First one in Frame[0] List
1812 FrameIndex
+= QhPtr
->Interval
;
1813 while (FrameIndex
< HcDev
->PeriodicFrameListLength
) {
1814 FrameEntryPtr
= (FRAME_LIST_ENTRY
*) (FrameEntryPtr
+ QhPtr
->Interval
);
1815 FrameEntryPtr
->LinkPointer
= (UINT32
) GET_0B_TO_31B (((UINTN
) &(QhPtr
->Qh
)) >> 5);
1816 FrameEntryPtr
->SelectType
= QH_SELECT_TYPE
;
1817 FrameEntryPtr
->LinkTerminate
= FALSE
;
1818 FrameIndex
+= QhPtr
->Interval
;
1820 } else if (QhPtr
->Interval
< QhPtr
->Prev
->Interval
) {
1822 // Qh is not the First one in Frame[0] List, and Prev.interval > Qh.interval
1824 FrameIndex
+= QhPtr
->Interval
;
1825 while (FrameIndex
< HcDev
->PeriodicFrameListLength
) {
1826 FrameEntryPtr
= (FRAME_LIST_ENTRY
*) (FrameEntryPtr
+ QhPtr
->Interval
);
1827 if ((FrameIndex
% QhPtr
->Prev
->Interval
) != 0) {
1828 FrameEntryPtr
->LinkPointer
= (UINT32
) GET_0B_TO_31B (((UINTN
) &(QhPtr
->Qh
)) >> 5);
1829 FrameEntryPtr
->SelectType
= QH_SELECT_TYPE
;
1830 FrameEntryPtr
->LinkTerminate
= FALSE
;
1833 FrameIndex
+= QhPtr
->Interval
;
1839 // SyncInterruptTransfer Qh
1842 if (!FrameEntryPtr
->LinkTerminate
) {
1844 // Not Null FrameList
1846 FindQhHwPtr
= (EHCI_QH_HW
*) (UINTN
) GET_0B_TO_31B (FrameEntryPtr
->LinkPointer
<< 5);
1847 FindQhPtr
= (EHCI_QH_ENTITY
*) GET_QH_ENTITY_ADDR (FindQhHwPtr
);
1849 // FindQh is Last Qh in the Asynchronous List, Link Qh after FindQh
1851 while (NULL
!= FindQhPtr
->Next
) {
1852 FindQhPtr
= FindQhPtr
->Next
;
1855 FindQhPtr
->Qh
.QhHorizontalPointer
= (UINT32
) GET_0B_TO_31B (((UINTN
) &(QhPtr
->Qh
)) >> 5);
1856 FindQhPtr
->Qh
.SelectType
= QH_SELECT_TYPE
;
1857 FindQhPtr
->Qh
.QhTerminate
= FALSE
;
1859 FindQhPtr
->Next
= QhPtr
;
1860 QhPtr
->Prev
= FindQhPtr
;
1865 FrameEntryPtr
->LinkPointer
= (UINT32
) GET_0B_TO_31B (((UINTN
) &(QhPtr
->Qh
)) >> 5);
1866 FrameEntryPtr
->SelectType
= QH_SELECT_TYPE
;
1867 FrameEntryPtr
->LinkTerminate
= FALSE
;
1875 UnlinkQhFromPeriodicList (
1876 IN USB2_HC_DEV
*HcDev
,
1877 IN EHCI_QH_ENTITY
*QhPtr
,
1882 Routine Description:
1884 Unlink Qh from Periodic Schedule List
1889 QhPtr - A pointer to Qh
1890 Interval - Interval of this periodic transfer
1898 FRAME_LIST_ENTRY
*FrameEntryPtr
;
1907 FrameEntryPtr
= (FRAME_LIST_ENTRY
*) HcDev
->PeriodicFrameListBuffer
;
1909 if (QhPtr
->TransferType
== ASYNC_INTERRUPT_TRANSFER
) {
1912 // AsyncInterruptTransfer Qh
1915 if (NULL
== QhPtr
->Prev
) {
1917 // Qh is the First one on Frame[0] List
1919 if (NULL
== QhPtr
->Next
) {
1921 // Only one on Frame[0] List
1923 while (FrameIndex
< HcDev
->PeriodicFrameListLength
) {
1924 FrameEntryPtr
->LinkPointer
= 0;
1925 FrameEntryPtr
->SelectType
= 0;
1926 FrameEntryPtr
->LinkTerminate
= TRUE
;
1927 FrameEntryPtr
+= Interval
;
1928 FrameIndex
+= Interval
;
1931 while (FrameIndex
< HcDev
->PeriodicFrameListLength
) {
1932 FrameEntryPtr
->LinkPointer
= (UINT32
) GET_0B_TO_31B (((UINTN
) &(QhPtr
->Next
->Qh
)) >> 5);
1933 FrameEntryPtr
->SelectType
= QH_SELECT_TYPE
;
1934 FrameEntryPtr
->LinkTerminate
= FALSE
;
1935 FrameEntryPtr
+= Interval
;
1936 FrameIndex
+= Interval
;
1942 // Not First one on Frame[0] List
1944 if (NULL
== QhPtr
->Next
) {
1946 // Qh is the Last one on Frame[0] List
1948 QhPtr
->Prev
->Qh
.QhHorizontalPointer
= 0;
1949 QhPtr
->Prev
->Qh
.SelectType
= 0;
1950 QhPtr
->Prev
->Qh
.QhTerminate
= TRUE
;
1952 QhPtr
->Prev
->Qh
.QhHorizontalPointer
= (UINT32
) GET_0B_TO_31B (((UINTN
) &(QhPtr
->Next
->Qh
)) >> 5);
1953 QhPtr
->Prev
->Qh
.SelectType
= QH_SELECT_TYPE
;
1954 QhPtr
->Prev
->Qh
.QhTerminate
= FALSE
;
1957 if (Interval
== QhPtr
->Prev
->Interval
) {
1959 // Interval is the same as Prev
1960 // Not involed Frame[X]
1966 while (FrameIndex
< HcDev
->PeriodicFrameListLength
) {
1967 if ((FrameIndex
% QhPtr
->Prev
->Interval
) != 0) {
1968 FrameEntryPtr
->LinkPointer
= QhPtr
->Prev
->Qh
.QhHorizontalPointer
;
1969 FrameEntryPtr
->SelectType
= QhPtr
->Prev
->Qh
.SelectType
;
1970 FrameEntryPtr
->LinkTerminate
= QhPtr
->Prev
->Qh
.QhTerminate
;
1972 FrameEntryPtr
+= Interval
;
1973 FrameIndex
+= Interval
;
1978 if (NULL
!= QhPtr
->Next
) {
1979 QhPtr
->Next
->Prev
= QhPtr
->Prev
;
1982 if (NULL
!= QhPtr
->Prev
) {
1983 QhPtr
->Prev
->Next
= QhPtr
->Next
;
1987 // SyncInterruptTransfer Qh
1989 if (NULL
== QhPtr
->Prev
) {
1991 // Qh is the only one Qh on Frame[0] List
1993 FrameEntryPtr
->LinkPointer
= 0;
1994 FrameEntryPtr
->SelectType
= 0;
1995 FrameEntryPtr
->LinkTerminate
= TRUE
;
1997 QhPtr
->Prev
->Qh
.QhHorizontalPointer
= 0;
1998 QhPtr
->Prev
->Qh
.SelectType
= 0;
1999 QhPtr
->Prev
->Qh
.QhTerminate
= TRUE
;
2002 if (NULL
!= QhPtr
->Prev
) {
2003 QhPtr
->Prev
->Next
= NULL
;
2011 LinkToAsyncReqeust (
2012 IN USB2_HC_DEV
*HcDev
,
2013 IN EHCI_ASYNC_REQUEST
*AsyncRequestPtr
2017 Routine Description:
2019 Llink AsyncRequest Entry to Async Request List
2024 AsyncRequestPtr - A pointer to Async Request Entry
2032 EHCI_ASYNC_REQUEST
*CurrentPtr
;
2034 CurrentPtr
= HcDev
->AsyncRequestList
;
2035 HcDev
->AsyncRequestList
= AsyncRequestPtr
;
2036 AsyncRequestPtr
->Prev
= NULL
;
2037 AsyncRequestPtr
->Next
= CurrentPtr
;
2039 if (NULL
!= CurrentPtr
) {
2040 CurrentPtr
->Prev
= AsyncRequestPtr
;
2047 UnlinkFromAsyncReqeust (
2048 IN USB2_HC_DEV
*HcDev
,
2049 IN EHCI_ASYNC_REQUEST
*AsyncRequestPtr
2053 Routine Description:
2055 Unlink AsyncRequest Entry from Async Request List
2060 AsyncRequestPtr - A pointer to Async Request Entry
2068 if (NULL
== AsyncRequestPtr
->Prev
) {
2069 HcDev
->AsyncRequestList
= AsyncRequestPtr
->Next
;
2070 if (NULL
!= AsyncRequestPtr
->Next
) {
2071 AsyncRequestPtr
->Next
->Prev
= NULL
;
2074 AsyncRequestPtr
->Prev
->Next
= AsyncRequestPtr
->Next
;
2075 if (NULL
!= AsyncRequestPtr
->Next
) {
2076 AsyncRequestPtr
->Next
->Prev
= AsyncRequestPtr
->Prev
;
2084 SetQtdBufferPointer (
2085 IN EHCI_QTD_HW
*QtdHwPtr
,
2091 Routine Description:
2093 Set data buffer pointers in Qtd
2097 QtdHwPtr - A pointer to Qtd hardware structure
2098 DataPtr - A pointer to user data buffer
2099 DataLen - Length of the user data buffer
2109 RemainLen
= DataLen
;
2113 // Set BufferPointer0, ExtBufferPointer0 and Offset
2115 QtdHwPtr
->BufferPointer0
= (UINT32
) (GET_0B_TO_31B (DataPtr
) >> 12);
2116 QtdHwPtr
->CurrentOffset
= (UINT32
) (GET_0B_TO_31B (DataPtr
) & EFI_PAGE_MASK
);
2117 QtdHwPtr
->ExtBufferPointer0
= (UINT32
) GET_32B_TO_63B (DataPtr
);
2120 // Set BufferPointer1 and ExtBufferPointer1
2122 RemainLen
= RemainLen
> (EFI_PAGE_SIZE
- QtdHwPtr
->CurrentOffset
) ? (RemainLen
- (EFI_PAGE_SIZE
- QtdHwPtr
->CurrentOffset
)) : 0;
2123 if (RemainLen
== 0) {
2127 QtdHwPtr
->BufferPointer1
= QtdHwPtr
->BufferPointer0
+ 1;
2128 QtdHwPtr
->ExtBufferPointer1
= QtdHwPtr
->ExtBufferPointer0
;
2131 // Set BufferPointer2 and ExtBufferPointer2
2133 RemainLen
= RemainLen
> EFI_PAGE_SIZE
? (RemainLen
- EFI_PAGE_SIZE
) : 0;
2134 if (RemainLen
== 0) {
2138 QtdHwPtr
->BufferPointer2
= QtdHwPtr
->BufferPointer1
+ 1;
2139 QtdHwPtr
->ExtBufferPointer2
= QtdHwPtr
->ExtBufferPointer0
;
2142 // Set BufferPointer3 and ExtBufferPointer3
2144 RemainLen
= RemainLen
> EFI_PAGE_SIZE
? (RemainLen
- EFI_PAGE_SIZE
) : 0;
2145 if (RemainLen
== 0) {
2149 QtdHwPtr
->BufferPointer3
= QtdHwPtr
->BufferPointer2
+ 1;
2150 QtdHwPtr
->ExtBufferPointer3
= QtdHwPtr
->ExtBufferPointer0
;
2153 // Set BufferPointer4 and ExtBufferPointer4
2155 RemainLen
= RemainLen
> EFI_PAGE_SIZE
? (RemainLen
- EFI_PAGE_SIZE
) : 0;
2156 if (RemainLen
== 0) {
2160 QtdHwPtr
->BufferPointer4
= QtdHwPtr
->BufferPointer3
+ 1;
2161 QtdHwPtr
->ExtBufferPointer4
= QtdHwPtr
->ExtBufferPointer0
;
2169 IN EHCI_QTD_HW
*HwQtdPtr
2173 Routine Description:
2175 Whether Qtd status is active or not
2179 HwQtdPtr - A pointer to hardware Qtd structure
2191 QtdStatus
= (UINT8
) (HwQtdPtr
->Status
);
2192 Value
= (BOOLEAN
) (QtdStatus
& QTD_STATUS_ACTIVE
);
2199 IN EHCI_QTD_HW
*HwQtdPtr
2203 Routine Description:
2205 Whether Qtd status is halted or not
2209 HwQtdPtr - A pointer to hardware Qtd structure
2221 QtdStatus
= (UINT8
) (HwQtdPtr
->Status
);
2222 Value
= (BOOLEAN
) (QtdStatus
& QTD_STATUS_HALTED
);
2228 IsQtdStatusBufferError (
2229 IN EHCI_QTD_HW
*HwQtdPtr
2233 Routine Description:
2235 Whether Qtd status is buffer error or not
2239 HwQtdPtr - A pointer to hardware Qtd structure
2244 FALSE No buffer error
2251 QtdStatus
= (UINT8
) (HwQtdPtr
->Status
);
2252 Value
= (BOOLEAN
) (QtdStatus
& QTD_STATUS_BUFFER_ERR
);
2258 IsQtdStatusBabbleError (
2259 IN EHCI_QTD_HW
*HwQtdPtr
2263 Routine Description:
2265 Whether Qtd status is babble error or not
2269 HwQtdPtr - A pointer to hardware Qtd structure
2274 FALSE No babble error
2281 QtdStatus
= (UINT8
) (HwQtdPtr
->Status
);
2282 Value
= (BOOLEAN
) (QtdStatus
& QTD_STATUS_BABBLE_ERR
);
2288 IsQtdStatusTransactionError (
2289 IN EHCI_QTD_HW
*HwQtdPtr
2293 Routine Description:
2295 Whether Qtd status is transaction error or not
2299 HwQtdPtr - A pointer to hardware Qtd structure
2303 TRUE Transaction error
2304 FALSE No transaction error
2311 QtdStatus
= (UINT8
) (HwQtdPtr
->Status
);
2312 Value
= (BOOLEAN
) (QtdStatus
& QTD_STATUS_TRANSACTION_ERR
);
2319 IN UINT8 EndPointAddress
2323 Routine Description:
2325 Whether is a DataIn direction transfer
2329 EndPointAddress - address of the endpoint
2340 if (EndPointAddress
& 0x80) {
2351 IN USB2_HC_DEV
*HcDev
,
2352 IN EFI_USB_DATA_DIRECTION TransferDirection
,
2354 IN OUT UINTN
*DataLength
,
2356 OUT UINT8
**DataCursor
,
2361 Routine Description:
2363 Map address of user data buffer
2368 TransferDirection - direction of transfer
2369 Data - A pointer to user data buffer
2370 DataLength - length of user data
2371 PktId - Packte Identificaion
2372 DataCursor - mapped address to return
2373 DataMap - identificaion of this mapping to return
2378 EFI_DEVICE_ERROR Fail
2383 EFI_PHYSICAL_ADDRESS TempPhysicalAddr
;
2385 Status
= EFI_SUCCESS
;
2387 switch (TransferDirection
) {
2391 *PktId
= INPUT_PACKET_ID
;
2393 // BusMasterWrite means cpu read
2395 Status
= HcDev
->PciIo
->Map (
2397 EfiPciIoOperationBusMasterWrite
,
2403 if (EFI_ERROR (Status
)) {
2404 DEBUG ((gEHCDebugLevel
, "MapDataBuffer Failed\n"));
2405 Status
= EFI_DEVICE_ERROR
;
2409 *DataCursor
= (UINT8
*) ((UINTN
) TempPhysicalAddr
);
2414 *PktId
= OUTPUT_PACKET_ID
;
2416 // BusMasterRead means cpu write
2418 Status
= HcDev
->PciIo
->Map (
2420 EfiPciIoOperationBusMasterRead
,
2426 if (EFI_ERROR (Status
)) {
2427 Status
= EFI_DEVICE_ERROR
;
2431 *DataCursor
= (UINT8
*) ((UINTN
) TempPhysicalAddr
);
2436 *PktId
= OUTPUT_PACKET_ID
;
2445 Status
= EFI_INVALID_PARAMETER
;
2454 IN USB2_HC_DEV
*HcDev
,
2455 IN OUT VOID
*Request
,
2456 OUT UINT8
**RequestCursor
,
2457 OUT VOID
**RequestMap
2461 Routine Description:
2463 Map address of request structure buffer
2468 Request - A pointer to request structure
2469 RequestCursor - Mapped address of request structure to return
2470 RequestMap - Identificaion of this mapping to return
2475 EFI_DEVICE_ERROR Fail
2481 EFI_PHYSICAL_ADDRESS TempPhysicalAddr
;
2483 RequestLen
= sizeof (EFI_USB_DEVICE_REQUEST
);
2484 Status
= HcDev
->PciIo
->Map (
2486 EfiPciIoOperationBusMasterRead
,
2488 (UINTN
*) &RequestLen
,
2492 if (EFI_ERROR (Status
)) {
2493 Status
= EFI_DEVICE_ERROR
;
2497 *RequestCursor
= (UINT8
*) ((UINTN
) TempPhysicalAddr
);
2504 DeleteAsyncRequestTransfer (
2505 IN USB2_HC_DEV
*HcDev
,
2506 IN UINT8 DeviceAddress
,
2507 IN UINT8 EndPointAddress
,
2508 OUT UINT8
*DataToggle
2512 Routine Description:
2514 Delete all asynchronous request transfer
2519 DeviceAddress - address of usb device
2520 EndPointAddress - address of endpoint
2521 DataToggle - stored data toggle
2526 EFI_DEVICE_ERROR Fail
2531 EHCI_ASYNC_REQUEST
*AsyncRequestPtr
;
2532 EHCI_ASYNC_REQUEST
*MatchPtr
;
2533 EHCI_QH_HW
*QhHwPtr
;
2536 if (NULL
== HcDev
->AsyncRequestList
) {
2537 Status
= EFI_INVALID_PARAMETER
;
2543 EndPointNum
= EndPointAddress
& 0x0f;
2544 AsyncRequestPtr
= HcDev
->AsyncRequestList
;
2547 // Find QH of AsyncRequest by DeviceAddress and EndPointNum
2551 QhHwPtr
= &(AsyncRequestPtr
->QhPtr
->Qh
);
2552 if (QhHwPtr
->DeviceAddr
== DeviceAddress
&& QhHwPtr
->EndpointNum
== EndPointNum
) {
2553 MatchPtr
= AsyncRequestPtr
;
2557 AsyncRequestPtr
= AsyncRequestPtr
->Next
;
2559 } while (NULL
!= AsyncRequestPtr
);
2561 if (NULL
== MatchPtr
) {
2562 Status
= EFI_INVALID_PARAMETER
;
2566 Status
= DisablePeriodicSchedule (HcDev
);
2567 if (EFI_ERROR (Status
)) {
2568 Status
= EFI_DEVICE_ERROR
;
2572 Status
= WaitForPeriodicScheduleDisable (HcDev
, EHCI_GENERIC_TIMEOUT
);
2573 if (EFI_ERROR (Status
)) {
2574 DEBUG ((gEHCErrorLevel
, "WaitForPeriodicScheduleDisable TimeOut\n"));
2575 Status
= EFI_TIMEOUT
;
2579 *DataToggle
= (UINT8
) MatchPtr
->QhPtr
->Qh
.DataToggle
;
2580 UnlinkQhFromPeriodicList (HcDev
, MatchPtr
->QhPtr
, MatchPtr
->QhPtr
->Interval
);
2581 UnlinkFromAsyncReqeust (HcDev
, MatchPtr
);
2583 if (NULL
== HcDev
->AsyncRequestList
) {
2585 Status
= StopPollingTimer (HcDev
);
2586 if (EFI_ERROR (Status
)) {
2587 Status
= EFI_DEVICE_ERROR
;
2593 Status
= EnablePeriodicSchedule (HcDev
);
2594 if (EFI_ERROR (Status
)) {
2595 Status
= EFI_DEVICE_ERROR
;
2599 Status
= WaitForPeriodicScheduleEnable (HcDev
, EHCI_GENERIC_TIMEOUT
);
2600 if (EFI_ERROR (Status
)) {
2601 DEBUG ((gEHCErrorLevel
, "WaitForPeriodicScheduleEnable TimeOut\n"));
2602 Status
= EFI_TIMEOUT
;
2606 if (IsEhcHalted (HcDev
)) {
2607 Status
= StartScheduleExecution (HcDev
);
2608 if (EFI_ERROR (Status
)) {
2609 Status
= EFI_DEVICE_ERROR
;
2616 DestoryQtds (HcDev
, MatchPtr
->QhPtr
->FirstQtdPtr
);
2617 DestoryQh (HcDev
, MatchPtr
->QhPtr
);
2618 EhciFreePool (HcDev
, (UINT8
*) MatchPtr
, sizeof (EHCI_ASYNC_REQUEST
));
2625 CleanUpAllAsyncRequestTransfer (
2626 IN USB2_HC_DEV
*HcDev
2630 Routine Description:
2632 Clean up all asynchronous request transfer
2644 EHCI_ASYNC_REQUEST
*AsyncRequestPtr
;
2645 EHCI_ASYNC_REQUEST
*FreePtr
;
2647 AsyncRequestPtr
= NULL
;
2650 StopPollingTimer (HcDev
);
2652 AsyncRequestPtr
= HcDev
->AsyncRequestList
;
2653 while (NULL
!= AsyncRequestPtr
) {
2655 FreePtr
= AsyncRequestPtr
;
2656 AsyncRequestPtr
= AsyncRequestPtr
->Next
;
2657 UnlinkFromAsyncReqeust (HcDev
, FreePtr
);
2658 UnlinkQhFromPeriodicList (HcDev
, FreePtr
->QhPtr
, FreePtr
->QhPtr
->Interval
);
2659 DestoryQtds (HcDev
, FreePtr
->QhPtr
->FirstQtdPtr
);
2660 DestoryQh (HcDev
, FreePtr
->QhPtr
);
2661 EhciFreePool (HcDev
, (UINT8
*) FreePtr
, sizeof (EHCI_ASYNC_REQUEST
));
2670 IN EHCI_QH_ENTITY
*QhPtr
2674 Routine Description:
2676 Zero out the fields in Qh structure
2680 QhPtr - A pointer to Qh structure
2688 QhPtr
->Qh
.CurrentQtdPointer
= 0;
2689 QhPtr
->Qh
.AltNextQtdPointer
= 0;
2690 QhPtr
->Qh
.NakCount
= 0;
2691 QhPtr
->Qh
.AltNextQtdTerminate
= 0;
2692 QhPtr
->Qh
.TotalBytes
= 0;
2693 QhPtr
->Qh
.InterruptOnComplete
= 0;
2694 QhPtr
->Qh
.CurrentPage
= 0;
2695 QhPtr
->Qh
.ErrorCount
= 0;
2696 QhPtr
->Qh
.PidCode
= 0;
2697 QhPtr
->Qh
.Status
= 0;
2698 QhPtr
->Qh
.BufferPointer0
= 0;
2699 QhPtr
->Qh
.CurrentOffset
= 0;
2700 QhPtr
->Qh
.BufferPointer1
= 0;
2701 QhPtr
->Qh
.CompleteSplitMask
= 0;
2702 QhPtr
->Qh
.BufferPointer2
= 0;
2703 QhPtr
->Qh
.SplitBytes
= 0;
2704 QhPtr
->Qh
.FrameTag
= 0;
2705 QhPtr
->Qh
.BufferPointer3
= 0;
2706 QhPtr
->Qh
.BufferPointer4
= 0;
2707 QhPtr
->Qh
.ExtBufferPointer0
= 0;
2708 QhPtr
->Qh
.ExtBufferPointer1
= 0;
2709 QhPtr
->Qh
.ExtBufferPointer2
= 0;
2710 QhPtr
->Qh
.ExtBufferPointer3
= 0;
2711 QhPtr
->Qh
.ExtBufferPointer4
= 0;
2715 UpdateAsyncRequestTransfer (
2716 IN EHCI_ASYNC_REQUEST
*AsyncRequestPtr
,
2717 IN UINT32 TransferResult
,
2722 Routine Description:
2724 Update asynchronous request transfer
2728 AsyncRequestPtr - A pointer to async request
2729 TransferResult - transfer result
2730 ErrQtdPos - postion of error Qtd
2738 EHCI_QTD_ENTITY
*QtdPtr
;
2742 if (EFI_USB_NOERROR
== TransferResult
) {
2745 // Update Qh for next trigger
2748 QtdPtr
= AsyncRequestPtr
->QhPtr
->FirstQtdPtr
;
2751 // Update fields in Qh
2755 // Get DataToggle from Overlay in Qh
2757 // ZeroOut Overlay in Qh except DataToggle, HostController will update this field
2759 ZeroOutQhOverlay (AsyncRequestPtr
->QhPtr
);
2760 AsyncRequestPtr
->QhPtr
->Qh
.NextQtdPointer
= (UINT32
) (GET_0B_TO_31B (&(QtdPtr
->Qtd
)) >> 5);
2761 AsyncRequestPtr
->QhPtr
->Qh
.NextQtdTerminate
= FALSE
;
2764 // Update fields in Qtd
2766 while (NULL
!= QtdPtr
) {
2767 QtdPtr
->Qtd
.TotalBytes
= QtdPtr
->StaticTotalBytes
;
2768 QtdPtr
->Qtd
.CurrentOffset
= QtdPtr
->StaticCurrentOffset
;
2769 QtdPtr
->Qtd
.CurrentPage
= 0;
2770 QtdPtr
->Qtd
.ErrorCount
= QTD_ERROR_COUNTER
;
2771 QtdPtr
->Qtd
.Status
= QTD_STATUS_ACTIVE
;
2773 QtdPtr
->TotalBytes
= QtdPtr
->StaticTotalBytes
;
2774 QtdPtr
= QtdPtr
->Next
;
2782 CheckQtdsTransferResult (
2783 IN BOOLEAN IsControl
,
2784 IN EHCI_QH_ENTITY
*QhPtr
,
2786 OUT UINTN
*ErrQtdPos
,
2787 OUT UINTN
*ActualLen
2791 Routine Description:
2793 Check transfer result of Qtds
2797 IsControl - Is control transfer or not
2798 QhPtr - A pointer to Qh
2799 Result - Transfer result
2800 ErrQtdPos - Error TD Position
2801 ActualLen - Actual Transfer Size
2810 UINTN ActualLenPerQtd
;
2811 EHCI_QTD_ENTITY
*QtdPtr
;
2812 EHCI_QTD_HW
*QtdHwPtr
;
2821 QtdPtr
= QhPtr
->FirstQtdPtr
;
2822 QtdHwPtr
= &(QtdPtr
->Qtd
);
2824 while (NULL
!= QtdHwPtr
) {
2826 if (IsQtdStatusActive (QtdHwPtr
)) {
2827 *Result
|= EFI_USB_ERR_NOTEXECUTE
;
2830 if (IsQtdStatusHalted (QtdHwPtr
)) {
2831 *Result
|= EFI_USB_ERR_STALL
;
2834 if (IsQtdStatusBufferError (QtdHwPtr
)) {
2835 *Result
|= EFI_USB_ERR_BUFFER
;
2838 if (IsQtdStatusBabbleError (QtdHwPtr
)) {
2839 *Result
|= EFI_USB_ERR_BABBLE
;
2842 if (IsQtdStatusTransactionError (QtdHwPtr
)) {
2843 *Result
|= EFI_USB_ERR_TIMEOUT
;
2846 ActualLenPerQtd
= QtdPtr
->TotalBytes
- QtdHwPtr
->TotalBytes
;
2847 QtdPtr
->TotalBytes
= QtdHwPtr
->TotalBytes
;
2849 // Accumulate actual transferred data length in each DataQtd.
2851 if (SETUP_PACKET_PID_CODE
!= QtdHwPtr
->PidCode
) {
2852 *ActualLen
+= ActualLenPerQtd
;
2860 if ((!IsControl
) && (QtdPtr
->TotalBytes
> 0)) {
2862 // Did something, but isn't full workload
2868 QtdHwPtr
= GetQtdNextPointer (QtdHwPtr
);
2869 QtdPtr
= (EHCI_QTD_ENTITY
*) GET_QTD_ENTITY_ADDR (QtdHwPtr
);
2878 IN USB2_HC_DEV
*HcDev
,
2879 IN BOOLEAN IsControl
,
2880 IN EHCI_QH_ENTITY
*QhPtr
,
2881 IN OUT UINTN
*ActualLen
,
2882 OUT UINT8
*DataToggle
,
2884 OUT UINT32
*TransferResult
2888 Routine Description:
2890 Execute Bulk or SyncInterrupt Transfer
2895 IsControl - Is control transfer or not
2896 QhPtr - A pointer to Qh
2897 ActualLen - Actual transfered Len
2898 DataToggle - Data Toggle
2899 TimeOut - TimeOut threshold
2900 TransferResult - Transfer result
2905 EFI_DEVICE_ERROR Fail
2915 Status
= EFI_SUCCESS
;
2917 *TransferResult
= EFI_USB_NOERROR
;
2918 RequireLen
= *ActualLen
;
2922 Delay
= (TimeOut
* STALL_1_MILLI_SECOND
/ 50) + 1;
2925 *TransferResult
= 0;
2926 Finished
= CheckQtdsTransferResult (
2937 // Qtd is inactive, which means bulk or interrupt transfer's end.
2939 if (!(*TransferResult
& EFI_USB_ERR_NOTEXECUTE
)) {
2943 gBS
->Stall (EHCI_SYNC_REQUEST_POLLING_TIME
);
2947 if (EFI_USB_NOERROR
!= *TransferResult
) {
2949 Status
= EFI_TIMEOUT
;
2951 Status
= EFI_DEVICE_ERROR
;
2956 // Special for Bulk and Interrupt Transfer
2958 *DataToggle
= (UINT8
) QhPtr
->Qh
.DataToggle
;
2964 AsyncRequestMoniter (
2969 Routine Description:
2971 Interrupt transfer periodic check handler
2974 Event - Interrupt event
2975 Context - Pointer to USB2_HC_DEV
2980 EFI_DEVICE_ERROR Fail
2986 EHCI_ASYNC_REQUEST
*AsyncRequestPtr
;
2987 EHCI_QTD_HW
*QtdHwPtr
;
2990 UINT32 TransferResult
;
2991 UINT8
*ReceiveBuffer
;
2992 UINT8
*ProcessBuffer
;
2994 Status
= EFI_SUCCESS
;
2996 ReceiveBuffer
= NULL
;
2997 ProcessBuffer
= NULL
;
2998 HcDev
= (USB2_HC_DEV
*) Context
;
2999 AsyncRequestPtr
= HcDev
->AsyncRequestList
;
3001 while (NULL
!= AsyncRequestPtr
) {
3007 CheckQtdsTransferResult (
3009 AsyncRequestPtr
->QhPtr
,
3015 if ((TransferResult
& EFI_USB_ERR_NAK
) || (TransferResult
& EFI_USB_ERR_NOTEXECUTE
)) {
3016 AsyncRequestPtr
= AsyncRequestPtr
->Next
;
3020 // Allocate memory for EHC private data structure
3022 ProcessBuffer
= AllocateZeroPool (ActualLen
);
3023 if (NULL
== ProcessBuffer
) {
3024 Status
= EFI_OUT_OF_RESOURCES
;
3028 QtdHwPtr
= &(AsyncRequestPtr
->QhPtr
->FirstQtdPtr
->Qtd
);
3029 ReceiveBuffer
= (UINT8
*) (UINTN
) GET_0B_TO_31B ((QtdHwPtr
->BufferPointer0
<< 12) | AsyncRequestPtr
->QhPtr
->FirstQtdPtr
->StaticCurrentOffset
);
3036 UpdateAsyncRequestTransfer (AsyncRequestPtr
, TransferResult
, ErrQtdPos
);
3038 if (EFI_USB_NOERROR
== TransferResult
) {
3040 if (AsyncRequestPtr
->CallBackFunc
!= NULL
) {
3041 (AsyncRequestPtr
->CallBackFunc
) (ProcessBuffer
, ActualLen
, AsyncRequestPtr
->Context
, TransferResult
);
3047 // leave error recovery to its related device driver. A common case of
3048 // the error recovery is to re-submit the interrupt transfer.
3049 // When an interrupt transfer is re-submitted, its position in the linked
3050 // list is changed. It is inserted to the head of the linked list, while
3051 // this function scans the whole list from head to tail. Thus, the
3052 // re-submitted interrupt transfer's callback function will not be called
3053 // again in this round.
3055 if (AsyncRequestPtr
->CallBackFunc
!= NULL
) {
3056 (AsyncRequestPtr
->CallBackFunc
) (NULL
, 0, AsyncRequestPtr
->Context
, TransferResult
);
3061 if (NULL
!= ProcessBuffer
) {
3062 gBS
->FreePool (ProcessBuffer
);
3065 AsyncRequestPtr
= AsyncRequestPtr
->Next
;