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