Esempio n. 1
0
/* 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);
}
Esempio n. 2
0
/* 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);
}