/** Initialize interrupt list. @Param Ohc Device private data @retval EFI_SUCCESS Initialization done **/ EFI_STATUS OhciInitializeInterruptList ( USB_OHCI_HC_DEV *Ohc ) { static UINT32 Leaf[32] = {0, 16, 8, 24, 4, 20, 12, 28, 2, 18, 10, 26, 6, 22, 14, 30, 1, 17, 9, 25, 5, 21, 13, 29, 3, 19, 11, 27, 7, 23, 15, 31}; UINT32 *HccaInterruptTable; UINTN Index; UINTN Level; UINTN Count; ED_DESCRIPTOR *NewEd; HccaInterruptTable = Ohc->HccaMemoryBlock->HccaInterruptTable; for (Index = 0; Index < 32; Index++) { NewEd = OhciCreateED (Ohc); if (NewEd == NULL) { return EFI_OUT_OF_RESOURCES; } HccaInterruptTable[Index] = (UINT32)(UINTN)NewEd; } for (Index = 0; Index < 32; Index++) { Ohc->IntervalList[0][Index] = (ED_DESCRIPTOR *)(UINTN)HccaInterruptTable[Leaf[Index]]; } Count = 32; for (Level = 1; Level <= 5; Level++) { Count = Count >> 1; for (Index = 0; Index < Count; Index++) { Ohc->IntervalList[Level][Index] = OhciCreateED (Ohc); if (HccaInterruptTable[Index] == 0) { return EFI_OUT_OF_RESOURCES; } Ohc->IntervalList[Level - 1][Index * 2 ]->NextED = (UINT32)(UINTN)Ohc->IntervalList[Level][Index]; Ohc->IntervalList[Level - 1][Index * 2 + 1]->NextED = (UINT32)(UINTN)Ohc->IntervalList[Level][Index]; } } return EFI_SUCCESS; }
/** Submits control transfer to a target USB device. @param PeiServices The pointer of EFI_PEI_SERVICES. @param This The pointer of PEI_USB_HOST_CONTROLLER_PPI. @param DeviceAddress The target device address. @param DeviceSpeed Target device speed. @param MaximumPacketLength Maximum packet size the default control transfer endpoint is capable of sending or receiving. @param Request USB device request to send. @param TransferDirection Specifies the data direction for the data stage. @param Data Data buffer to be transmitted or received from USB device. @param DataLength The size (in bytes) of the data buffer. @param TimeOut Indicates the maximum timeout, in millisecond. @param TransferResult Return the result of this control transfer. @retval EFI_SUCCESS Transfer was completed successfully. @retval EFI_OUT_OF_RESOURCES The transfer failed due to lack of resources. @retval EFI_INVALID_PARAMETER Some parameters are invalid. @retval EFI_TIMEOUT Transfer failed due to timeout. @retval EFI_DEVICE_ERROR Transfer failed due to host controller or device error. **/ EFI_STATUS EFIAPI OhciControlTransfer ( IN EFI_PEI_SERVICES **PeiServices, IN PEI_USB_HOST_CONTROLLER_PPI *This, IN UINT8 DeviceAddress, IN UINT8 DeviceSpeed, IN UINT8 MaxPacketLength, IN EFI_USB_DEVICE_REQUEST *Request, IN EFI_USB_DATA_DIRECTION TransferDirection, IN OUT VOID *Data, IN OUT UINTN *DataLength, IN UINTN TimeOut, OUT UINT32 *TransferResult ) { USB_OHCI_HC_DEV *Ohc; ED_DESCRIPTOR *Ed; TD_DESCRIPTOR *HeadTd; TD_DESCRIPTOR *SetupTd; TD_DESCRIPTOR *DataTd; TD_DESCRIPTOR *StatusTd; TD_DESCRIPTOR *EmptyTd; EFI_STATUS Status; UINT32 DataPidDir; UINT32 StatusPidDir; UINTN TimeCount; UINT32 ErrorCode; UINTN ActualSendLength; UINTN LeftLength; UINT8 DataToggle; EFI_PHYSICAL_ADDRESS ReqMapPhyAddr = 0; UINTN DataMapLength = 0; EFI_PHYSICAL_ADDRESS DataMapPhyAddr = 0; HeadTd = NULL; DataTd = NULL; if ((TransferDirection != EfiUsbDataOut && TransferDirection != EfiUsbDataIn && TransferDirection != EfiUsbNoData) || Request == NULL || DataLength == NULL || TransferResult == NULL || (TransferDirection == EfiUsbNoData && (*DataLength != 0 || Data != NULL)) || (TransferDirection != EfiUsbNoData && (*DataLength == 0 || Data == NULL)) || (DeviceSpeed != EFI_USB_SPEED_LOW && DeviceSpeed != EFI_USB_SPEED_FULL) || (MaxPacketLength != 8 && MaxPacketLength != 16 && MaxPacketLength != 32 && MaxPacketLength != 64)) { DEBUG ((EFI_D_INFO, "OhciControlTransfer: EFI_INVALID_PARAMETER\n")); return EFI_INVALID_PARAMETER; } if (*DataLength > MAX_BYTES_PER_TD) { DEBUG ((EFI_D_ERROR, "OhciControlTransfer: Request data size is too large\n")); return EFI_INVALID_PARAMETER; } Ohc = PEI_RECOVERY_USB_OHC_DEV_FROM_EHCI_THIS(This); if (TransferDirection == EfiUsbDataIn) { DataPidDir = TD_IN_PID; StatusPidDir = TD_OUT_PID; } else { DataPidDir = TD_OUT_PID; StatusPidDir = TD_IN_PID; } OhciSetHcControl (Ohc, CONTROL_ENABLE, 0); if (OhciGetHcControl (Ohc, CONTROL_ENABLE) != 0) { MicroSecondDelay (HC_1_MILLISECOND); if (OhciGetHcControl (Ohc, CONTROL_ENABLE) != 0) { *TransferResult = EFI_USB_ERR_SYSTEM; DEBUG ((EFI_D_INFO, "OhciControlTransfer: Fail to disable CONTROL transfer\n")); return EFI_DEVICE_ERROR; } } OhciSetMemoryPointer (Ohc, HC_CONTROL_HEAD, NULL); Ed = OhciCreateED (Ohc); if (Ed == NULL) { DEBUG ((EFI_D_INFO, "OhciControlTransfer: Fail to allocate ED buffer\n")); return EFI_OUT_OF_RESOURCES; } OhciSetEDField (Ed, ED_SKIP, 1); OhciSetEDField (Ed, ED_FUNC_ADD, DeviceAddress); OhciSetEDField (Ed, ED_ENDPT_NUM, 0); OhciSetEDField (Ed, ED_DIR, ED_FROM_TD_DIR); OhciSetEDField (Ed, ED_SPEED, DeviceSpeed); OhciSetEDField (Ed, ED_FORMAT | ED_HALTED | ED_DTTOGGLE, 0); OhciSetEDField (Ed, ED_MAX_PACKET, MaxPacketLength); OhciSetEDField (Ed, ED_PDATA, 0); OhciSetEDField (Ed, ED_ZERO, 0); OhciSetEDField (Ed, ED_TDHEAD_PTR, (UINT32) NULL); OhciSetEDField (Ed, ED_TDTAIL_PTR, (UINT32) NULL); OhciSetEDField (Ed, ED_NEXT_EDPTR, (UINT32) NULL); OhciAttachEDToList (Ohc, CONTROL_LIST, Ed, NULL); // // Setup Stage // if(Request != NULL) { ReqMapPhyAddr = (EFI_PHYSICAL_ADDRESS)(UINTN)Request; } SetupTd = OhciCreateTD (Ohc); if (SetupTd == NULL) { Status = EFI_OUT_OF_RESOURCES; DEBUG ((EFI_D_INFO, "OhciControlTransfer: Fail to allocate Setup TD buffer\n")); goto FREE_ED_BUFF; } HeadTd = SetupTd; OhciSetTDField (SetupTd, TD_PDATA, 0); OhciSetTDField (SetupTd, TD_BUFFER_ROUND, 1); OhciSetTDField (SetupTd, TD_DIR_PID, TD_SETUP_PID); OhciSetTDField (SetupTd, TD_DELAY_INT, TD_NO_DELAY); OhciSetTDField (SetupTd, TD_DT_TOGGLE, 2); OhciSetTDField (SetupTd, TD_ERROR_CNT, 0); OhciSetTDField (SetupTd, TD_COND_CODE, TD_TOBE_PROCESSED); OhciSetTDField (SetupTd, TD_CURR_BUFFER_PTR, (UINTN)ReqMapPhyAddr); OhciSetTDField (SetupTd, TD_NEXT_PTR, (UINT32) NULL); OhciSetTDField (SetupTd, TD_BUFFER_END_PTR, (UINTN)ReqMapPhyAddr + sizeof (EFI_USB_DEVICE_REQUEST) - 1); SetupTd->ActualSendLength = 0; SetupTd->DataBuffer = NULL; SetupTd->NextTDPointer = NULL; DataMapLength = *DataLength; if ((Data != NULL) && (DataMapLength != 0)) { DataMapPhyAddr = (EFI_PHYSICAL_ADDRESS)(UINTN)Data; } // //Data Stage // LeftLength = DataMapLength; ActualSendLength = DataMapLength; DataToggle = 1; while (LeftLength > 0) { ActualSendLength = LeftLength; if (LeftLength > MaxPacketLength) { ActualSendLength = MaxPacketLength; } DataTd = OhciCreateTD (Ohc); if (DataTd == NULL) { DEBUG ((EFI_D_INFO, "OhciControlTransfer: Fail to allocate Data TD buffer\n")); Status = EFI_OUT_OF_RESOURCES; goto FREE_TD_BUFF; } OhciSetTDField (DataTd, TD_PDATA, 0); OhciSetTDField (DataTd, TD_BUFFER_ROUND, 1); OhciSetTDField (DataTd, TD_DIR_PID, DataPidDir); OhciSetTDField (DataTd, TD_DELAY_INT, TD_NO_DELAY); OhciSetTDField (DataTd, TD_DT_TOGGLE, DataToggle); OhciSetTDField (DataTd, TD_ERROR_CNT, 0); OhciSetTDField (DataTd, TD_COND_CODE, TD_TOBE_PROCESSED); OhciSetTDField (DataTd, TD_CURR_BUFFER_PTR, (UINT32) DataMapPhyAddr); OhciSetTDField (DataTd, TD_BUFFER_END_PTR, (UINT32) DataMapPhyAddr + ActualSendLength - 1); OhciSetTDField (DataTd, TD_NEXT_PTR, (UINT32) NULL); DataTd->ActualSendLength = ActualSendLength; DataTd->DataBuffer = (UINT8 *)(UINTN)DataMapPhyAddr; DataTd->NextTDPointer = 0; OhciLinkTD (HeadTd, DataTd); DataToggle ^= 1; DataMapPhyAddr += ActualSendLength; LeftLength -= ActualSendLength; } // // Status Stage // StatusTd = OhciCreateTD (Ohc); if (StatusTd == NULL) { DEBUG ((EFI_D_INFO, "OhciControlTransfer: Fail to allocate Status TD buffer\n")); Status = EFI_OUT_OF_RESOURCES; goto FREE_TD_BUFF; } OhciSetTDField (StatusTd, TD_PDATA, 0); OhciSetTDField (StatusTd, TD_BUFFER_ROUND, 1); OhciSetTDField (StatusTd, TD_DIR_PID, StatusPidDir); OhciSetTDField (StatusTd, TD_DELAY_INT, 7); OhciSetTDField (StatusTd, TD_DT_TOGGLE, 3); OhciSetTDField (StatusTd, TD_ERROR_CNT, 0); OhciSetTDField (StatusTd, TD_COND_CODE, TD_TOBE_PROCESSED); OhciSetTDField (StatusTd, TD_CURR_BUFFER_PTR, (UINT32) NULL); OhciSetTDField (StatusTd, TD_NEXT_PTR, (UINT32) NULL); OhciSetTDField (StatusTd, TD_BUFFER_END_PTR, (UINT32) NULL); StatusTd->ActualSendLength = 0; StatusTd->DataBuffer = NULL; StatusTd->NextTDPointer = NULL; OhciLinkTD (HeadTd, StatusTd); // // Empty Stage // EmptyTd = OhciCreateTD (Ohc); if (EmptyTd == NULL) { Status = EFI_OUT_OF_RESOURCES; DEBUG ((EFI_D_INFO, "OhciControlTransfer: Fail to allocate Empty TD buffer\n")); goto FREE_TD_BUFF; } OhciSetTDField (EmptyTd, TD_PDATA, 0); OhciSetTDField (EmptyTd, TD_BUFFER_ROUND, 0); OhciSetTDField (EmptyTd, TD_DIR_PID, 0); OhciSetTDField (EmptyTd, TD_DELAY_INT, 0); //OhciSetTDField (EmptyTd, TD_DT_TOGGLE, CurrentToggle); EmptyTd->Word0.DataToggle = 0; OhciSetTDField (EmptyTd, TD_ERROR_CNT, 0); OhciSetTDField (EmptyTd, TD_COND_CODE, 0); OhciSetTDField (EmptyTd, TD_CURR_BUFFER_PTR, 0); OhciSetTDField (EmptyTd, TD_BUFFER_END_PTR, 0); OhciSetTDField (EmptyTd, TD_NEXT_PTR, 0); EmptyTd->ActualSendLength = 0; EmptyTd->DataBuffer = NULL; EmptyTd->NextTDPointer = NULL; OhciLinkTD (HeadTd, EmptyTd); Ed->TdTailPointer = EmptyTd; OhciAttachTDListToED (Ed, HeadTd); // OhciSetEDField (Ed, ED_SKIP, 0); MicroSecondDelay (20 * HC_1_MILLISECOND); OhciSetHcCommandStatus (Ohc, CONTROL_LIST_FILLED, 1); OhciSetHcControl (Ohc, CONTROL_ENABLE, 1); MicroSecondDelay (20 * HC_1_MILLISECOND); if (OhciGetHcControl (Ohc, CONTROL_ENABLE) != 1) { MicroSecondDelay (HC_1_MILLISECOND); if (OhciGetHcControl (Ohc, CONTROL_ENABLE) != 1) { *TransferResult = EFI_USB_ERR_SYSTEM; Status = EFI_DEVICE_ERROR; DEBUG ((EFI_D_INFO, "OhciControlTransfer: Fail to enable CONTROL transfer\n")); goto FREE_TD_BUFF; } } TimeCount = 0; Status = CheckIfDone (Ohc, CONTROL_LIST, Ed, HeadTd, &ErrorCode); while (Status == EFI_NOT_READY && TimeCount <= TimeOut) { MicroSecondDelay (HC_1_MILLISECOND); TimeCount++; Status = CheckIfDone (Ohc, CONTROL_LIST, Ed, HeadTd, &ErrorCode); } // *TransferResult = ConvertErrorCode (ErrorCode); if (ErrorCode != TD_NO_ERROR) { if (ErrorCode == TD_TOBE_PROCESSED) { DEBUG ((EFI_D_INFO, "Control pipe timeout, > %d mS\r\n", TimeOut)); } else { DEBUG ((EFI_D_INFO, "Control pipe broken\r\n")); } *DataLength = 0; } OhciSetHcControl (Ohc, CONTROL_ENABLE, 0); if (OhciGetHcControl (Ohc, CONTROL_ENABLE) != 0) { MicroSecondDelay (HC_1_MILLISECOND); if (OhciGetHcControl (Ohc, CONTROL_ENABLE) != 0) { *TransferResult = EFI_USB_ERR_SYSTEM; DEBUG ((EFI_D_INFO, "OhciControlTransfer: Cannot disable CONTROL_ENABLE transfer\n")); goto FREE_TD_BUFF; } } FREE_TD_BUFF: while (HeadTd) { DataTd = HeadTd; HeadTd = HeadTd->NextTDPointer; UsbHcFreeMem(Ohc->MemPool, DataTd, sizeof(TD_DESCRIPTOR)); } FREE_ED_BUFF: UsbHcFreeMem(Ohc->MemPool, Ed, sizeof(ED_DESCRIPTOR)); return Status; }
/** Submits bulk transfer to a bulk endpoint of a USB device. @param PeiServices The pointer of EFI_PEI_SERVICES. @param This The pointer of PEI_USB_HOST_CONTROLLER_PPI. @param DeviceAddress Target device address. @param EndPointAddress Endpoint number and its direction in bit 7. @param MaxiPacketLength Maximum packet size the endpoint is capable of sending or receiving. @param Data A pointers to the buffers of data to transmit from or receive into. @param DataLength The lenght of the data buffer. @param DataToggle On input, the initial data toggle for the transfer; On output, it is updated to to next data toggle to use of the subsequent bulk transfer. @param TimeOut Indicates the maximum time, in millisecond, which the transfer is allowed to complete. @param TransferResult A pointer to the detailed result information of the bulk transfer. @retval EFI_SUCCESS The transfer was completed successfully. @retval EFI_OUT_OF_RESOURCES The transfer failed due to lack of resource. @retval EFI_INVALID_PARAMETER Parameters are invalid. @retval EFI_TIMEOUT The transfer failed due to timeout. @retval EFI_DEVICE_ERROR The transfer failed due to host controller error. **/ EFI_STATUS EFIAPI OhciBulkTransfer ( IN EFI_PEI_SERVICES **PeiServices, IN PEI_USB_HOST_CONTROLLER_PPI *This, IN UINT8 DeviceAddress, IN UINT8 EndPointAddress, IN UINT8 MaxPacketLength, IN OUT VOID *Data, IN OUT UINTN *DataLength, IN OUT UINT8 *DataToggle, IN UINTN TimeOut, OUT UINT32 *TransferResult ) { USB_OHCI_HC_DEV *Ohc; ED_DESCRIPTOR *Ed; UINT32 DataPidDir; TD_DESCRIPTOR *HeadTd; TD_DESCRIPTOR *DataTd; TD_DESCRIPTOR *EmptyTd; EFI_STATUS Status; UINT8 EndPointNum; UINTN TimeCount; UINT32 ErrorCode; UINT8 CurrentToggle; UINTN MapLength; EFI_PHYSICAL_ADDRESS MapPyhAddr; UINTN LeftLength; UINTN ActualSendLength; BOOLEAN FirstTD; MapLength = 0; MapPyhAddr = 0; LeftLength = 0; Status = EFI_SUCCESS; if (Data == NULL || DataLength == NULL || DataToggle == NULL || TransferResult == NULL || *DataLength == 0 || (*DataToggle != 0 && *DataToggle != 1) || (MaxPacketLength != 8 && MaxPacketLength != 16 && MaxPacketLength != 32 && MaxPacketLength != 64)) { return EFI_INVALID_PARAMETER; } Ohc = PEI_RECOVERY_USB_OHC_DEV_FROM_EHCI_THIS (This); if ((EndPointAddress & 0x80) != 0) { DataPidDir = TD_IN_PID; } else { DataPidDir = TD_OUT_PID; } EndPointNum = (EndPointAddress & 0xF); OhciSetHcControl (Ohc, BULK_ENABLE, 0); if (OhciGetHcControl (Ohc, BULK_ENABLE) != 0) { MicroSecondDelay (HC_1_MILLISECOND); if (OhciGetHcControl (Ohc, BULK_ENABLE) != 0) { *TransferResult = EFI_USB_ERR_SYSTEM; return EFI_DEVICE_ERROR; } } OhciSetMemoryPointer (Ohc, HC_BULK_HEAD, NULL); Ed = OhciCreateED (Ohc); if (Ed == NULL) { DEBUG ((EFI_D_INFO, "OhcBulkTransfer: Fail to allocate ED buffer\r\n")); return EFI_OUT_OF_RESOURCES; } OhciSetEDField (Ed, ED_SKIP, 1); OhciSetEDField (Ed, ED_FUNC_ADD, DeviceAddress); OhciSetEDField (Ed, ED_ENDPT_NUM, EndPointNum); OhciSetEDField (Ed, ED_DIR, ED_FROM_TD_DIR); OhciSetEDField (Ed, ED_SPEED, HI_SPEED); OhciSetEDField (Ed, ED_FORMAT | ED_HALTED | ED_DTTOGGLE, 0); OhciSetEDField (Ed, ED_MAX_PACKET, MaxPacketLength); OhciSetEDField (Ed, ED_PDATA, 0); OhciSetEDField (Ed, ED_ZERO, 0); OhciSetEDField (Ed, ED_TDHEAD_PTR, (UINT32) NULL); OhciSetEDField (Ed, ED_TDTAIL_PTR, (UINT32) NULL); OhciSetEDField (Ed, ED_NEXT_EDPTR, (UINT32) NULL); OhciAttachEDToList (Ohc, BULK_LIST, Ed, NULL); if(Data != NULL) { MapLength = *DataLength; MapPyhAddr = (EFI_PHYSICAL_ADDRESS)(UINTN)Data; } // //Data Stage // LeftLength = MapLength; ActualSendLength = MapLength; CurrentToggle = *DataToggle; HeadTd = NULL; FirstTD = TRUE; while (LeftLength > 0) { ActualSendLength = LeftLength; if (LeftLength > MaxPacketLength) { ActualSendLength = MaxPacketLength; } DataTd = OhciCreateTD (Ohc); if (DataTd == NULL) { DEBUG ((EFI_D_INFO, "OhcBulkTransfer: Fail to allocate Data TD buffer\r\n")); Status = EFI_OUT_OF_RESOURCES; goto FREE_TD_BUFF; } OhciSetTDField (DataTd, TD_PDATA, 0); OhciSetTDField (DataTd, TD_BUFFER_ROUND, 1); OhciSetTDField (DataTd, TD_DIR_PID, DataPidDir); OhciSetTDField (DataTd, TD_DELAY_INT, TD_NO_DELAY); OhciSetTDField (DataTd, TD_DT_TOGGLE, CurrentToggle); OhciSetTDField (DataTd, TD_ERROR_CNT, 0); OhciSetTDField (DataTd, TD_COND_CODE, TD_TOBE_PROCESSED); OhciSetTDField (DataTd, TD_CURR_BUFFER_PTR, (UINT32) MapPyhAddr); OhciSetTDField (DataTd, TD_BUFFER_END_PTR, (UINT32) MapPyhAddr + ActualSendLength - 1); OhciSetTDField (DataTd, TD_NEXT_PTR, (UINT32) NULL); DataTd->ActualSendLength = ActualSendLength; DataTd->DataBuffer = (UINT8 *)(UINTN)MapPyhAddr; DataTd->NextTDPointer = 0; if (FirstTD) { HeadTd = DataTd; FirstTD = FALSE; } else { OhciLinkTD (HeadTd, DataTd); } CurrentToggle ^= 1; MapPyhAddr += ActualSendLength; LeftLength -= ActualSendLength; } // // Empty Stage // EmptyTd = OhciCreateTD (Ohc); if (EmptyTd == NULL) { Status = EFI_OUT_OF_RESOURCES; DEBUG ((EFI_D_INFO, "OhcBulkTransfer: Fail to allocate Empty TD buffer\r\n")); goto FREE_TD_BUFF; } OhciSetTDField (EmptyTd, TD_PDATA, 0); OhciSetTDField (EmptyTd, TD_BUFFER_ROUND, 0); OhciSetTDField (EmptyTd, TD_DIR_PID, 0); OhciSetTDField (EmptyTd, TD_DELAY_INT, 0); //OhciSetTDField (EmptyTd, TD_DT_TOGGLE, CurrentToggle); EmptyTd->Word0.DataToggle = 0; OhciSetTDField (EmptyTd, TD_ERROR_CNT, 0); OhciSetTDField (EmptyTd, TD_COND_CODE, 0); OhciSetTDField (EmptyTd, TD_CURR_BUFFER_PTR, 0); OhciSetTDField (EmptyTd, TD_BUFFER_END_PTR, 0); OhciSetTDField (EmptyTd, TD_NEXT_PTR, 0); EmptyTd->ActualSendLength = 0; EmptyTd->DataBuffer = NULL; EmptyTd->NextTDPointer = NULL; OhciLinkTD (HeadTd, EmptyTd); Ed->TdTailPointer = EmptyTd; OhciAttachTDListToED (Ed, HeadTd); OhciSetEDField (Ed, ED_SKIP, 0); OhciSetHcCommandStatus (Ohc, BULK_LIST_FILLED, 1); OhciSetHcControl (Ohc, BULK_ENABLE, 1); if (OhciGetHcControl (Ohc, BULK_ENABLE) != 1) { MicroSecondDelay (HC_1_MILLISECOND); if (OhciGetHcControl (Ohc, BULK_ENABLE) != 1) { *TransferResult = EFI_USB_ERR_SYSTEM; goto FREE_TD_BUFF; } } TimeCount = 0; Status = CheckIfDone (Ohc, BULK_LIST, Ed, HeadTd, &ErrorCode); while (Status == EFI_NOT_READY && TimeCount <= TimeOut) { MicroSecondDelay (HC_1_MILLISECOND); TimeCount++; Status = CheckIfDone (Ohc, BULK_LIST, Ed, HeadTd, &ErrorCode); } *TransferResult = ConvertErrorCode (ErrorCode); if (ErrorCode != TD_NO_ERROR) { if (ErrorCode == TD_TOBE_PROCESSED) { DEBUG ((EFI_D_INFO, "Bulk pipe timeout, > %d mS\r\n", TimeOut)); } else { DEBUG ((EFI_D_INFO, "Bulk pipe broken\r\n")); } *DataLength = 0; } *DataToggle = (UINT8) OhciGetEDField (Ed, ED_DTTOGGLE); FREE_TD_BUFF: while (HeadTd) { DataTd = HeadTd; HeadTd = HeadTd->NextTDPointer; UsbHcFreeMem(Ohc->MemPool, DataTd, sizeof(TD_DESCRIPTOR)); } UsbHcFreeMem(Ohc->MemPool, Ed, sizeof(ED_DESCRIPTOR)); return Status; }