Пример #1
0
static int open_device(const struct bladerf_devinfo *info,
                       libusb_context *context,
                       libusb_device *libusb_dev_in,
                       struct bladerf_lusb **dev_out)
{
    int status;
    struct bladerf_lusb *dev;

    *dev_out = NULL;

    dev = (struct bladerf_lusb *) calloc(1, sizeof(dev[0]));
    if (dev == NULL) {
        log_debug("Failed allocate handle for instance %d.\n",
                  info->instance);

        /* Report "no device" so we could try again with
         * another matching device */
        return BLADERF_ERR_NODEV;
    }

    dev->context = context;
    dev->dev = libusb_dev_in;

    status = libusb_open(libusb_dev_in, &dev->handle);
    if (status < 0) {
        log_debug("Failed to open device instance %d: %s\n",
                  info->instance, libusb_error_name(status));

        status = error_conv(status);
        goto error;
    }

    status = libusb_claim_interface(dev->handle, 0);
    if (status < 0) {
        log_debug("Failed to claim interface 0 for instance %d: %s\n",
                  info->instance, libusb_error_name(status));

        status = error_conv(status);
        goto error;
    }

error:
    if (status != 0) {
        if (dev->handle != NULL) {
            libusb_close(dev->handle);
        }

        free(dev);
    } else {
        *dev_out = dev;
    }

    return status;
}
Пример #2
0
static int lusb_control_transfer(void *driver,
                                 usb_target target_type, usb_request req_type,
                                 usb_direction dir, uint8_t request,
                                 uint16_t wvalue, uint16_t windex,
                                 void *buffer, uint32_t buffer_len,
                                 uint32_t timeout_ms)
{

    int status;
    struct bladerf_lusb *lusb = (struct bladerf_lusb *) driver;
    const uint8_t bm_req_type = bm_request_type(target_type, req_type, dir);

    status = libusb_control_transfer(lusb->handle,
                                     bm_req_type, request,
                                     wvalue, windex,
                                     buffer, buffer_len,
                                     timeout_ms);

    if (status >= 0 && (uint32_t)status == buffer_len) {
        status = 0;
    } else {
        log_debug("%s failed: status = %d\n", __FUNCTION__, status);
    }

    return error_conv(status);
}
Пример #3
0
static int lusb_change_setting(void *driver, uint8_t setting)
{
    struct bladerf_lusb *lusb = (struct bladerf_lusb *) driver;

    int status = libusb_set_interface_alt_setting(lusb->handle, 0, setting);

    return error_conv(status);
}
Пример #4
0
static int lusb_open(void **driver,
                     struct bladerf_devinfo *info_in,
                     struct bladerf_devinfo *info_out)
{
    int status;
    struct bladerf_lusb *lusb = NULL;
    libusb_context *context;

    /* Initialize libusb for device tree walking */
    status = libusb_init(&context);
    if (status) {
        log_error("Could not initialize libusb: %s\n",
                  libusb_error_name(status));
        return error_conv(status);
    }

    /* We can only print this out when log output is enabled, or else we'll
     * get snagged by -Werror=unused-but-set-variable */
#   ifdef LOGGING_ENABLED
    {
        char buf[64];
        get_libusb_version(buf, sizeof(buf));
        log_verbose("Using libusb version: %s\n", buf);
    }
#   endif

    status = find_and_open_device(context, info_in, &lusb, info_out);
    if (status != 0) {
        libusb_exit(context);

        if (status == BLADERF_ERR_NODEV) {
            log_debug("No devices available on the libusb backend.\n");
        } else {
            log_debug("Failed to open bladeRF on libusb backend: %s\n",
                    bladerf_strerror(status));
        }
    } else {
        assert(lusb != NULL);

        /* Cosmin and Marian from Null Team (null.ro) and YateBTS(.com) found
         * that it is possible to recover from "Issue #95: Not enough bandwidth
         * for altsetting" by performing a USB port reset prior to actually
         * trying to use the device.
         */
#       if ENABLE_USB_DEV_RESET_ON_OPEN
        if (bladerf_usb_reset_device_on_open) {
            status = reset_and_reopen(context, &lusb, info_out);
        }
#       endif

        if (status == 0) {
            *driver = (void *) lusb;
        }
    }

