/* Precondition: A transfer is available. */ static int submit_transfer(struct bladerf_stream *stream, void *buffer) { int status; struct bladerf_lusb *lusb = lusb_backend(stream->dev); struct lusb_stream_data *stream_data = stream->backend_data; struct libusb_transfer *transfer; size_t bytes_per_buffer; const unsigned char ep = stream->module == BLADERF_MODULE_TX ? SAMPLE_EP_OUT : SAMPLE_EP_IN; assert(stream_data->transfer_status[stream_data->i] == TRANSFER_AVAIL); transfer = stream_data->transfers[stream_data->i]; switch (stream->format) { case BLADERF_FORMAT_SC16_Q11: bytes_per_buffer = c16_samples_to_bytes(stream->samples_per_buffer); break; default: assert(!"Unexpected format"); return BLADERF_ERR_INVAL; } assert(bytes_per_buffer <= INT_MAX); libusb_fill_bulk_transfer(transfer, lusb->handle, ep, buffer, (int)bytes_per_buffer, lusb_stream_cb, stream, stream->dev->transfer_timeout[stream->module]); status = libusb_submit_transfer(transfer); if (status == 0) { stream_data->transfer_status[stream_data->i] = TRANSFER_IN_FLIGHT; stream_data->i = (stream_data->i + 1) % stream_data->num_transfers; assert(stream_data->num_avail_transfers != 0); stream_data->num_avail_transfers--; } else { log_error("Failed to submit transfer in %s: %s\n", __FUNCTION__, libusb_error_name(status)); } return error_conv(status); }
/* Precondition: A transfer is available. */ static int submit_transfer(struct bladerf_stream *stream, void *buffer) { int status; struct bladerf_lusb *lusb = lusb_backend(stream->dev); struct lusb_stream_data *stream_data = stream->backend_data; struct libusb_transfer *transfer; const size_t bytes_per_buffer = async_stream_buf_bytes(stream); size_t prev_idx; const unsigned char ep = stream->module == BLADERF_MODULE_TX ? SAMPLE_EP_OUT : SAMPLE_EP_IN; transfer = get_next_available_transfer(stream_data); assert(transfer != NULL); assert(bytes_per_buffer <= INT_MAX); libusb_fill_bulk_transfer(transfer, lusb->handle, ep, buffer, (int)bytes_per_buffer, lusb_stream_cb, stream, stream->dev->transfer_timeout[stream->module]); prev_idx = stream_data->i; stream_data->transfer_status[stream_data->i] = TRANSFER_IN_FLIGHT; stream_data->i = (stream_data->i + 1) % stream_data->num_transfers; assert(stream_data->num_avail != 0); stream_data->num_avail--; /* FIXME We have an inherent issue here with lock ordering between * stream->lock and libusb's underlying event lock, so we * have to drop the stream->lock as a workaround. * * This implies that a callback can potentially execute, * including a callback for this transfer. Therefore, the transfer * has been setup and its metadata logged. * * Ultimately, we need to review our async scheme and associated * lock schemes. */ MUTEX_UNLOCK(&stream->lock); status = libusb_submit_transfer(transfer); MUTEX_LOCK(&stream->lock); if (status != 0) { log_error("Failed to submit transfer in %s: %s\n", __FUNCTION__, libusb_error_name(status)); /* We need to undo the metadata we updated prior to dropping * the lock and attempting to submit the transfer */ assert(stream_data->transfer_status[prev_idx] == TRANSFER_IN_FLIGHT); stream_data->transfer_status[prev_idx] = TRANSFER_AVAIL; stream_data->num_avail++; if (stream_data->i == 0) { stream_data->i = stream_data->num_transfers - 1; } else { stream_data->i--; } } return error_conv(status); }