jtag: drivers: stlink: handle all versions with single config
[openocd.git] / src / jtag / drivers / ti_icdi_usb.c
1 /***************************************************************************
2 * *
3 * Copyright (C) 2012 by Spencer Oliver *
4 * spen@spen-soft.co.uk *
5 * *
6 * This program is free software; you can redistribute it and/or modify *
7 * it under the terms of the GNU General Public License as published by *
8 * the Free Software Foundation; either version 2 of the License, or *
9 * (at your option) any later version. *
10 * *
11 * This program is distributed in the hope that it will be useful, *
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14 * GNU General Public License for more details. *
15 * *
16 * You should have received a copy of the GNU General Public License *
17 * along with this program. If not, see <http://www.gnu.org/licenses/>. *
18 ***************************************************************************/
19
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23
24 /* project specific includes */
25 #include <helper/binarybuffer.h>
26 #include <jtag/interface.h>
27 #include <jtag/hla/hla_layout.h>
28 #include <jtag/hla/hla_transport.h>
29 #include <jtag/hla/hla_interface.h>
30 #include <target/target.h>
31
32 #include <target/cortex_m.h>
33
34 #include <libusb.h>
35
36 #define ICDI_WRITE_ENDPOINT 0x02
37 #define ICDI_READ_ENDPOINT 0x83
38
39 #define ICDI_WRITE_TIMEOUT 1000
40 #define ICDI_READ_TIMEOUT 1000
41 #define ICDI_PACKET_SIZE 2048
42
43 #define PACKET_START "$"
44 #define PACKET_END "#"
45
46 struct icdi_usb_handle_s {
47 libusb_context *usb_ctx;
48 libusb_device_handle *usb_dev;
49
50 char *read_buffer;
51 char *write_buffer;
52 int max_packet;
53 int read_count;
54 uint32_t max_rw_packet; /* max X packet (read/write memory) transfers */
55 };
56
57 static int icdi_usb_read_mem(void *handle, uint32_t addr, uint32_t size,
58 uint32_t count, uint8_t *buffer);
59 static int icdi_usb_write_mem(void *handle, uint32_t addr, uint32_t size,
60 uint32_t count, const uint8_t *buffer);
61
62 static int remote_escape_output(const char *buffer, int len, char *out_buf, int *out_len, int out_maxlen)
63 {
64 int input_index, output_index;
65
66 output_index = 0;
67
68 for (input_index = 0; input_index < len; input_index++) {
69
70 char b = buffer[input_index];
71
72 if (b == '$' || b == '#' || b == '}' || b == '*') {
73 /* These must be escaped. */
74 if (output_index + 2 > out_maxlen)
75 break;
76 out_buf[output_index++] = '}';
77 out_buf[output_index++] = b ^ 0x20;
78 } else {
79 if (output_index + 1 > out_maxlen)
80 break;
81 out_buf[output_index++] = b;
82 }
83 }
84
85 *out_len = input_index;
86 return output_index;
87 }
88
89 static int remote_unescape_input(const char *buffer, int len, char *out_buf, int out_maxlen)
90 {
91 int input_index, output_index;
92 int escaped;
93
94 output_index = 0;
95 escaped = 0;
96
97 for (input_index = 0; input_index < len; input_index++) {
98
99 char b = buffer[input_index];
100
101 if (output_index + 1 > out_maxlen)
102 LOG_ERROR("Received too much data from the target.");
103
104 if (escaped) {
105 out_buf[output_index++] = b ^ 0x20;
106 escaped = 0;
107 } else if (b == '}')
108 escaped = 1;
109 else
110 out_buf[output_index++] = b;
111 }
112
113 if (escaped)
114 LOG_ERROR("Unmatched escape character in target response.");
115
116 return output_index;
117 }
118
119 static int icdi_send_packet(void *handle, int len)
120 {
121 unsigned char cksum = 0;
122 struct icdi_usb_handle_s *h = handle;
123 int result, retry = 0;
124 int transferred = 0;
125
126 assert(handle != NULL);
127
128 /* check we have a large enough buffer for checksum "#00" */
129 if (len + 3 > h->max_packet) {
130 LOG_ERROR("packet buffer too small");
131 return ERROR_FAIL;
132 }
133
134 /* calculate checksum - offset start of packet */
135 for (int i = 1; i < len; i++)
136 cksum += h->write_buffer[i];
137
138 len += sprintf(&h->write_buffer[len], PACKET_END "%02x", cksum);
139
140 #ifdef _DEBUG_USB_COMMS_
141 char buffer[50];
142 char ch = h->write_buffer[1];
143 if (ch == 'x' || ch == 'X')
144 LOG_DEBUG("writing packet: <binary>");
145 else {
146 memcpy(buffer, h->write_buffer, len >= 50 ? 50-1 : len);
147 buffer[len] = 0;
148 LOG_DEBUG("writing packet: %s", buffer);
149 }
150 #endif
151
152 while (1) {
153
154 result = libusb_bulk_transfer(h->usb_dev, ICDI_WRITE_ENDPOINT, (unsigned char *)h->write_buffer, len,
155 &transferred, ICDI_WRITE_TIMEOUT);
156 if (result != 0 || transferred != len) {
157 LOG_DEBUG("Error TX Data %d", result);
158 return ERROR_FAIL;
159 }
160
161 /* check that the client got the message ok, or shall we resend */
162 result = libusb_bulk_transfer(h->usb_dev, ICDI_READ_ENDPOINT, (unsigned char *)h->read_buffer, h->max_packet,
163 &transferred, ICDI_READ_TIMEOUT);
164 if (result != 0 || transferred < 1) {
165 LOG_DEBUG("Error RX Data %d", result);
166 return ERROR_FAIL;
167 }
168
169 #ifdef _DEBUG_USB_COMMS_
170 LOG_DEBUG("received reply: '%c' : count %d", h->read_buffer[0], transferred);
171 #endif
172
173 if (h->read_buffer[0] == '-') {
174 LOG_DEBUG("Resending packet %d", ++retry);
175 } else {
176 if (h->read_buffer[0] != '+')
177 LOG_DEBUG("Unexpected Reply from ICDI: %c", h->read_buffer[0]);
178 break;
179 }
180
181 if (retry == 3) {
182 LOG_DEBUG("maximum nack retries attempted");
183 return ERROR_FAIL;
184 }
185 }
186
187 retry = 0;
188 h->read_count = transferred;
189
190 while (1) {
191
192 /* read reply from icdi */
193 result = libusb_bulk_transfer(h->usb_dev, ICDI_READ_ENDPOINT, (unsigned char *)h->read_buffer + h->read_count,
194 h->max_packet - h->read_count, &transferred, ICDI_READ_TIMEOUT);
195
196 #ifdef _DEBUG_USB_COMMS_
197 LOG_DEBUG("received data: count %d", transferred);
198 #endif
199
200 /* check for errors but retry for timeout */
201 if (result != 0) {
202
203 if (result == LIBUSB_ERROR_TIMEOUT) {
204 LOG_DEBUG("Error RX timeout %d", result);
205 } else {
206 LOG_DEBUG("Error RX Data %d", result);
207 return ERROR_FAIL;
208 }
209 }
210
211 h->read_count += transferred;
212
213 /* we need to make sure we have a full packet, including checksum */
214 if (h->read_count > 5) {
215
216 /* check that we have received an packet delimiter
217 * we do not validate the checksum
218 * reply should contain $...#AA - so we check for # */
219 if (h->read_buffer[h->read_count - 3] == '#')
220 return ERROR_OK;
221 }
222
223 if (retry++ == 3) {
224 LOG_DEBUG("maximum data retries attempted");
225 break;
226 }
227 }
228
229 return ERROR_FAIL;
230 }
231
232 static int icdi_send_cmd(void *handle, const char *cmd)
233 {
234 struct icdi_usb_handle_s *h = handle;
235
236 int cmd_len = snprintf(h->write_buffer, h->max_packet, PACKET_START "%s", cmd);
237 return icdi_send_packet(handle, cmd_len);
238 }
239
240 static int icdi_send_remote_cmd(void *handle, const char *data)
241 {
242 struct icdi_usb_handle_s *h = handle;
243
244 size_t cmd_len = sprintf(h->write_buffer, PACKET_START "qRcmd,");
245 cmd_len += hexify(h->write_buffer + cmd_len, (const uint8_t *)data,
246 strlen(data), h->max_packet - cmd_len);
247
248 return icdi_send_packet(handle, cmd_len);
249 }
250
251 static int icdi_get_cmd_result(void *handle)
252 {
253 struct icdi_usb_handle_s *h = handle;
254 int offset = 0;
255 char ch;
256
257 assert(handle != NULL);
258
259 do {
260 ch = h->read_buffer[offset++];
261 if (offset > h->read_count)
262 return ERROR_FAIL;
263 } while (ch != '$');
264
265 if (memcmp("OK", h->read_buffer + offset, 2) == 0)
266 return ERROR_OK;
267
268 if (h->read_buffer[offset] == 'E') {
269 /* get error code */
270 uint8_t result;
271 if (unhexify(&result, h->read_buffer + offset + 1, 1) != 1)
272 return ERROR_FAIL;
273 return result;
274 }
275
276 /* for now we assume everything else is ok */
277 return ERROR_OK;
278 }
279
280 static int icdi_usb_idcode(void *handle, uint32_t *idcode)
281 {
282 *idcode = 0;
283 return ERROR_OK;
284 }
285
286 static int icdi_usb_write_debug_reg(void *handle, uint32_t addr, uint32_t val)
287 {
288 uint8_t buf[4];
289 /* REVISIT: There's no target pointer here so there's no way to use target_buffer_set_u32().
290 * I guess all supported chips are little-endian anyway. */
291 h_u32_to_le(buf, val);
292 return icdi_usb_write_mem(handle, addr, 4, 1, buf);
293 }
294
295 static enum target_state icdi_usb_state(void *handle)
296 {
297 int result;
298 struct icdi_usb_handle_s *h = handle;
299 uint32_t dhcsr;
300 uint8_t buf[4];
301
302 result = icdi_usb_read_mem(h, DCB_DHCSR, 4, 1, buf);
303 if (result != ERROR_OK)
304 return TARGET_UNKNOWN;
305
306 /* REVISIT: There's no target pointer here so there's no way to use target_buffer_get_u32().
307 * I guess all supported chips are little-endian anyway. */
308 dhcsr = le_to_h_u32(buf);
309 if (dhcsr & S_HALT)
310 return TARGET_HALTED;
311
312 return TARGET_RUNNING;
313 }
314
315 static int icdi_usb_version(void *handle)
316 {
317 struct icdi_usb_handle_s *h = handle;
318
319 char version[20];
320
321 /* get info about icdi */
322 int result = icdi_send_remote_cmd(handle, "version");
323 if (result != ERROR_OK)
324 return result;
325
326 if (h->read_count < 8) {
327 LOG_ERROR("Invalid Reply Received");
328 return ERROR_FAIL;
329 }
330
331 /* convert reply */
332 if (unhexify((uint8_t *)version, h->read_buffer + 2, 4) != 4) {
333 LOG_WARNING("unable to get ICDI version");
334 return ERROR_OK;
335 }
336
337 /* null terminate and print info */
338 version[4] = 0;
339
340 LOG_INFO("ICDI Firmware version: %s", version);
341
342 return ERROR_OK;
343 }
344
345 static int icdi_usb_query(void *handle)
346 {
347 int result;
348
349 struct icdi_usb_handle_s *h = handle;
350
351 result = icdi_send_cmd(handle, "qSupported");
352 if (result != ERROR_OK)
353 return result;
354
355 /* check result */
356 result = icdi_get_cmd_result(handle);
357 if (result != ERROR_OK) {
358 LOG_ERROR("query supported failed: 0x%x", result);
359 return ERROR_FAIL;
360 }
361
362 /* from this we can get the max packet supported */
363
364 /* query packet buffer size */
365 char *offset = strstr(h->read_buffer, "PacketSize");
366 if (offset) {
367 char *separator;
368 int max_packet;
369
370 max_packet = strtol(offset + 11, &separator, 16);
371 if (!max_packet)
372 LOG_ERROR("invalid max packet, using defaults");
373 else
374 h->max_packet = max_packet;
375 LOG_DEBUG("max packet supported : %i bytes", h->max_packet);
376 }
377
378
379 /* if required re allocate packet buffer */
380 if (h->max_packet != ICDI_PACKET_SIZE) {
381 h->read_buffer = realloc(h->read_buffer, h->max_packet);
382 h->write_buffer = realloc(h->write_buffer, h->max_packet);
383 if (h->read_buffer == 0 || h->write_buffer == 0) {
384 LOG_ERROR("unable to reallocate memory");
385 return ERROR_FAIL;
386 }
387 }
388
389 /* set extended mode */
390 result = icdi_send_cmd(handle, "!");
391 if (result != ERROR_OK)
392 return result;
393
394 /* check result */
395 result = icdi_get_cmd_result(handle);
396 if (result != ERROR_OK) {
397 LOG_ERROR("unable to enable extended mode: 0x%x", result);
398 return ERROR_FAIL;
399 }
400
401 return ERROR_OK;
402 }
403
404 static int icdi_usb_reset(void *handle)
405 {
406 /* we do this in hla_target.c */
407 return ERROR_OK;
408 }
409
410 static int icdi_usb_assert_srst(void *handle, int srst)
411 {
412 /* TODO not supported yet */
413 return ERROR_COMMAND_NOTFOUND;
414 }
415
416 static int icdi_usb_run(void *handle)
417 {
418 int result;
419
420 /* resume target at current address */
421 result = icdi_send_cmd(handle, "c");
422 if (result != ERROR_OK)
423 return result;
424
425 /* check result */
426 result = icdi_get_cmd_result(handle);
427 if (result != ERROR_OK) {
428 LOG_ERROR("continue failed: 0x%x", result);
429 return ERROR_FAIL;
430 }
431
432 return result;
433 }
434
435 static int icdi_usb_halt(void *handle)
436 {
437 int result;
438
439 /* this query halts the target ?? */
440 result = icdi_send_cmd(handle, "?");
441 if (result != ERROR_OK)
442 return result;
443
444 /* check result */
445 result = icdi_get_cmd_result(handle);
446 if (result != ERROR_OK) {
447 LOG_ERROR("halt failed: 0x%x", result);
448 return ERROR_FAIL;
449 }
450
451 return result;
452 }
453
454 static int icdi_usb_step(void *handle)
455 {
456 int result;
457
458 /* step target at current address */
459 result = icdi_send_cmd(handle, "s");
460 if (result != ERROR_OK)
461 return result;
462
463 /* check result */
464 result = icdi_get_cmd_result(handle);
465 if (result != ERROR_OK) {
466 LOG_ERROR("step failed: 0x%x", result);
467 return ERROR_FAIL;
468 }
469
470 return result;
471 }
472
473 static int icdi_usb_read_regs(void *handle)
474 {
475 /* currently unsupported */
476 return ERROR_OK;
477 }
478
479 static int icdi_usb_read_reg(void *handle, int num, uint32_t *val)
480 {
481 int result;
482 struct icdi_usb_handle_s *h = handle;
483 char cmd[10];
484
485 snprintf(cmd, sizeof(cmd), "p%x", num);
486 result = icdi_send_cmd(handle, cmd);
487 if (result != ERROR_OK)
488 return result;
489
490 /* check result */
491 result = icdi_get_cmd_result(handle);
492 if (result != ERROR_OK) {
493 LOG_ERROR("register read failed: 0x%x", result);
494 return ERROR_FAIL;
495 }
496
497 /* convert result */
498 uint8_t buf[4];
499 if (unhexify(buf, h->read_buffer + 2, 4) != 4) {
500 LOG_ERROR("failed to convert result");
501 return ERROR_FAIL;
502 }
503 *val = le_to_h_u32(buf);
504
505 return result;
506 }
507
508 static int icdi_usb_write_reg(void *handle, int num, uint32_t val)
509 {
510 int result;
511 char cmd[20];
512 uint8_t buf[4];
513 h_u32_to_le(buf, val);
514
515 int cmd_len = snprintf(cmd, sizeof(cmd), "P%x=", num);
516 hexify(cmd + cmd_len, buf, 4, sizeof(cmd));
517
518 result = icdi_send_cmd(handle, cmd);
519 if (result != ERROR_OK)
520 return result;
521
522 /* check result */
523 result = icdi_get_cmd_result(handle);
524 if (result != ERROR_OK) {
525 LOG_ERROR("register write failed: 0x%x", result);
526 return ERROR_FAIL;
527 }
528
529 return result;
530 }
531
532 static int icdi_usb_read_mem_int(void *handle, uint32_t addr, uint32_t len, uint8_t *buffer)
533 {
534 int result;
535 struct icdi_usb_handle_s *h = handle;
536 char cmd[20];
537
538 snprintf(cmd, sizeof(cmd), "x%" PRIx32 ",%" PRIx32, addr, len);
539 result = icdi_send_cmd(handle, cmd);
540 if (result != ERROR_OK)
541 return result;
542
543 /* check result */
544 result = icdi_get_cmd_result(handle);
545 if (result != ERROR_OK) {
546 LOG_ERROR("memory read failed: 0x%x", result);
547 return ERROR_FAIL;
548 }
549
550 /* unescape input */
551 int read_len = remote_unescape_input(h->read_buffer + 5, h->read_count - 8, (char *)buffer, len);
552 if (read_len != (int)len) {
553 LOG_ERROR("read more bytes than expected: actual 0x%x expected 0x%" PRIx32, read_len, len);
554 return ERROR_FAIL;
555 }
556
557 return ERROR_OK;
558 }
559
560 static int icdi_usb_write_mem_int(void *handle, uint32_t addr, uint32_t len, const uint8_t *buffer)
561 {
562 int result;
563 struct icdi_usb_handle_s *h = handle;
564
565 size_t cmd_len = snprintf(h->write_buffer, h->max_packet, PACKET_START "X%" PRIx32 ",%" PRIx32 ":", addr, len);
566
567 int out_len;
568 cmd_len += remote_escape_output((const char *)buffer, len, h->write_buffer + cmd_len,
569 &out_len, h->max_packet - cmd_len);
570
571 if (out_len < (int)len) {
572 /* for now issue a error as we have no way of allocating a larger buffer */
573 LOG_ERROR("memory buffer too small: requires 0x%x actual 0x%" PRIx32, out_len, len);
574 return ERROR_FAIL;
575 }
576
577 result = icdi_send_packet(handle, cmd_len);
578 if (result != ERROR_OK)
579 return result;
580
581 /* check result */
582 result = icdi_get_cmd_result(handle);
583 if (result != ERROR_OK) {
584 LOG_ERROR("memory write failed: 0x%x", result);
585 return ERROR_FAIL;
586 }
587
588 return ERROR_OK;
589 }
590
591 static int icdi_usb_read_mem(void *handle, uint32_t addr, uint32_t size,
592 uint32_t count, uint8_t *buffer)
593 {
594 int retval = ERROR_OK;
595 struct icdi_usb_handle_s *h = handle;
596 uint32_t bytes_remaining;
597
598 /* calculate byte count */
599 count *= size;
600
601 while (count) {
602
603 bytes_remaining = h->max_rw_packet;
604 if (count < bytes_remaining)
605 bytes_remaining = count;
606
607 retval = icdi_usb_read_mem_int(handle, addr, bytes_remaining, buffer);
608 if (retval != ERROR_OK)
609 return retval;
610
611 buffer += bytes_remaining;
612 addr += bytes_remaining;
613 count -= bytes_remaining;
614 }
615
616 return retval;
617 }
618
619 static int icdi_usb_write_mem(void *handle, uint32_t addr, uint32_t size,
620 uint32_t count, const uint8_t *buffer)
621 {
622 int retval = ERROR_OK;
623 struct icdi_usb_handle_s *h = handle;
624 uint32_t bytes_remaining;
625
626 /* calculate byte count */
627 count *= size;
628
629 while (count) {
630
631 bytes_remaining = h->max_rw_packet;
632 if (count < bytes_remaining)
633 bytes_remaining = count;
634
635 retval = icdi_usb_write_mem_int(handle, addr, bytes_remaining, buffer);
636 if (retval != ERROR_OK)
637 return retval;
638
639 buffer += bytes_remaining;
640 addr += bytes_remaining;
641 count -= bytes_remaining;
642 }
643
644 return retval;
645 }
646
647 static int icdi_usb_override_target(const char *targetname)
648 {
649 return !strcmp(targetname, "cortex_m");
650 }
651
652 static int icdi_usb_close(void *handle)
653 {
654 struct icdi_usb_handle_s *h = handle;
655
656 if (!h)
657 return ERROR_OK;
658
659 if (h->usb_dev)
660 libusb_close(h->usb_dev);
661
662 if (h->usb_ctx)
663 libusb_exit(h->usb_ctx);
664
665 if (h->read_buffer)
666 free(h->read_buffer);
667
668 if (h->write_buffer)
669 free(h->write_buffer);
670
671 free(handle);
672
673 return ERROR_OK;
674 }
675
676 static int icdi_usb_open(struct hl_interface_param_s *param, void **fd)
677 {
678 int retval;
679 struct icdi_usb_handle_s *h;
680
681 LOG_DEBUG("icdi_usb_open");
682
683 h = calloc(1, sizeof(struct icdi_usb_handle_s));
684
685 if (h == 0) {
686 LOG_ERROR("unable to allocate memory");
687 return ERROR_FAIL;
688 }
689
690 LOG_DEBUG("transport: %d vid: 0x%04x pid: 0x%04x", param->transport,
691 param->vid[0], param->pid[0]);
692
693 /* TODO: convert libusb_ calls to jtag_libusb_ */
694 if (param->vid[1])
695 LOG_WARNING("Bad configuration: 'hla_vid_pid' command does not accept more than one VID PID pair on ti-icdi!");
696
697 if (libusb_init(&h->usb_ctx) != 0) {
698 LOG_ERROR("libusb init failed");
699 goto error_open;
700 }
701
702 h->usb_dev = libusb_open_device_with_vid_pid(h->usb_ctx, param->vid[0], param->pid[0]);
703 if (!h->usb_dev) {
704 LOG_ERROR("open failed");
705 goto error_open;
706 }
707
708 if (libusb_claim_interface(h->usb_dev, 2)) {
709 LOG_DEBUG("claim interface failed");
710 goto error_open;
711 }
712
713 /* check if mode is supported */
714 retval = ERROR_OK;
715
716 switch (param->transport) {
717 #if 0
718 /* TODO place holder as swd is not currently supported */
719 case HL_TRANSPORT_SWD:
720 #endif
721 case HL_TRANSPORT_JTAG:
722 break;
723 default:
724 retval = ERROR_FAIL;
725 break;
726 }
727
728 if (retval != ERROR_OK) {
729 LOG_ERROR("mode (transport) not supported by device");
730 goto error_open;
731 }
732
733 /* allocate buffer */
734 h->read_buffer = malloc(ICDI_PACKET_SIZE);
735 h->write_buffer = malloc(ICDI_PACKET_SIZE);
736 h->max_packet = ICDI_PACKET_SIZE;
737
738 if (h->read_buffer == 0 || h->write_buffer == 0) {
739 LOG_DEBUG("malloc failed");
740 goto error_open;
741 }
742
743 /* query icdi version etc */
744 retval = icdi_usb_version(h);
745 if (retval != ERROR_OK)
746 goto error_open;
747
748 /* query icdi support */
749 retval = icdi_usb_query(h);
750 if (retval != ERROR_OK)
751 goto error_open;
752
753 *fd = h;
754
755 /* set the max target read/write buffer in bytes
756 * as we are using gdb binary packets to transfer memory we have to
757 * reserve half the buffer for any possible escape chars plus
758 * at least 64 bytes for the gdb packet header */
759 h->max_rw_packet = (((h->max_packet - 64) / 4) * 4) / 2;
760
761 return ERROR_OK;
762
763 error_open:
764 icdi_usb_close(h);
765
766 return ERROR_FAIL;
767 }
768
769 struct hl_layout_api_s icdi_usb_layout_api = {
770 .open = icdi_usb_open,
771 .close = icdi_usb_close,
772 .idcode = icdi_usb_idcode,
773 .state = icdi_usb_state,
774 .reset = icdi_usb_reset,
775 .assert_srst = icdi_usb_assert_srst,
776 .run = icdi_usb_run,
777 .halt = icdi_usb_halt,
778 .step = icdi_usb_step,
779 .read_regs = icdi_usb_read_regs,
780 .read_reg = icdi_usb_read_reg,
781 .write_reg = icdi_usb_write_reg,
782 .read_mem = icdi_usb_read_mem,
783 .write_mem = icdi_usb_write_mem,
784 .write_debug_reg = icdi_usb_write_debug_reg,
785 .override_target = icdi_usb_override_target,
786 .custom_command = icdi_send_remote_cmd,
787 };

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)