jlink: add usb location support
[openocd.git] / src / jtag / drivers / jlink.c
index db211805243dfaf67a3e4ed82ca15e19a32d879d..8ce7c0d22fda8a39e24961da5706292654160164 100644 (file)
@@ -11,6 +11,9 @@
  *   Copyright (C) 2015 by Marc Schink                                     *
  *   openocd-dev@marcschink.de                                             *
  *                                                                         *
+ *   Copyright (C) 2015 by Paul Fertser                                    *
+ *   fercerpav@gmail.com                                                   *
+ *                                                                         *
  *   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     *
@@ -22,8 +25,7 @@
  *   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, write to the                         *
- *   Free Software Foundation, Inc.,                                       *
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>. *
  ***************************************************************************/
 
 #ifdef HAVE_CONFIG_H
@@ -36,6 +38,7 @@
 #include <jtag/interface.h>
 #include <jtag/swd.h>
 #include <jtag/commands.h>
+#include <jtag/drivers/jtag_usb_common.h>
 
 #include <libjaylink/libjaylink.h>
 
@@ -48,9 +51,10 @@ static uint8_t caps[JAYLINK_DEV_EXT_CAPS_SIZE];
 
 static uint32_t serial_number;
 static bool use_serial_number;
-static uint8_t usb_address;
+static bool use_usb_location;
+static enum jaylink_usb_address usb_address;
 static bool use_usb_address;
-static uint8_t iface = JAYLINK_TIF_JTAG;
+static enum jaylink_target_interface iface = JAYLINK_TIF_JTAG;
 static bool trace_enabled;
 
 #define JLINK_MAX_SPEED                        12000
@@ -83,23 +87,34 @@ static struct device_config tmp_config;
 static void jlink_end_state(tap_state_t state);
 static void jlink_state_move(void);
 static void jlink_path_move(int num_states, tap_state_t *path);
+static void jlink_stableclocks(int num_cycles);
 static void jlink_runtest(int num_cycles);
-static void jlink_scan(bool ir_scan, enum scan_type type, uint8_t *buffer,
-               int scan_size, struct scan_command *command);
 static void jlink_reset(int trst, int srst);
-static int jlink_swd_run_queue(struct adiv5_dap *dap);
-static void jlink_swd_queue_cmd(struct adiv5_dap *dap, uint8_t cmd,
-               uint32_t *dst, uint32_t data);
-static int jlink_swd_switch_seq(struct adiv5_dap *dap,
-               enum swd_special_seq seq);
+static int jlink_swd_run_queue(void);
+static void jlink_swd_queue_cmd(uint8_t cmd, uint32_t *dst, uint32_t data, uint32_t ap_delay_clk);
+static int jlink_swd_switch_seq(enum swd_special_seq seq);
 
 /* J-Link tap buffer functions */
 static void jlink_tap_init(void);
-static int jlink_tap_execute(void);
-static void jlink_tap_ensure_space(int scans, int bits);
-static void jlink_tap_append_step(int tms, int tdi);
-static void jlink_tap_append_scan(int length, uint8_t *buffer,
-               struct scan_command *command);
+static int jlink_flush(void);
+/**
+ * Queue data to go out and in, flushing the queue as many times as
+ * necessary.
+ *
+ * @param out A pointer to TDI data, if NULL, old stale data will be used.
+ * @param out_offset A bit offset for TDI data.
+ * @param tms_out A pointer to TMS data, if NULL, zeroes will be emitted.
+ * @param tms_offset A bit offset for TMS data.
+ * @param in A pointer to store TDO data to, if NULL the data will be discarded.
+ * @param in_offset A bit offset for TDO data.
+ * @param length Amount of bits to transfer out and in.
+ *
+ * @retval This function doesn't return any value.
+ */
+static void jlink_clock_data(const uint8_t *out, unsigned out_offset,
+                            const uint8_t *tms_out, unsigned tms_offset,
+                            uint8_t *in, unsigned in_offset,
+                            unsigned length);
 
 static enum tap_state jlink_last_state = TAP_RESET;
 static int queued_retval;
@@ -107,6 +122,12 @@ static int queued_retval;
 /***************************************************************************/
 /* External interface implementation */
 
+static void jlink_execute_stableclocks(struct jtag_command *cmd)
+{
+       DEBUG_JTAG_IO("stableclocks %i cycles", cmd->cmd.runtest->num_cycles);
+       jlink_stableclocks(cmd->cmd.runtest->num_cycles);
+}
+
 static void jlink_execute_runtest(struct jtag_command *cmd)
 {
        DEBUG_JTAG_IO("runtest %i cycles, end in %i", cmd->cmd.runtest->num_cycles,
@@ -135,19 +156,95 @@ static void jlink_execute_pathmove(struct jtag_command *cmd)
 
 static void jlink_execute_scan(struct jtag_command *cmd)
 {
-       int scan_size;
-       enum scan_type type;
-       uint8_t *buffer;
+       DEBUG_JTAG_IO("%s type:%d", cmd->cmd.scan->ir_scan ? "IRSCAN" : "DRSCAN",
+               jtag_scan_type(cmd->cmd.scan));
 
-       DEBUG_JTAG_IO("scan end in %s", tap_state_name(cmd->cmd.scan->end_state));
+       /* Make sure there are no trailing fields with num_bits == 0, or the logic below will fail. */
+       while (cmd->cmd.scan->num_fields > 0
+                       && cmd->cmd.scan->fields[cmd->cmd.scan->num_fields - 1].num_bits == 0) {
+               cmd->cmd.scan->num_fields--;
+               LOG_DEBUG("discarding trailing empty field");
+       }
+
+       if (cmd->cmd.scan->num_fields == 0) {
+               LOG_DEBUG("empty scan, doing nothing");
+               return;
+       }
+
+       if (cmd->cmd.scan->ir_scan) {
+               if (tap_get_state() != TAP_IRSHIFT) {
+                       jlink_end_state(TAP_IRSHIFT);
+                       jlink_state_move();
+               }
+       } else {
+               if (tap_get_state() != TAP_DRSHIFT) {
+                       jlink_end_state(TAP_DRSHIFT);
+                       jlink_state_move();
+               }
+       }
 
        jlink_end_state(cmd->cmd.scan->end_state);
 
-       scan_size = jtag_build_buffer(cmd->cmd.scan, &buffer);
-       DEBUG_JTAG_IO("scan input, length = %d", scan_size);
+       struct scan_field *field = cmd->cmd.scan->fields;
+       unsigned scan_size = 0;
+
+       for (int i = 0; i < cmd->cmd.scan->num_fields; i++, field++) {
+               scan_size += field->num_bits;
+               DEBUG_JTAG_IO("%s%s field %d/%d %d bits",
+                       field->in_value ? "in" : "",
+                       field->out_value ? "out" : "",
+                       i,
+                       cmd->cmd.scan->num_fields,
+                       field->num_bits);
+
+               if (i == cmd->cmd.scan->num_fields - 1 && tap_get_state() != tap_get_end_state()) {
+                       /* Last field, and we're leaving IRSHIFT/DRSHIFT. Clock last bit during tap
+                        * movement. This last field can't have length zero, it was checked above. */
+                       jlink_clock_data(field->out_value,
+                                        0,
+                                        NULL,
+                                        0,
+                                        field->in_value,
+                                        0,
+                                        field->num_bits - 1);
+                       uint8_t last_bit = 0;
+                       if (field->out_value)
+                               bit_copy(&last_bit, 0, field->out_value, field->num_bits - 1, 1);
+                       uint8_t tms_bits = 0x01;
+                       jlink_clock_data(&last_bit,
+                                        0,
+                                        &tms_bits,
+                                        0,
+                                        field->in_value,
+                                        field->num_bits - 1,
+                                        1);
+                       tap_set_state(tap_state_transition(tap_get_state(), 1));
+                       jlink_clock_data(NULL,
+                                        0,
+                                        &tms_bits,
+                                        1,
+                                        NULL,
+                                        0,
+                                        1);
+                       tap_set_state(tap_state_transition(tap_get_state(), 0));
+               } else
+                       jlink_clock_data(field->out_value,
+                                        0,
+                                        NULL,
+                                        0,
+                                        field->in_value,
+                                        0,
+                                        field->num_bits);
+       }
+
+       if (tap_get_state() != tap_get_end_state()) {
+               jlink_end_state(tap_get_end_state());
+               jlink_state_move();
+       }
 
-       type = jtag_scan_type(cmd->cmd.scan);
-       jlink_scan(cmd->cmd.scan->ir_scan, type, buffer, scan_size, cmd->cmd.scan);
+       DEBUG_JTAG_IO("%s scan, %i bits, end in %s",
+               (cmd->cmd.scan->ir_scan) ? "IR" : "DR", scan_size,
+               tap_state_name(tap_get_end_state()));
 }
 
 static void jlink_execute_reset(struct jtag_command *cmd)
@@ -155,21 +252,24 @@ static void jlink_execute_reset(struct jtag_command *cmd)
        DEBUG_JTAG_IO("reset trst: %i srst %i", cmd->cmd.reset->trst,
                cmd->cmd.reset->srst);
 
-       jlink_tap_execute();
+       jlink_flush();
        jlink_reset(cmd->cmd.reset->trst, cmd->cmd.reset->srst);
-       jlink_tap_execute();
+       jlink_flush();
 }
 
 static void jlink_execute_sleep(struct jtag_command *cmd)
 {
        DEBUG_JTAG_IO("sleep %" PRIi32 "", cmd->cmd.sleep->us);
-       jlink_tap_execute();
+       jlink_flush();
        jtag_sleep(cmd->cmd.sleep->us);
 }
 
 static int jlink_execute_command(struct jtag_command *cmd)
 {
        switch (cmd->type) {
+               case JTAG_STABLECLOCKS:
+                       jlink_execute_stableclocks(cmd);
+                       break;
                case JTAG_RUNTEST:
                        jlink_execute_runtest(cmd);
                        break;
@@ -210,27 +310,26 @@ static int jlink_execute_queue(void)
                cmd = cmd->next;
        }
 
-       return jlink_tap_execute();
+       return jlink_flush();
 }
 
 static int jlink_speed(int speed)
 {
        int ret;
-       uint32_t freq;
-       uint16_t div;
+       struct jaylink_speed tmp;
        int max_speed;
 
        if (jaylink_has_cap(caps, JAYLINK_DEV_CAP_GET_SPEEDS)) {
-               ret = jaylink_get_speeds(devh, &freq, &div);
+               ret = jaylink_get_speeds(devh, &tmp);
 
                if (ret != JAYLINK_OK) {
                        LOG_ERROR("jaylink_get_speeds() failed: %s.",
-                               jaylink_strerror_name(ret));
+                               jaylink_strerror(ret));
                        return ERROR_JTAG_DEVICE_ERROR;
                }
 
-               freq = freq / 1000;
-               max_speed = freq / div;
+               tmp.freq /= 1000;
+               max_speed = tmp.freq / tmp.div;
        } else {
                max_speed = JLINK_MAX_SPEED;
        }
@@ -252,7 +351,7 @@ static int jlink_speed(int speed)
 
        if (ret != JAYLINK_OK) {
                LOG_ERROR("jaylink_set_speed() failed: %s.",
-                       jaylink_strerror_name(ret));
+                       jaylink_strerror(ret));
                return ERROR_JTAG_DEVICE_ERROR;
        }
 
