/* Buf is assumed to be NIOS_PKT_LEN bytes */ static int nios_access(struct bladerf *dev, uint8_t *buf) { int status; void *driver; struct bladerf_usb *usb = usb_backend(dev, &driver); print_buf("NIOS II request:\n", buf, NIOS_PKT_LEN); /* Send the command */ status = usb->fn->bulk_transfer(driver, PERIPHERAL_EP_OUT, buf, NIOS_PKT_LEN, PERIPHERAL_TIMEOUT_MS); if (status != 0) { log_debug("Failed to send NIOS II request: %s\n", bladerf_strerror(status)); return status; } /* Retrieve the request */ status = usb->fn->bulk_transfer(driver, PERIPHERAL_EP_IN, buf, NIOS_PKT_LEN, PERIPHERAL_TIMEOUT_MS); if (status != 0) { log_debug("Failed to receive NIOS II response: %s\n", bladerf_strerror(status)); } print_buf("NIOS II response:\n", buf, NIOS_PKT_LEN); return status; }
static int usb_get_device_speed(struct bladerf *dev, bladerf_dev_speed *speed) { void *driver; struct bladerf_usb *usb = usb_backend(dev, &driver); return usb->fn->get_speed(driver, speed); }
/* Access device/module via the legacy NIOS II packet format. */ static int nios_access(struct bladerf *dev, uint8_t peripheral, usb_direction dir, struct uart_cmd *cmd, size_t len) { void *driver; struct bladerf_usb *usb = usb_backend(dev, &driver); int status; size_t i; uint8_t buf[16] = { 0 }; const uint8_t pkt_mode_dir = (dir == USB_DIR_HOST_TO_DEVICE) ? NIOS_PKT_LEGACY_MODE_DIR_WRITE : NIOS_PKT_LEGACY_MODE_DIR_READ; assert(len <= ((sizeof(buf) - 2) / 2)); /* Populate the buffer for transfer, given address data pairs */ buf[0] = NIOS_PKT_LEGACY_MAGIC; buf[1] = pkt_mode_dir | peripheral | (uint8_t)len; for (i = 0; i < len; i++) { buf[i * 2 + 2] = cmd[i].addr; buf[i * 2 + 3] = cmd[i].data; } print_buf("NIOS II access request:\n", buf, 16); /* Send the command */ status = usb->fn->bulk_transfer(driver, PERIPHERAL_EP_OUT, buf, sizeof(buf), PERIPHERAL_TIMEOUT_MS); if (status != 0) { log_debug("Failed to submit NIOS II request: %s\n", bladerf_strerror(status)); return status; } /* Read back the ACK. The command data is only used for a read operation, * and is thrown away otherwise */ status = usb->fn->bulk_transfer(driver, PERIPHERAL_EP_IN, buf, sizeof(buf), PERIPHERAL_TIMEOUT_MS); if (dir == NIOS_PKT_LEGACY_MODE_DIR_READ && status == 0) { for (i = 0; i < len; i++) { cmd[i].data = buf[i * 2 + 3]; } } if (status == 0) { print_buf("NIOS II access response:\n", buf, 16); } else { log_debug("Failed to receive NIOS II response: %s\n", bladerf_strerror(status)); } return status; }
static int write_page(struct bladerf *dev, uint16_t page, const uint8_t *buf) { int status; int32_t commit_status; uint16_t offset; uint16_t write_size; void *driver; struct bladerf_usb *usb = usb_backend(dev, &driver); if (dev->usb_speed == BLADERF_DEVICE_SPEED_SUPER) { write_size = BLADERF_FLASH_PAGE_SIZE; } else if (dev->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 < BLADERF_FLASH_PAGE_SIZE; offset += write_size) { status = usb->fn->control_transfer(driver, USB_TARGET_INTERFACE, 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, BLADE_USB_CMD_FLASH_WRITE, 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_jump_to_bootloader(struct bladerf *dev) { void *driver; struct bladerf_usb *usb = usb_backend(dev, &driver); return usb->fn->control_transfer(driver, USB_TARGET_INTERFACE, USB_REQUEST_VENDOR, USB_DIR_HOST_TO_DEVICE, BLADE_USB_CMD_JUMP_TO_BOOTLOADER, 0, 0, 0, 0, CTRL_TIMEOUT_MS); }
static int usb_device_reset(struct bladerf *dev) { void *driver; struct bladerf_usb *usb = usb_backend(dev, &driver); return usb->fn->control_transfer(driver, USB_TARGET_INTERFACE, USB_REQUEST_VENDOR, USB_DIR_HOST_TO_DEVICE, BLADE_USB_CMD_RESET, 0, 0, 0, 0, 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) { void *driver; struct bladerf_usb *usb = usb_backend(dev, &driver); return usb->fn->control_transfer(driver, USB_TARGET_INTERFACE, USB_REQUEST_VENDOR, dir, cmd, 0, 0, val, sizeof(int32_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) { void *driver; struct bladerf_usb *usb = usb_backend(dev, &driver); return usb->fn->control_transfer(driver, USB_TARGET_INTERFACE, USB_REQUEST_VENDOR, USB_DIR_DEVICE_TO_HOST, cmd, wvalue, 0, val, sizeof(uint32_t), CTRL_TIMEOUT_MS); }
static inline int change_setting(struct bladerf *dev, uint8_t setting) { int status; void *driver; struct bladerf_usb *usb = usb_backend(dev, &driver); log_verbose("Changing to USB alt setting %u\n", setting); status = usb->fn->change_setting(driver, setting); if (status != 0) { log_debug("Failed to change setting: %s\n", bladerf_strerror(status)); } return status; }
static int access_peripheral(struct bladerf *dev, uint8_t peripheral, usb_direction dir, struct uart_cmd *cmd, size_t len) { void *driver; struct bladerf_usb *usb = usb_backend(dev, &driver); int status; size_t i; uint8_t buf[16] = { 0 }; const uint8_t pkt_mode_dir = (dir == USB_DIR_HOST_TO_DEVICE) ? UART_PKT_MODE_DIR_WRITE : UART_PKT_MODE_DIR_READ; assert(len <= ((sizeof(buf) - 2) / 2)); /* Populate the buffer for transfer */ buf[0] = UART_PKT_MAGIC; buf[1] = pkt_mode_dir | peripheral | (uint8_t)len; for (i = 0; i < len; i++) { buf[i * 2 + 2] = cmd[i].addr; buf[i * 2 + 3] = cmd[i].data; } /* Send the command */ status = usb->fn->bulk_transfer(driver, PERIPHERAL_EP_OUT, buf, sizeof(buf), PERIPHERAL_TIMEOUT_MS); if (status != 0) { log_debug("Failed to write perperial access command: %s\n", bladerf_strerror(status)); return status; } /* Read back the ACK. The command data is only used for a read operation, * and is thrown away otherwise */ status = usb->fn->bulk_transfer(driver, PERIPHERAL_EP_IN, buf, sizeof(buf), PERIPHERAL_TIMEOUT_MS); if (dir == UART_PKT_MODE_DIR_READ && status == 0) { for (i = 0; i < len; i++) { cmd[i].data = buf[i * 2 + 3]; } } return status; }
static inline int perform_erase(struct bladerf *dev, uint16_t block) { int status, erase_ret; void *driver; struct bladerf_usb *usb = usb_backend(dev, &driver); status = usb->fn->control_transfer(driver, USB_TARGET_INTERFACE, 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 void usb_close(struct bladerf *dev) { int status; void *driver; struct bladerf_usb *usb = usb_backend(dev, &driver); 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(driver, USB_IF_NULL); if (status != 0) { log_error("Failed to switch to NULL interface: %s\n", bladerf_strerror(status)); } usb->fn->close(driver); free(usb); dev->backend = NULL; } }
static inline int read_page(struct bladerf *dev, uint8_t read_operation, uint16_t page, uint8_t *buf) { void *driver; struct bladerf_usb *usb = usb_backend(dev, &driver); int status; int32_t op_status; uint16_t read_size; uint16_t offset; uint8_t request; if (dev->usb_speed == BLADERF_DEVICE_SPEED_SUPER) { read_size = BLADERF_FLASH_PAGE_SIZE; } else if (dev->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"); } /* Retrieve data from the firmware page buffer */ for (offset = 0; offset < BLADERF_FLASH_PAGE_SIZE; offset += read_size) { status = usb->fn->control_transfer(driver, USB_TARGET_INTERFACE, 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_load_fpga(struct bladerf *dev, uint8_t *image, size_t image_size) { void *driver; struct bladerf_usb *usb = usb_backend(dev, &driver); unsigned int wait_count; const unsigned int timeout_ms = (2 * 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(driver, PERIPHERAL_EP_OUT, 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; } /* End programming */ status = end_fpga_programming(dev); if (status) { log_debug("Failed to complete FPGA programming: %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 rflink_and_fpga_version_load(dev); }