    return status;
}
Пример #5
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);
}
Пример #6
0
static int lusb_get_string_descriptor(void *driver, uint8_t index,
                                      void *buffer, uint32_t buffer_len)
{
    int status;
    struct bladerf_lusb *lusb = (struct bladerf_lusb *) driver;

    status = libusb_get_string_descriptor_ascii(lusb->handle, index,
                                                (unsigned char*)buffer,
                                                buffer_len);

    if (status > 0 && (uint32_t)status < buffer_len)  {
        status = 0;
    } else {
        status = BLADERF_ERR_UNEXPECTED;
    }

    return error_conv(status);
}
Пример #7
0
static int lusb_bulk_transfer(void *driver, uint8_t endpoint, void *buffer,
                              uint32_t buffer_len, uint32_t timeout_ms)
{
    int status;
    int n_transferred;
    struct bladerf_lusb *lusb = (struct bladerf_lusb *) driver;

    status = libusb_bulk_transfer(lusb->handle, endpoint, buffer, buffer_len,
                                  &n_transferred, timeout_ms);

    status = error_conv(status);
    if (status == 0 && ((uint32_t)n_transferred != buffer_len)) {
        log_debug("Short bulk transfer: requeted=%u, transferred=%u\n",
                  buffer_len, n_transferred);
        status = BLADERF_ERR_IO;
    }

    return status;
}
Пример #8
0
static int lusb_open_bootloader(void **driver, uint8_t bus, uint8_t addr)
{
    int status;
    struct libusb_device **dev_list = NULL;
    ssize_t dev_list_size, i;
    struct bladerf_lusb *lusb;

    *driver = NULL;

    lusb = calloc(1, sizeof(lusb[0]));
    if (lusb == NULL) {
        return BLADERF_ERR_MEM;
    }

    status = libusb_init(&lusb->context);
    if (status != 0) {
        log_debug("Failed to initialize libusb context: %s\n",
                  libusb_error_name(status));
        goto error;
    }

    dev_list_size = libusb_get_device_list(lusb->context, &dev_list);
    if (dev_list_size < 0) {
        log_debug("Failed to get device list: %s\n", libusb_error_name(status));
        status = (int) dev_list_size;
        goto error;
    }

    for (i = 0; i < dev_list_size; i++) {
        if (device_is_fx3_bootloader(dev_list[i]) &&
            bus_matches(bus, dev_list[i]) &&
            addr_matches(addr, dev_list[i])) {


            status = libusb_open(dev_list[i], &lusb->handle);
            if (status != 0) {
                log_debug("Failed to open device: %s\n",
                          libusb_error_name(status));
                goto error;
            } else {
                status = libusb_claim_interface(lusb->handle, 0);
                if (status < 0) {
                    log_debug("Failed to claim interface: %s\n",
                              libusb_error_name(status));

                    goto error;
                } else {
                    log_verbose("Opened bootloader at %u:%u\n",
                                libusb_get_bus_number(dev_list[i]),
                                libusb_get_device_address(dev_list[i]));
                    *driver = lusb;
                }
                break;
            }
        }
    }

error:
    if (dev_list != NULL) {
        libusb_free_device_list(dev_list, 1);
    }

    if (status != 0) {
        status = error_conv(status);
        lusb_close_bootloader(lusb);
    } else if (*driver == NULL) {
        status = BLADERF_ERR_NODEV;
        lusb_close_bootloader(lusb);
    }

    return status;
}
Пример #9
0
static int find_and_open_device(libusb_context *context,
                                const struct bladerf_devinfo *info_in,
                                struct bladerf_lusb **dev_out,
                                struct bladerf_devinfo *info_out)
{
    int status = BLADERF_ERR_NODEV;
    int i, n;
    ssize_t count;
    struct libusb_device **list;
    struct bladerf_devinfo curr_info;
    bool printed_access_warning = false;

    *dev_out = NULL;

    count = libusb_get_device_list(context, &list);
    if (count < 0) {
        if (count < INT_MIN) {
            /* Ensure we don't have a situation where we accidentally return 0
             * due to a narrowing conversion */
            return BLADERF_ERR_UNEXPECTED;
        } else {
            return error_conv((int) count);
        }
    }

