]> git.sur5r.net Git - openocd/commitdiff
ftdi: allow selecting device by usb bus location
authorMatthias Welwarsky <matthias.welwarsky@sysgo.com>
Tue, 2 Feb 2016 16:03:08 +0000 (17:03 +0100)
committerPaul Fertser <fercerpav@gmail.com>
Thu, 24 Mar 2016 08:52:14 +0000 (08:52 +0000)
This patch adds a 'ftdi_location' command to select an adapter by usb
bus number and port path.

This is helpful if you have a rack full of adapters in a testing or
manufacturing setup where the only constant is the physical usb bus
location of the adapter you want to address. Vid:Pid are not unique,
serial number _may_ be unique (and maybe not with embedded adapters) but
will change when a new target is plugged.

Specifying a location allows to understand instantly which board failed
bringup or testing.

Change-Id: I403c7c6c8e34fe42041b3f967db80f3160a4f1a3
Signed-off-by: Matthias Welwarsky <matthias.welwarsky@sysgo.com>
Reviewed-on: http://openocd.zylin.com/3351
Tested-by: jenkins
Reviewed-by: Paul Fertser <fercerpav@gmail.com>
doc/openocd.texi
src/jtag/drivers/ftdi.c
src/jtag/drivers/mpsse.c
src/jtag/drivers/mpsse.h

index f272f21988038d0bb84c1e0f3cca771056344f37..fb987e72772ca85c68fbd32e0bf2a1b265a7c653 100644 (file)
@@ -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.
index 7f113918a2eb9f44503a4ddd178a1fb43dee0188..b32fa6cb2338b545a3214998e6529cd9f608d8de 100644 (file)
@@ -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)
@@ -875,6 +889,13 @@ static const struct command_registration ftdi_command_handlers[] = {
                .help = "set the serial number of the FTDI device",
                .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,
index d9f73a2a794a790ae9a518be48964f74da69d2ba..a3820a2266890dd279d0cc04bfbc3232958d9c74 100644 (file)
@@ -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;
        }
index 3e287f75a6cb07684633b96f52d6d1cdb3e8545e..4c06bbdea9d104df2ecf2ded1551e8bec771ca23 100644 (file)
@@ -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);