@@ -281,7 +380,7 @@ static bool read_device_config(struct device_config *cfg)
 
        if (ret != JAYLINK_OK) {
                LOG_ERROR("jaylink_read_raw_config() failed: %s.",
-                       jaylink_strerror_name(ret));
+                       jaylink_strerror(ret));
                return false;
        }
 
@@ -312,7 +411,7 @@ static int select_interface(void)
 
        if (ret != JAYLINK_OK) {
                LOG_ERROR("jaylink_get_available_interfaces() failed: %s.",
-                       jaylink_strerror_name(ret));
+                       jaylink_strerror(ret));
                return ERROR_JTAG_INIT_FAILED;
        }
 
@@ -321,11 +420,11 @@ static int select_interface(void)
                return ERROR_JTAG_INIT_FAILED;
        }
 
-       ret = jaylink_select_interface(devh, iface);
+       ret = jaylink_select_interface(devh, iface, NULL);
 
        if (ret < 0) {
                LOG_ERROR("jaylink_select_interface() failed: %s.",
-                       jaylink_strerror_name(ret));
+                       jaylink_strerror(ret));
                return ERROR_JTAG_INIT_FAILED;
        }
 
@@ -335,23 +434,23 @@ static int select_interface(void)
 static int jlink_register(void)
 {
        int ret;
-       int i;
+       size_t i;
        bool handle_found;
+       size_t count;
 
        if (!jaylink_has_cap(caps, JAYLINK_DEV_CAP_REGISTER))
                return ERROR_OK;
 
-       ret = jaylink_register(devh, &conn, connlist, NULL, NULL);
+       ret = jaylink_register(devh, &conn, connlist, &count);
 
-       if (ret < 0) {
-               LOG_ERROR("jaylink_register() failed: %s.",
-                       jaylink_strerror_name(ret));
+       if (ret != JAYLINK_OK) {
+               LOG_ERROR("jaylink_register() failed: %s.", jaylink_strerror(ret));
                return ERROR_FAIL;
        }
 
        handle_found = false;
 
-       for (i = 0; i < ret; i++) {
+       for (i = 0; i < count; i++) {
                if (connlist[i].handle == conn.handle) {
                        handle_found = true;
                        break;
@@ -384,7 +483,7 @@ static bool adjust_swd_buffer_size(void)
 
        if (ret != JAYLINK_OK) {
                LOG_ERROR("jaylink_get_free_memory() failed: %s.",
-                       jaylink_strerror_name(ret));
+                       jaylink_strerror(ret));
                return false;
        }
 
@@ -404,6 +503,64 @@ static bool adjust_swd_buffer_size(void)
        return true;
 }
 
+static int jaylink_log_handler(const struct jaylink_context *ctx,
+               enum jaylink_log_level level, const char *format, va_list args,
+               void *user_data)
+{
+       enum log_levels tmp;
+
+       switch (level) {
+       case JAYLINK_LOG_LEVEL_ERROR:
+               tmp = LOG_LVL_ERROR;
+               break;
+       case JAYLINK_LOG_LEVEL_WARNING:
+               tmp = LOG_LVL_WARNING;
+               break;
+       /*
+        * Forward info messages to the debug output because they are more verbose
+        * than info messages of OpenOCD.
+        */
+       case JAYLINK_LOG_LEVEL_INFO:
+       case JAYLINK_LOG_LEVEL_DEBUG:
+               tmp = LOG_LVL_DEBUG;
+               break;
+       case JAYLINK_LOG_LEVEL_DEBUG_IO:
+               tmp = LOG_LVL_DEBUG_IO;
+               break;
+       default:
+               tmp = LOG_LVL_WARNING;
+       }
+
+       log_vprintf_lf(tmp, __FILE__, __LINE__, __func__, format, args);
+
+       return 0;
+}
+
+static bool jlink_usb_location_equal(struct jaylink_device *dev)
+{
+       int retval;
+       uint8_t bus;
+       uint8_t *ports;
+       size_t num_ports;
+       bool equal = false;
+
+       retval = jaylink_device_get_usb_bus_ports(dev, &bus, &ports, &num_ports);
+
+       if (retval == JAYLINK_ERR_NOT_SUPPORTED) {
+               return false;
+       } else if (retval != JAYLINK_OK) {
+               LOG_WARNING("jaylink_device_get_usb_bus_ports() failed: %s.",
+                       jaylink_strerror(retval));
+               return false;
+       }
+
+       equal = jtag_usb_location_equal(bus, ports,     num_ports);
+       free(ports);
+
+       return equal;
+}
+
+
 static int jlink_init(void)
 {
        int ret;
@@ -414,51 +571,115 @@ static int jlink_init(void)
        char *firmware_version;
        struct jaylink_hardware_version hwver;
        struct jaylink_hardware_status hwstatus;
+       enum jaylink_usb_address address;
+       size_t length;
+       size_t num_devices;
+       uint32_t host_interfaces;
+
+       LOG_DEBUG("Using libjaylink %s (compiled with %s).",
+               jaylink_version_package_get_string(), JAYLINK_VERSION_PACKAGE_STRING);
+
+       if (!jaylink_library_has_cap(JAYLINK_CAP_HIF_USB) && use_usb_address) {
+               LOG_ERROR("J-Link driver does not support USB devices.");
+               return ERROR_JTAG_INIT_FAILED;
+       }
 
        ret = jaylink_init(&jayctx);
 
        if (ret != JAYLINK_OK) {
-               LOG_ERROR("jaylink_init() failed: %s.",
-                       jaylink_strerror_name(ret));
+               LOG_ERROR("jaylink_init() failed: %s.", jaylink_strerror(ret));
                return ERROR_JTAG_INIT_FAILED;
        }
 
-       ret = jaylink_get_device_list(jayctx, &devs);
+       ret = jaylink_log_set_callback(jayctx, &jaylink_log_handler, NULL);
 
-       if (ret < 0) {
-               LOG_ERROR("jaylink_get_device_list() failed: %s.",
-                       jaylink_strerror_name(ret));
+       if (ret != JAYLINK_OK) {
+               LOG_ERROR("jaylink_log_set_callback() failed: %s.",
+                       jaylink_strerror(ret));
                jaylink_exit(jayctx);
                return ERROR_JTAG_INIT_FAILED;
        }
 
-       found_device = false;
+       host_interfaces = JAYLINK_HIF_USB;
+
+       if (use_serial_number)
+               host_interfaces |= JAYLINK_HIF_TCP;
+
+       ret = jaylink_discovery_scan(jayctx, host_interfaces);
+
+       if (ret != JAYLINK_OK) {
+               LOG_ERROR("jaylink_discovery_scan() failed: %s.",
+                       jaylink_strerror(ret));
+               jaylink_exit(jayctx);
+               return ERROR_JTAG_INIT_FAILED;
+       }
 
-       if (!use_serial_number && !use_usb_address)
-               LOG_INFO("No device selected, using first device.");
+       ret = jaylink_get_devices(jayctx, &devs, &num_devices);
+
+       if (ret != JAYLINK_OK) {
+               LOG_ERROR("jaylink_get_devices() failed: %s.", jaylink_strerror(ret));
+               jaylink_exit(jayctx);
+               return ERROR_JTAG_INIT_FAILED;
+       }
+
+       use_usb_location = (jtag_usb_get_location() != NULL);
+
+       if (!use_serial_number && !use_usb_address && !use_usb_location && num_devices > 1) {
+               LOG_ERROR("Multiple devices found, specify the desired device.");
+               jaylink_free_devices(devs, true);
+               jaylink_exit(jayctx);
+               return ERROR_JTAG_INIT_FAILED;
+       }
+
+       found_device = false;
 
        for (i = 0; devs[i]; i++) {
-               jaylink_device_get_serial_number(devs[i], &tmp);
-               ret = jaylink_device_get_usb_address(devs[i]);
+               struct jaylink_device *dev = devs[i];
 
-               if (use_usb_address && usb_address != ret)
-                       continue;
+               if (use_serial_number) {
+                       ret = jaylink_device_get_serial_number(dev, &tmp);
 
-               if (use_serial_number && tmp != serial_number)
-                       continue;
+                       if (ret == JAYLINK_ERR_NOT_AVAILABLE) {
+                               continue;
+                       } else if (ret != JAYLINK_OK) {
+                               LOG_WARNING("jaylink_device_get_serial_number() failed: %s.",
+                                       jaylink_strerror(ret));
+                               continue;
+                       }
 
-               ret = jaylink_open(devs[i], &devh);
+                       if (serial_number != tmp)
+                               continue;
+               }
 
-               if (ret != JAYLINK_OK) {
-                       LOG_ERROR("Failed to open device: %s.", jaylink_strerror_name(ret));
+               if (use_usb_address) {
+                       ret = jaylink_device_get_usb_address(dev, &address);
+
+                       if (ret == JAYLINK_ERR_NOT_SUPPORTED) {
+                               continue;
+                       } else if (ret != JAYLINK_OK) {
+                               LOG_WARNING("jaylink_device_get_usb_address() failed: %s.",
+                                       jaylink_strerror(ret));
+                               continue;
+                       }
+
+                       if (usb_address != address)
+                               continue;
+               }
+
+               if (use_usb_location && !jlink_usb_location_equal(dev))
                        continue;
+
+               ret = jaylink_open(dev, &devh);
+
+               if (ret == JAYLINK_OK) {
+                       found_device = true;
+                       break;
                }
 
-               found_device = true;
-               break;
+               LOG_ERROR("Failed to open device: %s.", jaylink_strerror(ret));
        }
 
-       jaylink_free_device_list(devs, 1);
+       jaylink_free_devices(devs, true);
 
        if (!found_device) {
                LOG_ERROR("No J-Link device found.");
@@ -471,26 +692,26 @@ static int jlink_init(void)
         * some devices are known to be sensitive regarding the order.
         */
 
-       ret = jaylink_get_firmware_version(devh, &firmware_version);
+       ret = jaylink_get_firmware_version(devh, &firmware_version, &length);
 
-       if (ret > 0) {
-               LOG_INFO("%s", firmware_version);
-               free(firmware_version);
-       } else if (!ret) {
-               LOG_WARNING("Device responds empty firmware version string.");
-       } else {
+       if (ret != JAYLINK_OK) {
                LOG_ERROR("jaylink_get_firmware_version() failed: %s.",
-                       jaylink_strerror_name(ret));
+                       jaylink_strerror(ret));
                jaylink_close(devh);
                jaylink_exit(jayctx);
                return ERROR_JTAG_INIT_FAILED;
+       } else if (length > 0) {
+               LOG_INFO("%s", firmware_version);
+               free(firmware_version);
+       } else {
+               LOG_WARNING("Device responds empty firmware version string.");
        }
 
        memset(caps, 0, JAYLINK_DEV_EXT_CAPS_SIZE);
        ret = jaylink_get_caps(devh, caps);
 
        if (ret != JAYLINK_OK) {
-               LOG_ERROR("jaylink_get_caps() failed: %s.", jaylink_strerror_name(ret));
+               LOG_ERROR("jaylink_get_caps() failed: %s.", jaylink_strerror(ret));
                jaylink_close(devh);
                jaylink_exit(jayctx);
                return ERROR_JTAG_INIT_FAILED;
@@ -501,21 +722,21 @@ static int jlink_init(void)
 
                if (ret != JAYLINK_OK) {
                        LOG_ERROR("jaylink_get_extended_caps() failed:  %s.",
-                               jaylink_strerror_name(ret));
+                               jaylink_strerror(ret));
                        jaylink_close(devh);
                        jaylink_exit(jayctx);
                        return ERROR_JTAG_INIT_FAILED;
                }
        }
 
-       jtag_command_version = JAYLINK_JTAG_V2;
+       jtag_command_version = JAYLINK_JTAG_VERSION_2;
 
        if (jaylink_has_cap(caps, JAYLINK_DEV_CAP_GET_HW_VERSION)) {
                ret = jaylink_get_hardware_version(devh, &hwver);
 
                if (ret != JAYLINK_OK) {
                        LOG_ERROR("Failed to retrieve hardware version: %s.",
-                               jaylink_strerror_name(ret));
+                               jaylink_strerror(ret));
                        jaylink_close(devh);
                        jaylink_exit(jayctx);
                        return ERROR_JTAG_INIT_FAILED;
@@ -524,7 +745,7 @@ static int jlink_init(void)
                LOG_INFO("Hardware version: %u.%02u", hwver.major, hwver.minor);
 
                if (hwver.major >= 5)
-                       jtag_command_version = JAYLINK_JTAG_V3;
+                       jtag_command_version = JAYLINK_JTAG_VERSION_3;
        }
 
        if (iface == JAYLINK_TIF_SWD) {
@@ -556,7 +777,7 @@ static int jlink_init(void)
 
        if (ret != JAYLINK_OK) {
                LOG_ERROR("jaylink_get_hardware_status() failed: %s.",
-                       jaylink_strerror_name(ret));
+                       jaylink_strerror(ret));
                jaylink_close(devh);
                jaylink_exit(jayctx);
                return ERROR_JTAG_INIT_FAILED;
@@ -567,7 +788,7 @@ static int jlink_init(void)
 
        conn.handle = 0;
        conn.pid = 0;
-       conn.hid = 0;
+       strcpy(conn.hid, "0.0.0.0");
        conn.iid = 0;
        conn.cid = 0;
 
@@ -599,10 +820,10 @@ static int jlink_init(void)
                 * if the first tap move is not divisible by 8, so we send a TLR on
                 * first power up.
                 */
-               for (i = 0; i < 8; i++)
-                       jlink_tap_append_step(1, 0);
+               uint8_t tms = 0xff;
+               jlink_clock_data(NULL, 0, &tms, 0, NULL, 0, 8);
 
-               jlink_tap_execute();
+               jlink_flush();
        }
 
        return ERROR_OK;
@@ -611,21 +832,21 @@ static int jlink_init(void)
 static int jlink_quit(void)
 {
        int ret;
+       size_t count;
 
        if (trace_enabled) {
                ret = jaylink_swo_stop(devh);
 
                if (ret != JAYLINK_OK)
-                       LOG_ERROR("jaylink_swo_stop() failed: %s.",
-                               jaylink_strerror_name(ret));
+                       LOG_ERROR("jaylink_swo_stop() failed: %s.", jaylink_strerror(ret));
        }
 
        if (jaylink_has_cap(caps, JAYLINK_DEV_CAP_REGISTER)) {
-               ret = jaylink_unregister(devh, &conn, connlist, NULL, NULL);
+               ret = jaylink_unregister(devh, &conn, connlist, &count);
 
-               if (ret < 0)
+               if (ret != JAYLINK_OK)
                        LOG_ERROR("jaylink_unregister() failed: %s.",
-                               jaylink_strerror_name(ret));
+                               jaylink_strerror(ret));
        }
 
        jaylink_close(devh);
@@ -650,18 +871,13 @@ static void jlink_end_state(tap_state_t state)
 /* Goes to the end state. */
 static void jlink_state_move(void)
 {
-       int i;
-       int tms = 0;
        uint8_t tms_scan;
        uint8_t tms_scan_bits;
 
        tms_scan = tap_get_tms_path(tap_get_state(), tap_get_end_state());
        tms_scan_bits = tap_get_tms_path_len(tap_get_state(), tap_get_end_state());
 
-       for (i = 0; i < tms_scan_bits; i++) {
-               tms = (tms_scan >> i) & 1;
-               jlink_tap_append_step(tms, 0);
-       }
+       jlink_clock_data(NULL, 0, &tms_scan, 0, NULL, 0, tms_scan_bits);
 
        tap_set_state(tap_get_end_state());
 }
@@ -669,12 +885,13 @@ static void jlink_state_move(void)
 static void jlink_path_move(int num_states, tap_state_t *path)
 {
        int i;
+       uint8_t tms = 0xff;
 
        for (i = 0; i < num_states; i++) {
                if (path[i] == tap_state_transition(tap_get_state(), false))
-                       jlink_tap_append_step(0, 0);
+                       jlink_clock_data(NULL, 0, NULL, 0, NULL, 0, 1);
                else if (path[i] == tap_state_transition(tap_get_state(), true))
-                       jlink_tap_append_step(1, 0);
+                       jlink_clock_data(NULL, 0, &tms, 0, NULL, 0, 1);
                else {
                        LOG_ERROR("BUG: %s -> %s isn't a valid TAP transition.",
                                tap_state_name(tap_get_state()), tap_state_name(path[i]));
@@ -687,13 +904,19 @@ static void jlink_path_move(int num_states, tap_state_t *path)
        tap_set_end_state(tap_get_state());
 }
 
-static void jlink_runtest(int num_cycles)
+static void jlink_stableclocks(int num_cycles)
 {
        int i;
 
-       tap_state_t saved_end_state = tap_get_end_state();
+       uint8_t tms = tap_get_state() == TAP_RESET;
+       /* Execute num_cycles. */
+       for (i = 0; i < num_cycles; i++)
+               jlink_clock_data(NULL, 0, &tms, 0, NULL, 0, 1);
+}
 
-       jlink_tap_ensure_space(1, num_cycles + 16);
+static void jlink_runtest(int num_cycles)
+{
+       tap_state_t saved_end_state = tap_get_end_state();
 
        /* Only do a state_move when we're not already in IDLE. */
        if (tap_get_state() != TAP_IDLE) {
@@ -702,9 +925,7 @@ static void jlink_runtest(int num_cycles)
                /* num_cycles--; */
        }
 
-       /* Execute num_cycles. */
-       for (i = 0; i < num_cycles; i++)
-               jlink_tap_append_step(0, 0);
+       jlink_stableclocks(num_cycles);
 
        /* Finish in end_state. */
        jlink_end_state(saved_end_state);
@@ -713,36 +934,6 @@ static void jlink_runtest(int num_cycles)
                jlink_state_move();
 }
 
-static void jlink_scan(bool ir_scan, enum scan_type type, uint8_t *buffer,
-               int scan_size, struct scan_command *command)
-{
-       tap_state_t saved_end_state;
-
-       jlink_tap_ensure_space(1, scan_size + 16);
-
-       saved_end_state = tap_get_end_state();
-
-       /* Move to appropriate scan state. */
-       jlink_end_state(ir_scan ? TAP_IRSHIFT : TAP_DRSHIFT);
-
-       /* Only move if we're not already there. */
-       if (tap_get_state() != tap_get_end_state())
-               jlink_state_move();
-
-       jlink_end_state(saved_end_state);
-
-       /* Scan. */
-       jlink_tap_append_scan(scan_size, buffer, command);
-
-       /* We are in Exit1, go to Pause. */
-       jlink_tap_append_step(0, 0);
-
-       tap_set_state(ir_scan ? TAP_IRPAUSE : TAP_DRPAUSE);
-
-       if (tap_get_state() != tap_get_end_state())
-               jlink_state_move();
-}
-
 static void jlink_reset(int trst, int srst)
 {
        LOG_DEBUG("TRST: %i, SRST: %i.", trst, srst);
@@ -763,21 +954,25 @@ static void jlink_reset(int trst, int srst)
 
 COMMAND_HANDLER(jlink_usb_command)
 {
+       int tmp;
+
        if (CMD_ARGC != 1) {
-               command_print(CMD_CTX, "Need exactly one argument for jlink usb.");
+               command_print(CMD, "Need exactly one argument for jlink usb.");
                return ERROR_COMMAND_SYNTAX_ERROR;
        }
 
-       if (sscanf(CMD_ARGV[0], "%" SCNd8, &usb_address) != 1) {
-               command_print(CMD_CTX, "Invalid USB address: %s.", CMD_ARGV[0]);
+       if (sscanf(CMD_ARGV[0], "%i", &tmp) != 1) {
+               command_print(CMD, "Invalid USB address: %s.", CMD_ARGV[0]);
                return ERROR_FAIL;
        }
 
-       if (usb_address > JAYLINK_USB_ADDRESS_3) {
-               command_print(CMD_CTX, "Invalid USB address: %s.", CMD_ARGV[0]);
+       if (tmp < JAYLINK_USB_ADDRESS_0 || tmp > JAYLINK_USB_ADDRESS_3) {
+               command_print(CMD, "Invalid USB address: %s.", CMD_ARGV[0]);
                return ERROR_FAIL;
        }
 
+       usb_address = tmp;
+
        use_serial_number = false;
        use_usb_address = true;
 
@@ -786,13 +981,21 @@ COMMAND_HANDLER(jlink_usb_command)
 
 COMMAND_HANDLER(jlink_serial_command)
 {
+       int ret;
+
        if (CMD_ARGC != 1) {
-               command_print(CMD_CTX, "Need exactly one argument for jlink serial.");
+               command_print(CMD, "Need exactly one argument for jlink serial.");
                return ERROR_COMMAND_SYNTAX_ERROR;
        }
 
-       if (sscanf(CMD_ARGV[0], "%" SCNd32, &serial_number) != 1) {
-               command_print(CMD_CTX, "Invalid serial number: %s.", CMD_ARGV[0]);
+       ret = jaylink_parse_serial_number(CMD_ARGV[0], &serial_number);
+
+       if (ret == JAYLINK_ERR) {
+               command_print(CMD, "Invalid serial number: %s.", CMD_ARGV[0]);
+               return ERROR_FAIL;
+       } else if (ret != JAYLINK_OK) {
+               command_print(CMD, "jaylink_parse_serial_number() failed: %s.",
+                       jaylink_strerror(ret));
                return ERROR_FAIL;
        }
 
@@ -810,20 +1013,20 @@ COMMAND_HANDLER(jlink_handle_hwstatus_command)
        ret = jaylink_get_hardware_status(devh, &status);
 
        if (ret != JAYLINK_OK) {
-               command_print(CMD_CTX, "jaylink_get_hardware_status() failed: %s.",
-                       jaylink_strerror_name(ret));
+               command_print(CMD, "jaylink_get_hardware_status() failed: %s.",
+                       jaylink_strerror(ret));
                return ERROR_FAIL;
        }
 
-       command_print(CMD_CTX, "VTarget = %u.%03u V",
+       command_print(CMD, "VTarget = %u.%03u V",
                status.target_voltage / 1000, status.target_voltage % 1000);
 
-       command_print(CMD_CTX, "TCK = %u TDI = %u TDO = %u TMS = %u SRST = %u "
+       command_print(CMD, "TCK = %u TDI = %u TDO = %u TMS = %u SRST = %u "
                "TRST = %u", status.tck, status.tdi, status.tdo, status.tms,
                status.tres, status.trst);
 
        if (status.target_voltage < 1500)
-               command_print(CMD_CTX, "Target voltage too low. Check target power.");
+               command_print(CMD, "Target voltage too low. Check target power.");
 
        return ERROR_OK;
 }
@@ -834,7 +1037,7 @@ COMMAND_HANDLER(jlink_handle_free_memory_command)
        uint32_t tmp;
 
        if (!jaylink_has_cap(caps, JAYLINK_DEV_CAP_GET_FREE_MEMORY)) {
-               command_print(CMD_CTX, "Retrieval of free memory is not supported by "
+               command_print(CMD, "Retrieval of free memory is not supported by "
                        "the device.");
                return ERROR_OK;
        }
@@ -842,12 +1045,12 @@ COMMAND_HANDLER(jlink_handle_free_memory_command)
        ret = jaylink_get_free_memory(devh, &tmp);
 
        if (ret != JAYLINK_OK) {
-               command_print(CMD_CTX, "jaylink_get_free_memory() failed: %s.",
-                       jaylink_strerror_name(ret));
+               command_print(CMD, "jaylink_get_free_memory() failed: %s.",
+                       jaylink_strerror(ret));
                return ERROR_FAIL;
        }
 
-       command_print(CMD_CTX, "Device has %u bytes of free memory.", tmp);
+       command_print(CMD, "Device has %u bytes of free memory.", tmp);
 
        return ERROR_OK;
 }
@@ -859,36 +1062,36 @@ COMMAND_HANDLER(jlink_handle_jlink_jtag_command)
 
        if (!CMD_ARGC) {
                switch (jtag_command_version) {
-                       case JAYLINK_JTAG_V2:
+                       case JAYLINK_JTAG_VERSION_2:
                                version = 2;
                                break;
-                       case JAYLINK_JTAG_V3:
+                       case JAYLINK_JTAG_VERSION_3:
                                version = 3;
                                break;
                        default:
                                return ERROR_FAIL;
                }
 
-               command_print(CMD_CTX, "JTAG command version: %i", version);
+               command_print(CMD, "JTAG command version: %i", version);
        } else if (CMD_ARGC == 1) {
                if (sscanf(CMD_ARGV[0], "%i", &tmp) != 1) {
-                       command_print(CMD_CTX, "Invalid argument: %s.", CMD_ARGV[0]);
+                       command_print(CMD, "Invalid argument: %s.", CMD_ARGV[0]);
                        return ERROR_COMMAND_SYNTAX_ERROR;
                }
 
                switch (tmp) {
                        case 2:
-                               jtag_command_version = JAYLINK_JTAG_V2;
+                               jtag_command_version = JAYLINK_JTAG_VERSION_2;
                                break;
                        case 3:
-                               jtag_command_version = JAYLINK_JTAG_V3;
+                               jtag_command_version = JAYLINK_JTAG_VERSION_3;
                                break;
                        default:
-                               command_print(CMD_CTX, "Invalid argument: %s.", CMD_ARGV[0]);
+                               command_print(CMD, "Invalid argument: %s.", CMD_ARGV[0]);
                                return ERROR_COMMAND_SYNTAX_ERROR;
                }
        } else {
-               command_print(CMD_CTX, "Need exactly one argument for jlink jtag.");
+               command_print(CMD, "Need exactly one argument for jlink jtag.");
                return ERROR_COMMAND_SYNTAX_ERROR;
        }
 
@@ -901,13 +1104,13 @@ COMMAND_HANDLER(jlink_handle_target_power_command)
        int enable;
 
        if (CMD_ARGC != 1) {
-               command_print(CMD_CTX, "Need exactly one argument for jlink "
+               command_print(CMD, "Need exactly one argument for jlink "
                        "targetpower.");
                return ERROR_COMMAND_SYNTAX_ERROR;
        }
 
        if (!jaylink_has_cap(caps, JAYLINK_DEV_CAP_SET_TARGET_POWER)) {
-               command_print(CMD_CTX, "Target power supply is not supported by the "
+               command_print(CMD, "Target power supply is not supported by the "
                        "device.");
                return ERROR_OK;
        }
@@ -917,64 +1120,64 @@ COMMAND_HANDLER(jlink_handle_target_power_command)
        } else if (!strcmp(CMD_ARGV[0], "off")) {
                enable = false;
        } else {
-               command_print(CMD_CTX, "Invalid argument: %s.", CMD_ARGV[0]);
+               command_print(CMD, "Invalid argument: %s.", CMD_ARGV[0]);
                return ERROR_FAIL;
        }
 
        ret = jaylink_set_target_power(devh, enable);
 
        if (ret != JAYLINK_OK) {
-               command_print(CMD_CTX, "jaylink_set_target_power() failed: %s.",
-                       jaylink_strerror_name(ret));
+               command_print(CMD, "jaylink_set_target_power() failed: %s.",
+                       jaylink_strerror(ret));
                return ERROR_FAIL;
        }
 
        return ERROR_OK;
 }
 
-static void show_config_usb_address(struct command_context *ctx)
+static void show_config_usb_address(struct command_invocation *cmd)
 {
        if (config.usb_address != tmp_config.usb_address)
-               command_print(ctx, "USB address: %u [%u]", config.usb_address,
+               command_print(cmd, "USB address: %u [%u]", config.usb_address,
                        tmp_config.usb_address);
        else
-               command_print(ctx, "USB address: %u", config.usb_address);
+               command_print(cmd, "USB address: %u", config.usb_address);
 }
 
-static void show_config_ip_address(struct command_context *ctx)
+static void show_config_ip_address(struct command_invocation *cmd)
 {
        if (!memcmp(config.ip_address, tmp_config.ip_address, 4))
-               command_print(ctx, "IP address: %d.%d.%d.%d",
+               command_print(cmd, "IP address: %d.%d.%d.%d",
                        config.ip_address[3], config.ip_address[2],
                        config.ip_address[1], config.ip_address[0]);
        else
-               command_print(ctx, "IP address: %d.%d.%d.%d [%d.%d.%d.%d]",
+               command_print(cmd, "IP address: %d.%d.%d.%d [%d.%d.%d.%d]",
                        config.ip_address[3], config.ip_address[2],
                        config.ip_address[1], config.ip_address[0],
                        tmp_config.ip_address[3], tmp_config.ip_address[2],
                        tmp_config.ip_address[1], tmp_config.ip_address[0]);
 
        if (!memcmp(config.subnet_mask, tmp_config.subnet_mask, 4))
-               command_print(ctx, "Subnet mask: %d.%d.%d.%d",
+               command_print(cmd, "Subnet mask: %d.%d.%d.%d",
                        config.subnet_mask[3], config.subnet_mask[2],
                        config.subnet_mask[1], config.subnet_mask[0]);
        else
-               command_print(ctx, "Subnet mask: %d.%d.%d.%d [%d.%d.%d.%d]",
+               command_print(cmd, "Subnet mask: %d.%d.%d.%d [%d.%d.%d.%d]",
                        config.subnet_mask[3], config.subnet_mask[2],
                        config.subnet_mask[1], config.subnet_mask[0],
                        tmp_config.subnet_mask[3], tmp_config.subnet_mask[2],
                        tmp_config.subnet_mask[1], tmp_config.subnet_mask[0]);
 }
 
-static void show_config_mac_address(struct command_context *ctx)
+static void show_config_mac_address(struct command_invocation *cmd)
 {
        if (!memcmp(config.mac_address, tmp_config.mac_address, 6))
-               command_print(ctx, "MAC address: %.02x:%.02x:%.02x:%.02x:%.02x:%.02x",
+               command_print(cmd, "MAC address: %.02x:%.02x:%.02x:%.02x:%.02x:%.02x",
                        config.mac_address[5], config.mac_address[4],
                        config.mac_address[3], config.mac_address[2],
                        config.mac_address[1], config.mac_address[0]);
        else
-               command_print(ctx, "MAC address: %.02x:%.02x:%.02x:%.02x:%.02x:%.02x "
+               command_print(cmd, "MAC address: %.02x:%.02x:%.02x:%.02x:%.02x:%.02x "
                        "[%.02x:%.02x:%.02x:%.02x:%.02x:%.02x]",
                        config.mac_address[5], config.mac_address[4],
                        config.mac_address[3], config.mac_address[2],
@@ -984,7 +1187,7 @@ static void show_config_mac_address(struct command_context *ctx)
                        tmp_config.mac_address[1], tmp_config.mac_address[0]);
 }
 
-static void show_config_target_power(struct command_context *ctx)
+static void show_config_target_power(struct command_invocation *cmd)
 {
        const char *target_power;
        const char *current_target_power;
@@ -1000,24 +1203,24 @@ static void show_config_target_power(struct command_context *ctx)
                current_target_power = "on";
 
        if (config.target_power != tmp_config.target_power)
-               command_print(ctx, "Target power supply: %s [%s]", target_power,
+               command_print(cmd, "Target power supply: %s [%s]", target_power,
                        current_target_power);
        else
-               command_print(ctx, "Target power supply: %s", target_power);
+               command_print(cmd, "Target power supply: %s", target_power);
 }
 
-static void show_config(struct command_context *ctx)
+static void show_config(struct command_invocation *cmd)
 {
-       command_print(ctx, "J-Link device configuration:");
+       command_print(cmd, "J-Link device configuration:");
 
-       show_config_usb_address(ctx);
+       show_config_usb_address(cmd);
 
        if (jaylink_has_cap(caps, JAYLINK_DEV_CAP_SET_TARGET_POWER))
-               show_config_target_power(ctx);
+               show_config_target_power(cmd);
 
        if (jaylink_has_cap(caps, JAYLINK_DEV_CAP_ETHERNET)) {
-               show_config_ip_address(ctx);
-               show_config_mac_address(ctx);
+               show_config_ip_address(cmd);
+               show_config_mac_address(cmd);
        }
 }
 
@@ -1031,7 +1234,7 @@ static int poll_trace(uint8_t *buf, size_t *size)
        ret = jaylink_swo_read(devh, buf, &length);
 
        if (ret != JAYLINK_OK) {
-               LOG_ERROR("jaylink_swo_read() failed: %s.", jaylink_strerror_name(ret));
+               LOG_ERROR("jaylink_swo_read() failed: %s.", jaylink_strerror(ret));
                return ERROR_FAIL;
        }
 
@@ -1052,7 +1255,7 @@ static uint32_t calculate_trace_buffer_size(void)
 
        if (ret != JAYLINK_OK) {
                LOG_ERROR("jaylink_get_free_memory() failed: %s.",
-                       jaylink_strerror_name(ret));
+                       jaylink_strerror(ret));
                return ERROR_FAIL;
        }
 
@@ -1064,26 +1267,26 @@ static uint32_t calculate_trace_buffer_size(void)
        return tmp & 0xffffff00;
 }
 
-static bool check_trace_freq(uint32_t freq, uint32_t div, uint32_t trace_freq)
+static bool check_trace_freq(struct jaylink_swo_speed speed,
+               uint32_t trace_freq)
 {
        double min;
        double deviation;
+       uint32_t divider;
 
-       min = fabs(1.0 - (freq / ((double)trace_freq * div)));
+       min = fabs(1.0 - (speed.freq / ((double)trace_freq * speed.min_div)));
 
-       while (freq / div > 0) {
-               deviation = fabs(1.0 - (freq / ((double)trace_freq * div)));
+       for (divider = speed.min_div; divider < speed.max_div; divider++) {
+               deviation = fabs(1.0 - (speed.freq / ((double)trace_freq * divider)));
 
                if (deviation < 0.03) {
                        LOG_DEBUG("Found suitable frequency divider %u with deviation of "
-                               "%.02f %%.", div, deviation);
+                               "%.02f %%.", divider, deviation);
                        return true;
                }
 
                if (deviation < min)
                        min = deviation;
-
-               div++;
        }
 
        LOG_ERROR("Selected trace frequency is not supported by the device. "
@@ -1094,20 +1297,19 @@ static bool check_trace_freq(uint32_t freq, uint32_t div, uint32_t trace_freq)
        return false;
 }
 
-static int config_trace(bool enabled, enum tpio_pin_protocol pin_protocol,
+static int config_trace(bool enabled, enum tpiu_pin_protocol pin_protocol,
                uint32_t port_size, unsigned int *trace_freq)
 {
        int ret;
        uint32_t buffer_size;
-       uint32_t freq;
-       uint32_t div;
+       struct jaylink_swo_speed speed;
 
        if (!jaylink_has_cap(caps, JAYLINK_DEV_CAP_SWO)) {
                LOG_ERROR("Trace capturing is not supported by the device.");
                return ERROR_FAIL;
        }
 
-       if (pin_protocol != ASYNC_UART) {
+       if (pin_protocol != TPIU_PIN_PROTOCOL_ASYNC_UART) {
                LOG_ERROR("Selected pin protocol is not supported.");
                return ERROR_FAIL;
        }
@@ -1117,7 +1319,7 @@ static int config_trace(bool enabled, enum tpio_pin_protocol pin_protocol,
        ret = jaylink_swo_stop(devh);
 
        if (ret != JAYLINK_OK) {
-               LOG_ERROR("jaylink_swo_stop() failed: %s.", jaylink_strerror_name(ret));
+               LOG_ERROR("jaylink_swo_stop() failed: %s.", jaylink_strerror(ret));
                return ERROR_FAIL;
        }
 
@@ -1139,18 +1341,18 @@ static int config_trace(bool enabled, enum tpio_pin_protocol pin_protocol,
                return ERROR_FAIL;
        }
 
-       ret = jaylink_swo_get_speeds(devh, JAYLINK_SWO_MODE_UART, &freq, &div);
+       ret = jaylink_swo_get_speeds(devh, JAYLINK_SWO_MODE_UART, &speed);
 
        if (ret != JAYLINK_OK) {
                LOG_ERROR("jaylink_swo_get_speeds() failed: %s.",
-                       jaylink_strerror_name(ret));
+                       jaylink_strerror(ret));
                return ERROR_FAIL;
        }
 
        if (!*trace_freq)
-               *trace_freq = freq / div;
+               *trace_freq = speed.freq / speed.min_div;
 
-       if (!check_trace_freq(freq, div, *trace_freq))
+       if (!check_trace_freq(speed, *trace_freq))
                return ERROR_FAIL;
 
        LOG_DEBUG("Using %u bytes device memory for trace capturing.", buffer_size);
@@ -1159,8 +1361,7 @@ static int config_trace(bool enabled, enum tpio_pin_protocol pin_protocol,
                buffer_size);
 
        if (ret != JAYLINK_OK) {
-               LOG_ERROR("jaylink_start_swo() failed: %s.",
-                       jaylink_strerror_name(ret));
+               LOG_ERROR("jaylink_start_swo() failed: %s.", jaylink_strerror(ret));
                return ERROR_FAIL;
        }
 
@@ -1179,27 +1380,27 @@ COMMAND_HANDLER(jlink_handle_config_usb_address_command)
        uint8_t tmp;
 
        if (!jaylink_has_cap(caps, JAYLINK_DEV_CAP_READ_CONFIG)) {
-               command_print(CMD_CTX, "Reading configuration is not supported by the "
+               command_print(CMD, "Reading configuration is not supported by the "
                        "device.");
                return ERROR_OK;
        }
 
        if (!CMD_ARGC) {
-               show_config_usb_address(CMD_CTX);
+               show_config_usb_address(CMD);
        } else if (CMD_ARGC == 1) {
                if (sscanf(CMD_ARGV[0], "%" SCNd8, &tmp) != 1) {
-                       command_print(CMD_CTX, "Invalid USB address: %s.", CMD_ARGV[0]);
+                       command_print(CMD, "Invalid USB address: %s.", CMD_ARGV[0]);
                        return ERROR_FAIL;
                }
 
                if (tmp > JAYLINK_USB_ADDRESS_3) {
-                       command_print(CMD_CTX, "Invalid USB address: %u.", tmp);
+                       command_print(CMD, "Invalid USB address: %u.", tmp);
                        return ERROR_FAIL;
                }
 
                tmp_config.usb_address = tmp;
        } else {
-               command_print(CMD_CTX, "Need exactly one argument for jlink config "
+               command_print(CMD, "Need exactly one argument for jlink config "
                        "usb.");
                return ERROR_COMMAND_SYNTAX_ERROR;
        }
@@ -1212,32 +1413,32 @@ COMMAND_HANDLER(jlink_handle_config_target_power_command)
        int enable;
 
        if (!jaylink_has_cap(caps, JAYLINK_DEV_CAP_READ_CONFIG)) {
-               command_print(CMD_CTX, "Reading configuration is not supported by the "
+               command_print(CMD, "Reading configuration is not supported by the "
                        "device.");
                return ERROR_OK;
        }
 
        if (!jaylink_has_cap(caps, JAYLINK_DEV_CAP_SET_TARGET_POWER)) {
-               command_print(CMD_CTX, "Target power supply is not supported by the "
+               command_print(CMD, "Target power supply is not supported by the "
                        "device.");
                return ERROR_OK;
        }
 
        if (!CMD_ARGC) {
-               show_config_target_power(CMD_CTX);
+               show_config_target_power(CMD);
        } else if (CMD_ARGC == 1) {
                if (!strcmp(CMD_ARGV[0], "on")) {
                        enable = true;
                } else if (!strcmp(CMD_ARGV[0], "off")) {
                        enable = false;
                } else {
-                       command_print(CMD_CTX, "Invalid argument: %s.", CMD_ARGV[0]);
+                       command_print(CMD, "Invalid argument: %s.", CMD_ARGV[0]);
                        return ERROR_FAIL;
                }
 
                tmp_config.target_power = enable;
        } else {
-               command_print(CMD_CTX, "Need exactly one argument for jlink config "
+               command_print(CMD, "Need exactly one argument for jlink config "
                        "targetpower.");
                return ERROR_COMMAND_SYNTAX_ERROR;
        }
@@ -1253,25 +1454,25 @@ COMMAND_HANDLER(jlink_handle_config_mac_address_command)
        const char *str;
 
        if (!jaylink_has_cap(caps, JAYLINK_DEV_CAP_READ_CONFIG)) {
-               command_print(CMD_CTX, "Reading configuration is not supported by the "
+               command_print(CMD, "Reading configuration is not supported by the "
                        "device.");
                return ERROR_OK;
        }
 
        if (!jaylink_has_cap(caps, JAYLINK_DEV_CAP_ETHERNET)) {
-               command_print(CMD_CTX, "Ethernet connectivity is not supported by the "
+               command_print(CMD, "Ethernet connectivity is not supported by the "
                        "device.");
                return ERROR_OK;
        }
 
        if (!CMD_ARGC) {
-               show_config_mac_address(CMD_CTX);
+               show_config_mac_address(CMD);
        } else if (CMD_ARGC == 1) {
                str = CMD_ARGV[0];
 
                if ((strlen(str) != 17) || (str[2] != ':' || str[5] != ':' || \
                                str[8] != ':' || str[11] != ':' || str[14] != ':')) {
-                       command_print(CMD_CTX, "Invalid MAC address format.");
+                       command_print(CMD, "Invalid MAC address format.");
                        return ERROR_COMMAND_SYNTAX_ERROR;
                }
 
@@ -1281,18 +1482,18 @@ COMMAND_HANDLER(jlink_handle_config_mac_address_command)
                }
 
                if (!(addr[0] | addr[1] | addr[2] | addr[3] | addr[4] | addr[5])) {
-                       command_print(CMD_CTX, "Invalid MAC address: zero address.");
+                       command_print(CMD, "Invalid MAC address: zero address.");
                        return ERROR_COMMAND_SYNTAX_ERROR;
                }
 
                if (!(0x01 & addr[0])) {
-                       command_print(CMD_CTX, "Invalid MAC address: multicast address.");
+                       command_print(CMD, "Invalid MAC address: multicast address.");
                        return ERROR_COMMAND_SYNTAX_ERROR;
                }
 
                memcpy(tmp_config.mac_address, addr, sizeof(addr));
        } else {
-               command_print(CMD_CTX, "Need exactly one argument for jlink config "
+               command_print(CMD, "Need exactly one argument for jlink config "
                        " mac.");
                return ERROR_COMMAND_SYNTAX_ERROR;
        }
@@ -1341,19 +1542,19 @@ COMMAND_HANDLER(jlink_handle_config_ip_address_command)
        uint8_t subnet_bits = 24;
 
        if (!jaylink_has_cap(caps, JAYLINK_DEV_CAP_READ_CONFIG)) {
-               command_print(CMD_CTX, "Reading configuration is not supported by the "
+               command_print(CMD, "Reading configuration is not supported by the "
                        "device.");
                return ERROR_OK;
        }
 
        if (!jaylink_has_cap(caps, JAYLINK_DEV_CAP_ETHERNET)) {
-               command_print(CMD_CTX, "Ethernet connectivity is not supported by the "
+               command_print(CMD, "Ethernet connectivity is not supported by the "
                        "device.");
                return ERROR_OK;
        }
 
        if (!CMD_ARGC) {
-               show_config_ip_address(CMD_CTX);
+               show_config_ip_address(CMD);
        } else {
                if (!string_to_ip(CMD_ARGV[0], ip_address, &i))
                        return ERROR_COMMAND_SYNTAX_ERROR;
@@ -1398,19 +1599,19 @@ COMMAND_HANDLER(jlink_handle_config_write_command)
        int ret;
 
        if (!jaylink_has_cap(caps, JAYLINK_DEV_CAP_READ_CONFIG)) {
-               command_print(CMD_CTX, "Reading configuration is not supported by the "
+               command_print(CMD, "Reading configuration is not supported by the "
                        "device.");
                return ERROR_OK;
        }
 
        if (!jaylink_has_cap(caps, JAYLINK_DEV_CAP_WRITE_CONFIG)) {
-               command_print(CMD_CTX, "Writing configuration is not supported by the "
+               command_print(CMD, "Writing configuration is not supported by the "
                        "device.");
                return ERROR_OK;
        }
 
        if (!memcmp(&config, &tmp_config, sizeof(struct device_config))) {
-               command_print(CMD_CTX, "Operation not performed due to no changes in "
+               command_print(CMD, "Operation not performed due to no changes in "
                        "the configuration.");
                return ERROR_OK;
        }
@@ -1419,7 +1620,7 @@ COMMAND_HANDLER(jlink_handle_config_write_command)
 
        if (ret != JAYLINK_OK) {
                LOG_ERROR("jaylink_write_raw_config() failed: %s.",
-                       jaylink_strerror_name(ret));
+                       jaylink_strerror(ret));
                return ERROR_FAIL;
        }
 
@@ -1435,7 +1636,7 @@ COMMAND_HANDLER(jlink_handle_config_write_command)
        }
 
        memcpy(&tmp_config, &config, sizeof(struct device_config));
-       command_print(CMD_CTX, "The new device configuration applies after power "
+       command_print(CMD, "The new device configuration applies after power "
                "cycling the J-Link device.");
 
        return ERROR_OK;
@@ -1444,12 +1645,129 @@ COMMAND_HANDLER(jlink_handle_config_write_command)
 COMMAND_HANDLER(jlink_handle_config_command)
 {
        if (!jaylink_has_cap(caps, JAYLINK_DEV_CAP_READ_CONFIG)) {
-               command_print(CMD_CTX, "Device doesn't support reading configuration.");
+               command_print(CMD, "Device doesn't support reading configuration.");
                return ERROR_OK;
        }
 
        if (CMD_ARGC == 0)
-               show_config(CMD_CTX);
+               show_config(CMD);
+
+       return ERROR_OK;
+}
+
+COMMAND_HANDLER(jlink_handle_emucom_write_command)
+{
+       int ret;
+       size_t tmp;
+       uint32_t channel;
+       uint32_t length;
+       uint8_t *buf;
+       size_t dummy;
+
+       if (CMD_ARGC != 2)
+               return ERROR_COMMAND_SYNTAX_ERROR;
+
+       if (!jaylink_has_cap(caps, JAYLINK_DEV_CAP_EMUCOM)) {
+               LOG_ERROR("Device does not support EMUCOM.");
+               return ERROR_FAIL;
+       }
+
+       COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], channel);
+
+       tmp = strlen(CMD_ARGV[1]);
+
+       if (tmp % 2 != 0) {
+               LOG_ERROR("Data must be encoded as hexadecimal pairs.");
+               return ERROR_COMMAND_ARGUMENT_INVALID;
+       }
+
+       buf = malloc(tmp / 2);
+
+       if (!buf) {
+               LOG_ERROR("Failed to allocate buffer.");
+               return ERROR_FAIL;
+       }
+
+       dummy = unhexify(buf, CMD_ARGV[1], tmp / 2);
+
+       if (dummy != (tmp / 2)) {
+               LOG_ERROR("Data must be encoded as hexadecimal pairs.");
+               free(buf);
+               return ERROR_COMMAND_ARGUMENT_INVALID;
+       }
+
+       length = tmp / 2;
+       ret = jaylink_emucom_write(devh, channel, buf, &length);
+
+       free(buf);
+
+       if (ret == JAYLINK_ERR_DEV_NOT_SUPPORTED) {
+               LOG_ERROR("Channel not supported by the device.");
+               return ERROR_FAIL;
+       } else if (ret != JAYLINK_OK) {
+               LOG_ERROR("Failed to write to channel: %s.", jaylink_strerror(ret));
+               return ERROR_FAIL;
+       }
+
+       if (length != (tmp / 2))
+               LOG_WARNING("Only %" PRIu32 " bytes written to the channel.", length);
+
+       return ERROR_OK;
+}
+
+COMMAND_HANDLER(jlink_handle_emucom_read_command)
+{
+       int ret;
+       uint32_t channel;
+       uint32_t length;
+       uint8_t *buf;
+       size_t tmp;
+
+       if (CMD_ARGC != 2)
+               return ERROR_COMMAND_SYNTAX_ERROR;
+
+       if (!jaylink_has_cap(caps, JAYLINK_DEV_CAP_EMUCOM)) {
+               LOG_ERROR("Device does not support EMUCOM.");
+               return ERROR_FAIL;
+       }
+
+       COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], channel);
+       COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], length);
+
+       buf = malloc(length * 3 + 1);
+
+       if (!buf) {
+               LOG_ERROR("Failed to allocate buffer.");
+               return ERROR_FAIL;
+       }
+
+       ret = jaylink_emucom_read(devh, channel, buf, &length);
+
+       if (ret == JAYLINK_ERR_DEV_NOT_SUPPORTED) {
+               LOG_ERROR("Channel is not supported by the device.");
+               free(buf);
+               return ERROR_FAIL;
+       } else if (ret == JAYLINK_ERR_DEV_NOT_AVAILABLE) {
+               LOG_ERROR("Channel is not available for the requested amount of data. "
+                       "%" PRIu32 " bytes are avilable.", length);
+               free(buf);
+               return ERROR_FAIL;
+       } else if (ret != JAYLINK_OK) {
+               LOG_ERROR("Failed to read from channel: %s.", jaylink_strerror(ret));
+               free(buf);
+               return ERROR_FAIL;
+       }
+
+       tmp = hexify((char *)buf + length, buf, length, 2 * length + 1);
+
+       if (tmp != 2 * length) {
+               LOG_ERROR("Failed to convert data into hexadecimal string.");
+               free(buf);
+               return ERROR_FAIL;
+       }
+
+       command_print(CMD, "%s", buf + length);
+       free(buf);
 
        return ERROR_OK;
 }
@@ -1488,13 +1806,33 @@ static const struct command_registration jlink_config_subcommand_handlers[] = {
                .name = "reset",
                .handler = &jlink_handle_config_reset_command,
                .mode = COMMAND_EXEC,
-               .help = "undo configuration changes"
+               .help = "undo configuration changes",
+               .usage = "",
        },
        {
                .name = "write",
                .handler = &jlink_handle_config_write_command,
                .mode = COMMAND_EXEC,
-               .help = "write configuration to the device"
+               .help = "write configuration to the device",
+               .usage = "",
+       },
+       COMMAND_REGISTRATION_DONE
+};
+
+static const struct command_registration jlink_emucom_subcommand_handlers[] = {
+       {
+               .name = "write",
+               .handler = &jlink_handle_emucom_write_command,
+               .mode = COMMAND_EXEC,
+               .help = "write to a channel",
+               .usage = "<channel> <data>",
+       },
+       {
+               .name = "read",
+               .handler = &jlink_handle_emucom_read_command,
+               .mode = COMMAND_EXEC,
+               .help = "read from a channel",
+               .usage = "<channel> <length>"
        },
        COMMAND_REGISTRATION_DONE
 };
@@ -1518,13 +1856,15 @@ static const struct command_registration jlink_subcommand_handlers[] = {
                .name = "freemem",
                .handler = &jlink_handle_free_memory_command,
                .mode = COMMAND_EXEC,
-               .help = "show free device memory"
+               .help = "show free device memory",
+               .usage = "",
        },
        {
                .name = "hwstatus",
                .handler = &jlink_handle_hwstatus_command,
                .mode = COMMAND_EXEC,
-               .help = "show the hardware status"
+               .help = "show the hardware status",
+               .usage = "",
        },
        {
                .name = "usb",
@@ -1547,6 +1887,14 @@ static const struct command_registration jlink_subcommand_handlers[] = {
                .help = "access the device configuration. If no argument is given "
                        "this will show the device configuration",
                .chain = jlink_config_subcommand_handlers,
+               .usage = "[<cmd>]",
+       },
+       {
+               .name = "emucom",
+               .mode = COMMAND_EXEC,
+               .help = "access EMUCOM channel",
+               .chain = jlink_emucom_subcommand_handlers,
+               .usage = "",
        },
        COMMAND_REGISTRATION_DONE
 };
@@ -1557,6 +1905,7 @@ static const struct command_registration jlink_command_handlers[] = {
                .mode = COMMAND_ANY,
                .help = "perform jlink management",
                .chain = jlink_subcommand_handlers,
+               .usage = "",
        },
        COMMAND_REGISTRATION_DONE
 };
@@ -1568,22 +1917,19 @@ static int jlink_swd_init(void)
        return ERROR_OK;
 }
 
-static void jlink_swd_write_reg(struct adiv5_dap *dap, uint8_t cmd,
-               uint32_t value)
+static void jlink_swd_write_reg(uint8_t cmd, uint32_t value, uint32_t ap_delay_clk)
 {
        assert(!(cmd & SWD_CMD_RnW));
-       jlink_swd_queue_cmd(dap, cmd, NULL, value);
+       jlink_swd_queue_cmd(cmd, NULL, value, ap_delay_clk);
 }
 
-static void jlink_swd_read_reg(struct adiv5_dap *dap, uint8_t cmd,
-               uint32_t *value)
+static void jlink_swd_read_reg(uint8_t cmd, uint32_t *value, uint32_t ap_delay_clk)
 {
        assert(cmd & SWD_CMD_RnW);
-       jlink_swd_queue_cmd(dap, cmd, value, 0);
+       jlink_swd_queue_cmd(cmd, value, 0, ap_delay_clk);
 }
 
-static int_least32_t jlink_swd_frequency(struct adiv5_dap *dap,
-               int_least32_t hz)
+static int_least32_t jlink_swd_frequency(int_least32_t hz)
 {
        if (hz > 0)
                jlink_speed(hz / 1000);
@@ -1601,10 +1947,14 @@ static uint8_t tdi_buffer[JLINK_TAP_BUFFER_SIZE];
 static uint8_t tdo_buffer[JLINK_TAP_BUFFER_SIZE];
 
 struct pending_scan_result {
-       int first; /* First bit position in tdo_buffer to read. */
-       int length; /* Number of bits to read. */
-       struct scan_command *command; /* Corresponding scan command. */
+       /** First bit position in tdo_buffer to read. */
+       unsigned first;
+       /** Number of bits to read. */
+       unsigned length;
+       /** Location to store the result */
        void *buffer;
+       /** Offset in the destination buffer */
+       unsigned buffer_offset;
 };
 
 #define MAX_PENDING_SCAN_RESULTS 256
@@ -1616,69 +1966,53 @@ static void jlink_tap_init(void)
 {
        tap_length = 0;
        pending_scan_results_length = 0;
+       memset(tms_buffer, 0, sizeof(tms_buffer));
+       memset(tdi_buffer, 0, sizeof(tdi_buffer));
 }
 
-static void jlink_tap_ensure_space(int scans, int bits)
+static void jlink_clock_data(const uint8_t *out, unsigned out_offset,
+                            const uint8_t *tms_out, unsigned tms_offset,
+                            uint8_t *in, unsigned in_offset,
+                            unsigned length)
 {
-       int available_scans = MAX_PENDING_SCAN_RESULTS - pending_scan_results_length;
-       int available_bits = JLINK_TAP_BUFFER_SIZE * 8 - tap_length - 32;
-
-       if (scans > available_scans || bits > available_bits)
-               jlink_tap_execute();
-}
-
-static void jlink_tap_append_step(int tms, int tdi)
-{
-       int index_var = tap_length / 8;
-
-       assert(index_var < JLINK_TAP_BUFFER_SIZE);
-
-       int bit_index = tap_length % 8;
-       uint8_t bit = 1 << bit_index;
-
-       /* We do not pad TMS, so be sure to initialize all bits. */
-       if (0 == bit_index)
-               tms_buffer[index_var] = tdi_buffer[index_var] = 0;
-
-       if (tms)
-               tms_buffer[index_var] |= bit;
-       else
-               tms_buffer[index_var] &= ~bit;
-
-       if (tdi)
-               tdi_buffer[index_var] |= bit;
-       else
-               tdi_buffer[index_var] &= ~bit;
+       do {
+               unsigned available_length = JLINK_TAP_BUFFER_SIZE - tap_length / 8;
+
+               if (!available_length ||
+                   (in && pending_scan_results_length == MAX_PENDING_SCAN_RESULTS)) {
+                       if (jlink_flush() != ERROR_OK)
+                               return;
+                       available_length = JLINK_TAP_BUFFER_SIZE;
+               }
 
-       tap_length++;
-}
+               struct pending_scan_result *pending_scan_result =
+                       &pending_scan_results_buffer[pending_scan_results_length];
 
-static void jlink_tap_append_scan(int length, uint8_t *buffer,
-               struct scan_command *command)
-{
-       struct pending_scan_result *pending_scan_result =
-               &pending_scan_results_buffer[pending_scan_results_length];
-       int i;
+               unsigned scan_length = length > available_length ?
+                       available_length : length;
 
-       pending_scan_result->first = tap_length;
-       pending_scan_result->length = length;
-       pending_scan_result->command = command;
-       pending_scan_result->buffer = buffer;
+               if (out)
+                       buf_set_buf(out, out_offset, tdi_buffer, tap_length, scan_length);
+               if (tms_out)
+                       buf_set_buf(tms_out, tms_offset, tms_buffer, tap_length, scan_length);
 
-       for (i = 0; i < length; i++) {
-               int tms = (i < (length - 1)) ? 0 : 1;
-               int tdi = (buffer[i / 8] & (1 << (i % 8))) != 0;
-               jlink_tap_append_step(tms, tdi);
-       }
+               if (in) {
+                       pending_scan_result->first = tap_length;
+                       pending_scan_result->length = scan_length;
+                       pending_scan_result->buffer = in;
+                       pending_scan_result->buffer_offset = in_offset;
+                       pending_scan_results_length++;
+               }
 
-       pending_scan_results_length++;
+               tap_length += scan_length;
+               out_offset += scan_length;
+               tms_offset += scan_length;
+               in_offset += scan_length;
+               length -= scan_length;
+       } while (length > 0);
 }
 
-/*
- * Pad and send a tap sequence to the device, and receive the answer. For the
- * purpose of padding we assume that we are in idle or pause state.
- */
-static int jlink_tap_execute(void)
+static int jlink_flush(void)
 {
        int i;
        int ret;
@@ -1689,37 +2023,22 @@ static int jlink_tap_execute(void)
        jlink_last_state = jtag_debug_state_machine(tms_buffer, tdi_buffer,
                tap_length, jlink_last_state);
 
-       jlink_last_state = jtag_debug_state_machine(tms_buffer, tdi_buffer,
-               tap_length, jlink_last_state);
-
        ret = jaylink_jtag_io(devh, tms_buffer, tdi_buffer, tdo_buffer,
                tap_length, jtag_command_version);
 
        if (ret != JAYLINK_OK) {
-               LOG_ERROR("jaylink_jtag_io() failed: %s.", jaylink_strerror_name(ret));
+               LOG_ERROR("jaylink_jtag_io() failed: %s.", jaylink_strerror(ret));
                jlink_tap_init();
                return ERROR_JTAG_QUEUE_FAILED;
        }
 
        for (i = 0; i < pending_scan_results_length; i++) {
-               struct pending_scan_result *pending_scan_result = &pending_scan_results_buffer[i];
-               uint8_t *buffer = pending_scan_result->buffer;
-               int length = pending_scan_result->length;
-               int first = pending_scan_result->first;
-               struct scan_command *command = pending_scan_result->command;
-
-               /* Copy to buffer. */
-               buf_set_buf(tdo_buffer, first, buffer, 0, length);
+               struct pending_scan_result *p = &pending_scan_results_buffer[i];
 
-               DEBUG_JTAG_IO("Pending scan result, length = %d.", length);
-
-               if (jtag_read_buffer(buffer, command) != ERROR_OK) {
-                       jlink_tap_init();
-                       return ERROR_JTAG_QUEUE_FAILED;
-               }
+               buf_set_buf(tdo_buffer, p->first, p->buffer,
+                           p->buffer_offset, p->length);
 
-               if (pending_scan_result->buffer != NULL)
-                       free(pending_scan_result->buffer);
+               DEBUG_JTAG_IO("Pending scan result, length = %d.", p->length);
        }
 
        jlink_tap_init();
@@ -1762,7 +2081,7 @@ static void jlink_queue_data_in(uint32_t len)
        tap_length += len;
 }
 
-static int jlink_swd_switch_seq(struct adiv5_dap *dap, enum swd_special_seq seq)
+static int jlink_swd_switch_seq(enum swd_special_seq seq)
 {
        const uint8_t *s;
        unsigned int s_len;
@@ -1793,7 +2112,7 @@ static int jlink_swd_switch_seq(struct adiv5_dap *dap, enum swd_special_seq seq)
        return ERROR_OK;
 }
 
-static int jlink_swd_run_queue(struct adiv5_dap *dap)
+static int jlink_swd_run_queue(void)
 {
        int i;
        int ret;
@@ -1814,7 +2133,7 @@ static int jlink_swd_run_queue(struct adiv5_dap *dap)
        ret = jaylink_swd_io(devh, tms_buffer, tdi_buffer, tdo_buffer, tap_length);
 
        if (ret != JAYLINK_OK) {
-               LOG_ERROR("jaylink_swd_io() failed: %s.", jaylink_strerror_name(ret));
+               LOG_ERROR("jaylink_swd_io() failed: %s.", jaylink_strerror(ret));
                goto skip;
        }
 
@@ -1849,14 +2168,13 @@ skip:
        return ret;
 }
 
-static void jlink_swd_queue_cmd(struct adiv5_dap *dap, uint8_t cmd,
-               uint32_t *dst, uint32_t data)
+static void jlink_swd_queue_cmd(uint8_t cmd, uint32_t *dst, uint32_t data, uint32_t ap_delay_clk)
 {
        uint8_t data_parity_trn[DIV_ROUND_UP(32 + 1, 8)];
-       if (tap_length + 46 + 8 + dap->ap[dap_ap_get_select(dap)].memaccess_tck >= sizeof(tdi_buffer) * 8 ||
+       if (tap_length + 46 + 8 + ap_delay_clk >= swd_buffer_size * 8 ||
            pending_scan_results_length == MAX_PENDING_SCAN_RESULTS) {
                /* Not enough room in the queue. Run the queue. */
-               queued_retval = jlink_swd_run_queue(dap);
+               queued_retval = jlink_swd_run_queue();
        }
 
        if (queued_retval != ERROR_OK)
@@ -1889,7 +2207,7 @@ static void jlink_swd_queue_cmd(struct adiv5_dap *dap, uint8_t cmd,
 
        /* Insert idle cycles after AP accesses to avoid WAIT. */
        if (cmd & SWD_CMD_APnDP)
-               jlink_queue_data_out(NULL, dap->ap[dap_ap_get_select(dap)].memaccess_tck);
+               jlink_queue_data_out(NULL, ap_delay_clk);
 }
 
 static const struct swd_driver jlink_swd = {

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)