J-Link serial number config option
[fw/openocd] / src / jtag / drivers / mpsse.c
index 92f9331a543c39385eaa538eaa64889bab62e879..d9f73a2a794a790ae9a518be48964f74da69d2ba 100644 (file)
@@ -15,7 +15,7 @@
  *   You should have received a copy of the GNU General Public License     *
  *   along with this program; if not, write to the                         *
  *   Free Software Foundation, Inc.,                                       *
- *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
+ *   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.           *
  ***************************************************************************/
 
 #ifdef HAVE_CONFIG_H
@@ -24,7 +24,7 @@
 
 #include "mpsse.h"
 #include "helper/log.h"
-#include <libusb-1.0/libusb.h>
+#include <libusb.h>
 
 /* Compatibility define for older libusb-1.0 */
 #ifndef LIBUSB_CALL
@@ -55,7 +55,6 @@
 #define FTDI_DEVICE_OUT_REQTYPE (LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE)
 #define FTDI_DEVICE_IN_REQTYPE (0x80 | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE)
 
-#define BITMODE_RESET 0x00
 #define BITMODE_MPSSE 0x02
 
 #define SIO_RESET_REQUEST             0x00
@@ -87,6 +86,7 @@ struct mpsse_ctx {
        uint8_t *read_chunk;
        unsigned read_chunk_size;
        struct bit_copy_queue read_queue;
+       int retval;
 };
 
 /* Returns true if the string descriptor indexed by str_index in device matches string */
