summaryrefslogtreecommitdiff
path: root/Radio/HW/BladeRF/src/backend/usb/usb.c
diff options
context:
space:
mode:
Diffstat (limited to 'Radio/HW/BladeRF/src/backend/usb/usb.c')
-rw-r--r--Radio/HW/BladeRF/src/backend/usb/usb.c1430
1 files changed, 1430 insertions, 0 deletions
diff --git a/Radio/HW/BladeRF/src/backend/usb/usb.c b/Radio/HW/BladeRF/src/backend/usb/usb.c
new file mode 100644
index 0000000..fba2c33
--- /dev/null
+++ b/Radio/HW/BladeRF/src/backend/usb/usb.c
@@ -0,0 +1,1430 @@
+/*
+ * This file is part of the bladeRF project:
+ * http://www.github.com/nuand/bladeRF
+ *
+ * Copyright (C) 2014-2017 Nuand LLC
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <string.h>
+#include <inttypes.h>
+
+#include "rel_assert.h"
+#include "log.h"
+#include "minmax.h"
+#include "conversions.h"
+#include "usb.h"
+
+#include "board/board.h"
+#include "backend/backend.h"
+#include "backend/backend_config.h"
+#include "backend/usb/usb.h"
+#include "driver/fx3_fw.h"
+#include "streaming/async.h"
+#include "helpers/version.h"
+
+#include "bladeRF.h"
+#include "nios_pkt_formats.h"
+#include "nios_legacy_access.h"
+#include "nios_access.h"
+
+#if ENABLE_USB_DEV_RESET_ON_OPEN
+bool bladerf_usb_reset_device_on_open = true;
+#endif
+
+static const struct usb_driver *usb_driver_list[] = BLADERF_USB_BACKEND_LIST;
+
+/* FW declaration of fn table declared at the end of this file */
+const struct backend_fns backend_fns_usb_legacy;
+
+/* Vendor command wrapper to gets a 32-bit integer and supplies a wIndex */
+static inline int vendor_cmd_int_windex(struct bladerf *dev, uint8_t cmd,
+ uint16_t windex, int32_t *val)
+{
+ struct bladerf_usb *usb = dev->backend_data;
+
+ return usb->fn->control_transfer(usb->driver,
+ USB_TARGET_DEVICE,
+ USB_REQUEST_VENDOR,
+ USB_DIR_DEVICE_TO_HOST,
+ cmd, 0, windex,
+ val, sizeof(uint32_t),
+ CTRL_TIMEOUT_MS);
+}
+
+/* Vendor command wrapper to get a 32-bit integer and supplies wValue */
+static inline int vendor_cmd_int_wvalue(struct bladerf *dev, uint8_t cmd,
+ uint16_t wvalue, int32_t *val)
+{
+ struct bladerf_usb *usb = dev->backend_data;
+
+ return usb->fn->control_transfer(usb->driver,
+ USB_TARGET_DEVICE,
+ USB_REQUEST_VENDOR,
+ USB_DIR_DEVICE_TO_HOST,
+ cmd, wvalue, 0,
+ val, sizeof(uint32_t),
+ CTRL_TIMEOUT_MS);
+}
+
+
+/* Vendor command that gets/sets a 32-bit integer value */
+static inline int vendor_cmd_int(struct bladerf *dev, uint8_t cmd,
+ usb_direction dir, int32_t *val)
+{
+ struct bladerf_usb *usb = dev->backend_data;
+
+ return usb->fn->control_transfer(usb->driver,
+ USB_TARGET_DEVICE,
+ USB_REQUEST_VENDOR,
+ dir, cmd, 0, 0,
+ val, sizeof(int32_t),
+ CTRL_TIMEOUT_MS);
+}
+
+static inline int change_setting(struct bladerf *dev, uint8_t setting)
+{
+ int status;
+ struct bladerf_usb *usb = dev->backend_data;
+
+ log_verbose("Changing to USB alt setting %u\n", setting);
+
+ status = usb->fn->change_setting(usb->driver, setting);
+ if (status != 0) {
+ log_debug("Failed to change setting: %s\n", bladerf_strerror(status));
+ }
+
+ return status;
+}
+
+static int usb_is_fpga_configured(struct bladerf *dev)
+{
+ int result = -1;
+ int status;
+
+ /* This environment variable provides a means to force libbladeRF to not
+ * attempt to access the FPGA.
+ *
+ * This provides a workaround for the situation where a user did not remove
+ * an FPGA in SPI flash prior to flashing new firmware and updating
+ * libbladeRF. Specifically, this has proven to be a problem with pre-v0.0.1
+ * FPGA images, as they do not provide version readback functionality.
+ */
+ if (getenv("BLADERF_FORCE_NO_FPGA_PRESENT")) {
+ log_debug("Reporting no FPGA present - "
+ "BLADERF_FORCE_NO_FPGA_PRESENT is set.\n");
+ return 0;
+ }
+
+ status = vendor_cmd_int(dev, BLADE_USB_CMD_QUERY_FPGA_STATUS,
+ USB_DIR_DEVICE_TO_HOST, &result);
+
+ if (status < 0) {
+ return status;
+ } else if (result == 0 || result == 1) {
+ return result;
+ } else {
+ log_debug("Unexpected result from FPGA status query: %d\n", result);
+ return BLADERF_ERR_UNEXPECTED;
+ }
+}
+
+static int usb_set_fpga_protocol(struct bladerf *dev, backend_fpga_protocol fpga_protocol)
+{
+ if (fpga_protocol == BACKEND_FPGA_PROTOCOL_NIOSII_LEGACY) {
+ dev->backend = &backend_fns_usb_legacy;
+ } else if (fpga_protocol == BACKEND_FPGA_PROTOCOL_NIOSII) {
+ dev->backend = &backend_fns_usb;
+ } else {
+ log_error("Unknown FPGA protocol: %d\n", fpga_protocol);
+ return BLADERF_ERR_INVAL;
+ }
+
+ return 0;
+}
+
+static bladerf_fpga_source usb_get_fpga_source(struct bladerf *dev)
+{
+ int result = -1;
+ int status;
+
+ status = vendor_cmd_int(dev, BLADE_USB_CMD_QUERY_FPGA_SOURCE,
+ USB_DIR_DEVICE_TO_HOST, &result);
+
+ if (status < 0) {
+ log_debug("%s: vendor_cmd_int returned %s\n", __FUNCTION__,
+ bladerf_strerror(status));
+ return BLADERF_FPGA_SOURCE_UNKNOWN;
+ } else if (0 == result || 1 == result || 2 == result) {
+ return (bladerf_fpga_source)result;
+ } else {
+ log_debug("Unexpected result from FPGA source query: %d\n", result);
+ return BLADERF_FPGA_SOURCE_UNKNOWN;
+ }
+}
+
+/* After performing a flash operation, switch back to either RF_LINK or the
+ * FPGA loader.
+ */
+static int restore_post_flash_setting(struct bladerf *dev)
+{
+ int fpga_loaded = usb_is_fpga_configured(dev);
+ int status;
+
+ if (fpga_loaded < 0) {
+ status = fpga_loaded;
+ log_debug("Failed to determine if FPGA is loaded (%d)\n", fpga_loaded);
+ } else if (fpga_loaded) {
+ status = change_setting(dev, USB_IF_RF_LINK);
+ } else {
+ status = change_setting(dev, USB_IF_CONFIG);
+ }
+
+ if (status < 0) {
+ log_debug("Failed to restore alt setting: %s\n",
+ bladerf_strerror(status));
+ }
+ return status;
+}
+
+static bool usb_matches(bladerf_backend backend)
+{
+ return backend == BLADERF_BACKEND_ANY ||
+ backend == BLADERF_BACKEND_LINUX ||
+ backend == BLADERF_BACKEND_LIBUSB ||
+ backend == BLADERF_BACKEND_CYPRESS;
+}
+
+static int usb_probe(backend_probe_target probe_target,
+ struct bladerf_devinfo_list *info_list)
+{
+ int status;
+ size_t i;
+
+ for (i = status = 0; i < ARRAY_SIZE(usb_driver_list); i++) {
+ status = usb_driver_list[i]->fn->probe(probe_target, info_list);
+ }
+
+ return status;
+}
+
+static void usb_close(struct bladerf *dev)
+{
+ int status;
+ struct bladerf_usb *usb = dev->backend_data;
+
+ if (usb != NULL) {
+ /* It seems we need to switch back to our NULL interface before closing,
+ * or else our device doesn't close upon exit in OSX and then fails to
+ * re-open cleanly */
+ status = usb->fn->change_setting(usb->driver, USB_IF_NULL);
+ if (status != 0) {
+ log_error("Failed to switch to NULL interface: %s\n",
+ bladerf_strerror(status));
+ }
+
+ usb->fn->close(usb->driver);
+ free(usb);
+ dev->backend_data = NULL;
+ }
+}
+
+static int usb_is_fw_ready(struct bladerf *dev)
+{
+ int status;
+ int result;
+
+ status = vendor_cmd_int(dev, BLADE_USB_CMD_QUERY_DEVICE_READY,
+ USB_DIR_DEVICE_TO_HOST, &result);
+ if (status < 0) {
+ return status;
+ } else if (result == 0 || result == 1) {
+ return result;
+ } else {
+ log_debug("Unexpected result from firmware status query: %d\n", result);
+ return BLADERF_ERR_UNEXPECTED;
+ }
+}
+
+static int usb_get_handle(struct bladerf *dev,
+ void **handle)
+{
+ struct bladerf_usb *usb = dev->backend_data;
+ int status;
+
+ status = usb->fn->get_handle(usb->driver, handle);
+
+ return status;
+}
+
+static int usb_get_fw_version(struct bladerf *dev,
+ struct bladerf_version *version)
+{
+ struct bladerf_usb *usb = dev->backend_data;
+ int status;
+
+ status = usb->fn->get_string_descriptor(usb->driver,
+ BLADE_USB_STR_INDEX_FW_VER,
+ (unsigned char *)version->describe,
+ BLADERF_VERSION_STR_MAX);
+ if (status == 0) {
+ status = str2version(version->describe, version);
+ } else {
+ log_warning("Failed to retrieve firmware version. This may be due "
+ "to an old firmware version that does not support "
+ "this request. A firmware update via the bootloader is "
+ "required.\n\n");
+ status = BLADERF_ERR_UPDATE_FW;
+ }
+
+ return status;
+}
+
+static int usb_get_fpga_version(struct bladerf *dev,
+ struct bladerf_version *version)
+{
+ int status;
+
+ status = change_setting(dev, USB_IF_RF_LINK);
+ if (status < 0) {
+ return status;
+ }
+
+ /* Read and store FPGA version info. This is only possible after
+ * we've entered RF link mode.
+ *
+ * The legacy mode is used here since we can't yet determine if
+ * the FPGA is capable of using the newer packet formats. */
+ return nios_legacy_get_fpga_version(dev, version);
+}
+
+static int usb_open(struct bladerf *dev, struct bladerf_devinfo *info)
+{
+ int status;
+ size_t i;
+ struct bladerf_usb *usb;
+
+ usb = malloc(sizeof(*usb));
+ if (usb == NULL) {
+ return BLADERF_ERR_MEM;
+ }
+
+ /* Try each matching usb driver */
+ for (i = 0; i < ARRAY_SIZE(usb_driver_list); i++) {
+ if (info->backend == BLADERF_BACKEND_ANY
+ || usb_driver_list[i]->id == info->backend) {
+ usb->fn = usb_driver_list[i]->fn;
+ status = usb->fn->open(&usb->driver, info, &dev->ident);
+ if (status == 0) {
+ break;
+ } else if (status == BLADERF_ERR_NODEV) {
+ continue;
+ } else {
+ free(usb);
+ return status;
+ }
+ }
+ }
+
+ /* If no usb driver was found */
+ if (i == ARRAY_SIZE(usb_driver_list)) {
+ free(usb);
+ return BLADERF_ERR_NODEV;
+ }
+
+ /* Default to legacy-mode access until we determine the FPGA is
+ * capable of handling newer request formats */
+ dev->backend = &backend_fns_usb_legacy;
+ dev->backend_data = usb;
+
+ /* Just out of paranoia, put the device into a known state */
+ status = change_setting(dev, USB_IF_NULL);
+ if (status < 0) {
+ log_debug("Failed to switch to USB_IF_NULL\n");
+ goto error;
+ }
+
+error:
+ if (status != 0) {
+ usb_close(dev);
+ }
+
+ return status;
+}
+
+static int usb_get_vid_pid(struct bladerf *dev, uint16_t *vid, uint16_t *pid)
+{
+ struct bladerf_usb *usb = dev->backend_data;
+
+ return usb->fn->get_vid_pid(usb->driver, vid, pid);
+}
+
+static int usb_get_flash_id(struct bladerf *dev, uint8_t *mid, uint8_t *did)
+{
+ int status;
+ int result;
+
+ status = vendor_cmd_int(dev, BLADE_USB_CMD_QUERY_FLASH_ID,
+ USB_DIR_DEVICE_TO_HOST, &result);
+ if (status < 0) {
+ log_debug("Could not read flash manufacturer ID and/or device ID. %s.\n",
+ bladerf_strerror(status));
+ } else {
+ *did = result & 0xFF;
+ *mid = (result >> 8) & 0xFF;
+ }
+ return status;
+}
+
+static int begin_fpga_programming(struct bladerf *dev)
+{
+ int result;
+ int status = vendor_cmd_int(dev, BLADE_USB_CMD_BEGIN_PROG,
+ USB_DIR_DEVICE_TO_HOST, &result);
+
+ if (status != 0) {
+ return status;
+ } else if (result != 0) {
+ log_debug("Startg fpga programming, result = %d\n", result);
+ return BLADERF_ERR_UNEXPECTED;
+ } else {
+ return 0;
+ }
+}
+
+static int usb_load_fpga(struct bladerf *dev, const uint8_t *image, size_t image_size)
+{
+ struct bladerf_usb *usb = dev->backend_data;
+
+ unsigned int wait_count;
+ const unsigned int timeout_ms = (3 * CTRL_TIMEOUT_MS);
+ int status;
+
+ /* Switch to the FPGA configuration interface */
+ status = change_setting(dev, USB_IF_CONFIG);
+ if(status < 0) {
+ log_debug("Failed to switch to FPGA config setting: %s\n",
+ bladerf_strerror(status));
+ return status;
+ }
+
+ /* Begin programming */
+ status = begin_fpga_programming(dev);
+ if (status < 0) {
+ log_debug("Failed to initiate FPGA programming: %s\n",
+ bladerf_strerror(status));
+ return status;
+ }
+
+ /* Send the file down */
+ assert(image_size <= UINT32_MAX);
+ status = usb->fn->bulk_transfer(usb->driver, PERIPHERAL_EP_OUT,
+ (void *)image,
+ (uint32_t)image_size,
+ timeout_ms);
+ if (status < 0) {
+ log_debug("Failed to write FPGA bitstream to FPGA: %s\n",
+ bladerf_strerror(status));
+ return status;
+ }
+
+ /* Poll FPGA status to determine if programming was a success */
+ wait_count = 10;
+ status = 0;
+
+ while (wait_count > 0 && status == 0) {
+ status = usb_is_fpga_configured(dev);
+ if (status == 1) {
+ break;
+ }
+
+ usleep(200000);
+ wait_count--;
+ }
+
+ /* Failed to determine if FPGA is loaded */
+ if (status < 0) {
+ log_debug("Failed to determine if FPGA is loaded: %s\n",
+ bladerf_strerror(status));
+ return status;
+ } else if (wait_count == 0 && status != 0) {
+ log_debug("Timeout while waiting for FPGA configuration status\n");
+ return BLADERF_ERR_TIMEOUT;
+ }
+
+ return 0;
+}
+
+static inline int perform_erase(struct bladerf *dev, uint16_t block)
+{
+ int status, erase_ret;
+ struct bladerf_usb *usb = dev->backend_data;
+
+ status = usb->fn->control_transfer(usb->driver,
+ USB_TARGET_DEVICE,
+ USB_REQUEST_VENDOR,
+ USB_DIR_DEVICE_TO_HOST,
+ BLADE_USB_CMD_FLASH_ERASE,
+ 0, block,
+ &erase_ret, sizeof(erase_ret),
+ CTRL_TIMEOUT_MS);
+
+
+ return status;
+}
+
+static int usb_erase_flash_blocks(struct bladerf *dev,
+ uint32_t eb,
+ uint16_t count)
+{
+ int status, restore_status;
+ uint16_t i;
+
+ status = change_setting(dev, USB_IF_SPI_FLASH);
+ if (status != 0) {
+ return status;
+ }
+
+ log_info("Erasing %u block%s starting at block %u\n", count,
+ 1 == count ? "" : "s", eb);
+
+ for (i = 0; i < count; i++) {
+ log_info("Erasing block %u (%u%%)...%c", eb + i,
+ (i + 1) == count ? 100 : 100 * i / count,
+ (i + 1) == count ? '\n' : '\r');
+
+ status = perform_erase(dev, eb + i);
+ if (status != 0) {
+ log_debug("Failed to erase block %u: %s\n", eb + i,
+ bladerf_strerror(status));
+ goto error;
+ }
+ }
+
+ log_info("Done erasing %u block%s\n", count, 1 == count ? "" : "s");
+
+error:
+ restore_status = restore_post_flash_setting(dev);
+ return status != 0 ? status : restore_status;
+}
+
+static inline int read_page(struct bladerf *dev, uint8_t read_operation,
+ uint16_t page, uint8_t *buf)
+{
+ struct bladerf_usb *usb = dev->backend_data;
+ bladerf_dev_speed usb_speed;
+ int status;
+ int32_t op_status;
+ uint16_t read_size;
+ uint16_t offset;
+ uint8_t request;
+
+ if (usb->fn->get_speed(usb->driver, &usb_speed) != 0) {
+ log_debug("Error getting USB speed in %s\n", __FUNCTION__);
+ return BLADERF_ERR_UNEXPECTED;
+ }
+
+ if (usb_speed == BLADERF_DEVICE_SPEED_SUPER) {
+ read_size = dev->flash_arch->psize_bytes;
+ } else if (usb_speed == BLADERF_DEVICE_SPEED_HIGH) {
+ read_size = 64;
+ } else {
+ log_debug("Encountered unknown USB speed in %s\n", __FUNCTION__);
+ return BLADERF_ERR_UNEXPECTED;
+ }
+
+ if (read_operation == BLADE_USB_CMD_FLASH_READ ||
+ read_operation == BLADE_USB_CMD_READ_OTP) {
+
+ status = vendor_cmd_int_windex(dev, read_operation, page, &op_status);
+ if (status != 0) {
+ return status;
+ } else if (op_status != 0) {
+ log_error("Firmware page read (op=%d) failed at page %u: %d\n",
+ read_operation, page, op_status);
+ return BLADERF_ERR_UNEXPECTED;
+ }
+
+ /* Both of these operations require a read from the FW's page buffer */
+ request = BLADE_USB_CMD_READ_PAGE_BUFFER;
+
+ } else if (read_operation == BLADE_USB_CMD_READ_CAL_CACHE) {
+ request = read_operation;
+ } else {
+ assert(!"Bug - invalid read_operation value");
+ return BLADERF_ERR_UNEXPECTED;
+ }
+
+ /* Retrieve data from the firmware page buffer */
+ for (offset = 0; offset < dev->flash_arch->psize_bytes; offset += read_size) {
+ status = usb->fn->control_transfer(usb->driver,
+ USB_TARGET_DEVICE,
+ USB_REQUEST_VENDOR,
+ USB_DIR_DEVICE_TO_HOST,
+ request,
+ 0,
+ offset, /* in bytes */
+ buf + offset,
+ read_size,
+ CTRL_TIMEOUT_MS);
+
+ if(status < 0) {
+ log_debug("Failed to read page buffer at offset 0x%02x: %s\n",
+ offset, bladerf_strerror(status));
+ return status;
+ }
+ }
+
+ return 0;
+}
+
+static int usb_read_flash_pages(struct bladerf *dev,
+ uint8_t *buf,
+ uint32_t page_u32,
+ uint32_t count_u32)
+{
+ int status;
+ size_t n_read;
+ uint16_t i;
+
+ /* 16-bit control transfer fields are used for these.
+ * The current bladeRF build only has a 4MiB flash, anyway. */
+ const uint16_t page = (uint16_t)page_u32;
+ const uint16_t count = (uint16_t)count_u32;
+
+ assert(page == page_u32);
+ assert(count == count_u32);
+
+ status = change_setting(dev, USB_IF_SPI_FLASH);
+ if (status != 0) {
+ return status;
+ }
+
+ log_info("Reading %u page%s starting at page %u\n", count,
+ 1 == count ? "" : "s", page);
+
+ for (n_read = i = 0; i < count; i++) {
+ log_info("Reading page %u (%u%%)...%c", page + i,
+ (i + 1) == count ? 100 : 100 * i / count,
+ (i + 1) == count ? '\n' : '\r');
+
+ status =
+ read_page(dev, BLADE_USB_CMD_FLASH_READ, page + i, buf + n_read);
+ if (status != 0) {
+ goto error;
+ }
+
+ n_read += dev->flash_arch->psize_bytes;
+ }
+
+ log_info("Done reading %u page%s\n", count, 1 == count ? "" : "s");
+
+error:
+ status = restore_post_flash_setting(dev);
+ return status;
+}
+
+static int write_page(struct bladerf *dev, uint8_t write_operation,
+ uint16_t page, const uint8_t *buf)
+{
+ int status;
+ int32_t commit_status;
+ uint16_t offset;
+ uint16_t write_size;
+ struct bladerf_usb *usb = dev->backend_data;
+ bladerf_dev_speed usb_speed;
+
+ if (usb->fn->get_speed(usb->driver, &usb_speed) != 0) {
+ log_debug("Error getting USB speed in %s\n", __FUNCTION__);
+ return BLADERF_ERR_UNEXPECTED;
+ }
+
+ if (usb_speed == BLADERF_DEVICE_SPEED_SUPER) {
+ write_size = dev->flash_arch->psize_bytes;
+ } else if (usb_speed == BLADERF_DEVICE_SPEED_HIGH) {
+ write_size = 64;
+ } else {
+ assert(!"BUG - unexpected device speed");
+ return BLADERF_ERR_UNEXPECTED;
+ }
+
+ /* Write the data to the firmware's page buffer.
+ * Casting away the buffer's const-ness here is gross, but this buffer
+ * will not be written to on an out transfer. */
+ for (offset = 0; offset < dev->flash_arch->psize_bytes; offset += write_size) {
+ status = usb->fn->control_transfer(usb->driver,
+ USB_TARGET_DEVICE,
+ USB_REQUEST_VENDOR,
+ USB_DIR_HOST_TO_DEVICE,
+ BLADE_USB_CMD_WRITE_PAGE_BUFFER,
+ 0,
+ offset,
+ (uint8_t*)&buf[offset],
+ write_size,
+ CTRL_TIMEOUT_MS);
+
+ if(status < 0) {
+ log_error("Failed to write page buffer at offset 0x%02x "
+ "for page %u: %s\n",
+ offset, page, bladerf_strerror(status));
+ return status;
+ }
+ }
+
+ /* Commit the page to flash */
+ status = vendor_cmd_int_windex(dev, write_operation, page, &commit_status);
+
+ if (status != 0) {
+ log_error("Failed to commit page %u: %s\n", page,
+ bladerf_strerror(status));
+ return status;
+
+ } else if (commit_status != 0) {
+ log_error("Failed to commit page %u, FW returned %d\n", page,
+ commit_status);
+
+ return BLADERF_ERR_UNEXPECTED;
+ }
+
+ return 0;
+}
+
+static int usb_write_flash_pages(struct bladerf *dev,
+ const uint8_t *buf,
+ uint32_t page_u32,
+ uint32_t count_u32)
+
+{
+ int status, restore_status;
+ uint16_t i;
+ size_t n_written;
+
+ /* 16-bit control transfer fields are used for these.
+ * The current bladeRF build only has a 4MiB flash, anyway. */
+ const uint16_t page = (uint16_t)page_u32;
+ const uint16_t count = (uint16_t)count_u32;
+
+ assert(page == page_u32);
+ assert(count == count_u32);
+
+ status = change_setting(dev, USB_IF_SPI_FLASH);
+ if (status != 0) {
+ return status;
+ }
+
+ log_info("Writing %u page%s starting at page %u\n", count,
+ 1 == count ? "" : "s", page);
+
+ n_written = 0;
+ for (i = 0; i < count; i++) {
+ log_info("Writing page %u (%u%%)...%c", page + i,
+ (i + 1) == count ? 100 : 100 * i / count,
+ (i + 1) == count ? '\n' : '\r');
+
+ status = write_page(dev, BLADE_USB_CMD_FLASH_WRITE, page + i, buf + n_written);
+ if (status) {
+ goto error;
+ }
+
+ n_written += dev->flash_arch->psize_bytes;
+ }
+ log_info("Done writing %u page%s\n", count, 1 == count ? "" : "s");
+
+error:
+ restore_status = restore_post_flash_setting(dev);
+ if (status != 0) {
+ return status;
+ } else if (restore_status != 0) {
+ return restore_status;
+ } else {
+ return 0;
+ }
+}
+
+static int usb_device_reset(struct bladerf *dev)
+{
+ struct bladerf_usb *usb = dev->backend_data;
+
+ return usb->fn->control_transfer(usb->driver, USB_TARGET_DEVICE,
+ USB_REQUEST_VENDOR,
+ USB_DIR_HOST_TO_DEVICE,
+ BLADE_USB_CMD_RESET,
+ 0, 0, 0, 0, CTRL_TIMEOUT_MS);
+
+}
+
+static int usb_jump_to_bootloader(struct bladerf *dev)
+{
+ struct bladerf_usb *usb = dev->backend_data;
+
+ return usb->fn->control_transfer(usb->driver, USB_TARGET_DEVICE,
+ USB_REQUEST_VENDOR,
+ USB_DIR_HOST_TO_DEVICE,
+ BLADE_USB_CMD_JUMP_TO_BOOTLOADER,
+ 0, 0, 0, 0, CTRL_TIMEOUT_MS);
+}
+
+static int usb_get_cal(struct bladerf *dev, char *cal)
+{
+ const uint16_t dummy_page = 0;
+ int status, restore_status;
+
+ assert(CAL_BUFFER_SIZE == dev->flash_arch->psize_bytes);
+
+ status = change_setting(dev, USB_IF_SPI_FLASH);
+ if (status) {
+ return status;
+ }
+
+ status = read_page(dev, BLADE_USB_CMD_READ_CAL_CACHE,
+ dummy_page, (uint8_t*)cal);
+
+ restore_status = restore_post_flash_setting(dev);
+ return status == 0 ? restore_status : status;
+}
+
+static int usb_get_otp(struct bladerf *dev, char *otp)
+{
+ int status, restore_status;
+ const uint16_t dummy_page = 0;
+
+ status = change_setting(dev, USB_IF_SPI_FLASH);
+ if (status) {
+ return status;
+ }
+
+ status = read_page(dev, BLADE_USB_CMD_READ_OTP, dummy_page, (uint8_t*)otp);
+ restore_status = restore_post_flash_setting(dev);
+ return status == 0 ? restore_status : status;
+}
+
+static int usb_write_otp(struct bladerf *dev, char *otp)
+{
+ int status, restore_status;
+ const uint16_t dummy_page = 0;
+
+ status = change_setting(dev, USB_IF_SPI_FLASH);
+ if (status) {
+ return status;
+ }
+
+ status = write_page(dev, BLADE_USB_CMD_WRITE_OTP, dummy_page, (uint8_t*)otp);
+ restore_status = restore_post_flash_setting(dev);
+ return status == 0 ? restore_status : status;
+}
+
+static int usb_lock_otp(struct bladerf *dev)
+{
+ int status, restore_status, commit_status;
+
+ status = change_setting(dev, USB_IF_SPI_FLASH);
+ if (status) {
+ return status;
+ }
+
+ status = vendor_cmd_int_windex(dev, BLADE_USB_CMD_LOCK_OTP,
+ 0, &commit_status);
+
+ if (commit_status != 0) {
+ log_error("Failed to lock OTP, FW returned %d\n", commit_status);
+ if (status == 0)
+ status = commit_status;
+ }
+
+ restore_status = restore_post_flash_setting(dev);
+ return status == 0 ? restore_status : status;
+}
+
+static int usb_get_device_speed(struct bladerf *dev, bladerf_dev_speed *speed)
+{
+ struct bladerf_usb *usb = dev->backend_data;
+
+ return usb->fn->get_speed(usb->driver, speed);
+}
+
+static int usb_set_firmware_loopback(struct bladerf *dev, bool enable) {
+ int result;
+ int status;
+
+ status = vendor_cmd_int_wvalue(dev, BLADE_USB_CMD_SET_LOOPBACK,
+ enable, &result);
+ if (status != 0) {
+ return status;
+ }
+
+
+ status = change_setting(dev, USB_IF_NULL);
+ if (status == 0) {
+ status = change_setting(dev, USB_IF_RF_LINK);
+ }
+
+ return status;
+}
+
+static int usb_get_firmware_loopback(struct bladerf *dev, bool *is_enabled)
+{
+ int status, result;
+
+ status = vendor_cmd_int(dev, BLADE_USB_CMD_GET_LOOPBACK,
+ USB_DIR_DEVICE_TO_HOST, &result);
+
+ if (status == 0) {
+ *is_enabled = (result != 0);
+ }
+
+ return status;
+}
+
+static int usb_enable_module(struct bladerf *dev, bladerf_direction dir, bool enable)
+{
+ int status;
+ int32_t fx3_ret = -1;
+ const uint16_t val = enable ? 1 : 0;
+ const uint8_t cmd = (dir == BLADERF_RX) ?
+ BLADE_USB_CMD_RF_RX : BLADE_USB_CMD_RF_TX;
+
+ status = vendor_cmd_int_wvalue(dev, cmd, val, &fx3_ret);
+ if (status != 0) {
+ log_debug("Could not enable RF %s (%d): %s\n",
+ (dir == BLADERF_RX) ? "RX" : "TX",
+ status, bladerf_strerror(status));
+
+ } else if (fx3_ret != 0) {
+ log_warning("FX3 reported error=0x%x when %s RF %s\n",
+ fx3_ret,
+ enable ? "enabling" : "disabling",
+ (dir == BLADERF_RX) ? "RX" : "TX");
+
+ /* FIXME: Work around what seems to be a harmless failure.
+ * It appears that in firmware or in the lib, we may be
+ * attempting to disable an already disabled channel, or
+ * enabling an already enabled channel.
+ *
+ * Further investigation required
+ *
+ * 0x44 corresponds to CY_U3P_ERROR_ALREADY_STARTED
+ */
+ if (fx3_ret != 0x44) {
+ status = BLADERF_ERR_UNEXPECTED;
+ }
+ }
+
+ return status;
+}
+
+static int usb_init_stream(struct bladerf_stream *stream, size_t num_transfers)
+{
+ struct bladerf_usb *usb = stream->dev->backend_data;
+ return usb->fn->init_stream(usb->driver, stream, num_transfers);
+}
+
+static int usb_stream(struct bladerf_stream *stream, bladerf_channel_layout layout)
+{
+ struct bladerf_usb *usb = stream->dev->backend_data;
+ return usb->fn->stream(usb->driver, stream, layout);
+}
+
+int usb_submit_stream_buffer(struct bladerf_stream *stream, void *buffer,
+ size_t *length, unsigned int timeout_ms, bool nonblock)
+{
+ struct bladerf_usb *usb = stream->dev->backend_data;
+ return usb->fn->submit_stream_buffer(usb->driver, stream, buffer,
+ length, timeout_ms, nonblock);
+}
+
+static void usb_deinit_stream(struct bladerf_stream *stream)
+{
+ struct bladerf_usb *usb = stream->dev->backend_data;
+ usb->fn->deinit_stream(usb->driver, stream);
+}
+
+/*
+ * Information about the boot image format and boot over USB can be found in
+ * Cypress AN76405: EZ-USB (R) FX3 (TM) Boot Options:
+ * http://www.cypress.com/?docID=49862
+ *
+ * There's a request (bRequset = 0xc0) for the bootloader revision.
+ * However, there doesn't appear to be any documented reason to check this and
+ * behave differently depending upon the returned value.
+ */
+
+/* Command fields for FX3 firmware upload vendor requests */
+#define FX3_BOOTLOADER_LOAD_BREQUEST 0xa0
+#define FX3_BOOTLOADER_ADDR_WVALUE(addr) (HOST_TO_LE16(addr & 0xffff))
+#define FX3_BOOTLOADER_ADDR_WINDEX(addr) (HOST_TO_LE16(((addr >> 16) & 0xffff)))
+#define FX3_BOOTLOADER_MAX_LOAD_LEN 4096
+
+static int write_and_verify_fw_chunk(struct bladerf_usb *usb, uint32_t addr,
+ uint8_t *data, uint32_t len,
+ uint8_t *readback_buf) {
+
+ int status;
+ log_verbose("Writing %u bytes to bootloader @ 0x%08x\n", len, addr);
+ status = usb->fn->control_transfer(usb->driver,
+ USB_TARGET_DEVICE,
+ USB_REQUEST_VENDOR,
+ USB_DIR_HOST_TO_DEVICE,
+ FX3_BOOTLOADER_LOAD_BREQUEST,
+ FX3_BOOTLOADER_ADDR_WVALUE(addr),
+ FX3_BOOTLOADER_ADDR_WINDEX(addr),
+ data,
+ len,
+ CTRL_TIMEOUT_MS);
+
+ if (status != 0) {
+ log_debug("Failed to write FW chunk (%d)\n", status);
+ return status;
+ }
+
+ log_verbose("Reading back %u bytes from bootloader @ 0x%08x\n", len, addr);
+ status = usb->fn->control_transfer(usb->driver,
+ USB_TARGET_DEVICE,
+ USB_REQUEST_VENDOR,
+ USB_DIR_DEVICE_TO_HOST,
+ FX3_BOOTLOADER_LOAD_BREQUEST,
+ FX3_BOOTLOADER_ADDR_WVALUE(addr),
+ FX3_BOOTLOADER_ADDR_WINDEX(addr),
+ readback_buf,
+ len,
+ CTRL_TIMEOUT_MS);
+
+ if (status != 0) {
+ log_debug("Failed to read back FW chunk (%d)\n", status);
+ return status;
+ }
+
+ if (memcmp(data, readback_buf, len) != 0) {
+ log_debug("Readback did match written data.\n");
+ status = BLADERF_ERR_UNEXPECTED;
+ }
+
+ return status;
+}
+
+static int execute_fw_from_bootloader(struct bladerf_usb *usb, uint32_t addr)
+{
+ int status;
+
+ status = usb->fn->control_transfer(usb->driver,
+ USB_TARGET_DEVICE,
+ USB_REQUEST_VENDOR,
+ USB_DIR_HOST_TO_DEVICE,
+ FX3_BOOTLOADER_LOAD_BREQUEST,
+ FX3_BOOTLOADER_ADDR_WVALUE(addr),
+ FX3_BOOTLOADER_ADDR_WINDEX(addr),
+ NULL,
+ 0,
+ CTRL_TIMEOUT_MS);
+
+ if (status != 0 && status != BLADERF_ERR_IO) {
+ log_debug("Failed to exec firmware: %s\n:",
+ bladerf_strerror(status));
+
+ } else if (status == BLADERF_ERR_IO) {
+ /* The device might drop out from underneath us as it starts executing
+ * the new firmware */
+ log_verbose("Device returned IO error due to FW boot.\n");
+ status = 0;
+ } else {
+ log_verbose("Booting new FW.\n");
+ }
+
+ return status;
+}
+
+static int write_fw_to_bootloader(void *driver, struct fx3_firmware *fw)
+{
+ int status = 0;
+ uint32_t to_write;
+ uint32_t data_len;
+ uint32_t addr;
+ uint8_t *data;
+ bool got_section;
+
+ uint8_t *readback = malloc(FX3_BOOTLOADER_MAX_LOAD_LEN);
+ if (readback == NULL) {
+ return BLADERF_ERR_MEM;
+ }
+
+ do {
+ got_section = fx3_fw_next_section(fw, &addr, &data, &data_len);
+ if (got_section) {
+ /* data_len should never be zero, as fw->num_sections should NOT
+ * include the terminating section in its count */
+ assert(data_len != 0);
+
+ do {
+ to_write = u32_min(data_len, FX3_BOOTLOADER_MAX_LOAD_LEN);
+
+ status = write_and_verify_fw_chunk(driver,
+ addr, data, to_write,
+ readback);
+
+ data_len -= to_write;
+ addr += to_write;
+ data += to_write;
+ } while (data_len != 0 && status == 0);
+ }
+ } while (got_section && status == 0);
+
+ if (status == 0) {
+ status = execute_fw_from_bootloader(driver, fx3_fw_entry_point(fw));
+ }
+
+ free(readback);
+ return status;
+}
+
+static int usb_load_fw_from_bootloader(bladerf_backend backend,
+ uint8_t bus, uint8_t addr,
+ struct fx3_firmware *fw)
+{
+ int status = 0;
+ size_t i;
+ struct bladerf_usb usb;
+
+ for (i = 0; i < ARRAY_SIZE(usb_driver_list); i++) {
+
+ if ((backend == BLADERF_BACKEND_ANY) ||
+ (usb_driver_list[i]->id == backend)) {
+
+ usb.fn = usb_driver_list[i]->fn;
+ status = usb.fn->open_bootloader(&usb.driver, bus, addr);
+ if (status == 0) {
+ status = write_fw_to_bootloader(&usb, fw);
+ usb.fn->close_bootloader(usb.driver);
+ break;
+ }
+ }
+ }
+
+ return status;
+}
+
+/* Default handlers for operations unsupported by the NIOS II legacy packet
+ * format */
+static int set_vctcxo_tamer_mode_unsupported(struct bladerf *dev,
+ bladerf_vctcxo_tamer_mode mode)
+{
+ log_debug("Operation not supported with legacy NIOS packet format.\n");
+ return BLADERF_ERR_UNSUPPORTED;
+}
+
+static int get_vctcxo_tamer_mode_unsupported(struct bladerf *dev,
+ bladerf_vctcxo_tamer_mode *mode)
+{
+ *mode = BLADERF_VCTCXO_TAMER_INVALID;
+ log_debug("Operation not supported with legacy NIOS packet format.\n");
+ return BLADERF_ERR_UNSUPPORTED;
+}
+
+static int usb_read_fw_log(struct bladerf *dev, logger_entry *e)
+{
+ int status;
+ *e = LOG_EOF;
+
+ status = vendor_cmd_int(dev, BLADE_USB_CMD_READ_LOG_ENTRY,
+ USB_DIR_DEVICE_TO_HOST, (int32_t*) e);
+
+ return status;
+}
+
+static int config_gpio_write(struct bladerf *dev, uint32_t val)
+{
+ struct bladerf_usb *usb = dev->backend_data;
+ bladerf_dev_speed usb_speed;
+
+ if (usb->fn->get_speed(usb->driver, &usb_speed) != 0) {
+ log_debug("Error getting USB speed in %s\n", __FUNCTION__);
+ return BLADERF_ERR_UNEXPECTED;
+ }
+
+ /* If we're connected at HS, we need to use smaller DMA transfers */
+ if (usb_speed == BLADERF_DEVICE_SPEED_HIGH) {
+ val |= BLADERF_GPIO_FEATURE_SMALL_DMA_XFER;
+ } else if (usb_speed == BLADERF_DEVICE_SPEED_SUPER) {
+ val &= ~BLADERF_GPIO_FEATURE_SMALL_DMA_XFER;
+ } else {
+ assert(!"Encountered unknown USB speed");
+ return BLADERF_ERR_UNEXPECTED;
+ }
+
+ return nios_config_write(dev, val);
+}
+
+static int set_agc_dc_correction_unsupported(struct bladerf *dev,
+ int16_t q_max, int16_t i_max,
+ int16_t q_mid, int16_t i_mid,
+ int16_t q_low, int16_t i_low)
+{
+ log_debug("Operation not supported with legacy NIOS packet format.\n");
+ return BLADERF_ERR_UNSUPPORTED;
+}
+
+static int legacy_config_gpio_write(struct bladerf *dev, uint32_t val)
+{
+ struct bladerf_usb *usb = dev->backend_data;
+ bladerf_dev_speed usb_speed;
+
+ if (usb->fn->get_speed(usb->driver, &usb_speed) != 0) {
+ log_debug("Error getting USB speed in %s\n", __FUNCTION__);
+ return BLADERF_ERR_UNEXPECTED;
+ }
+
+ /* If we're connected at HS, we need to use smaller DMA transfers */
+ if (usb_speed == BLADERF_DEVICE_SPEED_HIGH) {
+ val |= BLADERF_GPIO_FEATURE_SMALL_DMA_XFER;
+ } else if (usb_speed == BLADERF_DEVICE_SPEED_SUPER) {
+ val &= ~BLADERF_GPIO_FEATURE_SMALL_DMA_XFER;
+ } else {
+ assert(!"Encountered unknown USB speed");
+ return BLADERF_ERR_UNEXPECTED;
+ }
+
+ return nios_legacy_config_write(dev, val);
+}
+
+/* USB backend that used legacy format for communicating with NIOS II */
+const struct backend_fns backend_fns_usb_legacy = {
+ FIELD_INIT(.matches, usb_matches),
+
+ FIELD_INIT(.probe, usb_probe),
+
+ FIELD_INIT(.get_vid_pid, usb_get_vid_pid),
+ FIELD_INIT(.get_flash_id, usb_get_flash_id),
+ FIELD_INIT(.open, usb_open),
+ FIELD_INIT(.set_fpga_protocol, usb_set_fpga_protocol),
+ FIELD_INIT(.close, usb_close),
+
+ FIELD_INIT(.is_fw_ready, usb_is_fw_ready),
+
+ FIELD_INIT(.get_handle, usb_get_handle),
+
+ FIELD_INIT(.load_fpga, usb_load_fpga),
+ FIELD_INIT(.is_fpga_configured, usb_is_fpga_configured),
+ FIELD_INIT(.get_fpga_source, usb_get_fpga_source),
+
+ FIELD_INIT(.get_fw_version, usb_get_fw_version),
+ FIELD_INIT(.get_fpga_version, usb_get_fpga_version),
+
+ FIELD_INIT(.erase_flash_blocks, usb_erase_flash_blocks),
+ FIELD_INIT(.read_flash_pages, usb_read_flash_pages),
+ FIELD_INIT(.write_flash_pages, usb_write_flash_pages),
+
+ FIELD_INIT(.device_reset, usb_device_reset),
+ FIELD_INIT(.jump_to_bootloader, usb_jump_to_bootloader),
+
+ FIELD_INIT(.get_cal, usb_get_cal),
+ FIELD_INIT(.get_otp, usb_get_otp),
+ FIELD_INIT(.write_otp, usb_write_otp),
+ FIELD_INIT(.lock_otp, usb_lock_otp),
+ FIELD_INIT(.get_device_speed, usb_get_device_speed),
+
+ FIELD_INIT(.config_gpio_write, legacy_config_gpio_write),
+ FIELD_INIT(.config_gpio_read, nios_legacy_config_read),
+
+ FIELD_INIT(.expansion_gpio_write, nios_legacy_expansion_gpio_write),
+ FIELD_INIT(.expansion_gpio_read, nios_legacy_expansion_gpio_read),
+ FIELD_INIT(.expansion_gpio_dir_write, nios_legacy_expansion_gpio_dir_write),
+ FIELD_INIT(.expansion_gpio_dir_read, nios_legacy_expansion_gpio_dir_read),
+
+ FIELD_INIT(.set_iq_gain_correction, nios_legacy_set_iq_gain_correction),
+ FIELD_INIT(.set_iq_phase_correction, nios_legacy_set_iq_phase_correction),
+ FIELD_INIT(.get_iq_gain_correction, nios_legacy_get_iq_gain_correction),
+ FIELD_INIT(.get_iq_phase_correction, nios_legacy_get_iq_phase_correction),
+
+ FIELD_INIT(.set_agc_dc_correction, set_agc_dc_correction_unsupported),
+
+ FIELD_INIT(.get_timestamp, nios_legacy_get_timestamp),
+
+ FIELD_INIT(.si5338_write, nios_legacy_si5338_write),
+ FIELD_INIT(.si5338_read, nios_legacy_si5338_read),
+
+ FIELD_INIT(.lms_write, nios_legacy_lms6_write),
+ FIELD_INIT(.lms_read, nios_legacy_lms6_read),
+
+ FIELD_INIT(.ina219_write, nios_legacy_ina219_write),
+ FIELD_INIT(.ina219_read, nios_legacy_ina219_read),
+
+ FIELD_INIT(.ad9361_spi_write, nios_legacy_ad9361_spi_write),
+ FIELD_INIT(.ad9361_spi_read, nios_legacy_ad9361_spi_read),
+
+ FIELD_INIT(.adi_axi_write, nios_legacy_adi_axi_write),
+ FIELD_INIT(.adi_axi_read, nios_legacy_adi_axi_read),
+
+ FIELD_INIT(.rfic_command_write, nios_legacy_rfic_command_write),
+ FIELD_INIT(.rfic_command_read, nios_legacy_rfic_command_read),
+
+ FIELD_INIT(.rffe_control_write, nios_legacy_rffe_control_write),
+ FIELD_INIT(.rffe_control_read, nios_legacy_rffe_control_read),
+
+ FIELD_INIT(.rffe_fastlock_save, nios_legacy_rffe_fastlock_save),
+
+ FIELD_INIT(.ad56x1_vctcxo_trim_dac_write, nios_legacy_ad56x1_vctcxo_trim_dac_write),
+ FIELD_INIT(.ad56x1_vctcxo_trim_dac_read, nios_legacy_ad56x1_vctcxo_trim_dac_read),
+
+ FIELD_INIT(.adf400x_write, nios_legacy_adf400x_write),
+ FIELD_INIT(.adf400x_read, nios_legacy_adf400x_read),
+
+ FIELD_INIT(.vctcxo_dac_write, nios_legacy_vctcxo_trim_dac_write),
+ FIELD_INIT(.vctcxo_dac_read, nios_vctcxo_trim_dac_read),
+
+ FIELD_INIT(.set_vctcxo_tamer_mode, set_vctcxo_tamer_mode_unsupported),
+ FIELD_INIT(.get_vctcxo_tamer_mode, get_vctcxo_tamer_mode_unsupported),
+
+ FIELD_INIT(.xb_spi, nios_legacy_xb200_synth_write),
+
+ FIELD_INIT(.set_firmware_loopback, usb_set_firmware_loopback),
+ FIELD_INIT(.get_firmware_loopback, usb_get_firmware_loopback),
+
+ FIELD_INIT(.enable_module, usb_enable_module),
+
+ FIELD_INIT(.init_stream, usb_init_stream),
+ FIELD_INIT(.stream, usb_stream),
+ FIELD_INIT(.submit_stream_buffer, usb_submit_stream_buffer),
+ FIELD_INIT(.deinit_stream, usb_deinit_stream),
+
+ FIELD_INIT(.retune, nios_retune),
+ FIELD_INIT(.retune2, nios_retune2),
+
+ FIELD_INIT(.load_fw_from_bootloader, usb_load_fw_from_bootloader),
+
+ FIELD_INIT(.read_fw_log, usb_read_fw_log),
+
+ FIELD_INIT(.read_trigger, nios_legacy_read_trigger),
+ FIELD_INIT(.write_trigger, nios_legacy_write_trigger),
+
+ FIELD_INIT(.name, "usb"),
+};
+
+/* USB backend for use with FPGA supporting update NIOS II packet formats */
+const struct backend_fns backend_fns_usb = {
+ FIELD_INIT(.matches, usb_matches),
+
+ FIELD_INIT(.probe, usb_probe),
+
+ FIELD_INIT(.get_vid_pid, usb_get_vid_pid),
+ FIELD_INIT(.get_flash_id, usb_get_flash_id),
+ FIELD_INIT(.open, usb_open),
+ FIELD_INIT(.set_fpga_protocol, usb_set_fpga_protocol),
+ FIELD_INIT(.close, usb_close),
+
+ FIELD_INIT(.is_fw_ready, usb_is_fw_ready),
+
+ FIELD_INIT(.get_handle, usb_get_handle),
+
+ FIELD_INIT(.load_fpga, usb_load_fpga),
+ FIELD_INIT(.is_fpga_configured, usb_is_fpga_configured),
+ FIELD_INIT(.get_fpga_source, usb_get_fpga_source),
+
+ FIELD_INIT(.get_fw_version, usb_get_fw_version),
+ FIELD_INIT(.get_fpga_version, usb_get_fpga_version),
+
+ FIELD_INIT(.erase_flash_blocks, usb_erase_flash_blocks),
+ FIELD_INIT(.read_flash_pages, usb_read_flash_pages),
+ FIELD_INIT(.write_flash_pages, usb_write_flash_pages),
+
+ FIELD_INIT(.device_reset, usb_device_reset),
+ FIELD_INIT(.jump_to_bootloader, usb_jump_to_bootloader),
+
+ FIELD_INIT(.get_cal, usb_get_cal),
+ FIELD_INIT(.get_otp, usb_get_otp),
+ FIELD_INIT(.write_otp, usb_write_otp),
+ FIELD_INIT(.lock_otp, usb_lock_otp),
+ FIELD_INIT(.get_device_speed, usb_get_device_speed),
+
+ FIELD_INIT(.config_gpio_write, config_gpio_write),
+ FIELD_INIT(.config_gpio_read, nios_config_read),
+
+ FIELD_INIT(.expansion_gpio_write, nios_expansion_gpio_write),
+ FIELD_INIT(.expansion_gpio_read, nios_expansion_gpio_read),
+ FIELD_INIT(.expansion_gpio_dir_write, nios_expansion_gpio_dir_write),
+ FIELD_INIT(.expansion_gpio_dir_read, nios_expansion_gpio_dir_read),
+
+ FIELD_INIT(.set_iq_gain_correction, nios_set_iq_gain_correction),
+ FIELD_INIT(.set_iq_phase_correction, nios_set_iq_phase_correction),
+ FIELD_INIT(.get_iq_gain_correction, nios_get_iq_gain_correction),
+ FIELD_INIT(.get_iq_phase_correction, nios_get_iq_phase_correction),
+
+ FIELD_INIT(.set_agc_dc_correction, nios_set_agc_dc_correction),
+
+ FIELD_INIT(.get_timestamp, nios_get_timestamp),
+
+ FIELD_INIT(.si5338_write, nios_si5338_write),
+ FIELD_INIT(.si5338_read, nios_si5338_read),
+
+ FIELD_INIT(.lms_write, nios_lms6_write),
+ FIELD_INIT(.lms_read, nios_lms6_read),
+
+ FIELD_INIT(.ina219_write, nios_ina219_write),
+ FIELD_INIT(.ina219_read, nios_ina219_read),
+
+ FIELD_INIT(.ad9361_spi_write, nios_ad9361_spi_write),
+ FIELD_INIT(.ad9361_spi_read, nios_ad9361_spi_read),
+
+ FIELD_INIT(.adi_axi_write, nios_adi_axi_write),
+ FIELD_INIT(.adi_axi_read, nios_adi_axi_read),
+
+ FIELD_INIT(.wishbone_master_write, nios_wishbone_master_write),
+ FIELD_INIT(.wishbone_master_read, nios_wishbone_master_read),
+
+ FIELD_INIT(.rfic_command_write, nios_rfic_command_write),
+ FIELD_INIT(.rfic_command_read, nios_rfic_command_read),
+
+ FIELD_INIT(.rffe_control_write, nios_rffe_control_write),
+ FIELD_INIT(.rffe_control_read, nios_rffe_control_read),
+
+ FIELD_INIT(.rffe_fastlock_save, nios_rffe_fastlock_save),
+
+ FIELD_INIT(.ad56x1_vctcxo_trim_dac_write, nios_ad56x1_vctcxo_trim_dac_write),
+ FIELD_INIT(.ad56x1_vctcxo_trim_dac_read, nios_ad56x1_vctcxo_trim_dac_read),
+
+ FIELD_INIT(.adf400x_write, nios_adf400x_write),
+ FIELD_INIT(.adf400x_read, nios_adf400x_read),
+
+ FIELD_INIT(.vctcxo_dac_write, nios_vctcxo_trim_dac_write),
+ FIELD_INIT(.vctcxo_dac_read, nios_vctcxo_trim_dac_read),
+
+ FIELD_INIT(.set_vctcxo_tamer_mode, nios_set_vctcxo_tamer_mode),
+ FIELD_INIT(.get_vctcxo_tamer_mode, nios_get_vctcxo_tamer_mode),
+
+ FIELD_INIT(.xb_spi, nios_xb200_synth_write),
+
+ FIELD_INIT(.set_firmware_loopback, usb_set_firmware_loopback),
+ FIELD_INIT(.get_firmware_loopback, usb_get_firmware_loopback),
+
+ FIELD_INIT(.enable_module, usb_enable_module),
+
+ FIELD_INIT(.init_stream, usb_init_stream),
+ FIELD_INIT(.stream, usb_stream),
+ FIELD_INIT(.submit_stream_buffer, usb_submit_stream_buffer),
+ FIELD_INIT(.deinit_stream, usb_deinit_stream),
+
+ FIELD_INIT(.retune, nios_retune),
+ FIELD_INIT(.retune2, nios_retune2),
+
+ FIELD_INIT(.load_fw_from_bootloader, usb_load_fw_from_bootloader),
+
+ FIELD_INIT(.read_fw_log, usb_read_fw_log),
+
+ FIELD_INIT(.read_trigger, nios_read_trigger),
+ FIELD_INIT(.write_trigger, nios_write_trigger),
+
+ FIELD_INIT(.name, "usb"),
+};