adapter: run at default speed when clock speed not specified
[fw/openocd] / src / jtag / adapter.c
index 2035788bf38a5f8db822c6ae20b1740008b3c6cc..519505dc32466fd68b538fc79b4e9dea79fddaab 100644 (file)
@@ -1,35 +1,17 @@
-/***************************************************************************
- *   Copyright (C) 2005 by Dominic Rath                                    *
- *   Dominic.Rath@gmx.de                                                   *
- *                                                                         *
- *   Copyright (C) 2007-2010 Øyvind Harboe                                 *
- *   oyvind.harboe@zylin.com                                               *
- *                                                                         *
- *   Copyright (C) 2009 SoftPLC Corporation                                *
- *       http://softplc.com                                                *
- *   dick@softplc.com                                                      *
- *                                                                         *
- *   Copyright (C) 2009 Zachary T Welch                                    *
- *   zw@superlucidity.net                                                  *
- *                                                                         *
- *   This program is free software; you can redistribute it and/or modify  *
- *   it under the terms of the GNU General Public License as published by  *
- *   the Free Software Foundation; either version 2 of the License, or     *
- *   (at your option) any later version.                                   *
- *                                                                         *
- *   This program is distributed in the hope that it will be useful,       *
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
- *   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, see <http://www.gnu.org/licenses/>. *
- ***************************************************************************/
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (C) 2005 by Dominic Rath <Dominic.Rath@gmx.de>
+ * Copyright (C) 2007-2010 Øyvind Harboe <oyvind.harboe@zylin.com>
+ * Copyright (C) 2009 SoftPLC Corporation, http://softplc.com, Dick Hollenbeck <dick@softplc.com>
+ * Copyright (C) 2009 Zachary T Welch <zw@superlucidity.net>
+ * Copyright (C) 2018 Pengutronix, Oleksij Rempel <kernel@pengutronix.de>
+ */
 
 #ifdef HAVE_CONFIG_H
 #include "config.h"
 #endif
 
+#include "adapter.h"
 #include "jtag.h"
 #include "minidriver.h"
 #include "interface.h"
  * Holds support for configuring debug adapters from TCl scripts.
  */
 
-extern struct jtag_interface *jtag_interface;
+struct adapter_driver *adapter_driver;
 const char * const jtag_only[] = { "jtag", NULL };
 
-static int jim_adapter_name(Jim_Interp *interp, int argc, Jim_Obj * const *argv)
+enum adapter_clk_mode {
+       CLOCK_MODE_UNSELECTED = 0,
+       CLOCK_MODE_KHZ,
+       CLOCK_MODE_RCLK
+};
+
+#define DEFAULT_CLOCK_SPEED_KHZ                100U
+
+/**
+ * Adapter configuration
+ */
+static struct {
+       bool adapter_initialized;
+       char *usb_location;
+       char *serial;
+       enum adapter_clk_mode clock_mode;
+       int speed_khz;
+       int rclk_fallback_speed_khz;
+} adapter_config;
+
+bool is_adapter_initialized(void)
 {
-       Jim_GetOptInfo goi;
-       Jim_GetOpt_Setup(&goi, interp, argc-1, argv + 1);
+       return adapter_config.adapter_initialized;
+}
 