@@ -98,7 +98,7 @@ static bool string_descriptor_equal(libusb_device_handle *device, uint8_t str_in
        retval = libusb_get_string_descriptor_ascii(device, str_index, (unsigned char *)desc_string,
                        sizeof(desc_string));
        if (retval < 0) {
-               LOG_ERROR("libusb_get_string_descriptor_ascii() failed with %d", retval);
+               LOG_ERROR("libusb_get_string_descriptor_ascii() failed with %s", libusb_error_name(retval));
                return false;
        }
        return strncmp(string, desc_string, sizeof(desc_string)) == 0;
@@ -118,14 +118,14 @@ static bool open_matching_device(struct mpsse_ctx *ctx, const uint16_t *vid, con
        bool found = false;
        ssize_t cnt = libusb_get_device_list(ctx->usb_ctx, &list);
        if (cnt < 0)
-               LOG_ERROR("libusb_get_device_list() failed with %zi", cnt);
+               LOG_ERROR("libusb_get_device_list() failed with %s", libusb_error_name(cnt));
 
        for (ssize_t i = 0; i < cnt; i++) {
                libusb_device *device = list[i];
 
                err = libusb_get_device_descriptor(device, &desc);
                if (err != LIBUSB_SUCCESS) {
-                       LOG_ERROR("libusb_get_device_descriptor() failed with %d", err);
+                       LOG_ERROR("libusb_get_device_descriptor() failed with %s", libusb_error_name(err));
                        continue;
                }
 
@@ -136,7 +136,8 @@ static bool open_matching_device(struct mpsse_ctx *ctx, const uint16_t *vid, con
 
                err = libusb_open(device, &ctx->usb_dev);
                if (err != LIBUSB_SUCCESS) {
-                       LOG_ERROR("libusb_open() failed with %d", err);
+                       LOG_ERROR("libusb_open() failed with %s",
+                                 libusb_error_name(err));
                        continue;
                }
 
@@ -163,7 +164,7 @@ static bool open_matching_device(struct mpsse_ctx *ctx, const uint16_t *vid, con
 
        err = libusb_get_config_descriptor(libusb_get_device(ctx->usb_dev), 0, &config0);
        if (err != LIBUSB_SUCCESS) {
-               LOG_ERROR("libusb_get_config_descriptor() failed with %d", err);
+               LOG_ERROR("libusb_get_config_descriptor() failed with %s", libusb_error_name(err));
                libusb_close(ctx->usb_dev);
                return false;
        }
@@ -172,14 +173,14 @@ static bool open_matching_device(struct mpsse_ctx *ctx, const uint16_t *vid, con
        int cfg;
        err = libusb_get_configuration(ctx->usb_dev, &cfg);
        if (err != LIBUSB_SUCCESS) {
-               LOG_ERROR("libusb_get_configuration() failed with %d", err);
+               LOG_ERROR("libusb_get_configuration() failed with %s", libusb_error_name(err));
                goto error;
        }
 
        if (desc.bNumConfigurations > 0 && cfg != config0->bConfigurationValue) {
                err = libusb_set_configuration(ctx->usb_dev, config0->bConfigurationValue);
                if (err != LIBUSB_SUCCESS) {
-                       LOG_ERROR("libusb_set_configuration() failed with %d", err);
+                       LOG_ERROR("libusb_set_configuration() failed with %s", libusb_error_name(err));
                        goto error;
                }
        }
@@ -188,13 +189,13 @@ static bool open_matching_device(struct mpsse_ctx *ctx, const uint16_t *vid, con
        err = libusb_detach_kernel_driver(ctx->usb_dev, ctx->interface);
        if (err != LIBUSB_SUCCESS && err != LIBUSB_ERROR_NOT_FOUND
                        && err != LIBUSB_ERROR_NOT_SUPPORTED) {
-               LOG_ERROR("libusb_detach_kernel_driver() failed with %d", err);
+               LOG_ERROR("libusb_detach_kernel_driver() failed with %s", libusb_error_name(err));
                goto error;
        }
 
        err = libusb_claim_interface(ctx->usb_dev, ctx->interface);
        if (err != LIBUSB_SUCCESS) {
-               LOG_ERROR("libusb_claim_interface() failed with %d", err);
+               LOG_ERROR("libusb_claim_interface() failed with %s", libusb_error_name(err));
                goto error;
        }
 
@@ -203,7 +204,7 @@ static bool open_matching_device(struct mpsse_ctx *ctx, const uint16_t *vid, con
                        SIO_RESET_REQUEST, SIO_RESET_SIO,
                        ctx->index, NULL, 0, ctx->usb_write_timeout);
        if (err < 0) {
-               LOG_ERROR("failed to reset FTDI device: %d", err);
+               LOG_ERROR("failed to reset FTDI device: %s", libusb_error_name(err));
                goto error;
        }
 
@@ -287,7 +288,7 @@ struct mpsse_ctx *mpsse_open(const uint16_t *vid, const uint16_t *pid, const cha
 
        err = libusb_init(&ctx->usb_ctx);
        if (err != LIBUSB_SUCCESS) {
-               LOG_ERROR("libusb_init() failed with %d", err);
+               LOG_ERROR("libusb_init() failed with %s", libusb_error_name(err));
                goto error;
        }
 
@@ -309,20 +310,7 @@ struct mpsse_ctx *mpsse_open(const uint16_t *vid, const uint16_t *pid, const cha
                        SIO_SET_LATENCY_TIMER_REQUEST, 255, ctx->index, NULL, 0,
                        ctx->usb_write_timeout);
        if (err < 0) {
-               LOG_ERROR("unable to set latency timer: %d", err);
-               goto error;
-       }
-
-       err = libusb_control_transfer(ctx->usb_dev,
-                       FTDI_DEVICE_OUT_REQTYPE,
-                       SIO_SET_BITMODE_REQUEST,
-                       0x0b | (BITMODE_RESET << 8),
-                       ctx->index,
-                       NULL,
-                       0,
-                       ctx->usb_write_timeout);
-       if (err < 0) {
-               LOG_ERROR("unable to reset bitmode: %d", err);
+               LOG_ERROR("unable to set latency timer: %s", libusb_error_name(err));
                goto error;
        }
 
@@ -335,7 +323,7 @@ struct mpsse_ctx *mpsse_open(const uint16_t *vid, const uint16_t *pid, const cha
                        0,
                        ctx->usb_write_timeout);
        if (err < 0) {
-               LOG_ERROR("unable to set MPSSE bitmode: %d", err);
+               LOG_ERROR("unable to set MPSSE bitmode: %s", libusb_error_name(err));
                goto error;
        }
 
@@ -375,18 +363,19 @@ void mpsse_purge(struct mpsse_ctx *ctx)
        LOG_DEBUG("-");
        ctx->write_count = 0;
        ctx->read_count = 0;
+       ctx->retval = ERROR_OK;
        bit_copy_discard(&ctx->read_queue);
        err = libusb_control_transfer(ctx->usb_dev, FTDI_DEVICE_OUT_REQTYPE, SIO_RESET_REQUEST,
                        SIO_RESET_PURGE_RX, ctx->index, NULL, 0, ctx->usb_write_timeout);
        if (err < 0) {
-               LOG_ERROR("unable to purge ftdi rx buffers: %d", err);
+               LOG_ERROR("unable to purge ftdi rx buffers: %s", libusb_error_name(err));
                return;
        }
 
        err = libusb_control_transfer(ctx->usb_dev, FTDI_DEVICE_OUT_REQTYPE, SIO_RESET_REQUEST,
                        SIO_RESET_PURGE_TX, ctx->index, NULL, 0, ctx->usb_write_timeout);
        if (err < 0) {
-               LOG_ERROR("unable to purge ftdi tx buffers: %d", err);
+               LOG_ERROR("unable to purge ftdi tx buffers: %s", libusb_error_name(err));
                return;
        }
 }
@@ -430,24 +419,28 @@ static unsigned buffer_add_read(struct mpsse_ctx *ctx, uint8_t *in, unsigned in_
        return bit_count;
 }
 
-int mpsse_clock_data_out(struct mpsse_ctx *ctx, const uint8_t *out, unsigned out_offset,
+void mpsse_clock_data_out(struct mpsse_ctx *ctx, const uint8_t *out, unsigned out_offset,
        unsigned length, uint8_t mode)
 {
-       return mpsse_clock_data(ctx, out, out_offset, 0, 0, length, mode);
+       mpsse_clock_data(ctx, out, out_offset, 0, 0, length, mode);
 }
 
-int mpsse_clock_data_in(struct mpsse_ctx *ctx, uint8_t *in, unsigned in_offset, unsigned length,
+void mpsse_clock_data_in(struct mpsse_ctx *ctx, uint8_t *in, unsigned in_offset, unsigned length,
        uint8_t mode)
 {
-       return mpsse_clock_data(ctx, 0, 0, in, in_offset, length, mode);
+       mpsse_clock_data(ctx, 0, 0, in, in_offset, length, mode);
 }
 
-int mpsse_clock_data(struct mpsse_ctx *ctx, const uint8_t *out, unsigned out_offset, uint8_t *in,
+void mpsse_clock_data(struct mpsse_ctx *ctx, const uint8_t *out, unsigned out_offset, uint8_t *in,
        unsigned in_offset, unsigned length, uint8_t mode)
 {
        /* TODO: Fix MSB first modes */
        DEBUG_IO("%s%s %d bits", in ? "in" : "", out ? "out" : "", length);
-       int retval = ERROR_OK;
+
+       if (ctx->retval != ERROR_OK) {
+               DEBUG_IO("Ignoring command due to previous error");
+               return;
+       }
 
        /* TODO: On H chips, use command 0x8E/0x8F if in and out are both 0 */
        if (out || (!out && !in))
@@ -459,7 +452,7 @@ int mpsse_clock_data(struct mpsse_ctx *ctx, const uint8_t *out, unsigned out_off
                /* Guarantee buffer space enough for a minimum size transfer */
                if (buffer_write_space(ctx) + (length < 8) < (out || (!out && !in) ? 4 : 3)
                                || (in && buffer_read_space(ctx) < 1))
-                       retval = mpsse_flush(ctx);
+                       ctx->retval = mpsse_flush(ctx);
 
                if (length < 8) {
                        /* Transfer remaining bits in bit mode */
@@ -507,21 +500,24 @@ int mpsse_clock_data(struct mpsse_ctx *ctx, const uint8_t *out, unsigned out_off
                        }
                }
        }
-       return retval;
 }
 
-int mpsse_clock_tms_cs_out(struct mpsse_ctx *ctx, const uint8_t *out, unsigned out_offset,
+void mpsse_clock_tms_cs_out(struct mpsse_ctx *ctx, const uint8_t *out, unsigned out_offset,
        unsigned length, bool tdi, uint8_t mode)
 {
-       return mpsse_clock_tms_cs(ctx, out, out_offset, 0, 0, length, tdi, mode);
+       mpsse_clock_tms_cs(ctx, out, out_offset, 0, 0, length, tdi, mode);
 }
 
-int mpsse_clock_tms_cs(struct mpsse_ctx *ctx, const uint8_t *out, unsigned out_offset, uint8_t *in,
+void mpsse_clock_tms_cs(struct mpsse_ctx *ctx, const uint8_t *out, unsigned out_offset, uint8_t *in,
        unsigned in_offset, unsigned length, bool tdi, uint8_t mode)
 {
        DEBUG_IO("%sout %d bits, tdi=%d", in ? "in" : "", length, tdi);
        assert(out);
-       int retval = ERROR_OK;
+
+       if (ctx->retval != ERROR_OK) {
+               DEBUG_IO("Ignoring command due to previous error");
+               return;
+       }
 
        mode |= 0x42;
        if (in)
@@ -530,7 +526,7 @@ int mpsse_clock_tms_cs(struct mpsse_ctx *ctx, const uint8_t *out, unsigned out_o
        while (length > 0) {
                /* Guarantee buffer space enough for a minimum size transfer */
                if (buffer_write_space(ctx) < 3 || (in && buffer_read_space(ctx) < 1))
-                       retval = mpsse_flush(ctx);
+                       ctx->retval = mpsse_flush(ctx);
 
                /* Byte transfer */
                unsigned this_bits = length;
@@ -561,99 +557,109 @@ int mpsse_clock_tms_cs(struct mpsse_ctx *ctx, const uint8_t *out, unsigned out_o
                        length -= this_bits;
                }
        }
-       return retval;
 }
 
-int mpsse_set_data_bits_low_byte(struct mpsse_ctx *ctx, uint8_t data, uint8_t dir)
+void mpsse_set_data_bits_low_byte(struct mpsse_ctx *ctx, uint8_t data, uint8_t dir)
 {
        DEBUG_IO("-");
-       int retval = ERROR_OK;
+
+       if (ctx->retval != ERROR_OK) {
+               DEBUG_IO("Ignoring command due to previous error");
+               return;
+       }
 
        if (buffer_write_space(ctx) < 3)
-               retval = mpsse_flush(ctx);
+               ctx->retval = mpsse_flush(ctx);
 
        buffer_write_byte(ctx, 0x80);
        buffer_write_byte(ctx, data);
        buffer_write_byte(ctx, dir);
-
-       return retval;
 }
 
-int mpsse_set_data_bits_high_byte(struct mpsse_ctx *ctx, uint8_t data, uint8_t dir)
+void mpsse_set_data_bits_high_byte(struct mpsse_ctx *ctx, uint8_t data, uint8_t dir)
 {
        DEBUG_IO("-");
-       int retval = ERROR_OK;
+
+       if (ctx->retval != ERROR_OK) {
+               DEBUG_IO("Ignoring command due to previous error");
+               return;
+       }
 
        if (buffer_write_space(ctx) < 3)
-               retval = mpsse_flush(ctx);
+               ctx->retval = mpsse_flush(ctx);
 
        buffer_write_byte(ctx, 0x82);
        buffer_write_byte(ctx, data);
        buffer_write_byte(ctx, dir);
-
-       return retval;
 }
 
-int mpsse_read_data_bits_low_byte(struct mpsse_ctx *ctx, uint8_t *data)
+void mpsse_read_data_bits_low_byte(struct mpsse_ctx *ctx, uint8_t *data)
 {
        DEBUG_IO("-");
-       int retval = ERROR_OK;
 
-       if (buffer_write_space(ctx) < 1)
-               retval = mpsse_flush(ctx);
+       if (ctx->retval != ERROR_OK) {
+               DEBUG_IO("Ignoring command due to previous error");
+               return;
+       }
+
+       if (buffer_write_space(ctx) < 1 || buffer_read_space(ctx) < 1)
+               ctx->retval = mpsse_flush(ctx);
 
        buffer_write_byte(ctx, 0x81);
        buffer_add_read(ctx, data, 0, 8, 0);
-
-       return retval;
 }
 
-int mpsse_read_data_bits_high_byte(struct mpsse_ctx *ctx, uint8_t *data)
+void mpsse_read_data_bits_high_byte(struct mpsse_ctx *ctx, uint8_t *data)
 {
        DEBUG_IO("-");
-       int retval = ERROR_OK;
 
-       if (buffer_write_space(ctx) < 1)
-               retval = mpsse_flush(ctx);
+       if (ctx->retval != ERROR_OK) {
+               DEBUG_IO("Ignoring command due to previous error");
+               return;
+       }
+
+       if (buffer_write_space(ctx) < 1 || buffer_read_space(ctx) < 1)
+               ctx->retval = mpsse_flush(ctx);
 
        buffer_write_byte(ctx, 0x83);
        buffer_add_read(ctx, data, 0, 8, 0);
-
-       return retval;
 }
 
-static int single_byte_boolean_helper(struct mpsse_ctx *ctx, bool var, uint8_t val_if_true,
+static void single_byte_boolean_helper(struct mpsse_ctx *ctx, bool var, uint8_t val_if_true,
        uint8_t val_if_false)
 {
-       int retval = ERROR_OK;
+       if (ctx->retval != ERROR_OK) {
+               DEBUG_IO("Ignoring command due to previous error");
+               return;
+       }
 
        if (buffer_write_space(ctx) < 1)
-               retval = mpsse_flush(ctx);
+               ctx->retval = mpsse_flush(ctx);
 
        buffer_write_byte(ctx, var ? val_if_true : val_if_false);
-
-       return retval;
 }
 
-int mpsse_loopback_config(struct mpsse_ctx *ctx, bool enable)
+void mpsse_loopback_config(struct mpsse_ctx *ctx, bool enable)
 {
        LOG_DEBUG("%s", enable ? "on" : "off");
-       return single_byte_boolean_helper(ctx, enable, 0x84, 0x85);
+       single_byte_boolean_helper(ctx, enable, 0x84, 0x85);
 }
 
-int mpsse_set_divisor(struct mpsse_ctx *ctx, uint16_t divisor)
+void mpsse_set_divisor(struct mpsse_ctx *ctx, uint16_t divisor)
 {
        LOG_DEBUG("%d", divisor);
-       int retval = ERROR_OK;
+
+       if (ctx->retval != ERROR_OK) {
+               DEBUG_IO("Ignoring command due to previous error");
+               return;
+       }
 
        if (buffer_write_space(ctx) < 3)
-               retval = mpsse_flush(ctx);
+               ctx->retval = mpsse_flush(ctx);
 
        buffer_write_byte(ctx, 0x86);
        buffer_write_byte(ctx, divisor & 0xff);
        buffer_write_byte(ctx, divisor >> 8);
-
-       return retval;
 }
 
 int mpsse_divide_by_5_config(struct mpsse_ctx *ctx, bool enable)
@@ -662,8 +668,9 @@ int mpsse_divide_by_5_config(struct mpsse_ctx *ctx, bool enable)
                return ERROR_FAIL;
 
        LOG_DEBUG("%s", enable ? "on" : "off");
+       single_byte_boolean_helper(ctx, enable, 0x8b, 0x8a);
 
-       return single_byte_boolean_helper(ctx, enable, 0x8b, 0x8a);
+       return ERROR_OK;
 }
 
 int mpsse_rtck_config(struct mpsse_ctx *ctx, bool enable)
@@ -672,8 +679,9 @@ int mpsse_rtck_config(struct mpsse_ctx *ctx, bool enable)
                return ERROR_FAIL;
 
        LOG_DEBUG("%s", enable ? "on" : "off");
+       single_byte_boolean_helper(ctx, enable, 0x96, 0x97);
 
-       return single_byte_boolean_helper(ctx, enable, 0x96, 0x97);
+       return ERROR_OK;
 }
 
 int mpsse_set_frequency(struct mpsse_ctx *ctx, int frequency)
@@ -687,10 +695,7 @@ int mpsse_set_frequency(struct mpsse_ctx *ctx, int frequency)
 
        mpsse_rtck_config(ctx, false); /* just try */
 
-       if (frequency > 60000000 / 2 / 65536 && mpsse_is_high_speed(ctx)) {
-               int retval = mpsse_divide_by_5_config(ctx, false);
-               if (retval != ERROR_OK)
-                       return retval;
+       if (frequency > 60000000 / 2 / 65536 && mpsse_divide_by_5_config(ctx, false) == ERROR_OK) {
                base_clock = 60000000;
        } else {
                mpsse_divide_by_5_config(ctx, true); /* just try */
@@ -702,9 +707,7 @@ int mpsse_set_frequency(struct mpsse_ctx *ctx, int frequency)
                divisor = 65535;
        assert(divisor >= 0);
 
-       int retval = mpsse_set_divisor(ctx, divisor);
-       if (retval != ERROR_OK)
-               return retval;
+       mpsse_set_divisor(ctx, divisor);
 
        frequency = base_clock / 2 / (1 + divisor);
        LOG_DEBUG("actually %d Hz", frequency);
@@ -721,7 +724,7 @@ struct transfer_result {
 
 static LIBUSB_CALL void read_cb(struct libusb_transfer *transfer)
 {
-       struct transfer_result *res = (struct transfer_result *)transfer->user_data;
+       struct transfer_result *res = transfer->user_data;
        struct mpsse_ctx *ctx = res->ctx;
 
        unsigned packet_size = ctx->max_packet_size;
@@ -759,7 +762,7 @@ static LIBUSB_CALL void read_cb(struct libusb_transfer *transfer)
 
 static LIBUSB_CALL void write_cb(struct libusb_transfer *transfer)
 {
-       struct transfer_result *res = (struct transfer_result *)transfer->user_data;
+       struct transfer_result *res = transfer->user_data;
        struct mpsse_ctx *ctx = res->ctx;
 
        res->transferred += transfer->actual_length;
@@ -780,10 +783,18 @@ static LIBUSB_CALL void write_cb(struct libusb_transfer *transfer)
 
 int mpsse_flush(struct mpsse_ctx *ctx)
 {
+       int retval = ctx->retval;
+
+       if (retval != ERROR_OK) {
+               DEBUG_IO("Ignoring flush due to previous error");
+               assert(ctx->write_count == 0 && ctx->read_count == 0);
+               ctx->retval = ERROR_OK;
+               return retval;
+       }
+
        DEBUG_IO("write %d%s, read %d", ctx->write_count, ctx->read_count ? "+1" : "",
                        ctx->read_count);
        assert(ctx->write_count > 0 || ctx->read_count == 0); /* No read data without write data */
-       int retval = ERROR_OK;
 
        if (ctx->write_count == 0)
                return retval;
@@ -793,11 +804,8 @@ int mpsse_flush(struct mpsse_ctx *ctx)
        if (ctx->read_count) {
                buffer_write_byte(ctx, 0x87); /* SEND_IMMEDIATE */
                read_result.done = false;
-               read_transfer = libusb_alloc_transfer(0);
-               libusb_fill_bulk_transfer(read_transfer, ctx->usb_dev, ctx->in_ep, ctx->read_chunk,
-                       ctx->read_chunk_size, read_cb, &read_result,
-                       ctx->usb_read_timeout);
-               retval = libusb_submit_transfer(read_transfer);
+               /* delay read transaction to ensure the FTDI chip can support us with data
+                  immediately after processing the MPSSE commands in the write transaction */
        }
 
        struct transfer_result write_result = { .ctx = ctx, .done = false };
@@ -806,6 +814,14 @@ int mpsse_flush(struct mpsse_ctx *ctx)
                ctx->write_count, write_cb, &write_result, ctx->usb_write_timeout);
        retval = libusb_submit_transfer(write_transfer);
 
+       if (ctx->read_count) {
+               read_transfer = libusb_alloc_transfer(0);
+               libusb_fill_bulk_transfer(read_transfer, ctx->usb_dev, ctx->in_ep, ctx->read_chunk,
+                       ctx->read_chunk_size, read_cb, &read_result,
+                       ctx->usb_read_timeout);
+               retval = libusb_submit_transfer(read_transfer);
+       }
+
        /* Polling loop, more or less taken from libftdi */
        while (!write_result.done || !read_result.done) {
                retval = libusb_handle_events(ctx->usb_ctx);
@@ -821,7 +837,7 @@ int mpsse_flush(struct mpsse_ctx *ctx)
        }
 
        if (retval != LIBUSB_SUCCESS) {
-               LOG_ERROR("libusb_handle_events() failed with %d", retval);
+               LOG_ERROR("libusb_handle_events() failed with %s", libusb_error_name(retval));
                retval = ERROR_FAIL;
        } else if (write_result.transferred < ctx->write_count) {
                LOG_ERROR("ftdi device did not accept all data: %d, tried %d",