ftdi: make ftdi_location command depend on libusb1 version
[fw/openocd] / src / jtag / drivers / mpsse.c
index c5e0b61c10a54b05a6259627b55fd9f1531003f4..0d19f388c634e98e44cf966b9202c1459d151c81 100644 (file)
@@ -98,18 +98,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;
@@ -118,14 +173,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;
                }
 
@@ -141,6 +196,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;
@@ -164,7 +224,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;
        }
@@ -173,14 +233,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;
                }
        }
@@ -189,13 +249,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;
        }
 
@@ -204,7 +264,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;
        }
 
@@ -263,7 +323,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;
@@ -288,20 +348,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;
        }
@@ -310,7 +371,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;
        }
 
@@ -323,7 +384,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;
        }
 
@@ -368,14 +429,14 @@ void mpsse_purge(struct mpsse_ctx *ctx)
        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;
        }
 }
@@ -724,7 +785,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;
@@ -762,7 +823,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;
@@ -837,7 +898,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",