diff --git a/src/jtag/adapter.c b/src/jtag/adapter.c index 2035788bf..3fb52a71e 100644 --- a/src/jtag/adapter.c +++ b/src/jtag/adapter.c @@ -35,6 +35,7 @@ #include "interface.h" #include "interfaces.h" #include +#include #ifdef HAVE_STRINGS_H #include @@ -456,7 +457,54 @@ COMMAND_HANDLER(handle_adapter_khz_command) return retval; } +#ifndef HAVE_JTAG_MINIDRIVER_H +#ifdef HAVE_LIBUSB_GET_PORT_NUMBERS +COMMAND_HANDLER(handle_usb_location_command) +{ + if (CMD_ARGC == 1) + jtag_usb_set_location(CMD_ARGV[0]); + + command_print(CMD_CTX, "adapter usb location: %s", jtag_usb_get_location()); + + return ERROR_OK; +} +#endif /* HAVE_LIBUSB_GET_PORT_NUMBERS */ + +static const struct command_registration adapter_usb_command_handlers[] = { +#ifdef HAVE_LIBUSB_GET_PORT_NUMBERS + { + .name = "location", + .handler = &handle_usb_location_command, + .mode = COMMAND_CONFIG, + .help = "set the USB bus location of the USB device", + .usage = "-port[.port]...", + }, +#endif /* HAVE_LIBUSB_GET_PORT_NUMBERS */ + COMMAND_REGISTRATION_DONE +}; +#endif /* MINIDRIVER */ + +static const struct command_registration adapter_command_handlers[] = { +#ifndef HAVE_JTAG_MINIDRIVER_H + { + .name = "usb", + .mode = COMMAND_ANY, + .help = "usb adapter command group", + .usage = "", + .chain = adapter_usb_command_handlers, + }, +#endif /* MINIDRIVER */ + COMMAND_REGISTRATION_DONE +}; + static const struct command_registration interface_command_handlers[] = { + { + .name = "adapter", + .mode = COMMAND_ANY, + .help = "adapter command group", + .usage = "", + .chain = adapter_command_handlers, + }, { .name = "adapter_khz", .handler = handle_adapter_khz_command, diff --git a/src/jtag/drivers/Makefile.am b/src/jtag/drivers/Makefile.am index ccef018b8..572cd2441 100644 --- a/src/jtag/drivers/Makefile.am +++ b/src/jtag/drivers/Makefile.am @@ -19,6 +19,7 @@ DRIVERFILES = # Standard Driver: common files DRIVERFILES += %D%/driver.c +DRIVERFILES += %D%/jtag_usb_common.c if USE_LIBUSB1 DRIVERFILES += %D%/libusb1_common.c @@ -166,6 +167,7 @@ endif DRIVERHEADERS = \ %D%/bitbang.h \ %D%/bitq.h \ + %D%/jtag_usb_common.h \ %D%/libusb0_common.h \ %D%/libusb1_common.h \ %D%/libusb_common.h \ diff --git a/src/jtag/drivers/jtag_usb_common.c b/src/jtag/drivers/jtag_usb_common.c new file mode 100644 index 000000000..637e6c7f2 --- /dev/null +++ b/src/jtag/drivers/jtag_usb_common.c @@ -0,0 +1,85 @@ +/* + * SPDX-License-Identifier: GPL-2.0+ + * Copyright (c) 2018 Pengutronix, Oleksij Rempel + */ + +#include + +#include "jtag_usb_common.h" + +static char *jtag_usb_location; +/* + * 1 char: bus + * 2 * 7 chars: max 7 ports + * 1 char: test for overflow + * ------ + * 16 chars + */ +#define JTAG_USB_MAX_LOCATION_LENGHT 16 + +void jtag_usb_set_location(const char *location) +{ + if (strnlen(location, JTAG_USB_MAX_LOCATION_LENGHT) == + JTAG_USB_MAX_LOCATION_LENGHT) + LOG_WARNING("usb location string is too long!!\n"); + + if (jtag_usb_location) + free(jtag_usb_location); + + jtag_usb_location = strndup(location, JTAG_USB_MAX_LOCATION_LENGHT); +} + +const char *jtag_usb_get_location(void) +{ + return jtag_usb_location; +} + +bool jtag_usb_location_equal(uint8_t dev_bus, uint8_t *port_path, + size_t path_len) +{ + size_t path_step, string_lengh; + char *ptr, *loc; + bool equal = false; + + /* strtok need non const char */ + loc = strndup(jtag_usb_get_location(), JTAG_USB_MAX_LOCATION_LENGHT); + string_lengh = strnlen(loc, JTAG_USB_MAX_LOCATION_LENGHT); + + ptr = strtok(loc, "-"); + if (ptr == NULL) { + LOG_WARNING("no '-' in usb path\n"); + goto done; + } + + string_lengh -= 1; + /* check bus mismatch */ + if (atoi(ptr) != dev_bus) + goto done; + + path_step = 0; + while (path_step < path_len) { + ptr = strtok(NULL, "."); + + /* no more tokens in path */ + if (ptr == NULL) + break; + + /* path mismatch at some step */ + if (path_step < path_len && atoi(ptr) != port_path[path_step]) + break; + + path_step++; + string_lengh -= 2; + }; + + /* walked the full path, all elements match */ + if (path_step == path_len && !string_lengh) + equal = true; + else + LOG_WARNING("excluded by device path option: %s\n", + jtag_usb_get_location()); + +done: + free(loc); + return equal; +} diff --git a/src/jtag/drivers/jtag_usb_common.h b/src/jtag/drivers/jtag_usb_common.h new file mode 100644 index 000000000..8c03742e9 --- /dev/null +++ b/src/jtag/drivers/jtag_usb_common.h @@ -0,0 +1,14 @@ +/* + * SPDX-License-Identifier: GPL-2.0+ + * Copyright (c) 2018 Pengutronix, Oleksij Rempel + */ + +#ifndef OPENOCD_JTAG_USB_COMMON_H +#define OPENOCD_JTAG_USB_COMMON_H + +void jtag_usb_set_location(const char *location); +const char *jtag_usb_get_location(void); +bool jtag_usb_location_equal(uint8_t dev_bus, uint8_t *port_path, + size_t path_len); + +#endif /* OPENOCD_JTAG_USB_COMMON_H */ diff --git a/src/jtag/drivers/libusb1_common.c b/src/jtag/drivers/libusb1_common.c index ec52a1bce..d96ac7692 100644 --- a/src/jtag/drivers/libusb1_common.c +++ b/src/jtag/drivers/libusb1_common.c @@ -20,8 +20,15 @@ #ifdef HAVE_CONFIG_H #include "config.h" #endif -#include "log.h" +#include #include "libusb1_common.h" +#include "log.h" + +/* + * comment from libusb: + * As per the USB 3.0 specs, the current maximum limit for the depth is 7. + */ +#define MAX_USB_PORTS 7 static struct libusb_context *jtag_libusb_context; /**< Libusb context **/ static libusb_device **devs; /**< The usb device list **/ @@ -38,6 +45,31 @@ static bool jtag_libusb_match(struct libusb_device_descriptor *dev_desc, return false; } +#ifdef HAVE_LIBUSB_GET_PORT_NUMBERS +static bool jtag_libusb_location_equal(libusb_device *device) +{ + uint8_t port_path[MAX_USB_PORTS]; + uint8_t dev_bus; + int path_len; + + path_len = libusb_get_port_numbers(device, port_path, MAX_USB_PORTS); + if (path_len == LIBUSB_ERROR_OVERFLOW) { + LOG_WARNING("cannot determine path to usb device! (more than %i ports in path)\n", + MAX_USB_PORTS); + return false; + } + dev_bus = libusb_get_bus_number(device); + + return jtag_usb_location_equal(dev_bus, port_path, path_len); +} +#else /* HAVE_LIBUSB_GET_PORT_NUMBERS */ +static bool jtag_libusb_location_equal(libusb_device *device) +{ + return true; +} +#endif /* HAVE_LIBUSB_GET_PORT_NUMBERS */ + + /* Returns true if the string descriptor indexed by str_index in device matches string */ static bool string_descriptor_equal(libusb_device_handle *device, uint8_t str_index, const char *string) @@ -89,6 +121,9 @@ int jtag_libusb_open(const uint16_t vids[], const uint16_t pids[], if (!jtag_libusb_match(&dev_desc, vids, pids)) continue; + if (jtag_usb_get_location() && !jtag_libusb_location_equal(devs[idx])) + continue; + errCode = libusb_open(devs[idx], &libusb_handle); if (errCode) {