X-Git-Url: https://review.openocd.org/gitweb?p=openocd.git;a=blobdiff_plain;f=src%2Fjtag%2Fdrivers%2Fmpsse.c;h=0ef88ba2d57c1b0410a77067d7b66ebb2d2d05e8;hp=82703bf341c73d53889f554bd6affea1abcd6668;hb=d0e763ac7ef6aa17b17bd00ccdfbccfb4eacda69;hpb=71ee5f6b5f3172901135640de4ca827b14747465 diff --git a/src/jtag/drivers/mpsse.c b/src/jtag/drivers/mpsse.c index 82703bf341..0ef88ba2d5 100644 --- a/src/jtag/drivers/mpsse.c +++ b/src/jtag/drivers/mpsse.c @@ -13,9 +13,7 @@ * GNU General Public License for more details. * * * * 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., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * + * along with this program. If not, see . * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -24,7 +22,7 @@ #include "mpsse.h" #include "helper/log.h" -#include +#include /* Compatibility define for older libusb-1.0 */ #ifndef LIBUSB_CALL @@ -86,6 +84,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 */ @@ -97,18 +96,73 @@ 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; } +static bool device_location_equal(libusb_device *device, const char *location) +{ + bool result = false; +#ifdef HAVE_LIBUSB_GET_PORT_NUMBERS + char *loc = strdup(location); + uint8_t port_path[7]; + int path_step, path_len; + uint8_t dev_bus = libusb_get_bus_number(device); + char *ptr; + + path_len = libusb_get_port_numbers(device, port_path, 7); + if (path_len == LIBUSB_ERROR_OVERFLOW) { + LOG_ERROR("cannot determine path to usb device! (more than 7 ports in path)"); + goto done; + } + + LOG_DEBUG("device path has %i steps", path_len); + + ptr = strtok(loc, ":"); + if (ptr == NULL) { + LOG_DEBUG("no ':' in path"); + goto done; + } + if (atoi(ptr) != dev_bus) { + LOG_DEBUG("bus mismatch"); + goto done; + } + + path_step = 0; + while (path_step < 7) { + ptr = strtok(NULL, ","); + if (ptr == NULL) { + LOG_DEBUG("no more tokens in path at step %i", path_step); + break; + } + + if (path_step < path_len + && atoi(ptr) != port_path[path_step]) { + LOG_DEBUG("path mismatch at step %i", path_step); + break; + } + + path_step++; + }; + + /* walked the full path, all elements match */ + if (path_step == path_len) + result = true; + + done: + free(loc); +#endif + return result; +} + /* Helper to open a libusb device that matches vid, pid, product string and/or serial string. * Set any field to 0 as a wildcard. If the device is found true is returned, with ctx containing * the already opened handle. ctx->interface must be set to the desired interface (channel) number * prior to calling this function. */ static bool open_matching_device(struct mpsse_ctx *ctx, const uint16_t *vid, const uint16_t *pid, - const char *product, const char *serial) + const char *product, const char *serial, const char *location) { libusb_device **list; struct libusb_device_descriptor desc; @@ -117,14 +171,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; } @@ -140,6 +194,11 @@ static bool open_matching_device(struct mpsse_ctx *ctx, const uint16_t *vid, con continue; } + if (location && !device_location_equal(device, location)) { + libusb_close(ctx->usb_dev); + continue; + } + if (product && !string_descriptor_equal(ctx->usb_dev, desc.iProduct, product)) { libusb_close(ctx->usb_dev); continue; @@ -163,7 +222,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 +231,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 +247,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 +262,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; } @@ -262,7 +321,7 @@ error: } struct mpsse_ctx *mpsse_open(const uint16_t *vid, const uint16_t *pid, const char *description, - const char *serial, int channel) + const char *serial, const char *location, int channel) { struct mpsse_ctx *ctx = calloc(1, sizeof(*ctx)); int err; @@ -287,20 +346,21 @@ 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; } - if (!open_matching_device(ctx, vid, pid, description, serial)) { + if (!open_matching_device(ctx, vid, pid, description, serial, location)) { /* Four hex digits plus terminating zero each */ char vidstr[5]; char pidstr[5]; - LOG_ERROR("unable to open ftdi device with vid %s, pid %s, description '%s' and " - "serial '%s'", + LOG_ERROR("unable to open ftdi device with vid %s, pid %s, description '%s', " + "serial '%s' at bus location '%s'", vid ? sprintf(vidstr, "%04x", *vid), vidstr : "*", pid ? sprintf(pidstr, "%04x", *pid), pidstr : "*", description ? description : "*", - serial ? serial : "*"); + serial ? serial : "*", + location ? location : "*"); ctx->usb_dev = 0; goto error; } @@ -309,7 +369,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); + LOG_ERROR("unable to set latency timer: %s", libusb_error_name(err)); goto error; } @@ -322,7 +382,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; } @@ -362,18 +422,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; } } @@ -417,24 +478,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)) @@ -446,7 +511,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 */ @@ -494,21 +559,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) @@ -517,7 +585,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; @@ -548,99 +616,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) @@ -649,8 +727,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) @@ -659,8 +738,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) @@ -674,10 +754,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 */ @@ -689,9 +766,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); @@ -708,7 +783,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; @@ -746,7 +821,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; @@ -767,10 +842,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; @@ -813,7 +896,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",