-       /* return the name of the interface */
-       /* TCL code might need to know the exact type... */
-       /* FUTURE: we allow this as a means to "set" the interface. */
-       if (goi.argc != 0) {
-               Jim_WrongNumArgs(goi.interp, 1, goi.argv-1, "(no params)");
-               return JIM_ERR;
+/**
+ * Do low-level setup like initializing registers, output signals,
+ * and clocking.
+ */
+int adapter_init(struct command_context *cmd_ctx)
+{
+       if (is_adapter_initialized())
+               return ERROR_OK;
+
+       if (!adapter_driver) {
+               /* nothing was previously specified by "adapter driver" command */
+               LOG_ERROR("Debug Adapter has to be specified, "
+                       "see \"adapter driver\" command");
+               return ERROR_JTAG_INVALID_INTERFACE;
        }
-       const char *name = jtag_interface ? jtag_interface->name : NULL;
-       Jim_SetResultString(goi.interp, name ? : "undefined", -1);
-       return JIM_OK;
+
+       int retval;
+
+       if (adapter_config.clock_mode == CLOCK_MODE_UNSELECTED) {
+               LOG_WARNING("An adapter speed is not selected in the init scripts."
+                       " OpenOCD will try to run the adapter at the low speed (%d kHz)",
+                       DEFAULT_CLOCK_SPEED_KHZ);
+               LOG_WARNING("To remove this warnings and achieve reasonable communication speed with the target,"
+                   " set \"adapter speed\" or \"jtag_rclk\" in the init scripts.");
+               retval = adapter_config_khz(DEFAULT_CLOCK_SPEED_KHZ);
+               if (retval != ERROR_OK)
+                       return ERROR_JTAG_INIT_FAILED;
+       }
+
+       retval = adapter_driver->init();
+       if (retval != ERROR_OK)
+               return retval;
+       adapter_config.adapter_initialized = true;
+
+       if (!adapter_driver->speed) {
+               LOG_INFO("This adapter doesn't support configurable speed");
+               return ERROR_OK;
+       }
+
+       int requested_khz = adapter_get_speed_khz();
+       int actual_khz = requested_khz;
+       int speed_var = 0;
+       retval = adapter_get_speed(&speed_var);
+       if (retval != ERROR_OK)
+               return retval;
+       retval = adapter_driver->speed(speed_var);
+       if (retval != ERROR_OK)
+               return retval;
+       retval = adapter_get_speed_readable(&actual_khz);
+       if (retval != ERROR_OK)
+               LOG_INFO("adapter-specific clock speed value %d", speed_var);
+       else if (actual_khz) {
+               /* Adaptive clocking -- JTAG-specific */
+               if ((adapter_config.clock_mode == CLOCK_MODE_RCLK)
+                               || ((adapter_config.clock_mode == CLOCK_MODE_KHZ) && !requested_khz)) {
+                       LOG_INFO("RCLK (adaptive clock speed) not supported - fallback to %d kHz"
+                       , actual_khz);
+               } else
+                       LOG_INFO("clock speed %d kHz", actual_khz);
+       } else
+               LOG_INFO("RCLK (adaptive clock speed)");
+
+       return ERROR_OK;
 }
 
-static int default_khz(int khz, int *jtag_speed)
+int adapter_quit(void)
 {
-       LOG_ERROR("Translation from khz to jtag_speed not implemented");
-       return ERROR_FAIL;
+       if (is_adapter_initialized() && adapter_driver->quit) {
+               /* close the JTAG interface */
+               int result = adapter_driver->quit();
+               if (result != ERROR_OK)
+                       LOG_ERROR("failed: %d", result);
+       }
+
+       free(adapter_config.serial);
+       free(adapter_config.usb_location);
+
+       struct jtag_tap *t = jtag_all_taps();
+       while (t) {
+               struct jtag_tap *n = t->next_tap;
+               jtag_tap_free(t);
+               t = n;
+       }
+
+       return ERROR_OK;
 }
 
-static int default_speed_div(int speed, int *khz)
+unsigned int adapter_get_speed_khz(void)
 {
-       LOG_ERROR("Translation from jtag_speed to khz not implemented");
-       return ERROR_FAIL;
+       return adapter_config.speed_khz;
 }
 
-static int default_power_dropout(int *dropout)
+static int adapter_khz_to_speed(unsigned int khz, int *speed)
 {
-       *dropout = 0; /* by default we can't detect power dropout */
+       LOG_DEBUG("convert khz to adapter specific speed value");
+       adapter_config.speed_khz = khz;
+       if (!is_adapter_initialized())
+               return ERROR_OK;
+       LOG_DEBUG("have adapter set up");
+       if (!adapter_driver->khz) {
+               LOG_ERROR("Translation from khz to adapter speed not implemented");
+               return ERROR_FAIL;
+       }
+       int speed_div1;
+       int retval = adapter_driver->khz(adapter_get_speed_khz(), &speed_div1);
+       if (retval != ERROR_OK)
+               return retval;
+       *speed = speed_div1;
        return ERROR_OK;
 }
 
-static int default_srst_asserted(int *srst_asserted)
+static int adapter_rclk_to_speed(unsigned int fallback_speed_khz, int *speed)
+{
+       int retval = adapter_khz_to_speed(0, speed);
+       if ((retval != ERROR_OK) && fallback_speed_khz) {
+               LOG_DEBUG("trying fallback speed...");
+               retval = adapter_khz_to_speed(fallback_speed_khz, speed);
+       }
+       return retval;
+}
+
+static int adapter_set_speed(int speed)
 {
-       *srst_asserted = 0; /* by default we can't detect srst asserted */
+       /* this command can be called during CONFIG,
+        * in which case adapter isn't initialized */
+       return is_adapter_initialized() ? adapter_driver->speed(speed) : ERROR_OK;
+}
+
+int adapter_config_khz(unsigned int khz)
+{
+       LOG_DEBUG("handle adapter khz");
+       adapter_config.clock_mode = CLOCK_MODE_KHZ;
+       int speed = 0;
+       int retval = adapter_khz_to_speed(khz, &speed);
+       return (retval != ERROR_OK) ? retval : adapter_set_speed(speed);
+}
+
+int adapter_config_rclk(unsigned int fallback_speed_khz)
+{
+       LOG_DEBUG("handle adapter rclk");
+       adapter_config.clock_mode = CLOCK_MODE_RCLK;
+       adapter_config.rclk_fallback_speed_khz = fallback_speed_khz;
+       int speed = 0;
+       int retval = adapter_rclk_to_speed(fallback_speed_khz, &speed);
+       return (retval != ERROR_OK) ? retval : adapter_set_speed(speed);
+}
+
+int adapter_get_speed(int *speed)
+{
+       switch (adapter_config.clock_mode) {
+               case CLOCK_MODE_KHZ:
+                       adapter_khz_to_speed(adapter_get_speed_khz(), speed);
+                       break;
+               case CLOCK_MODE_RCLK:
+                       adapter_rclk_to_speed(adapter_config.rclk_fallback_speed_khz, speed);
+                       break;
+               default:
+                       LOG_ERROR("BUG: unknown adapter clock mode");
+                       return ERROR_FAIL;
+       }
        return ERROR_OK;
 }
 
-COMMAND_HANDLER(interface_transport_command)
+int adapter_get_speed_readable(int *khz)
+{
+       int speed_var = 0;
+       int retval = adapter_get_speed(&speed_var);
+       if (retval != ERROR_OK)
+               return retval;
+       if (!is_adapter_initialized())
+               return ERROR_OK;
+       if (!adapter_driver->speed_div) {
+               LOG_ERROR("Translation from adapter speed to khz not implemented");
+               return ERROR_FAIL;
+       }
+       return adapter_driver->speed_div(speed_var, khz);
+}
+
+const char *adapter_get_required_serial(void)
+{
+       return adapter_config.serial;
+}
+
+/*
+ * 1 char: bus
+ * 2 * 7 chars: max 7 ports
+ * 1 char: test for overflow
+ * ------
+ * 16 chars
+ */
+#define USB_MAX_LOCATION_LENGTH         16
+
+#ifdef HAVE_LIBUSB_GET_PORT_NUMBERS
+static void adapter_usb_set_location(const char *location)
+{
+       if (strnlen(location, USB_MAX_LOCATION_LENGTH) == USB_MAX_LOCATION_LENGTH)
+               LOG_WARNING("usb location string is too long!!");
+
+       free(adapter_config.usb_location);
+
+       adapter_config.usb_location = strndup(location, USB_MAX_LOCATION_LENGTH);
+}
+#endif /* HAVE_LIBUSB_GET_PORT_NUMBERS */
+
+const char *adapter_usb_get_location(void)
+{
+       return adapter_config.usb_location;
+}
+
+bool adapter_usb_location_equal(uint8_t dev_bus, uint8_t *port_path, size_t path_len)
+{
+       size_t path_step, string_length;
+       char *ptr, *loc;
+       bool equal = false;
+
+       if (!adapter_usb_get_location())
+               return equal;
+
+       /* strtok need non const char */
+       loc = strndup(adapter_usb_get_location(), USB_MAX_LOCATION_LENGTH);
+       string_length = strnlen(loc, USB_MAX_LOCATION_LENGTH);
+
+       ptr = strtok(loc, "-");
+       if (!ptr) {
+               LOG_WARNING("no '-' in usb path\n");
+               goto done;
+       }
+
+       string_length -= strnlen(ptr, string_length);
+       /* 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)
+                       break;
+
+               /* path mismatch at some step */
+               if (path_step < path_len && atoi(ptr) != port_path[path_step])
+                       break;
+
+               path_step++;
+               string_length -= strnlen(ptr, string_length) + 1;
+       };
+
+       /* walked the full path, all elements match */
+       if (path_step == path_len && !string_length)
+               equal = true;
+
+done:
+       free(loc);
+       return equal;
+}
+
+static int jim_adapter_name(Jim_Interp *interp, int argc, Jim_Obj * const *argv)
+{
+       struct jim_getopt_info goi;
+       jim_getopt_setup(&goi, interp, argc-1, argv + 1);
+
+       /* return the name of the interface */
+       /* TCL code might need to know the exact type... */
+       /* FUTURE: we allow this as a means to "set" the interface. */
+       if (goi.argc != 0) {
+               Jim_WrongNumArgs(goi.interp, 1, goi.argv-1, "(no params)");
+               return JIM_ERR;
+       }
+       const char *name = adapter_driver ? adapter_driver->name : NULL;
+       Jim_SetResultString(goi.interp, name ? name : "undefined", -1);
+       return JIM_OK;
+}
+
+COMMAND_HANDLER(adapter_transports_command)
 {
        char **transports;
        int retval;
@@ -108,26 +349,26 @@ COMMAND_HANDLER(interface_transport_command)
        return retval;
 }
 