    for (i = 0, n = 0; (i < count) && (*dev_out == NULL); i++) {
        if (device_is_bladerf(list[i])) {
            log_verbose("Found a bladeRF (idx=%d)\n", i);

            /* Open the USB device and get some information */
            status = get_devinfo(list[i], &curr_info);
            if (status < 0) {

                /* Give the user a helpful hint in case the have forgotten
                 * to update their udev rules */
                if (status == LIBUSB_ERROR_ACCESS && !printed_access_warning) {
                    printed_access_warning = true;
                    log_warning("Found a bladeRF via VID/PID, but could not "
                                "open it due to insufficient permissions.\n");
                } else {
                    log_debug("Could not open bladeRF device: %s\n",
                               libusb_error_name(status) );
                }

                status = BLADERF_ERR_NODEV;
                continue; /* Continue trying the next devices */
            } else {
                curr_info.instance = n++;
            }

            /* Check to see if this matches the info struct */
            if (bladerf_devinfo_matches(&curr_info, info_in)) {
                status = open_device(&curr_info, context, list[i], dev_out);
                if (status < 0) {
                    status = BLADERF_ERR_NODEV;
                    continue; /* Continue trying the next matching device */
                } else {
                    memcpy(info_out, &curr_info, sizeof(info_out[0]));
                }
            } else {
                status = BLADERF_ERR_NODEV;

                log_verbose("Devinfo doesn't match - skipping"
                        "(instance=%d, serial=%d, bus/addr=%d\n",
                        bladerf_instance_matches(&curr_info, info_in),
                        bladerf_serial_matches(&curr_info, info_in),
                        bladerf_bus_addr_matches(&curr_info, info_in));
            }
        }
    }

    if (status == 0) {
        /* Returning 0 indicates this function is providing a device */
        assert(*dev_out != NULL);
    }

    libusb_free_device_list(list, 1);
    return status;
}
Пример #10
0
static int lusb_stream(void *driver, struct bladerf_stream *stream,
                       bladerf_module module)
{
    size_t i;
    int status = 0;
    void *buffer;
    struct bladerf_metadata metadata;
    struct bladerf *dev = stream->dev;
    struct bladerf_lusb *lusb = (struct bladerf_lusb *) driver;
    struct lusb_stream_data *stream_data = stream->backend_data;
    struct timeval tv = { 0, LIBUSB_HANDLE_EVENTS_TIMEOUT_NSEC };

    /* Currently unused, so zero it out for a sanity check when debugging */
    memset(&metadata, 0, sizeof(metadata));

    MUTEX_LOCK(&stream->lock);

    /* Set up initial set of buffers */
    for (i = 0; i < stream_data->num_transfers; i++) {
        if (module == BLADERF_MODULE_TX) {
            buffer = stream->cb(dev,
                                stream,
                                &metadata,
                                NULL,
                                stream->samples_per_buffer,
                                stream->user_data);

            if (buffer == BLADERF_STREAM_SHUTDOWN) {
                /* If we have transfers in flight and the user prematurely
                 * cancels the stream, we'll start shutting down */
                if (stream_data->num_avail != stream_data->num_transfers) {
                    stream->state = STREAM_SHUTTING_DOWN;
                } else {
                    /* No transfers have been shipped out yet so we can
                     * simply enter our "done" state */
                    stream->state = STREAM_DONE;
                }

                /* In either of the above we don't want to attempt to
                 * get any more buffers from the user */
                break;
            }
        } else {
            buffer = stream->buffers[i];
        }

        if (buffer != BLADERF_STREAM_NO_DATA) {
            status = submit_transfer(stream, buffer);

            /* If we failed to submit any transfers, cancel everything in
             * flight.  We'll leave the stream in the running state so we can
             * have libusb fire off callbacks with the cancelled status*/
            if (status < 0) {
                stream->error_code = status;
                cancel_all_transfers(stream);
            }
        }
    }
    MUTEX_UNLOCK(&stream->lock);

    /* This loop is required so libusb can do callbacks and whatnot */
    while (stream->state != STREAM_DONE) {
        status = libusb_handle_events_timeout(lusb->context, &tv);

        if (status < 0 && status != LIBUSB_ERROR_INTERRUPTED) {
            log_warning("unexpected value from events processing: "
                        "%d: %s\n", status, libusb_error_name(status));
            status = error_conv(status);
        }
    }

    return status;
}
Пример #11
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);
}
Пример #12
0
static int lusb_open(void **driver,
                     struct bladerf_devinfo *info_in,
                     struct bladerf_devinfo *info_out)
{
    int status, i, n;
    int fx3_status;
    ssize_t count;
    struct bladerf_lusb *lusb = NULL;
    libusb_device **list = NULL;
    struct bladerf_devinfo thisinfo;

