static void DoTestLockIntegrity(THREADID tid, THREAD_INFO *info, UINT32 *done) { // This test checks to see if two threads can be in the PIN_LOCK mutex // simultaneously. PIN_GetLock(&Lock, tid); THREADID owner = HasLock; HasLock = tid; if (owner != INVALID_THREADID) { std::cout << "Two theads in lock simultaneously: " << std::dec << tid << " and " << owner << std::endl; PIN_ExitProcess(1); } ATOMIC::OPS::Delay(DELAY_COUNT); HasLock = INVALID_THREADID; THREADID ret = PIN_ReleaseLock(&Lock); if (ret != tid) { std::cout << "PIN_ReleaseLock returned unexpected value " << std::dec << ret << " (expected " << tid << ")" << std::endl; PIN_ExitProcess(1); } CheckIfDone(info, done); }
static void DoTestReaderTryStress(THREAD_INFO *info, UINT32 *done) { // Try to acquire / release PIN_RWMUTEX as a reader using "try" as fast as possible. if (PIN_RWMutexTryReadLock(&RWMutex)) PIN_RWMutexUnlock(&RWMutex); CheckIfDone(info, done); }
static void DoTestMutexTryStress(THREAD_INFO *info, UINT32 *done) { // Try to acquire / release PIN_MUTEX as fast as possible, using "try". if (PIN_MutexTryLock(&Mutex)) PIN_MutexUnlock(&Mutex); CheckIfDone(info, done); }
static void DoTestReaderStress(THREAD_INFO *info, UINT32 *done) { // This test just tries to acquire and release PIN_RWMUTEX as fast as possible // as a reader lock. PIN_RWMutexReadLock(&RWMutex); PIN_RWMutexUnlock(&RWMutex); CheckIfDone(info, done); }
static void DoTestWriterStress(THREAD_INFO *info, UINT32 *done) { // This test just tries to acquire and release PIN_RWMUTEX as fast as possible // as a writer lock to see if we can provoke a deadlock due to missing a wakeup. PIN_RWMutexWriteLock(&RWMutex); PIN_RWMutexUnlock(&RWMutex); CheckIfDone(info, done); }
static void DoTestLockStress(THREADID tid, THREAD_INFO *info, UINT32 *done) { // This test just tries to acquire and release PIN_LOCK as fast as possible // to see if we can provoke a deadlock due to missing a wakeup. PIN_GetLock(&Lock, tid); PIN_ReleaseLock(&Lock); CheckIfDone(info, done); }
static void DoTestSemaphore(THREAD_INFO *info, UINT32 *done) { // This test assumes exactly two threads. The two threads take turns pinging // each other's semaphore. We make sure that a thread does not wake up from // the semaphore unless it is set. We also check for deadlocks due to missing // wakeups. if (info->_workerId == 0) { PIN_SemaphoreWait(&Sem1); if (!PIN_SemaphoreIsSet(&Sem1)) { std::cout << "SemaphoreWait returned, but semaphore is not set" << std::endl; PIN_ExitProcess(1); } PIN_MutexLock(&Mutex); PIN_SemaphoreClear(&Sem1); PIN_SemaphoreSet(&Sem2); PIN_MutexUnlock(&Mutex); } else { PIN_SemaphoreWait(&Sem2); if (!PIN_SemaphoreIsSet(&Sem2)) { std::cout << "SemaphoreWait returned, but semaphore is not set" << std::endl; PIN_ExitProcess(1); } PIN_MutexLock(&Mutex); PIN_SemaphoreClear(&Sem2); PIN_SemaphoreSet(&Sem1); PIN_MutexUnlock(&Mutex); } if (CheckIfDone(info, done)) { PIN_SemaphoreSet(&Sem1); PIN_SemaphoreSet(&Sem2); } }
static void DoTestReaderWriterIntegrity(THREAD_INFO *info, UINT32 *done) { // This test checks that a "writer" thread can never hold the lock while // there is an active reader. if (info->_workerId & 1) { // Reader thread. // PIN_RWMutexReadLock(&RWMutex); ATOMIC::OPS::Increment(&ActiveReaders, 1); if (ATOMIC::OPS::Load(&IsActiveWriter)) { std::cout << "Reader got lock while there is an active writer" << std::endl; PIN_ExitProcess(1); } ATOMIC::OPS::Delay(DELAY_COUNT); ATOMIC::OPS::Increment(&ActiveReaders, -1); PIN_RWMutexUnlock(&RWMutex); } else { // Writer thread. // PIN_RWMutexWriteLock(&RWMutex); ATOMIC::OPS::Store<BOOL>(&IsActiveWriter, TRUE); if (ATOMIC::OPS::Load(&ActiveReaders) != 0) { std::cout << "Writer has lock while there are active readers" << std::endl; PIN_ExitProcess(1); } ATOMIC::OPS::Delay(DELAY_COUNT); ATOMIC::OPS::Store<BOOL>(&IsActiveWriter, FALSE); PIN_RWMutexUnlock(&RWMutex); } CheckIfDone(info, done); }
static void DoTestReaderWriterStress(THREAD_INFO *info, UINT32 *done) { // This test uses a mix of "reader" and "writer" threads to acquire and // release the PIN_RWMUTEX as fast as possible. if (info->_workerId & 1) { // Reader thread. // PIN_RWMutexReadLock(&RWMutex); PIN_RWMutexUnlock(&RWMutex); } else { // Writer thread. // PIN_RWMutexWriteLock(&RWMutex); PIN_RWMutexUnlock(&RWMutex); } CheckIfDone(info, done); }
static void DoTestWriterIntegrity(THREADID tid, THREAD_INFO *info, UINT32 *done) { // This test checks to see if two writer threads can be in the PIN_RWMUTEX mutex // simultaneously. PIN_RWMutexWriteLock(&RWMutex); THREADID owner = HasLock; HasLock = tid; if (owner != INVALID_THREADID) { std::cout << "Two writer theads in rwmutex simultaneously: " << std::dec << tid << " and " << owner << std::endl; PIN_ExitProcess(1); } ATOMIC::OPS::Delay(DELAY_COUNT); HasLock = INVALID_THREADID; PIN_RWMutexUnlock(&RWMutex); CheckIfDone(info, done); }
/** 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; }