int ReapTransfer(transfer_wrapper* wrapper, int timeout) { void* context (wrapper->usb); libusb_transfer* transfer (&wrapper->libusb); if (transfer->flags & LIBUSB_TRANSFER_FREE_TRANSFER) { libusb_free_transfer(transfer); return(0); } const int read = usb_reap_async_nocancel(context, timeout); bool processed (true); if (read > 0) { PreprocessTransfer(transfer, read); } else if (0 == read) { const int pkts (transfer->num_iso_packets); for (int i=0; i<pkts; ++i) { libusb_iso_packet_descriptor& desc (transfer->iso_packet_desc[i]); desc.actual_length = 0; } } else if (read < 0) { enum { ETIMEOUT = -116 }; if (ETIMEOUT == read) { if (LIBUSB_TRANSFER_CANCELLED != transfer->status) processed = false; } else { libusb_cancel_transfer(transfer); processed = false; } } if (processed) { TListTransfers::Remove(wrapper); transfer->callback(transfer); if (read > 0) memset(transfer->buffer, 0, transfer->length); } return(read); }
int TransferAsync(struct BENCHMARK_TRANSFER_PARAM* transferParam, struct BENCHMARK_TRANSFER_HANDLE** handleRef) { int ret; struct BENCHMARK_TRANSFER_HANDLE* handle; *handleRef = NULL; // Submit transfers until the maximum number of outstanding transfer(s) is reached. while (transferParam->OutstandingTransferCount < transferParam->Test->BufferCount) { // Get the next available benchmark transfer handle. *handleRef = handle = &transferParam->TransferHandles[transferParam->TransferHandleNextIndex]; // If a libusb-win32 transfer context hasn't been setup for this benchmark transfer // handle, do it now. // if (!handle->Context) { // Data buffer(s) are located at the end of the transfer param. handle->Data = transferParam->Buffer + (transferParam->TransferHandleNextIndex * transferParam->Test->BufferSize); handle->DataMaxLength = transferParam->Test->BufferSize; switch (ENDPOINT_TYPE(transferParam)) { case USB_ENDPOINT_TYPE_ISOCHRONOUS: ret = usb_isochronous_setup_async(transferParam->Test->DeviceHandle, &handle->Context, transferParam->Ep.bEndpointAddress, transferParam->IsoPacketSize ? transferParam->IsoPacketSize : transferParam->Ep.wMaxPacketSize); break; case USB_ENDPOINT_TYPE_BULK: ret = usb_bulk_setup_async(transferParam->Test->DeviceHandle, &handle->Context, transferParam->Ep.bEndpointAddress); break; case USB_ENDPOINT_TYPE_INTERRUPT: ret = usb_interrupt_setup_async(transferParam->Test->DeviceHandle, &handle->Context, transferParam->Ep.bEndpointAddress); break; default: ret = -1; break; } if (ret < 0) { CONERR("failed creating transfer context ret=%d\n",ret); goto Done; } } // Submit this transfer now. handle->ReturnCode = ret = usb_submit_async(handle->Context, handle->Data, handle->DataMaxLength); if (ret < 0) goto Done; // Mark this handle has InUse. handle->InUse = TRUE; // When transfers ir successfully submitted, OutstandingTransferCount goes up; when // they are completed it goes down. // transferParam->OutstandingTransferCount++; // Move TransferHandleNextIndex to the next available transfer. INC_ROLL(transferParam->TransferHandleNextIndex, transferParam->Test->BufferCount); } // If the number of outstanding transfers has reached the limit, wait for the // oldest outstanding transfer to complete. // if (transferParam->OutstandingTransferCount == transferParam->Test->BufferCount) { // TransferHandleWaitIndex is the index of the oldest outstanding transfer. *handleRef = handle = &transferParam->TransferHandles[transferParam->TransferHandleWaitIndex]; // Only wait, cancelling & freeing is handled by the caller. handle->ReturnCode = ret = usb_reap_async_nocancel(handle->Context, transferParam->Test->Timeout); if (ret < 0) goto Done; // Mark this handle has no longer InUse. handle->InUse = FALSE; // When transfers ir successfully submitted, OutstandingTransferCount goes up; when // they are completed it goes down. // transferParam->OutstandingTransferCount--; // Move TransferHandleWaitIndex to the oldest outstanding transfer. INC_ROLL(transferParam->TransferHandleWaitIndex, transferParam->Test->BufferCount); } Done: return ret; }