-COMMAND_HANDLER(handle_interface_list_command)
+COMMAND_HANDLER(handle_adapter_list_command)
 {
-       if (strcmp(CMD_NAME, "interface_list") == 0 && CMD_ARGC > 0)
+       if (strcmp(CMD_NAME, "list") == 0 && CMD_ARGC > 0)
                return ERROR_COMMAND_SYNTAX_ERROR;
 
-       command_print(CMD_CTX, "The following debug interfaces are available:");
-       for (unsigned i = 0; NULL != jtag_interfaces[i]; i++) {
-               const char *name = jtag_interfaces[i]->name;
-               command_print(CMD_CTX, "%u: %s", i + 1, name);
+       command_print(CMD, "The following debug adapters are available:");
+       for (unsigned i = 0; adapter_drivers[i]; i++) {
+               const char *name = adapter_drivers[i]->name;
+               command_print(CMD, "%u: %s", i + 1, name);
        }
 
        return ERROR_OK;
 }
 
-COMMAND_HANDLER(handle_interface_command)
+COMMAND_HANDLER(handle_adapter_driver_command)
 {
        int retval;
 
        /* check whether the interface is already configured */
-       if (jtag_interface) {
+       if (adapter_driver) {
                LOG_WARNING("Interface already configured, ignoring");
                return ERROR_OK;
        }
@@ -136,42 +377,19 @@ COMMAND_HANDLER(handle_interface_command)
        if (CMD_ARGC != 1 || CMD_ARGV[0][0] == '\0')
                return ERROR_COMMAND_SYNTAX_ERROR;
 
-       for (unsigned i = 0; NULL != jtag_interfaces[i]; i++) {
-               if (strcmp(CMD_ARGV[0], jtag_interfaces[i]->name) != 0)
+       for (unsigned i = 0; adapter_drivers[i]; i++) {
+               if (strcmp(CMD_ARGV[0], adapter_drivers[i]->name) != 0)
                        continue;
 
-               if (NULL != jtag_interfaces[i]->commands) {
-                       retval = register_commands(CMD_CTX, NULL,
-                                       jtag_interfaces[i]->commands);
-                       if (ERROR_OK != retval)
+               if (adapter_drivers[i]->commands) {
+                       retval = register_commands(CMD_CTX, NULL, adapter_drivers[i]->commands);
+                       if (retval != ERROR_OK)
                                return retval;
                }
 
-               jtag_interface = jtag_interfaces[i];
-
-               /* LEGACY SUPPORT ... adapter drivers  must declare what
-                * transports they allow.  Until they all do so, assume
-                * the legacy drivers are JTAG-only
-                */
-               if (!jtag_interface->transports)
-                       LOG_WARNING("Adapter driver '%s' did not declare "
-                               "which transports it allows; assuming "
-                               "legacy JTAG-only", jtag_interface->name);
-               retval = allow_transports(CMD_CTX, jtag_interface->transports
-                                               ? jtag_interface->transports : jtag_only);
-                       if (ERROR_OK != retval)
-                               return retval;
+               adapter_driver = adapter_drivers[i];
 
-               if (jtag_interface->khz == NULL)
-                       jtag_interface->khz = default_khz;
-               if (jtag_interface->speed_div == NULL)
-                       jtag_interface->speed_div = default_speed_div;
-               if (jtag_interface->power_dropout == NULL)
-                       jtag_interface->power_dropout = default_power_dropout;
-               if (jtag_interface->srst_asserted == NULL)
-                       jtag_interface->srst_asserted = default_srst_asserted;
-
-               return ERROR_OK;
+               return allow_transports(CMD_CTX, adapter_driver->transports);
        }
 
        /* no valid interface was found (i.e. the configuration option,
@@ -179,7 +397,7 @@ COMMAND_HANDLER(handle_interface_command)
         */
        LOG_ERROR("The specified debug interface was not found (%s)",
                                CMD_ARGV[0]);
-       CALL_COMMAND_HANDLER(handle_interface_list_command);
+       CALL_COMMAND_HANDLER(handle_adapter_list_command);
        return ERROR_JTAG_INVALID_INTERFACE;
 }
 
@@ -393,14 +611,14 @@ next:
                modes[5] = "";
        }
 
-       command_print(CMD_CTX, "%s %s%s%s%s%s",
+       command_print(CMD, "%s %s%s%s%s%s",
                        modes[0], modes[1],
                        modes[2], modes[3], modes[4], modes[5]);
 
        return ERROR_OK;
 }
 
-COMMAND_HANDLER(handle_adapter_nsrst_delay_command)
+COMMAND_HANDLER(handle_adapter_srst_delay_command)
 {
        if (CMD_ARGC > 1)
                return ERROR_COMMAND_SYNTAX_ERROR;
@@ -410,11 +628,11 @@ COMMAND_HANDLER(handle_adapter_nsrst_delay_command)
 
                jtag_set_nsrst_delay(delay);
        }
-       command_print(CMD_CTX, "adapter_nsrst_delay: %u", jtag_get_nsrst_delay());
+       command_print(CMD, "adapter srst delay: %u", jtag_get_nsrst_delay());
        return ERROR_OK;
 }
 
-COMMAND_HANDLER(handle_adapter_nsrst_assert_width_command)
+COMMAND_HANDLER(handle_adapter_srst_pulse_width_command)
 {
        if (CMD_ARGC > 1)
                return ERROR_COMMAND_SYNTAX_ERROR;
@@ -424,11 +642,11 @@ COMMAND_HANDLER(handle_adapter_nsrst_assert_width_command)
 
                jtag_set_nsrst_assert_width(width);
        }
-       command_print(CMD_CTX, "adapter_nsrst_assert_width: %u", jtag_get_nsrst_assert_width());
+       command_print(CMD, "adapter srst pulse_width: %u", jtag_get_nsrst_assert_width());
        return ERROR_OK;
 }
 
-COMMAND_HANDLER(handle_adapter_khz_command)
+COMMAND_HANDLER(handle_adapter_speed_command)
 {
        if (CMD_ARGC > 1)
                return ERROR_COMMAND_SYNTAX_ERROR;
@@ -438,75 +656,247 @@ COMMAND_HANDLER(handle_adapter_khz_command)
                unsigned khz = 0;
                COMMAND_PARSE_NUMBER(uint, CMD_ARGV[0], khz);
 
-               retval = jtag_config_khz(khz);
-               if (ERROR_OK != retval)
+               retval = adapter_config_khz(khz);
+               if (retval != ERROR_OK)
                        return retval;
        }
 
-       int cur_speed = jtag_get_speed_khz();
-       retval = jtag_get_speed_readable(&cur_speed);
-       if (ERROR_OK != retval)
+       int cur_speed = adapter_get_speed_khz();
+       retval = adapter_get_speed_readable(&cur_speed);
+       if (retval != ERROR_OK)
                return retval;
 
        if (cur_speed)
-               command_print(CMD_CTX, "adapter speed: %d kHz", cur_speed);
+               command_print(CMD, "adapter speed: %d kHz", cur_speed);
        else
-               command_print(CMD_CTX, "adapter speed: RCLK - adaptive");
+               command_print(CMD, "adapter speed: RCLK - adaptive");
 
        return retval;
 }
 