    libusb_context *context;

    /* Initialize libusb for device tree walking */
    status = libusb_init(&context);
    if (status) {
        log_error("Could not initialize libusb: %s\n",
                  libusb_error_name(status));
        status = error_conv(status);
        goto error;
    }

    /* We can only print this out when log output is enabled, or else we'll
     * get snagged by -Werror=unused-but-set-variable */
#   ifdef LOGGING_ENABLED
    {
        char buf[64];
        get_libusb_version(buf, sizeof(buf));
        log_verbose("Using libusb version: %s\n", buf);
    }
#   endif

    /* Iterate through all the USB devices */
    count = libusb_get_device_list(context, &list);
    for (i = 0, n = 0; i < count; i++) {
        if (device_is_bladerf(list[i])) {
            log_verbose("Found a bladeRF (based upon VID/PID)\n");

            /* Open the USB device and get some information */
            status = get_devinfo(list[i], &thisinfo);
            if(status < 0) {
                log_debug("Could not open bladeRF device: %s\n",
                          libusb_error_name(status) );
                status = error_conv(status);
                goto error;
            }
            thisinfo.instance = n++;

            /* Check to see if this matches the info struct */
            if (bladerf_devinfo_matches(&thisinfo, info_in)) {

                lusb = (struct bladerf_lusb *)malloc(sizeof(struct bladerf_lusb));
                if (lusb == NULL) {
                    log_debug("Skipping instance %d due to failed allocation\n",
                              thisinfo.instance);
                    lusb = NULL;
                    continue;
                }

                lusb->context = context;
                lusb->dev = list[i];

                status = libusb_open(list[i], &lusb->handle);
                if (status < 0) {
                    status = error_conv(status);
                    goto error;
                }

                status = libusb_claim_interface(lusb->handle, 0);
                if(status < 0) {
                    log_debug("Could not claim interface: %s\n",
                              libusb_error_name(status));
                    status = error_conv(status);
                    goto error;
                }

                memcpy(info_out, &thisinfo, sizeof(struct bladerf_devinfo));
                *driver = lusb;
                break;

            } else {
                log_verbose("Devinfo doesn't match - skipping"
                            "(instance=%d, serial=%d, bus/addr=%d\n",
                            bladerf_instance_matches(&thisinfo, info_in),
                            bladerf_serial_matches(&thisinfo, info_in),
                            bladerf_bus_addr_matches(&thisinfo, info_in));
            }
        }

        if (device_is_fx3_bootloader(list[i])) {
            fx3_status = get_devinfo(list[i], &thisinfo);
            if (fx3_status != 0) {
                log_debug("Could not open FX3 bootloader device: %s\n",
                          libusb_error_name(fx3_status));
                continue;
            }

            log_info("Found FX3 bootloader device on bus=%d addr=%d. "
                     "This may be a bladeRF.\n",
                     thisinfo.usb_bus, thisinfo.usb_addr);

            log_info("Use bladeRF-cli command \"recover %d %d "
                     "<FX3 firmware>\" to boot the bladeRF firmware.\n",
                     thisinfo.usb_bus, thisinfo.usb_addr);
        }
    }


error:
    if (list) {
        libusb_free_device_list(list, 1);
    }

    if (lusb == NULL) {
        log_debug("No devices available on the libusb backend.\n");
        status = BLADERF_ERR_NODEV;
    }

    if (status != 0) {
        if (lusb != NULL) {
            if (lusb->handle) {
                libusb_close(lusb->handle);
            }

            free(lusb);
        }

        libusb_exit(context);
    }
    return status;
}