jtag: cmsis-dap: developer tool - enter a command by hex nuber
[openocd.git] / src / jtag / drivers / cmsis_dap_usb.c
index dd37522ad169e595cc05cedd0a2f3caed93e0cdb..9d6bf7fc04b491bc6efbf1dc9f0391580bf6a2fb 100644 (file)
@@ -166,7 +166,7 @@ static const char * const info_caps_str[] = {
 struct cmsis_dap {
        hid_device *dev_handle;
        uint16_t packet_size;
-       uint16_t packet_count;
+       int packet_count;
        uint8_t *packet_buffer;
        uint8_t caps;
        uint8_t mode;
@@ -178,6 +178,11 @@ struct pending_transfer_result {
        void *buffer;
 };
 
+struct pending_request_block {
+       struct pending_transfer_result *transfers;
+       int transfer_count;
+};
+
 struct pending_scan_result {
        /** Offset in bytes in the CMD_DAP_JTAG_SEQ response buffer. */
        unsigned first;
@@ -189,8 +194,16 @@ struct pending_scan_result {
        unsigned buffer_offset;
 };
 
-static int pending_transfer_count, pending_queue_len;
-static struct pending_transfer_result *pending_transfers;
+/* Up to MIN(packet_count, MAX_PENDING_REQUESTS) requests may be issued
+ * until the first response arrives */
+#define MAX_PENDING_REQUESTS 3
+
+/* Pending requests are organized as a FIFO - circular buffer */
+/* Each block in FIFO can contain up to pending_queue_len transfers */
+static int pending_queue_len;
+static struct pending_request_block pending_fifo[MAX_PENDING_REQUESTS];
+static int pending_fifo_put_idx, pending_fifo_get_idx;
+static int pending_fifo_block_count;
 
 /* pointers to buffers that will receive jtag scan results on the next flush */
 #define MAX_PENDING_SCAN_RESULTS 256
@@ -206,6 +219,8 @@ static uint8_t queued_seq_buf[1024]; /* TODO: make dynamic / move into cmsis obj
 
 static int queued_retval;
 
+static uint8_t output_pins = SWJ_PIN_SRST | SWJ_PIN_TRST;
+
 static struct cmsis_dap *cmsis_dap_handle;
 
 static int cmsis_dap_usb_open(void)
@@ -344,14 +359,16 @@ static void cmsis_dap_usb_close(struct cmsis_dap *dap)
        cmsis_dap_handle = NULL;
        free(cmsis_dap_serial);
        cmsis_dap_serial = NULL;
-       free(pending_transfers);
-       pending_transfers = NULL;
+
+       for (int i = 0; i < MAX_PENDING_REQUESTS; i++) {
+               free(pending_fifo[i].transfers);
+               pending_fifo[i].transfers = NULL;
+       }
 
        return;
 }
 
-/* Send a message and receive the reply */
-static int cmsis_dap_usb_xfer(struct cmsis_dap *dap, int txlen)
+static int cmsis_dap_usb_write(struct cmsis_dap *dap, int txlen)
 {
 #ifdef CMSIS_DAP_JTAG_DEBUG
        LOG_DEBUG("cmsis-dap usb xfer cmd=%02X", dap->packet_buffer[1]);
@@ -366,6 +383,26 @@ static int cmsis_dap_usb_xfer(struct cmsis_dap *dap, int txlen)
                return ERROR_FAIL;
        }
 
+       return ERROR_OK;
+}
+
+/* Send a message and receive the reply */
+static int cmsis_dap_usb_xfer(struct cmsis_dap *dap, int txlen)
+{
+       if (pending_fifo_block_count) {
+               LOG_ERROR("pending %d blocks, flushing", pending_fifo_block_count);
+               while (pending_fifo_block_count) {
+                       hid_read_timeout(dap->dev_handle, dap->packet_buffer, dap->packet_size, 10);
+                       pending_fifo_block_count--;
+               }
+               pending_fifo_put_idx = 0;
+               pending_fifo_get_idx = 0;
+       }
+
+       int retval = cmsis_dap_usb_write(dap, txlen);
+       if (retval != ERROR_OK)
+               return retval;
+
        /* get reply */
        retval = hid_read_timeout(dap->dev_handle, dap->packet_buffer, dap->packet_size, USB_TIMEOUT);
        if (retval == -1 || retval == 0) {
@@ -592,31 +629,33 @@ static int cmsis_dap_cmd_DAP_Delay(uint16_t delay_us)
 }
 #endif
 
-static int cmsis_dap_swd_run_queue(void)
+static void cmsis_dap_swd_write_from_queue(struct cmsis_dap *dap)
 {
-       uint8_t *buffer = cmsis_dap_handle->packet_buffer;
+       uint8_t *buffer = dap->packet_buffer;
+       struct pending_request_block *block = &pending_fifo[pending_fifo_put_idx];
 
-       LOG_DEBUG("Executing %d queued transactions", pending_transfer_count);
+       LOG_DEBUG_IO("Executing %d queued transactions from FIFO index %d", block->transfer_count, pending_fifo_put_idx);
 
        if (queued_retval != ERROR_OK) {
                LOG_DEBUG("Skipping due to previous errors: %d", queued_retval);
                goto skip;
        }
 
-       if (!pending_transfer_count)
+       if (block->transfer_count == 0)
                goto skip;
 
        size_t idx = 0;
        buffer[idx++] = 0;      /* report number */
        buffer[idx++] = CMD_DAP_TFER;
        buffer[idx++] = 0x00;   /* DAP Index */
-       buffer[idx++] = pending_transfer_count;
+       buffer[idx++] = block->transfer_count;
 
-       for (int i = 0; i < pending_transfer_count; i++) {
-               uint8_t cmd = pending_transfers[i].cmd;
-               uint32_t data = pending_transfers[i].data;
+       for (int i = 0; i < block->transfer_count; i++) {
+               struct pending_transfer_result *transfer = &(block->transfers[i]);
+               uint8_t cmd = transfer->cmd;
+               uint32_t data = transfer->data;
 
-               LOG_DEBUG("%s %s reg %x %"PRIx32,
+               LOG_DEBUG_IO("%s %s reg %x %"PRIx32,
                                cmd & SWD_CMD_APnDP ? "AP" : "DP",
                                cmd & SWD_CMD_RnW ? "read" : "write",
                          (cmd & SWD_CMD_A32) >> 1, data);
@@ -649,47 +688,100 @@ static int cmsis_dap_swd_run_queue(void)
                }
        }
 
-       queued_retval = cmsis_dap_usb_xfer(cmsis_dap_handle, idx);
+       queued_retval = cmsis_dap_usb_write(dap, idx);
        if (queued_retval != ERROR_OK)
                goto skip;
 
-       idx = 2;
-       uint8_t ack = buffer[idx] & 0x07;
-       if (ack != SWD_ACK_OK || (buffer[idx] & 0x08)) {
-               LOG_DEBUG("SWD ack not OK: %d %s", buffer[idx-1],
+       pending_fifo_put_idx = (pending_fifo_put_idx + 1) % dap->packet_count;
+       pending_fifo_block_count++;
+       if (pending_fifo_block_count > dap->packet_count)
+               LOG_ERROR("too much pending writes %d", pending_fifo_block_count);
+
+       return;
+
+skip:
+       block->transfer_count = 0;
+}
+
+static void cmsis_dap_swd_read_process(struct cmsis_dap *dap, int timeout_ms)
+{
+       uint8_t *buffer = dap->packet_buffer;
+       struct pending_request_block *block = &pending_fifo[pending_fifo_get_idx];
+
+       if (pending_fifo_block_count == 0)
+               LOG_ERROR("no pending write");
+
+       /* get reply */
+       int retval = hid_read_timeout(dap->dev_handle, dap->packet_buffer, dap->packet_size, timeout_ms);
+       if (retval == 0 && timeout_ms < USB_TIMEOUT)
+               return;
+
+       if (retval == -1 || retval == 0) {
+               LOG_DEBUG("error reading data: %ls", hid_error(dap->dev_handle));
+               queued_retval = ERROR_FAIL;
+               goto skip;
+       }
+
+       if (buffer[2] & 0x08) {
+               LOG_DEBUG("CMSIS-DAP Protocol Error @ %d (wrong parity)", buffer[1]);
+               queued_retval = ERROR_FAIL;
+               goto skip;
+       }
+       uint8_t ack = buffer[2] & 0x07;
+       if (ack != SWD_ACK_OK) {
+               LOG_DEBUG("SWD ack not OK @ %d %s", buffer[1],
                          ack == SWD_ACK_WAIT ? "WAIT" : ack == SWD_ACK_FAULT ? "FAULT" : "JUNK");
                queued_retval = ack == SWD_ACK_WAIT ? ERROR_WAIT : ERROR_FAIL;
                goto skip;
        }
-       idx++;
 
-       if (pending_transfer_count != buffer[1])
+       if (block->transfer_count != buffer[1])
                LOG_ERROR("CMSIS-DAP transfer count mismatch: expected %d, got %d",
-                         pending_transfer_count, buffer[1]);
+                         block->transfer_count, buffer[1]);
 
+       LOG_DEBUG_IO("Received results of %d queued transactions FIFO index %d", buffer[1], pending_fifo_get_idx);
+       size_t idx = 3;
        for (int i = 0; i < buffer[1]; i++) {
-               if (pending_transfers[i].cmd & SWD_CMD_RnW) {
+               struct pending_transfer_result *transfer = &(block->transfers[i]);
+               if (transfer->cmd & SWD_CMD_RnW) {
                        static uint32_t last_read;
                        uint32_t data = le_to_h_u32(&buffer[idx]);
                        uint32_t tmp = data;
                        idx += 4;
 
-                       LOG_DEBUG("Read result: %"PRIx32, data);
+                       LOG_DEBUG_IO("Read result: %"PRIx32, data);
 
                        /* Imitate posted AP reads */
-                       if ((pending_transfers[i].cmd & SWD_CMD_APnDP) ||
-                           ((pending_transfers[i].cmd & SWD_CMD_A32) >> 1 == DP_RDBUFF)) {
+                       if ((transfer->cmd & SWD_CMD_APnDP) ||
+                           ((transfer->cmd & SWD_CMD_A32) >> 1 == DP_RDBUFF)) {
                                tmp = last_read;
                                last_read = data;
                        }
 
-                       if (pending_transfers[i].buffer)
-                               *(uint32_t *)pending_transfers[i].buffer = tmp;
+                       if (transfer->buffer)
+                               *(uint32_t *)(transfer->buffer) = tmp;
                }
        }
 
 skip:
-       pending_transfer_count = 0;
+       block->transfer_count = 0;
+       pending_fifo_get_idx = (pending_fifo_get_idx + 1) % dap->packet_count;
+       pending_fifo_block_count--;
+}
+
+static int cmsis_dap_swd_run_queue(void)
+{
+       if (pending_fifo_block_count)
+               cmsis_dap_swd_read_process(cmsis_dap_handle, 0);
+
+       cmsis_dap_swd_write_from_queue(cmsis_dap_handle);
+
+       while (pending_fifo_block_count)
+               cmsis_dap_swd_read_process(cmsis_dap_handle, USB_TIMEOUT);
+
+       pending_fifo_put_idx = 0;
+       pending_fifo_get_idx = 0;
+
        int retval = queued_retval;
        queued_retval = ERROR_OK;
 
@@ -698,21 +790,29 @@ skip:
 
 static void cmsis_dap_swd_queue_cmd(uint8_t cmd, uint32_t *dst, uint32_t data)
 {
-       if (pending_transfer_count == pending_queue_len) {
+       if (pending_fifo[pending_fifo_put_idx].transfer_count == pending_queue_len) {
+               if (pending_fifo_block_count)
+                       cmsis_dap_swd_read_process(cmsis_dap_handle, 0);
+
                /* Not enough room in the queue. Run the queue. */
-               queued_retval = cmsis_dap_swd_run_queue();
+               cmsis_dap_swd_write_from_queue(cmsis_dap_handle);
+
+               if (pending_fifo_block_count >= cmsis_dap_handle->packet_count)
+                       cmsis_dap_swd_read_process(cmsis_dap_handle, USB_TIMEOUT);
        }
 
        if (queued_retval != ERROR_OK)
                return;
 
-       pending_transfers[pending_transfer_count].data = data;
-       pending_transfers[pending_transfer_count].cmd = cmd;
+       struct pending_request_block *block = &pending_fifo[pending_fifo_put_idx];
+       struct pending_transfer_result *transfer = &(block->transfers[block->transfer_count]);
+       transfer->data = data;
+       transfer->cmd = cmd;
        if (cmd & SWD_CMD_RnW) {
                /* Queue a read transaction */
-               pending_transfers[pending_transfer_count].buffer = dst;
+               transfer->buffer = dst;
        }
-       pending_transfer_count++;
+       block->transfer_count++;
 }
 
 static void cmsis_dap_swd_write_reg(uint8_t cmd, uint32_t value, uint32_t ap_delay_clk)
@@ -727,6 +827,20 @@ static void cmsis_dap_swd_read_reg(uint8_t cmd, uint32_t *value, uint32_t ap_del
        cmsis_dap_swd_queue_cmd(cmd, value, 0);
 }
 
+static int cmsis_dap_get_serial_info(void)
+{
+       uint8_t *data;
+
+       int retval = cmsis_dap_cmd_DAP_Info(INFO_ID_SERNUM, &data);
+       if (retval != ERROR_OK)
+               return retval;
+
+       if (data[0]) /* strlen */
+               LOG_INFO("CMSIS-DAP: Serial# = %s", &data[1]);
+
+       return ERROR_OK;
+}
+
 static int cmsis_dap_get_version_info(void)
 {
        uint8_t *data;
@@ -790,15 +904,20 @@ static int cmsis_dap_swd_switch_seq(enum swd_special_seq seq)
        unsigned int s_len;
        int retval;
 
-       /* First disconnect before connecting, Atmel EDBG needs it for SAMD/R/L/C */
-       cmsis_dap_cmd_DAP_Disconnect();
+       if ((output_pins & (SWJ_PIN_SRST | SWJ_PIN_TRST)) == (SWJ_PIN_SRST | SWJ_PIN_TRST)) {
+               /* Following workaround deasserts reset on most adapters.
+                * Do not reconnect if a reset line is active!
+                * Reconnecting would break connecting under reset. */
 
-       /* When we are reconnecting, DAP_Connect needs to be rerun, at
-        * least on Keil ULINK-ME */
-       retval = cmsis_dap_cmd_DAP_Connect(seq == LINE_RESET || seq == JTAG_TO_SWD ?
-                                          CONNECT_SWD : CONNECT_JTAG);
-       if (retval != ERROR_OK)
-               return retval;
+               /* First disconnect before connecting, Atmel EDBG needs it for SAMD/R/L/C */
+               cmsis_dap_cmd_DAP_Disconnect();
+
+               /* When we are reconnecting, DAP_Connect needs to be rerun, at
+                * least on Keil ULINK-ME */
+               retval = cmsis_dap_cmd_DAP_Connect(CONNECT_SWD);
+               if (retval != ERROR_OK)
+                       return retval;
+       }
 
        switch (seq) {
        case LINE_RESET:
@@ -821,24 +940,19 @@ static int cmsis_dap_swd_switch_seq(enum swd_special_seq seq)
                return ERROR_FAIL;
        }
 
-       return cmsis_dap_cmd_DAP_SWJ_Sequence(s_len, s);
+       retval = cmsis_dap_cmd_DAP_SWJ_Sequence(s_len, s);
+       if (retval != ERROR_OK)
+               return retval;
+
+       /* Atmel EDBG needs renew clock setting after SWJ_Sequence
+        * otherwise default frequency is used */
+       return cmsis_dap_cmd_DAP_SWJ_Clock(jtag_get_speed_khz());
 }
 
 static int cmsis_dap_swd_open(void)
 {
        int retval;
 
-       if (cmsis_dap_handle == NULL) {
-               /* SWD init */
-               retval = cmsis_dap_usb_open();
-               if (retval != ERROR_OK)
-                       return retval;
-
-               retval = cmsis_dap_get_caps_info();
-               if (retval != ERROR_OK)
-                       return retval;
-       }
-
        if (!(cmsis_dap_handle->caps & INFO_CAPS_SWD)) {
                LOG_ERROR("CMSIS-DAP: SWD not supported");
                return ERROR_JTAG_DEVICE_ERROR;
@@ -859,23 +973,27 @@ static int cmsis_dap_init(void)
        int retval;
        uint8_t *data;
 
-       if (swd_mode) {
-               retval = cmsis_dap_swd_open();
-               if (retval != ERROR_OK)
-                       return retval;
-       }
+       retval = cmsis_dap_usb_open();
+       if (retval != ERROR_OK)
+               return retval;
 
-       if (cmsis_dap_handle == NULL) {
+       retval = cmsis_dap_get_caps_info();
+       if (retval != ERROR_OK)
+               return retval;
 
-               /* JTAG init */
-               retval = cmsis_dap_usb_open();
-               if (retval != ERROR_OK)
-                       return retval;
+       retval = cmsis_dap_get_version_info();
+       if (retval != ERROR_OK)
+               return retval;
 
-               retval = cmsis_dap_get_caps_info();
+       retval = cmsis_dap_get_serial_info();
+       if (retval != ERROR_OK)
+               return retval;
+
+       if (swd_mode) {
+               retval = cmsis_dap_swd_open();
                if (retval != ERROR_OK)
                        return retval;
-
+       } else {
                /* Connect in JTAG mode */
                if (!(cmsis_dap_handle->caps & INFO_CAPS_JTAG)) {
                        LOG_ERROR("CMSIS-DAP: JTAG not supported");
@@ -889,9 +1007,10 @@ static int cmsis_dap_init(void)
                LOG_INFO("CMSIS-DAP: Interface Initialised (JTAG)");
        }
 
-       retval = cmsis_dap_get_version_info();
-       if (retval != ERROR_OK)
-               return retval;
+       /* Be conservative and supress submiting multiple HID requests
+        * until we get packet count info from the adaptor */
+       cmsis_dap_handle->packet_count = 1;
+       pending_queue_len = 12;
 
        /* INFO_ID_PKT_SZ - short */
        retval = cmsis_dap_cmd_DAP_Info(INFO_ID_PKT_SZ, &data);
@@ -905,11 +1024,6 @@ static int cmsis_dap_init(void)
                 * write. For bulk read sequences just 4 bytes are
                 * needed per transfer, so this is suboptimal. */
                pending_queue_len = (pkt_sz - 4) / 5;
-               pending_transfers = malloc(pending_queue_len * sizeof(*pending_transfers));
-               if (!pending_transfers) {
-                       LOG_ERROR("Unable to allocate memory for CMSIS-DAP queue");
-                       return ERROR_FAIL;
-               }
 
                if (cmsis_dap_handle->packet_size != pkt_sz + 1) {
                        /* reallocate buffer */
@@ -931,11 +1045,23 @@ static int cmsis_dap_init(void)
                return retval;
 
        if (data[0] == 1) { /* byte */
-               uint16_t pkt_cnt = data[1];
-               cmsis_dap_handle->packet_count = pkt_cnt;
-               LOG_DEBUG("CMSIS-DAP: Packet Count = %" PRId16, pkt_cnt);
+               int pkt_cnt = data[1];
+               if (pkt_cnt > 1)
+                       cmsis_dap_handle->packet_count = MIN(MAX_PENDING_REQUESTS, pkt_cnt);
+
+               LOG_DEBUG("CMSIS-DAP: Packet Count = %d", pkt_cnt);
        }
 
+       LOG_DEBUG("Allocating FIFO for %d pending HID requests", cmsis_dap_handle->packet_count);
+       for (int i = 0; i < cmsis_dap_handle->packet_count; i++) {
+               pending_fifo[i].transfers = malloc(pending_queue_len * sizeof(struct pending_transfer_result));
+               if (!pending_fifo[i].transfers) {
+                       LOG_ERROR("Unable to allocate memory for CMSIS-DAP queue");
+                       return ERROR_FAIL;
+               }
+       }
+
+
        retval = cmsis_dap_get_status();
        if (retval != ERROR_OK)
                return ERROR_FAIL;
@@ -952,11 +1078,14 @@ static int cmsis_dap_init(void)
        retval = cmsis_dap_cmd_DAP_TFER_Configure(0, 64, 0);
        if (retval != ERROR_OK)
                return ERROR_FAIL;
-       /* Data Phase (bit 2) must be set to 1 if sticky overrun
-        * detection is enabled */
-       retval = cmsis_dap_cmd_DAP_SWD_Configure(0);    /* 1 TRN, no Data Phase */
-       if (retval != ERROR_OK)
-               return ERROR_FAIL;
+
+       if (swd_mode) {
+               /* Data Phase (bit 2) must be set to 1 if sticky overrun
+                * detection is enabled */
+               retval = cmsis_dap_cmd_DAP_SWD_Configure(0);    /* 1 TRN, no Data Phase */
+               if (retval != ERROR_OK)
+                       return ERROR_FAIL;
+       }
 
        retval = cmsis_dap_cmd_DAP_LED(0x03);           /* Both LEDs on */
        if (retval != ERROR_OK)
@@ -1001,14 +1130,14 @@ static void cmsis_dap_execute_reset(struct jtag_command *cmd)
 {
        /* Set both TRST and SRST even if they're not enabled as
         * there's no way to tristate them */
-       uint8_t pins = 0;
 
+       output_pins = 0;
        if (!cmd->cmd.reset->srst)
-               pins |= SWJ_PIN_SRST;
+               output_pins |= SWJ_PIN_SRST;
        if (!cmd->cmd.reset->trst)
-               pins |= SWJ_PIN_TRST;
+               output_pins |= SWJ_PIN_TRST;
 
-       int retval = cmsis_dap_cmd_DAP_SWJ_Pins(pins,
+       int retval = cmsis_dap_cmd_DAP_SWJ_Pins(output_pins,
                        SWJ_PIN_TRST | SWJ_PIN_SRST, 0, NULL);
        if (retval != ERROR_OK)
                LOG_ERROR("CMSIS-DAP: Interface reset failed");
@@ -1441,6 +1570,12 @@ static void cmsis_dap_execute_stableclocks(struct jtag_command *cmd)
        cmsis_dap_stableclocks(cmd->cmd.runtest->num_cycles);
 }
 
+static void cmsis_dap_execute_tms(struct jtag_command *cmd)
+{
+       DEBUG_JTAG_IO("TMS: %d bits", cmd->cmd.tms->num_bits);
+       cmsis_dap_cmd_DAP_SWJ_Sequence(cmd->cmd.tms->num_bits, cmd->cmd.tms->bits);
+}
+
 /* TODO: Is there need to call cmsis_dap_flush() for the JTAG_PATHMOVE,
  * JTAG_RUNTEST, JTAG_STABLECLOCKS? */
 static void cmsis_dap_execute_command(struct jtag_command *cmd)
@@ -1471,6 +1606,8 @@ static void cmsis_dap_execute_command(struct jtag_command *cmd)
                        cmsis_dap_execute_stableclocks(cmd);
                        break;
                case JTAG_TMS:
+                       cmsis_dap_execute_tms(cmd);
+                       break;
                default:
                        LOG_ERROR("BUG: unknown JTAG command type 0x%X encountered", cmd->type);
                        exit(-1);
@@ -1493,13 +1630,11 @@ static int cmsis_dap_execute_queue(void)
 
 static int cmsis_dap_speed(int speed)
 {
-       if (speed > DAP_MAX_CLOCK) {
-               LOG_INFO("reduce speed request: %dkHz to %dkHz maximum", speed, DAP_MAX_CLOCK);
-               speed = DAP_MAX_CLOCK;
-       }
+       if (speed > DAP_MAX_CLOCK)
+               LOG_INFO("High speed (adapter_khz %d) may be limited by adapter firmware.", speed);
 
        if (speed == 0) {
-               LOG_INFO("RTCK not supported");
+               LOG_ERROR("RTCK not supported. Set nonzero adapter_khz.");
                return ERROR_JTAG_NOT_IMPLEMENTED;
        }
 
@@ -1535,6 +1670,30 @@ COMMAND_HANDLER(cmsis_dap_handle_info_command)
        return ERROR_OK;
 }
 
+COMMAND_HANDLER(cmsis_dap_handle_cmd_command)
+{
+       int retval;
+       unsigned i;
+       uint8_t *buffer = cmsis_dap_handle->packet_buffer;
+
+       buffer[0] = 0;  /* report number */
+
+       for (i = 0; i < CMD_ARGC; i++)
+               buffer[i + 1] = strtoul(CMD_ARGV[i], NULL, 16);
+
+       retval = cmsis_dap_usb_xfer(cmsis_dap_handle, CMD_ARGC + 1);
+
+       if (retval != ERROR_OK) {
+               LOG_ERROR("CMSIS-DAP command failed.");
+               return ERROR_JTAG_DEVICE_ERROR;
+       }
+
+       LOG_INFO("Returned data %02" PRIx8 " %02" PRIx8 " %02" PRIx8 " %02" PRIx8,
+               buffer[1], buffer[2], buffer[3], buffer[4]);
+
+       return ERROR_OK;
+}
+
 COMMAND_HANDLER(cmsis_dap_handle_vid_pid_command)
 {
        if (CMD_ARGC > MAX_USB_IDS * 2) {
@@ -1594,6 +1753,13 @@ static const struct command_registration cmsis_dap_subcommand_handlers[] = {
                .usage = "",
                .help = "show cmsis-dap info",
        },
+       {
+               .name = "cmd",
+               .handler = &cmsis_dap_handle_cmd_command,
+               .mode = COMMAND_EXEC,
+               .usage = "",
+               .help = "issue cmsis-dap command",
+       },
        COMMAND_REGISTRATION_DONE
 };
 
@@ -1635,6 +1801,7 @@ static const char * const cmsis_dap_transport[] = { "swd", "jtag", NULL };
 
 struct jtag_interface cmsis_dap_interface = {
        .name = "cmsis-dap",
+       .supported = DEBUG_CAP_TMS_SEQ,
        .commands = cmsis_dap_command_handlers,
        .swd = &cmsis_dap_swd_driver,
        .transports = cmsis_dap_transport,

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)