-static const struct command_registration interface_command_handlers[] = {
+COMMAND_HANDLER(handle_adapter_serial_command)
+{
+       if (CMD_ARGC != 1)
+               return ERROR_COMMAND_SYNTAX_ERROR;
+
+       free(adapter_config.serial);
+       adapter_config.serial = strdup(CMD_ARGV[0]);
+       return ERROR_OK;
+}
+
+COMMAND_HANDLER(handle_adapter_reset_de_assert)
+{
+       enum values {
+               VALUE_UNDEFINED = -1,
+               VALUE_DEASSERT  = 0,
+               VALUE_ASSERT    = 1,
+       };
+       enum values value;
+       enum values srst = VALUE_UNDEFINED;
+       enum values trst = VALUE_UNDEFINED;
+       enum reset_types jtag_reset_config = jtag_get_reset_config();
+       char *signal;
+
+       if (CMD_ARGC == 0) {
+               if (transport_is_jtag()) {
+                       if (jtag_reset_config & RESET_HAS_TRST)
+                               signal = jtag_get_trst() ? "asserted" : "deasserted";
+                       else
+                               signal = "not present";
+                       command_print(CMD, "trst %s", signal);
+               }
+
+               if (jtag_reset_config & RESET_HAS_SRST)
+                       signal = jtag_get_srst() ? "asserted" : "deasserted";
+               else
+                       signal = "not present";
+               command_print(CMD, "srst %s", signal);
+
+               return ERROR_OK;
+       }
+
+       if (CMD_ARGC != 1 && CMD_ARGC != 3)
+               return ERROR_COMMAND_SYNTAX_ERROR;
+
+       value = (strcmp(CMD_NAME, "assert") == 0) ? VALUE_ASSERT : VALUE_DEASSERT;
+       if (strcmp(CMD_ARGV[0], "srst") == 0)
+               srst = value;
+       else if (strcmp(CMD_ARGV[0], "trst") == 0)
+               trst = value;
+       else
+               return ERROR_COMMAND_SYNTAX_ERROR;
+
+       if (CMD_ARGC == 3) {
+               if (strcmp(CMD_ARGV[1], "assert") == 0)
+                       value = VALUE_ASSERT;
+               else if (strcmp(CMD_ARGV[1], "deassert") == 0)
+                       value = VALUE_DEASSERT;
+               else
+                       return ERROR_COMMAND_SYNTAX_ERROR;
+
+               if (strcmp(CMD_ARGV[2], "srst") == 0 && srst == VALUE_UNDEFINED)
+                       srst = value;
+               else if (strcmp(CMD_ARGV[2], "trst") == 0 && trst == VALUE_UNDEFINED)
+                       trst = value;
+               else
+                       return ERROR_COMMAND_SYNTAX_ERROR;
+       }
+
+       if (trst == VALUE_UNDEFINED) {
+               if (transport_is_jtag())
+                       trst = jtag_get_trst() ? VALUE_ASSERT : VALUE_DEASSERT;
+               else
+                       trst = VALUE_DEASSERT; /* unused, safe value */
+       }
+
+       if (srst == VALUE_UNDEFINED) {
+               if (jtag_reset_config & RESET_HAS_SRST)
+                       srst = jtag_get_srst() ? VALUE_ASSERT : VALUE_DEASSERT;
+               else
+                       srst = VALUE_DEASSERT; /* unused, safe value */
+       }
+
+       if (trst == VALUE_ASSERT && !transport_is_jtag()) {
+               LOG_ERROR("transport has no trst signal");
+               return ERROR_FAIL;
+       }
+
+       if (srst == VALUE_ASSERT && !(jtag_reset_config & RESET_HAS_SRST)) {
+               LOG_ERROR("adapter has no srst signal");
+               return ERROR_FAIL;
+       }
+
+       return adapter_resets((trst == VALUE_DEASSERT) ? TRST_DEASSERT : TRST_ASSERT,
+                                                 (srst == VALUE_DEASSERT) ? SRST_DEASSERT : SRST_ASSERT);
+}
+
+#ifdef HAVE_LIBUSB_GET_PORT_NUMBERS
+COMMAND_HANDLER(handle_usb_location_command)
+{
+       if (CMD_ARGC == 1)
+               adapter_usb_set_location(CMD_ARGV[0]);
+
+       command_print(CMD, "adapter usb location: %s", adapter_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 = "display or set the USB bus location of the USB device",
+               .usage = "[<bus>-port[.port]...]",
+       },
+#endif /* HAVE_LIBUSB_GET_PORT_NUMBERS */
+       COMMAND_REGISTRATION_DONE
+};
+
+static const struct command_registration adapter_srst_command_handlers[] = {
+       {
+               .name = "delay",
+               .handler = handle_adapter_srst_delay_command,
+               .mode = COMMAND_ANY,
+               .help = "delay after deasserting SRST in ms",
+               .usage = "[milliseconds]",
+       },
+       {
+               .name = "pulse_width",
+               .handler = handle_adapter_srst_pulse_width_command,
+               .mode = COMMAND_ANY,
+               .help = "SRST assertion pulse width in ms",
+               .usage = "[milliseconds]",
+       },
+       COMMAND_REGISTRATION_DONE
+};
+
+static const struct command_registration adapter_command_handlers[] = {
+       {
+               .name = "driver",
+               .handler = handle_adapter_driver_command,
+               .mode = COMMAND_CONFIG,
+               .help = "Select a debug adapter driver",
+               .usage = "driver_name",
+       },
        {
-               .name = "adapter_khz",
-               .handler = handle_adapter_khz_command,
+               .name = "speed",
+               .handler = handle_adapter_speed_command,
                .mode = COMMAND_ANY,
                .help = "With an argument, change to the specified maximum "
                        "jtag speed.  For JTAG, 0 KHz signifies adaptive "
-                       " clocking. "
+                       "clocking. "
                        "With or without argument, display current setting.",
                .usage = "[khz]",
        },
        {
-               .name = "adapter_name",
+               .name = "serial",
+               .handler = handle_adapter_serial_command,
+               .mode = COMMAND_CONFIG,
+               .help = "Set the serial number of the adapter",
+               .usage = "serial_string",
+       },
+       {
+               .name = "list",
+               .handler = handle_adapter_list_command,
+               .mode = COMMAND_ANY,
+               .help = "List all built-in debug adapter drivers",
+               .usage = "",
+       },
+       {
+               .name = "name",
                .mode = COMMAND_ANY,
                .jim_handler = jim_adapter_name,
                .help = "Returns the name of the currently "
                        "selected adapter (driver)",
        },
        {
-               .name = "adapter_nsrst_delay",
-               .handler = handle_adapter_nsrst_delay_command,
+               .name = "srst",
                .mode = COMMAND_ANY,
-               .help = "delay after deasserting SRST in ms",
-               .usage = "[milliseconds]",
+               .help = "srst adapter command group",
+               .usage = "",
+               .chain = adapter_srst_command_handlers,
        },
        {
-               .name = "adapter_nsrst_assert_width",
-               .handler = handle_adapter_nsrst_assert_width_command,
+               .name = "transports",
+               .handler = adapter_transports_command,
+               .mode = COMMAND_CONFIG,
+               .help = "Declare transports the adapter supports.",
+               .usage = "transport ...",
+       },
+       {
+               .name = "usb",
                .mode = COMMAND_ANY,
-               .help = "delay after asserting SRST in ms",
-               .usage = "[milliseconds]",
+               .help = "usb adapter command group",
+               .usage = "",
+               .chain = adapter_usb_command_handlers,
        },
        {
-               .name = "interface",
-               .handler = handle_interface_command,
-               .mode = COMMAND_CONFIG,
-               .help = "Select a debug adapter interface (driver)",
-               .usage = "driver_name",
+               .name = "assert",
+               .handler = handle_adapter_reset_de_assert,
+               .mode = COMMAND_EXEC,
+               .help = "Controls SRST and TRST lines.",
+               .usage = "|deassert [srst|trst [assert|deassert srst|trst]]",
        },
        {
-               .name = "interface_transports",
-               .handler = interface_transport_command,
-               .mode = COMMAND_CONFIG,
-               .help = "Declare transports the interface supports.",
-               .usage = "transport ... ",
+               .name = "deassert",
+               .handler = handle_adapter_reset_de_assert,
+               .mode = COMMAND_EXEC,
+               .help = "Controls SRST and TRST lines.",
+               .usage = "|assert [srst|trst [deassert|assert srst|trst]]",
        },
+       COMMAND_REGISTRATION_DONE
+};
+
+static const struct command_registration interface_command_handlers[] = {
        {
-               .name = "interface_list",
-               .handler = handle_interface_list_command,
+               .name = "adapter",
                .mode = COMMAND_ANY,
-               .help = "List all built-in debug adapter interfaces (drivers)",
+               .help = "adapter command group",
+               .usage = "",
+               .chain = adapter_command_handlers,
        },
        {
                .name = "reset_config",
@@ -529,7 +919,7 @@ static const struct command_registration interface_command_handlers[] = {
  * @todo Remove internal assumptions that all debug adapters use JTAG for
  * transport.  Various types and data structures are not named generically.
  */
-int interface_register_commands(struct command_context *ctx)
+int adapter_register_commands(struct command_context *ctx)
 {
        return register_commands(ctx, NULL, interface_command_handlers);
 }