aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/openocd.texi8
-rw-r--r--src/jtag/drivers/ftdi.c23
-rw-r--r--src/jtag/drivers/mpsse.c71
-rw-r--r--src/jtag/drivers/mpsse.h2
4 files changed, 96 insertions, 8 deletions
diff --git a/doc/openocd.texi b/doc/openocd.texi
index f272f21..fb987e7 100644
--- a/doc/openocd.texi
+++ b/doc/openocd.texi
@@ -2558,6 +2558,14 @@ If not specified, serial numbers are not considered.
and are not restricted to containing only decimal digits.)
@end deffn
+@deffn {Config Command} {ftdi_location} <bus>:<port>[,<port>]...
+Specifies the physical USB port of the adapter to use. The path
+roots at @var{bus} and walks down the physical ports, with each
+@var{port} option specifying a deeper level in the bus topology, the last
+@var{port} denoting where the target adapter is actually plugged.
+The USB bus topology can be queried with the command @emph{lsusb -t}.
+@end deffn
+
@deffn {Config Command} {ftdi_channel} channel
Selects the channel of the FTDI device to use for MPSSE operations. Most
adapters use the default, channel 0, but there are exceptions.
diff --git a/src/jtag/drivers/ftdi.c b/src/jtag/drivers/ftdi.c
index 7f11391..b32fa6c 100644
--- a/src/jtag/drivers/ftdi.c
+++ b/src/jtag/drivers/ftdi.c
@@ -91,6 +91,7 @@
static char *ftdi_device_desc;
static char *ftdi_serial;
+static char *ftdi_location;
static uint8_t ftdi_channel;
static uint8_t ftdi_jtag_mode = JTAG_MODE;
@@ -631,7 +632,7 @@ static int ftdi_initialize(void)
for (int i = 0; ftdi_vid[i] || ftdi_pid[i]; i++) {
mpsse_ctx = mpsse_open(&ftdi_vid[i], &ftdi_pid[i], ftdi_device_desc,
- ftdi_serial, ftdi_channel);
+ ftdi_serial, ftdi_location, ftdi_channel);
if (mpsse_ctx)
break;
}
@@ -698,6 +699,19 @@ COMMAND_HANDLER(ftdi_handle_serial_command)
return ERROR_OK;
}
+COMMAND_HANDLER(ftdi_handle_location_command)
+{
+ if (CMD_ARGC == 1) {
+ if (ftdi_location)
+ free(ftdi_location);
+ ftdi_location = strdup(CMD_ARGV[0]);
+ } else {
+ return ERROR_COMMAND_SYNTAX_ERROR;
+ }
+
+ return ERROR_OK;
+}
+
COMMAND_HANDLER(ftdi_handle_channel_command)
{
if (CMD_ARGC == 1)
@@ -876,6 +890,13 @@ static const struct command_registration ftdi_command_handlers[] = {
.usage = "serial_string",
},
{
+ .name = "ftdi_location",
+ .handler = &ftdi_handle_location_command,
+ .mode = COMMAND_CONFIG,
+ .help = "set the USB bus location of the FTDI device",
+ .usage = "<bus>:port[,port]...",
+ },
+ {
.name = "ftdi_channel",
.handler = &ftdi_handle_channel_command,
.mode = COMMAND_CONFIG,
diff --git a/src/jtag/drivers/mpsse.c b/src/jtag/drivers/mpsse.c
index d9f73a2..a3820a2 100644
--- a/src/jtag/drivers/mpsse.c
+++ b/src/jtag/drivers/mpsse.c
@@ -104,12 +104,65 @@ static bool string_descriptor_equal(libusb_device_handle *device, uint8_t str_in
return strncmp(string, desc_string, sizeof(desc_string)) == 0;
}
+static bool device_location_equal(libusb_device *device, const char *location)
+{
+ 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;
+ bool result = false;
+
+ 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);
+ 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;
@@ -141,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;
@@ -263,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;
@@ -292,16 +350,17 @@ struct mpsse_ctx *mpsse_open(const uint16_t *vid, const uint16_t *pid, const cha
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;
}
diff --git a/src/jtag/drivers/mpsse.h b/src/jtag/drivers/mpsse.h
index 3e287f7..4c06bbd 100644
--- a/src/jtag/drivers/mpsse.h
+++ b/src/jtag/drivers/mpsse.h
@@ -43,7 +43,7 @@ struct mpsse_ctx;
/* Device handling */
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);
void mpsse_close(struct mpsse_ctx *ctx);
bool mpsse_is_high_speed(struct mpsse_ctx *ctx);