summaryrefslogtreecommitdiff
path: root/EdkModulePkg/Bus/Pci/Ehci/Dxe/EhciSched.c
diff options
context:
space:
mode:
authorljin6 <ljin6@6f19259b-4bc3-4df7-8a09-765794883524>2006-07-18 04:13:40 +0000
committerljin6 <ljin6@6f19259b-4bc3-4df7-8a09-765794883524>2006-07-18 04:13:40 +0000
commit562d28495df348923812281161e64bc9514e15e6 (patch)
tree121f4f3c37c23b23a4dabe21cf4fc46c78a0c5b3 /EdkModulePkg/Bus/Pci/Ehci/Dxe/EhciSched.c
parent4b9fc76f7bba0d847d36cb2070a2d3305ae87acc (diff)
downloadedk2-platforms-562d28495df348923812281161e64bc9514e15e6.tar.xz
Add DevicePathUtilities DevicePathToText DevciePathFromText USB2HostController protocols
git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@1037 6f19259b-4bc3-4df7-8a09-765794883524
Diffstat (limited to 'EdkModulePkg/Bus/Pci/Ehci/Dxe/EhciSched.c')
-rw-r--r--EdkModulePkg/Bus/Pci/Ehci/Dxe/EhciSched.c3072
1 files changed, 3072 insertions, 0 deletions
diff --git a/EdkModulePkg/Bus/Pci/Ehci/Dxe/EhciSched.c b/EdkModulePkg/Bus/Pci/Ehci/Dxe/EhciSched.c
new file mode 100644
index 0000000000..3dc1ff74af
--- /dev/null
+++ b/EdkModulePkg/Bus/Pci/Ehci/Dxe/EhciSched.c
@@ -0,0 +1,3072 @@
+/*++
+
+Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+Module Name:
+
+ EhciSched.c
+
+Abstract:
+
+
+Revision History
+--*/
+
+#include "Ehci.h"
+
+EFI_STATUS
+InitialPeriodicFrameList (
+ IN USB2_HC_DEV *HcDev,
+ IN UINTN Length
+ )
+/*++
+
+Routine Description:
+
+ Initialize Periodic Schedule Frame List
+
+Arguments:
+
+ HcDev - USB2_HC_DEV
+ Length - Frame List Length
+
+Returns:
+
+ EFI_SUCCESS Success
+ EFI_DEVICE_ERROR Fail
+
+--*/
+{
+ EFI_STATUS Status;
+ VOID *CommonBuffer;
+ EFI_PHYSICAL_ADDRESS FrameBuffer;
+ VOID *Map;
+ UINTN BufferSizeInPages;
+ UINTN BufferSizeInBytes;
+ UINTN FrameIndex;
+ FRAME_LIST_ENTRY *FrameEntryPtr;
+
+ //
+ // The Frame List is a common buffer that will be
+ // accessed by both the cpu and the usb bus master
+ // at the same time.
+ // The Frame List ocupies 4K bytes,
+ // and must be aligned on 4-Kbyte boundaries.
+ //
+ if (EHCI_MAX_FRAME_LIST_LENGTH != Length && IsFrameListProgrammable (HcDev)) {
+ Status = SetFrameListLen (HcDev, Length);
+ if (EFI_ERROR (Status)) {
+ Status = EFI_INVALID_PARAMETER;
+ goto exit;
+ }
+ }
+
+ BufferSizeInBytes = EFI_PAGE_SIZE;
+ BufferSizeInPages = EFI_SIZE_TO_PAGES (BufferSizeInBytes);
+ Status = HcDev->PciIo->AllocateBuffer (
+ HcDev->PciIo,
+ AllocateAnyPages,
+ EfiBootServicesData,
+ BufferSizeInPages,
+ &CommonBuffer,
+ 0
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((gEHCErrorLevel, "PciIo->AllocateBuffer Failed\n"));
+ Status = EFI_OUT_OF_RESOURCES;
+ goto exit;
+ }
+
+ Status = HcDev->PciIo->Map (
+ HcDev->PciIo,
+ EfiPciIoOperationBusMasterCommonBuffer,
+ CommonBuffer,
+ &BufferSizeInBytes,
+ &FrameBuffer,
+ &Map
+ );
+ if (EFI_ERROR (Status) || (BufferSizeInBytes != EFI_PAGE_SIZE)) {
+ DEBUG ((gEHCErrorLevel, "PciIo->MapBuffer Failed\n"));
+ Status = EFI_OUT_OF_RESOURCES;
+ goto free_buffer;
+ }
+
+ //
+ // Put high 32bit into CtrlDataStructSeg reg
+ // when 64bit addressing range capability
+ //
+ if (HcDev->Is64BitCapable != 0) {
+ HcDev->High32BitAddr = (UINT32) GET_32B_TO_63B (FrameBuffer);
+
+ Status = SetCtrlDataStructSeg (HcDev);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((gEHCErrorLevel, "SetCtrlDataStructSeg Failed\n"));
+ Status = EFI_DEVICE_ERROR;
+ goto unmap_buffer;
+ }
+ }
+
+ //
+ // Tell the Host Controller where the Frame List lies,
+ // by set the Frame List Base Address Register.
+ //
+ Status = SetFrameListBaseAddr (HcDev, (UINT32) FrameBuffer);
+ if (EFI_ERROR (Status)) {
+ Status = EFI_DEVICE_ERROR;
+ goto unmap_buffer;
+ }
+
+ HcDev->PeriodicFrameListLength = Length;
+ HcDev->PeriodicFrameListBuffer = (VOID *) ((UINTN) FrameBuffer);
+ HcDev->PeriodicFrameListMap = Map;
+
+ //
+ // Init Frame List Array fields
+ //
+ FrameEntryPtr = (FRAME_LIST_ENTRY *) HcDev->PeriodicFrameListBuffer;
+ for (FrameIndex = 0; FrameIndex < HcDev->PeriodicFrameListLength; FrameIndex++) {
+ FrameEntryPtr->LinkPointer = 0;
+ FrameEntryPtr->Rsvd = 0;
+ FrameEntryPtr->SelectType = 0;
+ FrameEntryPtr->LinkTerminate = TRUE;
+ FrameEntryPtr++;
+ }
+
+ goto exit;
+
+unmap_buffer:
+ HcDev->PciIo->Unmap (HcDev->PciIo, Map);
+free_buffer:
+ HcDev->PciIo->FreeBuffer (HcDev->PciIo, BufferSizeInPages, CommonBuffer);
+exit:
+ return Status;
+}
+
+VOID
+DeinitialPeriodicFrameList (
+ IN USB2_HC_DEV *HcDev
+ )
+/*++
+
+Routine Description:
+
+ Deinitialize Periodic Schedule Frame List
+
+Arguments:
+
+ HcDev - USB2_HC_DEV
+
+Returns:
+
+ VOID
+
+--*/
+{
+ HcDev->PciIo->Unmap (HcDev->PciIo, HcDev->PeriodicFrameListMap);
+ HcDev->PciIo->FreeBuffer (HcDev->PciIo, EFI_SIZE_TO_PAGES (EFI_PAGE_SIZE), HcDev->PeriodicFrameListBuffer);
+ return ;
+}
+
+EFI_STATUS
+CreatePollingTimer (
+ IN USB2_HC_DEV *HcDev,
+ IN EFI_EVENT_NOTIFY NotifyFunction
+ )
+/*++
+
+Routine Description:
+
+ Create Async Request Polling Timer
+
+Arguments:
+
+ HcDev - USB2_HC_DEV
+ NotifyFunction - Timer Notify Function
+
+Returns:
+
+ EFI_SUCCESS Success
+ EFI_DEVICE_ERROR Fail
+
+--*/
+{
+ return gBS->CreateEvent (
+ EFI_EVENT_TIMER | EFI_EVENT_NOTIFY_SIGNAL,
+ EFI_TPL_NOTIFY,
+ NotifyFunction,
+ HcDev,
+ &HcDev->AsyncRequestEvent
+ );
+}
+
+EFI_STATUS
+DestoryPollingTimer (
+ IN USB2_HC_DEV *HcDev
+ )
+/*++
+
+Routine Description:
+
+ Destory Async Request Polling Timer
+
+Arguments:
+
+ HcDev - USB2_HC_DEV
+
+Returns:
+
+ EFI_SUCCESS Success
+ EFI_DEVICE_ERROR Fail
+
+--*/
+{
+ return gBS->CloseEvent (HcDev->AsyncRequestEvent);
+}
+
+EFI_STATUS
+StartPollingTimer (
+ IN USB2_HC_DEV *HcDev
+ )
+/*++
+
+Routine Description:
+
+ Start Async Request Polling Timer
+
+Arguments:
+
+ HcDev - USB2_HC_DEV
+
+Returns:
+
+ EFI_SUCCESS Success
+ EFI_DEVICE_ERROR Fail
+
+--*/
+{
+ return gBS->SetTimer (
+ HcDev->AsyncRequestEvent,
+ TimerPeriodic,
+ EHCI_ASYNC_REQUEST_POLLING_TIME
+ );
+}
+
+EFI_STATUS
+StopPollingTimer (
+ IN USB2_HC_DEV *HcDev
+ )
+/*++
+
+Routine Description:
+
+ Stop Async Request Polling Timer
+
+Arguments:
+
+ HcDev - USB2_HC_DEV
+
+Returns:
+
+ EFI_SUCCESS Success
+ EFI_DEVICE_ERROR Fail
+
+--*/
+{
+ return gBS->SetTimer (
+ HcDev->AsyncRequestEvent,
+ TimerCancel,
+ EHCI_ASYNC_REQUEST_POLLING_TIME
+ );
+}
+
+EFI_STATUS
+CreateQh (
+ IN USB2_HC_DEV *HcDev,
+ IN UINT8 DeviceAddr,
+ IN UINT8 Endpoint,
+ IN UINT8 DeviceSpeed,
+ IN UINTN MaxPacketLen,
+ OUT EHCI_QH_ENTITY **QhPtrPtr
+ )
+/*++
+
+Routine Description:
+
+ Create Qh Structure and Pre-Initialize
+
+Arguments:
+
+ HcDev - USB2_HC_DEV
+ DeviceAddr - Address of Device
+ Endpoint - Endpoint Number
+ DeviceSpeed - Device Speed
+ MaxPacketLen - Max Length of one Packet
+ QhPtrPtr - A pointer of pointer to Qh for return
+
+Returns:
+
+ EFI_SUCCESS Success
+ EFI_OUT_OF_RESOURCES Cannot allocate resources
+
+--*/
+{
+ EFI_STATUS Status;
+ EHCI_QH_HW *QhHwPtr;
+
+ ASSERT (HcDev);
+ ASSERT (QhPtrPtr);
+
+ *QhPtrPtr = NULL;
+
+ //
+ // Allocate memory for Qh structure
+ //
+ Status = EhciAllocatePool (
+ HcDev,
+ (UINT8 **) QhPtrPtr,
+ sizeof (EHCI_QH_ENTITY)
+ );
+ if (EFI_ERROR (Status)) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto exit;
+ }
+ //
+ // Init fields in Qh
+ //
+ gBS->SetMem (*QhPtrPtr, sizeof (EHCI_QH_ENTITY), 0);
+
+ //
+ // Software field
+ //
+ (*QhPtrPtr)->Next = NULL;
+ (*QhPtrPtr)->Prev = NULL;
+ (*QhPtrPtr)->FirstQtdPtr = NULL;
+ (*QhPtrPtr)->AltQtdPtr = NULL;
+ (*QhPtrPtr)->LastQtdPtr = NULL;
+
+ //
+ // Hardware field
+ //
+ QhHwPtr = &((*QhPtrPtr)->Qh);
+ QhHwPtr->QhHorizontalPointer = 0;
+ QhHwPtr->SelectType = 0;
+ QhHwPtr->MaxPacketLen = (UINT32) MaxPacketLen;
+ QhHwPtr->EndpointSpeed = (DeviceSpeed & 0x3);
+ QhHwPtr->EndpointNum = (Endpoint & 0x0f);
+ QhHwPtr->DeviceAddr = (DeviceAddr & 0x7f);
+ QhHwPtr->Multiplier = HIGH_BANDWIDTH_PIPE_MULTIPLIER;
+ QhHwPtr->Rsvd1 = 0;
+ QhHwPtr->Rsvd2 = 0;
+ QhHwPtr->Rsvd3 = 0;
+ QhHwPtr->Rsvd4 = 0;
+ QhHwPtr->Rsvd5 = 0;
+ QhHwPtr->Rsvd6 = 0;
+
+exit:
+ return Status;
+}
+
+VOID
+DestoryQh (
+ IN USB2_HC_DEV *HcDev,
+ IN EHCI_QH_ENTITY *QhPtr
+ )
+/*++
+
+Routine Description:
+
+ Destory Qh Structure
+
+Arguments:
+
+ HcDev - USB2_HC_DEV
+ QhPtr - A pointer to Qh
+
+Returns:
+
+ EFI_SUCCESS Success
+ EFI_DEVICE_ERROR Fail
+
+--*/
+{
+ ASSERT (HcDev);
+ ASSERT (QhPtr);
+
+ EhciFreePool (HcDev, (UINT8 *) QhPtr, sizeof (EHCI_QH_ENTITY));
+ return ;
+}
+
+EFI_STATUS
+CreateControlQh (
+ IN USB2_HC_DEV *HcDev,
+ IN UINT8 DeviceAddr,
+ IN UINT8 DeviceSpeed,
+ IN UINTN MaxPacketLen,
+ IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,
+ OUT EHCI_QH_ENTITY **QhPtrPtr
+ )
+/*++
+
+Routine Description:
+
+ Create Qh for Control Transfer
+
+Arguments:
+
+ HcDev - USB2_HC_DEV
+ DeviceAddr - Address of Device
+ DeviceSpeed - Device Speed
+ MaxPacketLen - Max Length of one Packet
+ Translator - Translator Transaction for SplitX
+ QhPtrPtr - A pointer of pointer to Qh for return
+
+Returns:
+
+ EFI_SUCCESS Success
+ EFI_OUT_OF_RESOURCES Cannot allocate resources
+
+--*/
+{
+ EFI_STATUS Status;
+
+ //
+ // Create and init Control Qh
+ //
+ Status = CreateQh (
+ HcDev,
+ DeviceAddr,
+ 0,
+ DeviceSpeed,
+ MaxPacketLen,
+ QhPtrPtr
+ );
+ if (EFI_ERROR (Status)) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto exit;
+ }
+ //
+ // Software field
+ //
+ (*QhPtrPtr)->Next = (*QhPtrPtr);
+ (*QhPtrPtr)->Prev = (*QhPtrPtr);
+ (*QhPtrPtr)->TransferType = CONTROL_TRANSFER;
+
+ //
+ // Hardware field
+ //
+ // Control Transfer use DataToggleControl
+ //
+ (*QhPtrPtr)->Qh.DataToggleControl = TRUE;
+ (*QhPtrPtr)->Qh.QhHorizontalPointer = (UINT32) (GET_0B_TO_31B (&((*QhPtrPtr)->Qh)) >> 5);
+ (*QhPtrPtr)->Qh.SelectType = QH_SELECT_TYPE;
+ (*QhPtrPtr)->Qh.QhTerminate = FALSE;
+ (*QhPtrPtr)->Qh.ControlEndpointFlag = TRUE;
+ (*QhPtrPtr)->Qh.NakCountReload = NAK_COUNT_RELOAD;
+ if (NULL != Translator) {
+ (*QhPtrPtr)->Qh.PortNum = Translator->TranslatorPortNumber;
+ (*QhPtrPtr)->Qh.HubAddr = Translator->TranslatorHubAddress;
+ (*QhPtrPtr)->Qh.Status |= QTD_STATUS_DO_START_SPLIT;
+ }
+
+exit:
+ return Status;
+}
+
+EFI_STATUS
+CreateBulkQh (
+ IN USB2_HC_DEV *HcDev,
+ IN UINT8 DeviceAddr,
+ IN UINT8 EndPointAddr,
+ IN UINT8 DeviceSpeed,
+ IN UINT8 DataToggle,
+ IN UINTN MaxPacketLen,
+ IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,
+ OUT EHCI_QH_ENTITY **QhPtrPtr
+ )
+/*++
+
+Routine Description:
+
+ Create Qh for Bulk Transfer
+
+Arguments:
+
+ HcDev - USB2_HC_DEV
+ DeviceAddr - Address of Device
+ EndPointAddr - Address of Endpoint
+ DeviceSpeed - Device Speed
+ MaxPacketLen - Max Length of one Packet
+ Translator - Translator Transaction for SplitX
+ QhPtrPtr - A pointer of pointer to Qh for return
+
+Returns:
+
+ EFI_SUCCESS Success
+ EFI_OUT_OF_RESOURCES Cannot allocate resources
+
+--*/
+{
+ EFI_STATUS Status;
+
+ //
+ // Create and init Bulk Qh
+ //
+ Status = CreateQh (
+ HcDev,
+ DeviceAddr,
+ EndPointAddr,
+ DeviceSpeed,
+ MaxPacketLen,
+ QhPtrPtr
+ );
+ if (EFI_ERROR (Status)) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto exit;
+ }
+
+ //
+ // Software fields
+ //
+ (*QhPtrPtr)->Next = (*QhPtrPtr);
+ (*QhPtrPtr)->Prev = (*QhPtrPtr);
+ (*QhPtrPtr)->TransferType = BULK_TRANSFER;
+
+ //
+ // Hardware fields
+ //
+ // BulkTransfer don't use DataToggleControl
+ //
+ (*QhPtrPtr)->Qh.DataToggleControl = FALSE;
+ (*QhPtrPtr)->Qh.QhHorizontalPointer = (UINT32) (GET_0B_TO_31B (&((*QhPtrPtr)->Qh)) >> 5);
+ (*QhPtrPtr)->Qh.SelectType = QH_SELECT_TYPE;
+ (*QhPtrPtr)->Qh.QhTerminate = FALSE;
+ (*QhPtrPtr)->Qh.NakCountReload = NAK_COUNT_RELOAD;
+ (*QhPtrPtr)->Qh.DataToggle = DataToggle;
+ if (NULL != Translator) {
+ (*QhPtrPtr)->Qh.PortNum = Translator->TranslatorPortNumber;
+ (*QhPtrPtr)->Qh.HubAddr = Translator->TranslatorHubAddress;
+ (*QhPtrPtr)->Qh.Status |= QTD_STATUS_DO_START_SPLIT;
+ }
+
+exit:
+ return Status;
+}
+
+EFI_STATUS
+CreateInterruptQh (
+ IN USB2_HC_DEV *HcDev,
+ IN UINT8 DeviceAddr,
+ IN UINT8 EndPointAddr,
+ IN UINT8 DeviceSpeed,
+ IN UINT8 DataToggle,
+ IN UINTN MaxPacketLen,
+ IN UINTN Interval,
+ IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,
+ OUT EHCI_QH_ENTITY **QhPtrPtr
+ )
+/*++
+
+Routine Description:
+
+ Create Qh for Control Transfer
+
+Arguments:
+
+ HcDev - USB2_HC_DEV
+ DeviceAddr - Address of Device
+ EndPointAddr - Address of Endpoint
+ DeviceSpeed - Device Speed
+ MaxPacketLen - Max Length of one Packet
+ Interval - value of interval
+ Translator - Translator Transaction for SplitX
+ QhPtrPtr - A pointer of pointer to Qh for return
+
+Returns:
+
+ EFI_SUCCESS Success
+ EFI_OUT_OF_RESOURCES Cannot allocate resources
+
+--*/
+{
+ EFI_STATUS Status;
+
+ //
+ // Create and init InterruptQh
+ //
+ Status = CreateQh (
+ HcDev,
+ DeviceAddr,
+ EndPointAddr,
+ DeviceSpeed,
+ MaxPacketLen,
+ QhPtrPtr
+ );
+ if (EFI_ERROR (Status)) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto exit;
+ }
+
+ //
+ // Software fields
+ //
+ if (Interval == 0) {
+ (*QhPtrPtr)->TransferType = SYNC_INTERRUPT_TRANSFER;
+ } else {
+ (*QhPtrPtr)->TransferType = ASYNC_INTERRUPT_TRANSFER;
+ }
+ (*QhPtrPtr)->Interval = GetApproxiOfInterval (Interval);
+
+ //
+ // Hardware fields
+ //
+ // InterruptTranfer don't use DataToggleControl
+ //
+ (*QhPtrPtr)->Qh.DataToggleControl = FALSE;
+ (*QhPtrPtr)->Qh.QhHorizontalPointer = 0;
+ (*QhPtrPtr)->Qh.QhTerminate = TRUE;
+ (*QhPtrPtr)->Qh.NakCountReload = 0;
+ (*QhPtrPtr)->Qh.InerruptScheduleMask = MICRO_FRAME_0_CHANNEL;
+ (*QhPtrPtr)->Qh.SplitComletionMask = (MICRO_FRAME_2_CHANNEL | MICRO_FRAME_3_CHANNEL | MICRO_FRAME_4_CHANNEL);
+ (*QhPtrPtr)->Qh.DataToggle = DataToggle;
+ if (NULL != Translator) {
+ (*QhPtrPtr)->Qh.PortNum = Translator->TranslatorPortNumber;
+ (*QhPtrPtr)->Qh.HubAddr = Translator->TranslatorHubAddress;
+ (*QhPtrPtr)->Qh.Status |= QTD_STATUS_DO_START_SPLIT;
+ }
+
+exit:
+ return Status;
+}
+
+EFI_STATUS
+CreateQtd (
+ IN USB2_HC_DEV *HcDev,
+ IN UINT8 *DataPtr,
+ IN UINTN DataLen,
+ IN UINT8 PktId,
+ IN UINT8 Toggle,
+ IN UINT8 QtdStatus,
+ OUT EHCI_QTD_ENTITY **QtdPtrPtr
+ )
+/*++
+
+Routine Description:
+
+ Create Qtd Structure and Pre-Initialize it
+
+Arguments:
+
+ HcDev - USB2_HC_DEV
+ DataPtr - A pointer to user data buffer to transfer
+ DataLen - Length of user data to transfer
+ PktId - Packet Identification of this Qtd
+ Toggle - Data Toggle of this Qtd
+ QtdStatus - Default value of status of this Qtd
+ QtdPtrPtr - A pointer of pointer to Qtd for return
+
+Returns:
+
+ EFI_SUCCESS Success
+ EFI_OUT_OF_RESOURCES Cannot allocate resources
+
+--*/
+{
+ EFI_STATUS Status;
+ EHCI_QTD_HW *QtdHwPtr;
+
+ ASSERT (HcDev);
+ ASSERT (QtdPtrPtr);
+
+ //
+ // Create memory for Qtd structure
+ //
+ Status = EhciAllocatePool (
+ HcDev,
+ (UINT8 **) QtdPtrPtr,
+ sizeof (EHCI_QTD_ENTITY)
+ );
+ if (EFI_ERROR (Status)) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto exit;
+ }
+ //
+ // Init fields in Qtd
+ //
+ gBS->SetMem (*QtdPtrPtr, sizeof (EHCI_QTD_ENTITY), 0);
+
+ //
+ // Software field
+ //
+ (*QtdPtrPtr)->TotalBytes = (UINT32) DataLen;
+ (*QtdPtrPtr)->StaticTotalBytes = (UINT32) DataLen;
+ (*QtdPtrPtr)->Prev = NULL;
+ (*QtdPtrPtr)->Next = NULL;
+
+ //
+ // Hardware field
+ //
+ QtdHwPtr = &((*QtdPtrPtr)->Qtd);
+ QtdHwPtr->NextQtdPointer = 0;
+ QtdHwPtr->NextQtdTerminate = TRUE;
+ QtdHwPtr->AltNextQtdPointer = 0;
+ QtdHwPtr->AltNextQtdTerminate = TRUE;
+ QtdHwPtr->DataToggle = Toggle;
+ QtdHwPtr->TotalBytes = (UINT32) DataLen;
+ QtdHwPtr->CurrentPage = 0;
+ QtdHwPtr->ErrorCount = QTD_ERROR_COUNTER;
+ QtdHwPtr->Status = QtdStatus;
+ QtdHwPtr->Rsvd1 = 0;
+ QtdHwPtr->Rsvd2 = 0;
+ QtdHwPtr->Rsvd3 = 0;
+ QtdHwPtr->Rsvd4 = 0;
+ QtdHwPtr->Rsvd5 = 0;
+ QtdHwPtr->Rsvd6 = 0;
+
+ //
+ // Set PacketID [Setup/Data/Status]
+ //
+ switch (PktId) {
+ case SETUP_PACKET_ID:
+ QtdHwPtr->PidCode = SETUP_PACKET_PID_CODE;
+ break;
+
+ case INPUT_PACKET_ID:
+ QtdHwPtr->PidCode = INPUT_PACKET_PID_CODE;
+ break;
+
+ case OUTPUT_PACKET_ID:
+ QtdHwPtr->PidCode = OUTPUT_PACKET_PID_CODE;
+ break;
+
+ default:
+ Status = EFI_INVALID_PARAMETER;
+ goto exit;
+ }
+
+ //
+ // Set Data Buffer Pointers
+ //
+ if (NULL != DataPtr) {
+ SetQtdBufferPointer (
+ QtdHwPtr,
+ DataPtr,
+ DataLen
+ );
+ (*QtdPtrPtr)->StaticCurrentOffset = QtdHwPtr->CurrentOffset;
+ }
+
+exit:
+ return Status;
+}
+
+EFI_STATUS
+CreateSetupQtd (
+ IN USB2_HC_DEV *HcDev,
+ IN UINT8 *DevReqPtr,
+ OUT EHCI_QTD_ENTITY **QtdPtrPtr
+ )
+/*++
+
+Routine Description:
+
+ Create Qtd Structure for Setup
+
+Arguments:
+
+ HcDev - USB2_HC_DEV
+ DevReqPtr - A pointer to Device Request Data
+ QtdPtrPtr - A pointer of pointer to Qtd for return
+
+Returns:
+
+ EFI_SUCCESS Success
+ EFI_OUT_OF_RESOURCES Cannot allocate resources
+
+--*/
+{
+ return CreateQtd (
+ HcDev,
+ DevReqPtr,
+ sizeof (EFI_USB_DEVICE_REQUEST),
+ SETUP_PACKET_ID,
+ DATA0,
+ QTD_STATUS_ACTIVE,
+ QtdPtrPtr
+ );
+}
+
+EFI_STATUS
+CreateDataQtd (
+ IN USB2_HC_DEV *HcDev,
+ IN UINT8 *DataPtr,
+ IN UINTN DataLen,
+ IN UINT8 PktId,
+ IN UINT8 Toggle,
+ OUT EHCI_QTD_ENTITY **QtdPtrPtr
+ )
+/*++
+
+Routine Description:
+
+ Create Qtd Structure for data
+
+Arguments:
+
+ HcDev - USB2_HC_DEV
+ DataPtr - A pointer to user data buffer to transfer
+ DataLen - Length of user data to transfer
+ PktId - Packet Identification of this Qtd
+ Toggle - Data Toggle of this Qtd
+ QtdPtrPtr - A pointer of pointer to Qtd for return
+
+Returns:
+
+ EFI_SUCCESS Success
+ EFI_OUT_OF_RESOURCES Cannot allocate resources
+
+--*/
+{
+ return CreateQtd (
+ HcDev,
+ DataPtr,
+ DataLen,
+ PktId,
+ Toggle,
+ QTD_STATUS_ACTIVE,
+ QtdPtrPtr
+ );
+}
+
+EFI_STATUS
+CreateAltQtd (
+ IN USB2_HC_DEV *HcDev,
+ IN UINT8 PktId,
+ OUT EHCI_QTD_ENTITY **QtdPtrPtr
+ )
+/*++
+
+Routine Description:
+
+ Create Qtd Structure for Alternative
+
+Arguments:
+
+ HcDev - USB2_HC_DEV
+ PktId - Packet Identification of this Qtd
+ QtdPtrPtr - A pointer of pointer to Qtd for return
+
+Returns:
+
+ EFI_SUCCESS Success
+ EFI_OUT_OF_RESOURCES Cannot allocate resources
+
+--*/
+{
+ return CreateQtd (
+ HcDev,
+ NULL,
+ 0,
+ PktId,
+ 0,
+ QTD_STATUS_ACTIVE,
+ QtdPtrPtr
+ );
+}
+
+EFI_STATUS
+CreateStatusQtd (
+ IN USB2_HC_DEV *HcDev,
+ IN UINT8 PktId,
+ OUT EHCI_QTD_ENTITY **QtdPtrPtr
+ )
+/*++
+
+Routine Description:
+
+ Create Qtd Structure for status
+
+Arguments:
+
+ HcDev - USB2_HC_DEV
+ PktId - Packet Identification of this Qtd
+ QtdPtrPtr - A pointer of pointer to Qtd for return
+
+Returns:
+
+ EFI_SUCCESS Success
+ EFI_OUT_OF_RESOURCES Cannot allocate resources
+
+--*/
+{
+ return CreateQtd (
+ HcDev,
+ NULL,
+ 0,
+ PktId,
+ DATA1,
+ QTD_STATUS_ACTIVE,
+ QtdPtrPtr
+ );
+}
+
+EFI_STATUS
+CreateControlQtds (
+ IN USB2_HC_DEV *HcDev,
+ IN UINT8 DataPktId,
+ IN UINT8 *RequestCursor,
+ IN UINT8 *DataCursor,
+ IN UINTN DataLen,
+ IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,
+ OUT EHCI_QTD_ENTITY **ControlQtdsHead
+ )
+/*++
+
+Routine Description:
+
+ Create Qtds list for Control Transfer
+
+Arguments:
+
+ HcDev - USB2_HC_DEV
+ DataPktId - Packet Identification of Data Qtds
+ RequestCursor - A pointer to request structure buffer to transfer
+ DataCursor - A pointer to user data buffer to transfer
+ DataLen - Length of user data to transfer
+ ControlQtdsHead - A pointer of pointer to first Qtd for control tranfer for return
+
+Returns:
+
+ EFI_SUCCESS Success
+ EFI_OUT_OF_RESOURCES Cannot allocate resources
+
+--*/
+{
+ EFI_STATUS Status;
+ EHCI_QTD_ENTITY *QtdPtr;
+ EHCI_QTD_ENTITY *PreQtdPtr;
+ EHCI_QTD_ENTITY *SetupQtdPtr;
+ EHCI_QTD_ENTITY *FirstDataQtdPtr;
+ EHCI_QTD_ENTITY *LastDataQtdPtr;
+ EHCI_QTD_ENTITY *StatusQtdPtr;
+ UINT8 DataToggle;
+ UINT8 StatusPktId;
+ UINTN CapacityOfQtd;
+ UINTN SizePerQtd;
+ UINTN DataCount;
+ UINTN Xnum;
+
+ QtdPtr = NULL;
+ PreQtdPtr = NULL;
+ SetupQtdPtr = NULL;
+ FirstDataQtdPtr = NULL;
+ LastDataQtdPtr = NULL;
+ StatusQtdPtr = NULL;
+ CapacityOfQtd = 0;
+
+ //
+ // Setup Stage of Control Transfer
+ //
+ Status = CreateSetupQtd (
+ HcDev,
+ RequestCursor,
+ &SetupQtdPtr
+ );
+ if (EFI_ERROR (Status)) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto exit;
+ }
+
+ //
+ // Data Stage of Control Transfer
+ //
+ DataToggle = 1;
+ DataCount = DataLen;
+
+ //
+ // Create Qtd structure and link together
+ //
+ while (DataCount > 0) {
+ //
+ // PktSize is the data load size that each Qtd.
+ //
+ CapacityOfQtd = GetCapacityOfQtd (DataCursor);
+ SizePerQtd = DataCount;
+ if (DataCount > CapacityOfQtd) {
+ SizePerQtd = CapacityOfQtd;
+ }
+
+ Status = CreateDataQtd (
+ HcDev,
+ DataCursor,
+ SizePerQtd,
+ DataPktId,
+ DataToggle,
+ &QtdPtr
+ );
+ if (EFI_ERROR (Status)) {
+ Status = EFI_OUT_OF_RESOURCES;
+ if (NULL == FirstDataQtdPtr) {
+ goto destory_setup_qtd;
+ } else {
+ goto destory_qtds;
+ }
+ }
+
+ if (NULL == FirstDataQtdPtr) {
+ FirstDataQtdPtr = QtdPtr;
+ } else {
+ LinkQtdToQtd (PreQtdPtr, QtdPtr);
+ }
+
+ //
+ // Reverse Data Toggle or not determined by parity of transactions of one qtd
+ //
+ Xnum = Translator ? GetNumberOfTransaction (SizePerQtd, EHCI_BLOCK_SIZE_WITH_TT) : GetNumberOfTransaction (SizePerQtd, EHCI_BLOCK_SIZE);
+ if (Xnum % 2 != 0) {
+ DataToggle ^= 1;
+ }
+
+ PreQtdPtr = QtdPtr;
+ DataCursor += SizePerQtd;
+ DataCount -= SizePerQtd;
+ }
+
+ LastDataQtdPtr = QtdPtr;
+
+ //
+ // Status Stage of Control Transfer
+ //
+ if (OUTPUT_PACKET_ID == DataPktId) {
+ StatusPktId = INPUT_PACKET_ID;
+ } else {
+ StatusPktId = OUTPUT_PACKET_ID;
+ }
+
+ Status = CreateStatusQtd (
+ HcDev,
+ StatusPktId,
+ &StatusQtdPtr
+ );
+ if (EFI_ERROR (Status)) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto destory_qtds;
+ }
+
+ //
+ // Link setup Qtd -> data Qtds -> status Qtd
+ //
+ if (FirstDataQtdPtr != NULL) {
+ LinkQtdToQtd (SetupQtdPtr, FirstDataQtdPtr);
+ LinkQtdToQtd (LastDataQtdPtr, StatusQtdPtr);
+ } else {
+ LinkQtdToQtd (SetupQtdPtr, StatusQtdPtr);
+ }
+
+ *ControlQtdsHead = SetupQtdPtr;
+
+ goto exit;
+
+destory_qtds:
+ DestoryQtds (HcDev, FirstDataQtdPtr);
+destory_setup_qtd:
+ DestoryQtds (HcDev, SetupQtdPtr);
+exit:
+ return Status;
+}
+
+EFI_STATUS
+CreateBulkOrInterruptQtds (
+ IN USB2_HC_DEV *HcDev,
+ IN UINT8 PktId,
+ IN UINT8 *DataCursor,
+ IN UINTN DataLen,
+ IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,
+ OUT EHCI_QTD_ENTITY **QtdsHead
+ )
+/*++
+
+Routine Description:
+
+ Create Qtds list for Bulk or Interrupt Transfer
+
+Arguments:
+
+ HcDev - USB2_HC_DEV
+ PktId - Packet Identification of Qtds
+ DataCursor - A pointer to user data buffer to transfer
+ DataLen - Length of user data to transfer
+ DataToggle - Data Toggle to start
+ Translator - Translator Transaction for SplitX
+ QtdsHead - A pointer of pointer to first Qtd for control tranfer for return
+
+Returns:
+
+ EFI_SUCCESS Success
+ EFI_OUT_OF_RESOURCES Cannot allocate resources
+
+--*/
+{
+ EFI_STATUS Status;
+ EHCI_QTD_ENTITY *QtdPtr;
+ EHCI_QTD_ENTITY *PreQtdPtr;
+ EHCI_QTD_ENTITY *FirstQtdPtr;
+ EHCI_QTD_ENTITY *AltQtdPtr;
+ UINTN DataCount;
+ UINTN CapacityOfQtd;
+ UINTN SizePerQtd;
+
+ Status = EFI_SUCCESS;
+ QtdPtr = NULL;
+ PreQtdPtr = NULL;
+ FirstQtdPtr = NULL;
+ AltQtdPtr = NULL;
+ CapacityOfQtd = 0;
+
+ DataCount = DataLen;
+ while (DataCount > 0) {
+
+ CapacityOfQtd = GetCapacityOfQtd (DataCursor);
+ SizePerQtd = DataCount;
+ if (DataCount > CapacityOfQtd) {
+ SizePerQtd = CapacityOfQtd;
+ }
+
+ Status = CreateDataQtd (
+ HcDev,
+ DataCursor,
+ SizePerQtd,
+ PktId,
+ 0,
+ &QtdPtr
+ );
+ if (EFI_ERROR (Status)) {
+ Status = EFI_OUT_OF_RESOURCES;
+ if (NULL == FirstQtdPtr) {
+ goto exit;
+ } else {
+ goto destory_qtds;
+ }
+ }
+
+ if (NULL == FirstQtdPtr) {
+ FirstQtdPtr = QtdPtr;
+ } else {
+ LinkQtdToQtd (PreQtdPtr, QtdPtr);
+ }
+
+ PreQtdPtr = QtdPtr;
+ DataCursor += SizePerQtd;
+ DataCount -= SizePerQtd;
+ }
+
+ //
+ // Set Alternate Qtd
+ //
+ if (INPUT_PACKET_ID == PktId && 1 < GetNumberOfQtd (FirstQtdPtr)) {
+ Status = CreateAltQtd (
+ HcDev,
+ PktId,
+ &AltQtdPtr
+ );
+ if (EFI_ERROR (Status)) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto destory_qtds;
+ }
+
+ LinkQtdsToAltQtd (FirstQtdPtr, AltQtdPtr);
+ }
+
+ *QtdsHead = FirstQtdPtr;
+ goto exit;
+
+destory_qtds:
+ DestoryQtds (HcDev, FirstQtdPtr);
+exit:
+ return Status;
+}
+
+VOID
+DestoryQtds (
+ IN USB2_HC_DEV *HcDev,
+ IN EHCI_QTD_ENTITY *FirstQtdPtr
+ )
+/*++
+
+Routine Description:
+
+ Destory all Qtds in the list
+
+Arguments:
+
+ HcDev - USB2_HC_DEV
+ FirstQtdPtr - A pointer to first Qtd in the list
+
+Returns:
+
+ VOID
+
+--*/
+{
+ EHCI_QTD_ENTITY *PrevQtd;
+ EHCI_QTD_ENTITY *NextQtd;
+
+ if (!FirstQtdPtr) {
+ goto exit;
+ }
+
+ PrevQtd = FirstQtdPtr;
+
+ //
+ // Delete all the Qtds.
+ //
+ do {
+ NextQtd = PrevQtd->Next;
+ EhciFreePool (HcDev, (UINT8 *) PrevQtd, sizeof (EHCI_QTD_ENTITY));
+ PrevQtd = NextQtd;
+ } while (NULL != PrevQtd);
+
+exit:
+ return ;
+}
+
+UINTN
+GetNumberOfQtd (
+ IN EHCI_QTD_ENTITY *FirstQtdPtr
+ )
+/*++
+
+Routine Description:
+
+ Number of Qtds in the list
+
+Arguments:
+
+ FirstQtdPtr - A pointer to first Qtd in the list
+
+Returns:
+
+ Number of Qtds in the list
+
+--*/
+{
+ UINTN Count;
+ EHCI_QTD_ENTITY *QtdPtr;
+ Count = 0;
+ QtdPtr = FirstQtdPtr;
+
+ ;
+
+ while (NULL != QtdPtr) {
+ Count++;
+ QtdPtr = QtdPtr->Next;
+ }
+
+ return Count;
+}
+
+UINTN
+GetNumberOfTransaction (
+ IN UINTN SizeOfData,
+ IN UINTN SizeOfTransaction
+ )
+/*++
+
+Routine Description:
+
+ Number of Transactions in one Qtd
+
+Arguments:
+
+ SizeOfData - Size of one Qtd
+ SizeOfTransaction - Size of one Transaction
+
+Returns:
+
+ Number of Transactions in this Qtd
+
+--*/
+{
+
+ return ((SizeOfData & (SizeOfTransaction - 1)) ? SizeOfData / SizeOfTransaction + 1 : SizeOfData / SizeOfTransaction);
+
+}
+
+UINTN
+GetCapacityOfQtd (
+ IN UINT8 *BufferCursor
+ )
+/*++
+
+Routine Description:
+
+ Get Size of First Qtd
+
+Arguments:
+
+ BufferCursor - BufferCursor of the Qtd
+
+Returns:
+
+ Size of First Qtd
+
+--*/
+{
+
+ return (EHCI_MAX_QTD_CAPACITY - (EHCI_BLOCK_SIZE * GetNumberOfTransaction (EFI_PAGE_MASK & GET_0B_TO_31B (BufferCursor), EHCI_BLOCK_SIZE)));
+
+}
+
+UINTN
+GetApproxiOfInterval (
+ IN UINTN Interval
+ )
+/*++
+
+Routine Description:
+
+ Get the approximate value in the 2 index sequence
+
+Arguments:
+
+ Interval - the value of interval
+
+Returns:
+
+ approximate value of interval in the 2 index sequence
+
+--*/
+{
+ UINTN Orignate;
+ UINTN Approxi;
+
+ Orignate = Interval;
+ Approxi = 1;
+
+ while (Orignate != 1 && Orignate != 0) {
+ Orignate = Orignate >> 1;
+ Approxi = Approxi << 1;
+ }
+
+ if (Interval & (Approxi >> 1)) {
+ Approxi = Approxi << 1;
+ }
+
+ return Approxi;
+}
+
+EHCI_QTD_HW *
+GetQtdAlternateNextPointer (
+ IN EHCI_QTD_HW *HwQtdPtr
+ )
+/*++
+
+Routine Description:
+
+ Get Qtd alternate next pointer field
+
+Arguments:
+
+ HwQtdPtr - A pointer to hardware Qtd structure
+
+Returns:
+
+ A pointer to hardware alternate Qtd
+
+--*/
+{
+ EHCI_QTD_HW *Value;
+
+ Value = NULL;
+
+ if (!HwQtdPtr->AltNextQtdTerminate) {
+ Value = (EHCI_QTD_HW *) GET_0B_TO_31B (HwQtdPtr->AltNextQtdPointer << 5);
+ }
+
+ return Value;
+}
+
+EHCI_QTD_HW *
+GetQtdNextPointer (
+ IN EHCI_QTD_HW *HwQtdPtr
+ )
+/*++
+
+Routine Description:
+
+ Get Qtd next pointer field
+
+Arguments:
+
+ HwQtdPtr - A pointer to hardware Qtd structure
+
+Returns:
+
+ A pointer to next hardware Qtd structure
+
+--*/
+{
+ EHCI_QTD_HW *Value;
+
+ Value = NULL;
+
+ if (!HwQtdPtr->NextQtdTerminate) {
+ Value = (EHCI_QTD_HW *) GET_0B_TO_31B (HwQtdPtr->NextQtdPointer << 5);
+ }
+
+ return Value;
+}
+
+VOID LinkQtdToQtd (
+ IN EHCI_QTD_ENTITY * PreQtdPtr,
+ IN EHCI_QTD_ENTITY * QtdPtr
+ )
+/*++
+
+Routine Description:
+
+ Link Qtds together
+
+Arguments:
+
+ PreQtdPtr - A pointer to pre Qtd
+ QtdPtr - A pointer to next Qtd
+
+Returns:
+
+ VOID
+
+--*/
+{
+ EHCI_QTD_HW *QtdHwPtr;
+
+ ASSERT(PreQtdPtr);
+ ASSERT(QtdPtr);
+
+ //
+ // Software link
+ //
+ PreQtdPtr->Next = QtdPtr;
+ QtdPtr->Prev = PreQtdPtr;
+
+ //
+ // Hardware link
+ //
+ QtdHwPtr = &(QtdPtr->Qtd);
+ PreQtdPtr->Qtd.NextQtdPointer = (UINT32) (GET_0B_TO_31B(QtdHwPtr) >> 5);
+ PreQtdPtr->Qtd.NextQtdTerminate = FALSE;
+
+ return ;
+}
+
+
+VOID LinkQtdsToAltQtd (
+ IN EHCI_QTD_ENTITY * FirstQtdPtr,
+ IN EHCI_QTD_ENTITY * AltQtdPtr
+ )
+/*++
+
+Routine Description:
+
+ Link AlterQtds together
+
+Arguments:
+
+ FirstQtdPtr - A pointer to first Qtd in the list
+ AltQtdPtr - A pointer to alternative Qtd
+
+Returns:
+
+ VOID
+
+--*/
+{
+ EHCI_QTD_ENTITY *QtdPtr;
+ EHCI_QTD_HW *AltQtdHwPtr;
+
+ ASSERT(FirstQtdPtr);
+ ASSERT(AltQtdPtr);
+
+ AltQtdHwPtr = &(AltQtdPtr->Qtd);
+ QtdPtr = FirstQtdPtr;
+
+ while (NULL != QtdPtr) {
+ //
+ // Software link
+ //
+ QtdPtr->AltNext = AltQtdPtr;
+ //
+ // Hardware link
+ //
+ QtdPtr->Qtd.AltNextQtdPointer = (UINT32) (GET_0B_TO_31B(AltQtdHwPtr) >> 5);
+ QtdPtr->Qtd.AltNextQtdTerminate = FALSE;
+ QtdPtr = QtdPtr->Next;
+ }
+
+ return ;
+}
+
+VOID
+LinkQtdToQh (
+ IN EHCI_QH_ENTITY *QhPtr,
+ IN EHCI_QTD_ENTITY *QtdPtr
+ )
+/*++
+
+Routine Description:
+
+ Link Qtds list to Qh
+
+Arguments:
+
+ QhPtr - A pointer to Qh
+ QtdPtr - A pointer to first Qtd in the list
+
+Returns:
+
+ VOID
+
+--*/
+{
+ EHCI_QTD_ENTITY *Cursor;
+ EHCI_QTD_HW *QtdHwPtr;
+
+ ASSERT (QhPtr);
+ ASSERT (QtdPtr);
+
+ QhPtr->FirstQtdPtr = QtdPtr;
+ if (NULL != QtdPtr->AltNext) {
+ QhPtr->AltQtdPtr = QtdPtr->AltNext;
+ }
+
+ Cursor = QtdPtr;
+ while (NULL != Cursor) {
+ Cursor->SelfQh = QhPtr;
+ if (NULL == Cursor->Next) {
+ QhPtr->LastQtdPtr = Cursor;
+ }
+
+ Cursor = Cursor->Next;
+ }
+
+ QtdHwPtr = &(QtdPtr->Qtd);
+ QhPtr->Qh.NextQtdPointer = (UINT32) (GET_0B_TO_31B (QtdHwPtr) >> 5);
+ QhPtr->Qh.NextQtdTerminate = FALSE;
+
+ return ;
+}
+
+EFI_STATUS
+LinkQhToAsyncList (
+ IN USB2_HC_DEV *HcDev,
+ IN EHCI_QH_ENTITY *QhPtr
+ )
+/*++
+
+Routine Description:
+
+ Link Qh to Async Schedule List
+
+Arguments:
+
+ HcDev - USB2_HC_DEV
+ QhPtr - A pointer to Qh
+
+Returns:
+
+ EFI_SUCCESS Success
+ EFI_DEVICE_ERROR Fail
+
+--*/
+{
+ EFI_STATUS Status;
+
+ ASSERT (HcDev);
+ ASSERT (QhPtr);
+
+ QhPtr->Qh.HeadReclamationFlag = TRUE;
+
+ Status = SetAsyncListAddr (HcDev, QhPtr);
+ if (EFI_ERROR (Status)) {
+ Status = EFI_DEVICE_ERROR;
+ goto exit;
+ }
+
+ if (!IsAsyncScheduleEnabled (HcDev)) {
+
+ Status = EnableAsynchronousSchedule (HcDev);
+ if (EFI_ERROR (Status)) {
+ Status = EFI_DEVICE_ERROR;
+ goto exit;
+ }
+
+ Status = WaitForAsyncScheduleEnable (HcDev, EHCI_GENERIC_TIMEOUT);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((gEHCDebugLevel, "WaitForAsyncScheduleEnable TimeOut"));
+ Status = EFI_TIMEOUT;
+ goto exit;
+ }
+
+ if (IsEhcHalted (HcDev)) {
+ Status = StartScheduleExecution (HcDev);
+ if (EFI_ERROR (Status)) {
+ Status = EFI_DEVICE_ERROR;
+ }
+ }
+
+ }
+
+exit:
+ return Status;
+}
+
+EFI_STATUS
+UnlinkQhFromAsyncList (
+ IN USB2_HC_DEV *HcDev,
+ IN EHCI_QH_ENTITY *QhPtr
+ )
+/*++
+
+Routine Description:
+
+ Unlink Qh from Async Schedule List
+
+Arguments:
+
+ HcDev - USB2_HC_DEV
+ QhPtr - A pointer to Qh
+
+Returns:
+
+ EFI_SUCCESS Success
+ EFI_DEVICE_ERROR Fail
+
+--*/
+{
+ EFI_STATUS Status;
+
+ Status = EFI_SUCCESS;
+
+ ASSERT (HcDev);
+ ASSERT (QhPtr);
+
+ if (QhPtr == QhPtr->Next) {
+
+ Status = DisableAsynchronousSchedule (HcDev);
+ if (EFI_ERROR (Status)) {
+ Status = EFI_DEVICE_ERROR;
+ goto exit;
+ }
+
+ Status = WaitForAsyncScheduleDisable (HcDev, EHCI_GENERIC_TIMEOUT);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((gEHCErrorLevel, "WaitForAsyncScheduleDisable TimeOut\n"));
+ Status = EFI_TIMEOUT;
+ goto exit;
+ }
+
+ }
+
+exit:
+ return Status;
+}
+
+VOID
+LinkQhToPeriodicList (
+ IN USB2_HC_DEV *HcDev,
+ IN EHCI_QH_ENTITY *QhPtr
+ )
+/*++
+
+Routine Description:
+
+ Link Qh to Periodic Schedule List
+
+Arguments:
+
+ HcDev - USB2_HC_DEV
+ QhPtr - A pointer to Qh
+
+Returns:
+
+ VOID
+
+--*/
+{
+ FRAME_LIST_ENTRY *FrameEntryPtr;
+ EHCI_QH_ENTITY *FindQhPtr;
+ EHCI_QH_HW *FindQhHwPtr;
+ UINTN FrameIndex;
+
+ ASSERT (HcDev);
+ ASSERT (QhPtr);
+
+ FindQhPtr = NULL;
+ FindQhHwPtr = NULL;
+ FrameIndex = 0;
+ FrameEntryPtr = (FRAME_LIST_ENTRY *) HcDev->PeriodicFrameListBuffer;
+
+ QhPtr->Qh.HeadReclamationFlag = FALSE;
+
+ if (QhPtr->TransferType == ASYNC_INTERRUPT_TRANSFER) {
+
+ //
+ // AsyncInterruptTransfer Qh
+ //
+
+ //
+ // Link to Frame[0] List
+ //
+ if (!FrameEntryPtr->LinkTerminate) {
+ //
+ // Not Null FrameList
+ //
+ FindQhHwPtr = (EHCI_QH_HW *) GET_0B_TO_31B (FrameEntryPtr->LinkPointer << 5);
+ FindQhPtr = (EHCI_QH_ENTITY *) GET_QH_ENTITY_ADDR (FindQhHwPtr);
+ //
+ // FindQh is Left/Right to Qh
+ //
+ while ((NULL != FindQhPtr->Next) && (FindQhPtr->Interval > QhPtr->Interval)) {
+ FindQhPtr = FindQhPtr->Next;
+ }
+
+ if (FindQhPtr->Interval == QhPtr->Interval) {
+ //
+ // Link Qh after FindQh
+ //
+ if (NULL != FindQhPtr->Next) {
+ FindQhPtr->Next->Prev = QhPtr;
+ QhPtr->Qh.QhHorizontalPointer = (UINT32) GET_0B_TO_31B (&(FindQhPtr->Next->Qh) >> 5);
+ QhPtr->Qh.SelectType = QH_SELECT_TYPE;
+ QhPtr->Qh.QhTerminate = FALSE;
+ }
+
+ FindQhPtr->Qh.QhHorizontalPointer = (UINT32) GET_0B_TO_31B (&(QhPtr->Qh) >> 5);
+ FindQhPtr->Qh.SelectType = QH_SELECT_TYPE;
+ FindQhPtr->Qh.QhTerminate = FALSE;
+
+ QhPtr->Prev = FindQhPtr;
+ QhPtr->Next = FindQhPtr->Next;
+ FindQhPtr->Next = QhPtr;
+ } else if (FindQhPtr->Interval < QhPtr->Interval) {
+ //
+ // Link Qh before FindQh
+ //
+ if (NULL == FindQhPtr->Prev) {
+ //
+ // Qh is the First one in Frame[0] List
+ //
+ FrameEntryPtr->LinkPointer = (UINT32) GET_0B_TO_31B (&(QhPtr->Qh) >> 5);
+ FrameEntryPtr->SelectType = QH_SELECT_TYPE;
+ FrameEntryPtr->LinkTerminate = FALSE;
+ } else {
+ //
+ // Qh is not the First one in Frame[0] List
+ //
+ FindQhPtr->Prev->Next = QhPtr;
+ FindQhPtr->Prev->Qh.QhHorizontalPointer = (UINT32) GET_0B_TO_31B (&(QhPtr->Qh) >> 5);
+ FindQhPtr->Prev->Qh.SelectType = QH_SELECT_TYPE;
+ FindQhPtr->Prev->Qh.QhTerminate = FALSE;
+ }
+
+ QhPtr->Qh.QhHorizontalPointer = (UINT32) GET_0B_TO_31B (&(FindQhPtr->Qh) >> 5);
+ QhPtr->Qh.SelectType = QH_SELECT_TYPE;
+ QhPtr->Qh.QhTerminate = FALSE;
+
+ QhPtr->Next = FindQhPtr;
+ QhPtr->Prev = FindQhPtr->Prev;
+ FindQhPtr->Prev = QhPtr;
+ } else {
+ //
+ // Link Qh after FindQh, Qh is the Last one
+ //
+ FindQhPtr->Qh.QhHorizontalPointer = (UINT32) GET_0B_TO_31B (&(QhPtr->Qh) >> 5);
+ FindQhPtr->Prev->Qh.SelectType = QH_SELECT_TYPE;
+ FindQhPtr->Qh.QhTerminate = FALSE;
+
+ QhPtr->Prev = FindQhPtr;
+ QhPtr->Next = NULL;
+ FindQhPtr->Next = QhPtr;
+ }
+ } else {
+ //
+ // Null FrameList
+ //
+ FrameEntryPtr->LinkPointer = (UINT32) GET_0B_TO_31B (&(QhPtr->Qh) >> 5);
+ FrameEntryPtr->SelectType = QH_SELECT_TYPE;
+ FrameEntryPtr->LinkTerminate = FALSE;
+ }
+ //
+ // Other Frame[X]
+ //
+ if (NULL == QhPtr->Prev) {
+ //
+ // Qh is the First one in Frame[0] List
+ //
+ FrameIndex += QhPtr->Interval;
+ while (FrameIndex < HcDev->PeriodicFrameListLength) {
+ FrameEntryPtr = (FRAME_LIST_ENTRY *) (FrameEntryPtr + QhPtr->Interval);
+ FrameEntryPtr->LinkPointer = (UINT32) GET_0B_TO_31B (&(QhPtr->Qh) >> 5);
+ FrameEntryPtr->SelectType = QH_SELECT_TYPE;
+ FrameEntryPtr->LinkTerminate = FALSE;
+ FrameIndex += QhPtr->Interval;
+ }
+ } else if (QhPtr->Interval < QhPtr->Prev->Interval) {
+ //
+ // Qh is not the First one in Frame[0] List, and Prev.interval > Qh.interval
+ //
+ FrameIndex += QhPtr->Interval;
+ while (FrameIndex < HcDev->PeriodicFrameListLength) {
+ FrameEntryPtr = (FRAME_LIST_ENTRY *) (FrameEntryPtr + QhPtr->Interval);
+ if ((FrameIndex % QhPtr->Prev->Interval) != 0) {
+ FrameEntryPtr->LinkPointer = (UINT32) GET_0B_TO_31B (&(QhPtr->Qh) >> 5);
+ FrameEntryPtr->SelectType = QH_SELECT_TYPE;
+ FrameEntryPtr->LinkTerminate = FALSE;
+ }
+
+ FrameIndex += QhPtr->Interval;
+ }
+ }
+ } else {
+
+ //
+ // SyncInterruptTransfer Qh
+ //
+
+ if (!FrameEntryPtr->LinkTerminate) {
+ //
+ // Not Null FrameList
+ //
+ FindQhHwPtr = (EHCI_QH_HW *) GET_0B_TO_31B (FrameEntryPtr->LinkPointer << 5);
+ FindQhPtr = (EHCI_QH_ENTITY *) GET_QH_ENTITY_ADDR (FindQhHwPtr);
+ //
+ // FindQh is Last Qh in the Asynchronous List, Link Qh after FindQh
+ //
+ while (NULL != FindQhPtr->Next) {
+ FindQhPtr = FindQhPtr->Next;
+ }
+
+ FindQhPtr->Qh.QhHorizontalPointer = (UINT32) GET_0B_TO_31B (&(QhPtr->Qh) >> 5);
+ FindQhPtr->Qh.SelectType = QH_SELECT_TYPE;
+ FindQhPtr->Qh.QhTerminate = FALSE;
+
+ FindQhPtr->Next = QhPtr;
+ QhPtr->Prev = FindQhPtr;
+ } else {
+ //
+ // Null FrameList
+ //
+ FrameEntryPtr->LinkPointer = (UINT32) GET_0B_TO_31B (&(QhPtr->Qh) >> 5);
+ FrameEntryPtr->SelectType = QH_SELECT_TYPE;
+ FrameEntryPtr->LinkTerminate = FALSE;
+ }
+ }
+
+ return ;
+}
+
+VOID
+UnlinkQhFromPeriodicList (
+ IN USB2_HC_DEV *HcDev,
+ IN EHCI_QH_ENTITY *QhPtr,
+ IN UINTN Interval
+ )
+/*++
+
+Routine Description:
+
+ Unlink Qh from Periodic Schedule List
+
+Arguments:
+
+ HcDev - USB2_HC_DEV
+ QhPtr - A pointer to Qh
+ Interval - Interval of this periodic transfer
+
+Returns:
+
+ VOID
+
+--*/
+{
+ FRAME_LIST_ENTRY *FrameEntryPtr;
+ UINTN FrameIndex;
+
+ FrameIndex = 0;
+
+ ASSERT (HcDev);
+ ASSERT (QhPtr);
+
+ FrameIndex = 0;
+ FrameEntryPtr = (FRAME_LIST_ENTRY *) HcDev->PeriodicFrameListBuffer;
+
+ if (QhPtr->TransferType == ASYNC_INTERRUPT_TRANSFER) {
+
+ //
+ // AsyncInterruptTransfer Qh
+ //
+
+ if (NULL == QhPtr->Prev) {
+ //
+ // Qh is the First one on Frame[0] List
+ //
+ if (NULL == QhPtr->Next) {
+ //
+ // Only one on Frame[0] List
+ //
+ while (FrameIndex < HcDev->PeriodicFrameListLength) {
+ FrameEntryPtr->LinkPointer = 0;
+ FrameEntryPtr->SelectType = 0;
+ FrameEntryPtr->LinkTerminate = TRUE;
+ FrameEntryPtr += Interval;
+ FrameIndex += Interval;
+ }
+ } else {
+ while (FrameIndex < HcDev->PeriodicFrameListLength) {
+ FrameEntryPtr->LinkPointer = (UINT32) GET_0B_TO_31B (&(QhPtr->Next->Qh) >> 5);
+ FrameEntryPtr->SelectType = QH_SELECT_TYPE;
+ FrameEntryPtr->LinkTerminate = FALSE;
+ FrameEntryPtr += Interval;
+ FrameIndex += Interval;
+ }
+ }
+ } else {
+
+ //
+ // Not First one on Frame[0] List
+ //
+ if (NULL == QhPtr->Next) {
+ //
+ // Qh is the Last one on Frame[0] List
+ //
+ QhPtr->Prev->Qh.QhHorizontalPointer = 0;
+ QhPtr->Prev->Qh.SelectType = 0;
+ QhPtr->Prev->Qh.QhTerminate = TRUE;
+ } else {
+ QhPtr->Prev->Qh.QhHorizontalPointer = (UINT32) GET_0B_TO_31B (&(QhPtr->Next->Qh) >> 5);
+ QhPtr->Prev->Qh.SelectType = QH_SELECT_TYPE;
+ QhPtr->Prev->Qh.QhTerminate = FALSE;
+ }
+
+ if (Interval == QhPtr->Prev->Interval) {
+ //
+ // Interval is the same as Prev
+ // Not involed Frame[X]
+ //
+ } else {
+ //
+ // Other Frame[X]
+ //
+ while (FrameIndex < HcDev->PeriodicFrameListLength) {
+ if ((FrameIndex % QhPtr->Prev->Interval) != 0) {
+ FrameEntryPtr->LinkPointer = QhPtr->Prev->Qh.QhHorizontalPointer;
+ FrameEntryPtr->SelectType = QhPtr->Prev->Qh.SelectType;
+ FrameEntryPtr->LinkTerminate = QhPtr->Prev->Qh.QhTerminate;
+ }
+ FrameEntryPtr += Interval;
+ FrameIndex += Interval;
+ }
+ }
+ }
+
+ if (NULL != QhPtr->Next) {
+ QhPtr->Next->Prev = QhPtr->Prev;
+ }
+
+ if (NULL != QhPtr->Prev) {
+ QhPtr->Prev->Next = QhPtr->Next;
+ }
+ } else {
+ //
+ // SyncInterruptTransfer Qh
+ //
+ if (NULL == QhPtr->Prev) {
+ //
+ // Qh is the only one Qh on Frame[0] List
+ //
+ FrameEntryPtr->LinkPointer = 0;
+ FrameEntryPtr->SelectType = 0;
+ FrameEntryPtr->LinkTerminate = TRUE;
+ } else {
+ QhPtr->Prev->Qh.QhHorizontalPointer = 0;
+ QhPtr->Prev->Qh.SelectType = 0;
+ QhPtr->Prev->Qh.QhTerminate = TRUE;
+ }
+
+ if (NULL != QhPtr->Prev) {
+ QhPtr->Prev->Next = NULL;
+ }
+ }
+
+ return ;
+}
+
+VOID
+LinkToAsyncReqeust (
+ IN USB2_HC_DEV *HcDev,
+ IN EHCI_ASYNC_REQUEST *AsyncRequestPtr
+ )
+/*++
+
+Routine Description:
+
+ Llink AsyncRequest Entry to Async Request List
+
+Arguments:
+
+ HcDev - USB2_HC_DEV
+ AsyncRequestPtr - A pointer to Async Request Entry
+
+Returns:
+
+ VOID
+
+--*/
+{
+ EHCI_ASYNC_REQUEST *CurrentPtr;
+
+ CurrentPtr = HcDev->AsyncRequestList;
+ HcDev->AsyncRequestList = AsyncRequestPtr;
+ AsyncRequestPtr->Prev = NULL;
+ AsyncRequestPtr->Next = CurrentPtr;
+
+ if (NULL != CurrentPtr) {
+ CurrentPtr->Prev = AsyncRequestPtr;
+ }
+
+ return ;
+}
+
+VOID
+UnlinkFromAsyncReqeust (
+ IN USB2_HC_DEV *HcDev,
+ IN EHCI_ASYNC_REQUEST *AsyncRequestPtr
+ )
+/*++
+
+Routine Description:
+
+ Unlink AsyncRequest Entry from Async Request List
+
+Arguments:
+
+ HcDev - USB2_HC_DEV
+ AsyncRequestPtr - A pointer to Async Request Entry
+
+Returns:
+
+ VOID
+
+--*/
+{
+ if (NULL == AsyncRequestPtr->Prev) {
+ HcDev->AsyncRequestList = AsyncRequestPtr->Next;
+ if (NULL != AsyncRequestPtr->Next) {
+ AsyncRequestPtr->Next->Prev = NULL;
+ }
+ } else {
+ AsyncRequestPtr->Prev->Next = AsyncRequestPtr->Next;
+ if (NULL != AsyncRequestPtr->Next) {
+ AsyncRequestPtr->Next->Prev = AsyncRequestPtr->Prev;
+ }
+ }
+
+ return ;
+}
+
+VOID
+SetQtdBufferPointer (
+ IN EHCI_QTD_HW *QtdHwPtr,
+ IN VOID *DataPtr,
+ IN UINTN DataLen
+ )
+/*++
+
+Routine Description:
+
+ Set data buffer pointers in Qtd
+
+Arguments:
+
+ QtdHwPtr - A pointer to Qtd hardware structure
+ DataPtr - A pointer to user data buffer
+ DataLen - Length of the user data buffer
+
+Returns:
+
+ VOID
+
+--*/
+{
+ UINTN RemainLen;
+
+ RemainLen = DataLen;
+ ASSERT (QtdHwPtr);
+
+ //
+ // Set BufferPointer0, ExtBufferPointer0 and Offset
+ //
+ QtdHwPtr->BufferPointer0 = (UINT32) (GET_0B_TO_31B (DataPtr) >> 12);
+ QtdHwPtr->CurrentOffset = (UINT32) (GET_0B_TO_31B (DataPtr) & EFI_PAGE_MASK);
+ QtdHwPtr->ExtBufferPointer0 = (UINT32) GET_32B_TO_63B (DataPtr);
+
+ //
+ // Set BufferPointer1 and ExtBufferPointer1
+ //
+ RemainLen = RemainLen > (EFI_PAGE_SIZE - QtdHwPtr->CurrentOffset) ? (RemainLen - (EFI_PAGE_SIZE - QtdHwPtr->CurrentOffset)) : 0;
+ if (RemainLen == 0) {
+ goto exit;
+ }
+
+ QtdHwPtr->BufferPointer1 = QtdHwPtr->BufferPointer0 + 1;
+ QtdHwPtr->ExtBufferPointer1 = QtdHwPtr->ExtBufferPointer0;
+
+ //
+ // Set BufferPointer2 and ExtBufferPointer2
+ //
+ RemainLen = RemainLen > EFI_PAGE_SIZE ? (RemainLen - EFI_PAGE_SIZE) : 0;
+ if (RemainLen == 0) {
+ goto exit;
+ }
+
+ QtdHwPtr->BufferPointer2 = QtdHwPtr->BufferPointer1 + 1;
+ QtdHwPtr->ExtBufferPointer2 = QtdHwPtr->ExtBufferPointer0;
+
+ //
+ // Set BufferPointer3 and ExtBufferPointer3
+ //
+ RemainLen = RemainLen > EFI_PAGE_SIZE ? (RemainLen - EFI_PAGE_SIZE) : 0;
+ if (RemainLen == 0) {
+ goto exit;
+ }
+
+ QtdHwPtr->BufferPointer3 = QtdHwPtr->BufferPointer2 + 1;
+ QtdHwPtr->ExtBufferPointer3 = QtdHwPtr->ExtBufferPointer0;
+
+ //
+ // Set BufferPointer4 and ExtBufferPointer4
+ //
+ RemainLen = RemainLen > EFI_PAGE_SIZE ? (RemainLen - EFI_PAGE_SIZE) : 0;
+ if (RemainLen == 0) {
+ goto exit;
+ }
+
+ QtdHwPtr->BufferPointer4 = QtdHwPtr->BufferPointer3 + 1;
+ QtdHwPtr->ExtBufferPointer4 = QtdHwPtr->ExtBufferPointer0;
+
+exit:
+ return ;
+}
+
+BOOLEAN
+IsQtdStatusActive (
+ IN EHCI_QTD_HW *HwQtdPtr
+ )
+/*++
+
+Routine Description:
+
+ Whether Qtd status is active or not
+
+Arguments:
+
+ HwQtdPtr - A pointer to hardware Qtd structure
+
+Returns:
+
+ TRUE Active
+ FALSE Inactive
+
+--*/
+{
+ UINT8 QtdStatus;
+ BOOLEAN Value;
+
+ QtdStatus = (UINT8) (HwQtdPtr->Status);
+ Value = (BOOLEAN) (QtdStatus & QTD_STATUS_ACTIVE);
+
+ return Value;
+}
+
+BOOLEAN
+IsQtdStatusHalted (
+ IN EHCI_QTD_HW *HwQtdPtr
+ )
+/*++
+
+Routine Description:
+
+ Whether Qtd status is halted or not
+
+Arguments:
+
+ HwQtdPtr - A pointer to hardware Qtd structure
+
+Returns:
+
+ TRUE Halted
+ FALSE Not halted
+
+--*/
+{
+ UINT8 QtdStatus;
+ BOOLEAN Value;
+
+ QtdStatus = (UINT8) (HwQtdPtr->Status);
+ Value = (BOOLEAN) (QtdStatus & QTD_STATUS_HALTED);
+
+ return Value;
+}
+
+BOOLEAN
+IsQtdStatusBufferError (
+ IN EHCI_QTD_HW *HwQtdPtr
+ )
+/*++
+
+Routine Description:
+
+ Whether Qtd status is buffer error or not
+
+Arguments:
+
+ HwQtdPtr - A pointer to hardware Qtd structure
+
+Returns:
+
+ TRUE Buffer error
+ FALSE No buffer error
+
+--*/
+{
+ UINT8 QtdStatus;
+ BOOLEAN Value;
+
+ QtdStatus = (UINT8) (HwQtdPtr->Status);
+ Value = (BOOLEAN) (QtdStatus & QTD_STATUS_BUFFER_ERR);
+
+ return Value;
+}
+
+BOOLEAN
+IsQtdStatusBabbleError (
+ IN EHCI_QTD_HW *HwQtdPtr
+ )
+/*++
+
+Routine Description:
+
+ Whether Qtd status is babble error or not
+
+Arguments:
+
+ HwQtdPtr - A pointer to hardware Qtd structure
+
+Returns:
+
+ TRUE Babble error
+ FALSE No babble error
+
+--*/
+{
+ UINT8 QtdStatus;
+ BOOLEAN Value;
+
+ QtdStatus = (UINT8) (HwQtdPtr->Status);
+ Value = (BOOLEAN) (QtdStatus & QTD_STATUS_BABBLE_ERR);
+
+ return Value;
+}
+
+BOOLEAN
+IsQtdStatusTransactionError (
+ IN EHCI_QTD_HW *HwQtdPtr
+ )
+/*++
+
+Routine Description:
+
+ Whether Qtd status is transaction error or not
+
+Arguments:
+
+ HwQtdPtr - A pointer to hardware Qtd structure
+
+Returns:
+
+ TRUE Transaction error
+ FALSE No transaction error
+
+--*/
+{
+ UINT8 QtdStatus;
+ BOOLEAN Value;
+
+ QtdStatus = (UINT8) (HwQtdPtr->Status);
+ Value = (BOOLEAN) (QtdStatus & QTD_STATUS_TRANSACTION_ERR);
+
+ return Value;
+}
+
+BOOLEAN
+IsDataInTransfer (
+ IN UINT8 EndPointAddress
+ )
+/*++
+
+Routine Description:
+
+ Whether is a DataIn direction transfer
+
+Arguments:
+
+ EndPointAddress - address of the endpoint
+
+Returns:
+
+ TRUE DataIn
+ FALSE DataOut
+
+--*/
+{
+ BOOLEAN Value;
+
+ if (EndPointAddress & 0x80) {
+ Value = TRUE;
+ } else {
+ Value = FALSE;
+ }
+
+ return Value;
+}
+
+EFI_STATUS
+MapDataBuffer (
+ IN USB2_HC_DEV *HcDev,
+ IN EFI_USB_DATA_DIRECTION TransferDirection,
+ IN VOID *Data,
+ IN OUT UINTN *DataLength,
+ OUT UINT8 *PktId,
+ OUT UINT8 **DataCursor,
+ OUT VOID **DataMap
+ )
+/*++
+
+Routine Description:
+
+ Map address of user data buffer
+
+Arguments:
+
+ HcDev - USB2_HC_DEV
+ TransferDirection - direction of transfer
+ Data - A pointer to user data buffer
+ DataLength - length of user data
+ PktId - Packte Identificaion
+ DataCursor - mapped address to return
+ DataMap - identificaion of this mapping to return
+
+Returns:
+
+ EFI_SUCCESS Success
+ EFI_DEVICE_ERROR Fail
+
+--*/
+{
+ EFI_STATUS Status;
+ EFI_PHYSICAL_ADDRESS TempPhysicalAddr;
+
+ Status = EFI_SUCCESS;
+
+ switch (TransferDirection) {
+
+ case EfiUsbDataIn:
+
+ *PktId = INPUT_PACKET_ID;
+ //
+ // BusMasterWrite means cpu read
+ //
+ Status = HcDev->PciIo->Map (
+ HcDev->PciIo,
+ EfiPciIoOperationBusMasterWrite,
+ Data,
+ DataLength,
+ &TempPhysicalAddr,
+ DataMap
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((gEHCDebugLevel, "MapDataBuffer Failed\n"));
+ Status = EFI_DEVICE_ERROR;
+ goto exit;
+ }
+
+ *DataCursor = (UINT8 *) ((UINTN) TempPhysicalAddr);
+ break;
+
+ case EfiUsbDataOut:
+
+ *PktId = OUTPUT_PACKET_ID;
+ //
+ // BusMasterRead means cpu write
+ //
+ Status = HcDev->PciIo->Map (
+ HcDev->PciIo,
+ EfiPciIoOperationBusMasterRead,
+ Data,
+ DataLength,
+ &TempPhysicalAddr,
+ DataMap
+ );
+ if (EFI_ERROR (Status)) {
+ Status = EFI_DEVICE_ERROR;
+ goto exit;
+ }
+
+ *DataCursor = (UINT8 *) ((UINTN) TempPhysicalAddr);
+ break;
+
+ case EfiUsbNoData:
+
+ *PktId = OUTPUT_PACKET_ID;
+ Data = NULL;
+ *DataLength = 0;
+ *DataCursor = NULL;
+ *DataMap = NULL;
+ break;
+
+ default:
+
+ Status = EFI_INVALID_PARAMETER;
+ }
+
+exit:
+ return Status;
+}
+
+EFI_STATUS
+MapRequestBuffer (
+ IN USB2_HC_DEV *HcDev,
+ IN OUT VOID *Request,
+ OUT UINT8 **RequestCursor,
+ OUT VOID **RequestMap
+ )
+/*++
+
+Routine Description:
+
+ Map address of request structure buffer
+
+Arguments:
+
+ HcDev - USB2_HC_DEV
+ Request - A pointer to request structure
+ RequestCursor - Mapped address of request structure to return
+ RequestMap - Identificaion of this mapping to return
+
+Returns:
+
+ EFI_SUCCESS Success
+ EFI_DEVICE_ERROR Fail
+
+--*/
+{
+ EFI_STATUS Status;
+ UINTN RequestLen;
+ EFI_PHYSICAL_ADDRESS TempPhysicalAddr;
+
+ RequestLen = sizeof (EFI_USB_DEVICE_REQUEST);
+ Status = HcDev->PciIo->Map (
+ HcDev->PciIo,
+ EfiPciIoOperationBusMasterRead,
+ (UINT8 *) Request,
+ (UINTN *) &RequestLen,
+ &TempPhysicalAddr,
+ RequestMap
+ );
+ if (EFI_ERROR (Status)) {
+ Status = EFI_DEVICE_ERROR;
+ goto exit;
+ }
+
+ *RequestCursor = (UINT8 *) ((UINTN) TempPhysicalAddr);
+
+exit:
+ return Status;
+}
+
+EFI_STATUS
+DeleteAsyncRequestTransfer (
+ IN USB2_HC_DEV *HcDev,
+ IN UINT8 DeviceAddress,
+ IN UINT8 EndPointAddress,
+ OUT UINT8 *DataToggle
+ )
+/*++
+
+Routine Description:
+
+ Delete all asynchronous request transfer
+
+Arguments:
+
+ HcDev - USB2_HC_DEV
+ DeviceAddress - address of usb device
+ EndPointAddress - address of endpoint
+ DataToggle - stored data toggle
+
+Returns:
+
+ EFI_SUCCESS Success
+ EFI_DEVICE_ERROR Fail
+
+--*/
+{
+ EFI_STATUS Status;
+ EHCI_ASYNC_REQUEST *AsyncRequestPtr;
+ EHCI_ASYNC_REQUEST *MatchPtr;
+ EHCI_QH_HW *QhHwPtr;
+ UINT8 EndPointNum;
+
+ if (NULL == HcDev->AsyncRequestList) {
+ Status = EFI_INVALID_PARAMETER;
+ goto exit;
+ }
+
+ MatchPtr = NULL;
+ QhHwPtr = NULL;
+ EndPointNum = EndPointAddress & 0x0f;
+ AsyncRequestPtr = HcDev->AsyncRequestList;
+
+ //
+ // Find QH of AsyncRequest by DeviceAddress and EndPointNum
+ //
+ do {
+
+ QhHwPtr = &(AsyncRequestPtr->QhPtr->Qh);
+ if (QhHwPtr->DeviceAddr == DeviceAddress && QhHwPtr->EndpointNum == EndPointNum) {
+ MatchPtr = AsyncRequestPtr;
+ break;
+ }
+
+ AsyncRequestPtr = AsyncRequestPtr->Next;
+
+ } while (NULL != AsyncRequestPtr);
+
+ if (NULL == MatchPtr) {
+ Status = EFI_INVALID_PARAMETER;
+ goto exit;
+ }
+
+ Status = DisablePeriodicSchedule (HcDev);
+ if (EFI_ERROR (Status)) {
+ Status = EFI_DEVICE_ERROR;
+ goto exit;
+ }
+
+ Status = WaitForPeriodicScheduleDisable (HcDev, EHCI_GENERIC_TIMEOUT);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((gEHCErrorLevel, "WaitForPeriodicScheduleDisable TimeOut\n"));
+ Status = EFI_TIMEOUT;
+ goto exit;
+ }
+
+ *DataToggle = (UINT8) MatchPtr->QhPtr->Qh.DataToggle;
+ UnlinkQhFromPeriodicList (HcDev, MatchPtr->QhPtr, MatchPtr->QhPtr->Interval);
+ UnlinkFromAsyncReqeust (HcDev, MatchPtr);
+
+ if (NULL == HcDev->AsyncRequestList) {
+
+ Status = StopPollingTimer (HcDev);
+ if (EFI_ERROR (Status)) {
+ Status = EFI_DEVICE_ERROR;
+ goto exit;
+ }
+
+ } else {
+
+ Status = EnablePeriodicSchedule (HcDev);
+ if (EFI_ERROR (Status)) {
+ Status = EFI_DEVICE_ERROR;
+ goto exit;
+ }
+
+ Status = WaitForPeriodicScheduleEnable (HcDev, EHCI_GENERIC_TIMEOUT);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((gEHCErrorLevel, "WaitForPeriodicScheduleEnable TimeOut\n"));
+ Status = EFI_TIMEOUT;
+ goto exit;
+ }
+
+ if (IsEhcHalted (HcDev)) {
+ Status = StartScheduleExecution (HcDev);
+ if (EFI_ERROR (Status)) {
+ Status = EFI_DEVICE_ERROR;
+ goto exit;
+ }
+ }
+
+ }
+
+ DestoryQtds (HcDev, MatchPtr->QhPtr->FirstQtdPtr);
+ DestoryQh (HcDev, MatchPtr->QhPtr);
+ EhciFreePool (HcDev, (UINT8 *) MatchPtr, sizeof (EHCI_ASYNC_REQUEST));
+
+exit:
+ return Status;
+}
+
+VOID
+CleanUpAllAsyncRequestTransfer (
+ IN USB2_HC_DEV *HcDev
+ )
+/*++
+
+Routine Description:
+
+ Clean up all asynchronous request transfer
+
+Arguments:
+
+ HcDev - USB2_HC_DEV
+
+Returns:
+
+ VOID
+
+--*/
+{
+ EHCI_ASYNC_REQUEST *AsyncRequestPtr;
+ EHCI_ASYNC_REQUEST *FreePtr;
+
+ AsyncRequestPtr = NULL;
+ FreePtr = NULL;
+
+ StopPollingTimer (HcDev);
+
+ AsyncRequestPtr = HcDev->AsyncRequestList;
+ while (NULL != AsyncRequestPtr) {
+
+ FreePtr = AsyncRequestPtr;
+ AsyncRequestPtr = AsyncRequestPtr->Next;
+ UnlinkFromAsyncReqeust (HcDev, FreePtr);
+ UnlinkQhFromPeriodicList (HcDev, FreePtr->QhPtr, FreePtr->QhPtr->Interval);
+ DestoryQtds (HcDev, FreePtr->QhPtr->FirstQtdPtr);
+ DestoryQh (HcDev, FreePtr->QhPtr);
+ EhciFreePool (HcDev, (UINT8 *) FreePtr, sizeof (EHCI_ASYNC_REQUEST));
+
+ }
+
+ return ;
+}
+
+VOID
+ZeroOutQhOverlay (
+ IN EHCI_QH_ENTITY *QhPtr
+ )
+/*++
+
+Routine Description:
+
+ Zero out the fields in Qh structure
+
+Arguments:
+
+ QhPtr - A pointer to Qh structure
+
+Returns:
+
+ VOID
+
+--*/
+{
+ QhPtr->Qh.CurrentQtdPointer = 0;
+ QhPtr->Qh.AltNextQtdPointer = 0;
+ QhPtr->Qh.NakCount = 0;
+ QhPtr->Qh.AltNextQtdTerminate = 0;
+ QhPtr->Qh.TotalBytes = 0;
+ QhPtr->Qh.InterruptOnComplete = 0;
+ QhPtr->Qh.CurrentPage = 0;
+ QhPtr->Qh.ErrorCount = 0;
+ QhPtr->Qh.PidCode = 0;
+ QhPtr->Qh.Status = 0;
+ QhPtr->Qh.BufferPointer0 = 0;
+ QhPtr->Qh.CurrentOffset = 0;
+ QhPtr->Qh.BufferPointer1 = 0;
+ QhPtr->Qh.CompleteSplitMask = 0;
+ QhPtr->Qh.BufferPointer2 = 0;
+ QhPtr->Qh.SplitBytes = 0;
+ QhPtr->Qh.FrameTag = 0;
+ QhPtr->Qh.BufferPointer3 = 0;
+ QhPtr->Qh.BufferPointer4 = 0;
+ QhPtr->Qh.ExtBufferPointer0 = 0;
+ QhPtr->Qh.ExtBufferPointer1 = 0;
+ QhPtr->Qh.ExtBufferPointer2 = 0;
+ QhPtr->Qh.ExtBufferPointer3 = 0;
+ QhPtr->Qh.ExtBufferPointer4 = 0;
+}
+
+VOID
+UpdateAsyncRequestTransfer (
+ IN EHCI_ASYNC_REQUEST *AsyncRequestPtr,
+ IN UINT32 TransferResult,
+ IN UINTN ErrQtdPos
+ )
+/*++
+
+Routine Description:
+
+ Update asynchronous request transfer
+
+Arguments:
+
+ AsyncRequestPtr - A pointer to async request
+ TransferResult - transfer result
+ ErrQtdPos - postion of error Qtd
+
+Returns:
+
+ VOID
+
+--*/
+{
+ EHCI_QTD_ENTITY *QtdPtr;
+
+ QtdPtr = NULL;
+
+ if (EFI_USB_NOERROR == TransferResult) {
+
+ //
+ // Update Qh for next trigger
+ //
+
+ QtdPtr = AsyncRequestPtr->QhPtr->FirstQtdPtr;
+
+ //
+ // Update fields in Qh
+ //
+
+ //
+ // Get DataToggle from Overlay in Qh
+ //
+ // ZeroOut Overlay in Qh except DataToggle, HostController will update this field
+ //
+ ZeroOutQhOverlay (AsyncRequestPtr->QhPtr);
+ AsyncRequestPtr->QhPtr->Qh.NextQtdPointer = (UINT32) (GET_0B_TO_31B (&(QtdPtr->Qtd)) >> 5);
+ AsyncRequestPtr->QhPtr->Qh.NextQtdTerminate = FALSE;
+
+ //
+ // Update fields in Qtd
+ //
+ while (NULL != QtdPtr) {
+ QtdPtr->Qtd.TotalBytes = QtdPtr->StaticTotalBytes;
+ QtdPtr->Qtd.CurrentOffset = QtdPtr->StaticCurrentOffset;
+ QtdPtr->Qtd.CurrentPage = 0;
+ QtdPtr->Qtd.ErrorCount = QTD_ERROR_COUNTER;
+ QtdPtr->Qtd.Status = QTD_STATUS_ACTIVE;
+
+ QtdPtr->TotalBytes = QtdPtr->StaticTotalBytes;
+ QtdPtr = QtdPtr->Next;
+ }
+ }
+
+ return ;
+}
+
+BOOLEAN
+CheckQtdsTransferResult (
+ IN BOOLEAN IsControl,
+ IN EHCI_QH_ENTITY *QhPtr,
+ OUT UINT32 *Result,
+ OUT UINTN *ErrQtdPos,
+ OUT UINTN *ActualLen
+ )
+/*++
+
+Routine Description:
+
+ Check transfer result of Qtds
+
+Arguments:
+
+ IsControl - Is control transfer or not
+ QhPtr - A pointer to Qh
+ Result - Transfer result
+ ErrQtdPos - Error TD Position
+ ActualLen - Actual Transfer Size
+
+Returns:
+
+ TRUE Qtds finished
+ FALSE Not finish
+
+--*/
+{
+ UINTN ActualLenPerQtd;
+ EHCI_QTD_ENTITY *QtdPtr;
+ EHCI_QTD_HW *QtdHwPtr;
+ BOOLEAN Value;
+
+ ASSERT (QhPtr);
+ ASSERT (Result);
+ ASSERT (ErrQtdPos);
+ ASSERT (ActualLen);
+
+ Value = TRUE;
+ QtdPtr = QhPtr->FirstQtdPtr;
+ QtdHwPtr = &(QtdPtr->Qtd);
+
+ while (NULL != QtdHwPtr) {
+
+ if (IsQtdStatusActive (QtdHwPtr)) {
+ *Result |= EFI_USB_ERR_NOTEXECUTE;
+ }
+
+ if (IsQtdStatusHalted (QtdHwPtr)) {
+ *Result |= EFI_USB_ERR_STALL;
+ }
+
+ if (IsQtdStatusBufferError (QtdHwPtr)) {
+ *Result |= EFI_USB_ERR_BUFFER;
+ }
+
+ if (IsQtdStatusBabbleError (QtdHwPtr)) {
+ *Result |= EFI_USB_ERR_BABBLE;
+ }
+
+ if (IsQtdStatusTransactionError (QtdHwPtr)) {
+ *Result |= EFI_USB_ERR_TIMEOUT;
+ }
+
+ ActualLenPerQtd = QtdPtr->TotalBytes - QtdHwPtr->TotalBytes;
+ QtdPtr->TotalBytes = QtdHwPtr->TotalBytes;
+ //
+ // Accumulate actual transferred data length in each DataQtd.
+ //
+ if (SETUP_PACKET_PID_CODE != QtdHwPtr->PidCode) {
+ *ActualLen += ActualLenPerQtd;
+ }
+
+ if (*Result) {
+ Value = FALSE;
+ break;
+ }
+
+ if ((!IsControl) && (QtdPtr->TotalBytes > 0)) {
+ //
+ // Did something, but isn't full workload
+ //
+ break;
+ }
+
+ (*ErrQtdPos)++;
+ QtdHwPtr = GetQtdNextPointer (QtdHwPtr);
+ QtdPtr = (EHCI_QTD_ENTITY *) GET_QTD_ENTITY_ADDR (QtdHwPtr);
+
+ }
+
+ return Value;
+}
+
+EFI_STATUS
+ExecuteTransfer (
+ IN USB2_HC_DEV *HcDev,
+ IN BOOLEAN IsControl,
+ IN EHCI_QH_ENTITY *QhPtr,
+ IN OUT UINTN *ActualLen,
+ OUT UINT8 *DataToggle,
+ IN UINTN TimeOut,
+ OUT UINT32 *TransferResult
+ )
+/*++
+
+Routine Description:
+
+ Execute Bulk or SyncInterrupt Transfer
+
+Arguments:
+
+ HcDev - USB2_HC_DEV
+ IsControl - Is control transfer or not
+ QhPtr - A pointer to Qh
+ ActualLen - Actual transfered Len
+ DataToggle - Data Toggle
+ TimeOut - TimeOut threshold
+ TransferResult - Transfer result
+
+Returns:
+
+ EFI_SUCCESS Sucess
+ EFI_DEVICE_ERROR Fail
+
+--*/
+{
+ EFI_STATUS Status;
+ UINTN ErrQtdPos;
+ UINTN Delay;
+ UINTN RequireLen;
+ BOOLEAN Finished;
+
+ Status = EFI_SUCCESS;
+ ErrQtdPos = 0;
+ *TransferResult = EFI_USB_NOERROR;
+ RequireLen = *ActualLen;
+ *ActualLen = 0;
+ Finished = FALSE;
+
+ Delay = (TimeOut * STALL_1_MILLI_SECOND / 50) + 1;
+
+ do {
+ *TransferResult = 0;
+ Finished = CheckQtdsTransferResult (
+ IsControl,
+ QhPtr,
+ TransferResult,
+ &ErrQtdPos,
+ ActualLen
+ );
+ if (Finished) {
+ break;
+ }
+ //
+ // Qtd is inactive, which means bulk or interrupt transfer's end.
+ //
+ if (!(*TransferResult & EFI_USB_ERR_NOTEXECUTE)) {
+ break;
+ }
+
+ gBS->Stall (EHCI_SYNC_REQUEST_POLLING_TIME);
+
+ } while (--Delay);
+
+ if (EFI_USB_NOERROR != *TransferResult) {
+ if (0 == Delay) {
+ Status = EFI_TIMEOUT;
+ } else {
+ Status = EFI_DEVICE_ERROR;
+ }
+ }
+
+ //
+ // Special for Bulk and Interrupt Transfer
+ //
+ *DataToggle = (UINT8) QhPtr->Qh.DataToggle;
+
+ return Status;
+}
+
+EFI_STATUS
+AsyncRequestMoniter (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+/*++
+Routine Description:
+
+ Interrupt transfer periodic check handler
+
+Arguments:
+ Event - Interrupt event
+ Context - Pointer to USB2_HC_DEV
+
+Returns:
+
+ EFI_SUCCESS Success
+ EFI_DEVICE_ERROR Fail
+
+--*/
+{
+ EFI_STATUS Status;
+ USB2_HC_DEV *HcDev;
+ EHCI_ASYNC_REQUEST *AsyncRequestPtr;
+ EHCI_QTD_HW *QtdHwPtr;
+ UINTN ErrQtdPos;
+ UINTN ActualLen;
+ UINT32 TransferResult;
+ UINT8 *ReceiveBuffer;
+ UINT8 *ProcessBuffer;
+
+ Status = EFI_SUCCESS;
+ QtdHwPtr = NULL;
+ ReceiveBuffer = NULL;
+ ProcessBuffer = NULL;
+ HcDev = (USB2_HC_DEV *) Context;
+ AsyncRequestPtr = HcDev->AsyncRequestList;
+
+ while (NULL != AsyncRequestPtr) {
+
+ TransferResult = 0;
+ ErrQtdPos = 0;
+ ActualLen = 0;
+
+ CheckQtdsTransferResult (
+ FALSE,
+ AsyncRequestPtr->QhPtr,
+ &TransferResult,
+ &ErrQtdPos,
+ &ActualLen
+ );
+
+ if ((TransferResult & EFI_USB_ERR_NAK) || (TransferResult & EFI_USB_ERR_NOTEXECUTE)) {
+ AsyncRequestPtr = AsyncRequestPtr->Next;
+ continue;
+ }
+ //
+ // Allocate memory for EHC private data structure
+ //
+ ProcessBuffer = AllocateZeroPool (ActualLen);
+ if (NULL == ProcessBuffer) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto exit;
+ }
+
+ QtdHwPtr = &(AsyncRequestPtr->QhPtr->FirstQtdPtr->Qtd);
+ ReceiveBuffer = (UINT8 *) GET_0B_TO_31B ((QtdHwPtr->BufferPointer0 << 12) | AsyncRequestPtr->QhPtr->FirstQtdPtr->StaticCurrentOffset);
+ CopyMem (
+ ProcessBuffer,
+ ReceiveBuffer,
+ ActualLen
+ );
+
+ UpdateAsyncRequestTransfer (AsyncRequestPtr, TransferResult, ErrQtdPos);
+
+ if (EFI_USB_NOERROR == TransferResult) {
+
+ if (AsyncRequestPtr->CallBackFunc != NULL) {
+ (AsyncRequestPtr->CallBackFunc) (ProcessBuffer, ActualLen, AsyncRequestPtr->Context, TransferResult);
+ }
+
+ } else {
+
+ //
+ // leave error recovery to its related device driver. A common case of
+ // the error recovery is to re-submit the interrupt transfer.
+ // When an interrupt transfer is re-submitted, its position in the linked
+ // list is changed. It is inserted to the head of the linked list, while
+ // this function scans the whole list from head to tail. Thus, the
+ // re-submitted interrupt transfer's callback function will not be called
+ // again in this round.
+ //
+ if (AsyncRequestPtr->CallBackFunc != NULL) {
+ (AsyncRequestPtr->CallBackFunc) (NULL, 0, AsyncRequestPtr->Context, TransferResult);
+ }
+
+ }
+
+ if (NULL != ProcessBuffer) {
+ gBS->FreePool (ProcessBuffer);
+ }
+
+ AsyncRequestPtr = AsyncRequestPtr->Next;
+
+ }
+
+exit:
+ return Status;
+}
+