1 /***************************************************************************
3 * Copyright (C) 2009 by Cahya Wirawan <cahya@gmx.at> *
4 * Based on opendous driver by Vladimir Fonov *
6 * Copyright (C) 2009 by Vladimir Fonov <vladimir.fonov@gmai.com> *
7 * Based on J-link driver by Juergen Stuber *
9 * Copyright (C) 2007 by Juergen Stuber <juergen@jstuber.net> *
10 * based on Dominic Rath's and Benedikt Sauter's usbprog.c *
12 * Copyright (C) 2008 by Spencer Oliver *
13 * spen@spen-soft.co.uk *
15 * This program is free software; you can redistribute it and/or modify *
16 * it under the terms of the GNU General Public License as published by *
17 * the Free Software Foundation; either version 2 of the License, or *
18 * (at your option) any later version. *
20 * This program is distributed in the hope that it will be useful, *
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
23 * GNU General Public License for more details. *
25 * You should have received a copy of the GNU General Public License *
26 * along with this program; if not, write to the *
27 * Free Software Foundation, Inc., *
28 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
29 ***************************************************************************/
35 #include <jtag/interface.h>
36 #include <jtag/commands.h>
37 #include "libusb_common.h"
39 #include <sys/timeb.h>
42 #define ESTICK_VID 0x1781
43 #define ESTICK_PID 0xC0C0
45 #define OPENDOUS_VID 0x03EB
46 #define OPENDOUS_PID 0x204F
48 /* pid could be specified at runtime */
49 static uint16_t vids
[] = { OPENDOUS_VID
, ESTICK_VID
, 0 };
50 static uint16_t pids
[] = { OPENDOUS_PID
, ESTICK_PID
, 0 };
52 #define OPENDOUS_WRITE_ENDPOINT 0x02
53 #define OPENDOUS_READ_ENDPOINT 0x81
55 static unsigned int opendous_hw_jtag_version
= 1;
57 #define OPENDOUS_USB_TIMEOUT 1000
59 #define OPENDOUS_USB_BUFFER_SIZE 360
60 #define OPENDOUS_IN_BUFFER_SIZE (OPENDOUS_USB_BUFFER_SIZE)
61 #define OPENDOUS_OUT_BUFFER_SIZE (OPENDOUS_USB_BUFFER_SIZE)
63 /* Global USB buffers */
64 static uint8_t usb_in_buffer
[OPENDOUS_IN_BUFFER_SIZE
];
65 static uint8_t usb_out_buffer
[OPENDOUS_OUT_BUFFER_SIZE
];
67 /* Constants for OPENDOUS command */
69 #define OPENDOUS_MAX_SPEED 66
70 #define OPENDOUS_MAX_TAP_TRANSMIT 350 /* even number is easier to handle */
71 #define OPENDOUS_MAX_INPUT_DATA (OPENDOUS_MAX_TAP_TRANSMIT*4)
73 #define OPENDOUS_TAP_BUFFER_SIZE 65536
75 #define MAX_PENDING_SCAN_RESULTS (OPENDOUS_MAX_INPUT_DATA)
77 /* JTAG usb commands */
78 #define JTAG_CMD_TAP_OUTPUT 0x0
79 #define JTAG_CMD_SET_TRST 0x1
80 #define JTAG_CMD_SET_SRST 0x2
81 #define JTAG_CMD_READ_INPUT 0x3
82 #define JTAG_CMD_TAP_OUTPUT_EMU 0x4
83 #define JTAG_CMD_SET_DELAY 0x5
84 #define JTAG_CMD_SET_SRST_TRST 0x6
85 #define JTAG_CMD_READ_CONFIG 0x7
87 /* External interface functions */
88 static int opendous_execute_queue(void);
89 static int opendous_speed(int speed
);
90 static int opendous_speed_div(int speed
, int *khz
);
91 static int opendous_khz(int khz
, int *jtag_speed
);
92 static int opendous_init(void);
93 static int opendous_quit(void);
95 /* Queue command functions */
96 static void opendous_end_state(tap_state_t state
);
97 static void opendous_state_move(void);
98 static void opendous_path_move(int num_states
, tap_state_t
*path
);
99 static void opendous_runtest(int num_cycles
);
100 static void opendous_scan(int ir_scan
, enum scan_type type
, uint8_t *buffer
,
101 int scan_size
, struct scan_command
*command
);
102 static void opendous_reset(int trst
, int srst
);
103 static void opendous_simple_command(uint8_t command
, uint8_t _data
);
104 static int opendous_get_status(void);
106 /* opendous tap buffer functions */
107 static void opendous_tap_init(void);
108 static int opendous_tap_execute(void);
109 static void opendous_tap_ensure_space(int scans
, int bits
);
110 static void opendous_tap_append_step(int tms
, int tdi
);
111 static void opendous_tap_append_scan(int length
, uint8_t *buffer
, struct scan_command
*command
);
113 /* opendous lowlevel functions */
114 struct opendous_jtag
{
115 struct jtag_libusb_device_handle
*usb_handle
;
118 static struct opendous_jtag
*opendous_usb_open(void);
119 static void opendous_usb_close(struct opendous_jtag
*opendous_jtag
);
120 static int opendous_usb_message(struct opendous_jtag
*opendous_jtag
, int out_length
, int in_length
);
121 static int opendous_usb_write(struct opendous_jtag
*opendous_jtag
, int out_length
);
122 static int opendous_usb_read(struct opendous_jtag
*opendous_jtag
);
124 /* helper functions */
125 int opendous_get_version_info(void);
127 #ifdef _DEBUG_USB_COMMS_
129 static void opendous_debug_buffer(uint8_t *buffer
, int length
);
130 char *opendous_get_time(char *);
133 static struct opendous_jtag
*opendous_jtag_handle
;
135 /***************************************************************************/
136 /* External interface implementation */
138 COMMAND_HANDLER(opendous_handle_opendous_info_command
)
140 if (opendous_get_version_info() == ERROR_OK
) {
141 /* attempt to get status */
142 opendous_get_status();
148 COMMAND_HANDLER(opendous_handle_opendous_hw_jtag_command
)
152 command_print(CMD_CTX
, "opendous hw jtag %i", opendous_hw_jtag_version
);
156 int request_version
= atoi(CMD_ARGV
[0]);
157 switch (request_version
) {
160 opendous_hw_jtag_version
= request_version
;
164 return ERROR_COMMAND_SYNTAX_ERROR
;
170 return ERROR_COMMAND_SYNTAX_ERROR
;
176 static const struct command_registration opendous_command_handlers
[] = {
178 .name
= "opendous_info",
179 .handler
= &opendous_handle_opendous_info_command
,
180 .mode
= COMMAND_EXEC
,
181 .help
= "show opendous info",
184 .name
= "opendous_hw_jtag",
185 .handler
= &opendous_handle_opendous_hw_jtag_command
,
186 .mode
= COMMAND_EXEC
,
187 .help
= "access opendous HW JTAG command version",
190 COMMAND_REGISTRATION_DONE
193 struct jtag_interface opendous_interface
= {
195 .commands
= opendous_command_handlers
,
196 .execute_queue
= opendous_execute_queue
,
197 .speed
= opendous_speed
,
198 .speed_div
= opendous_speed_div
,
200 .init
= opendous_init
,
201 .quit
= opendous_quit
,
204 static int opendous_execute_queue(void)
206 struct jtag_command
*cmd
= jtag_command_queue
;
211 while (cmd
!= NULL
) {
214 DEBUG_JTAG_IO("runtest %i cycles, end in %i", cmd
->cmd
.runtest
->num_cycles
, \
215 cmd
->cmd
.runtest
->end_state
);
217 if (cmd
->cmd
.runtest
->end_state
!= -1)
218 opendous_end_state(cmd
->cmd
.runtest
->end_state
);
219 opendous_runtest(cmd
->cmd
.runtest
->num_cycles
);
223 DEBUG_JTAG_IO("statemove end in %i", cmd
->cmd
.statemove
->end_state
);
225 if (cmd
->cmd
.statemove
->end_state
!= -1)
226 opendous_end_state(cmd
->cmd
.statemove
->end_state
);
227 opendous_state_move();
231 DEBUG_JTAG_IO("pathmove: %i states, end in %i", \
232 cmd
->cmd
.pathmove
->num_states
, \
233 cmd
->cmd
.pathmove
->path
[cmd
->cmd
.pathmove
->num_states
- 1]);
235 opendous_path_move(cmd
->cmd
.pathmove
->num_states
, cmd
->cmd
.pathmove
->path
);
239 DEBUG_JTAG_IO("scan end in %i", cmd
->cmd
.scan
->end_state
);
241 if (cmd
->cmd
.scan
->end_state
!= -1)
242 opendous_end_state(cmd
->cmd
.scan
->end_state
);
244 scan_size
= jtag_build_buffer(cmd
->cmd
.scan
, &buffer
);
245 DEBUG_JTAG_IO("scan input, length = %d", scan_size
);
247 #ifdef _DEBUG_USB_COMMS_
248 opendous_debug_buffer(buffer
, (scan_size
+ 7) / 8);
250 type
= jtag_scan_type(cmd
->cmd
.scan
);
251 opendous_scan(cmd
->cmd
.scan
->ir_scan
, type
, buffer
, scan_size
, cmd
->cmd
.scan
);
255 DEBUG_JTAG_IO("reset trst: %i srst %i", cmd
->cmd
.reset
->trst
, cmd
->cmd
.reset
->srst
);
257 opendous_tap_execute();
259 if (cmd
->cmd
.reset
->trst
== 1)
260 tap_set_state(TAP_RESET
);
261 opendous_reset(cmd
->cmd
.reset
->trst
, cmd
->cmd
.reset
->srst
);
265 DEBUG_JTAG_IO("sleep %i", cmd
->cmd
.sleep
->us
);
266 opendous_tap_execute();
267 jtag_sleep(cmd
->cmd
.sleep
->us
);
271 LOG_ERROR("BUG: unknown JTAG command type encountered");
276 return opendous_tap_execute();
279 /* Sets speed in kHz. */
280 static int opendous_speed(int speed
)
282 if (speed
<= OPENDOUS_MAX_SPEED
) {
286 LOG_INFO("Requested speed %dkHz exceeds maximum of %dkHz, ignored", speed
, OPENDOUS_MAX_SPEED
);
291 static int opendous_speed_div(int speed
, int *khz
)
298 static int opendous_khz(int khz
, int *jtag_speed
)
301 /* TODO: convert this into delay value for opendous */
306 static int opendous_init(void)
310 opendous_jtag_handle
= opendous_usb_open();
312 if (opendous_jtag_handle
== 0) {
313 LOG_ERROR("Cannot find opendous Interface! Please check connection and permissions.");
314 return ERROR_JTAG_INIT_FAILED
;
318 while (check_cnt
< 3) {
319 if (opendous_get_version_info() == ERROR_OK
) {
320 /* attempt to get status */
321 opendous_get_status();
328 LOG_INFO("opendous JTAG Interface ready");
330 opendous_reset(0, 0);
336 static int opendous_quit(void)
338 opendous_usb_close(opendous_jtag_handle
);
342 /***************************************************************************/
343 /* Queue command implementations */
345 void opendous_end_state(tap_state_t state
)
347 if (tap_is_state_stable(state
))
348 tap_set_end_state(state
);
350 LOG_ERROR("BUG: %i is not a valid end state", state
);
355 /* Goes to the end state. */
356 void opendous_state_move(void)
360 uint8_t tms_scan
= tap_get_tms_path(tap_get_state(), tap_get_end_state());
361 uint8_t tms_scan_bits
= tap_get_tms_path_len(tap_get_state(), tap_get_end_state());
363 for (i
= 0; i
< tms_scan_bits
; i
++) {
364 tms
= (tms_scan
>> i
) & 1;
365 opendous_tap_append_step(tms
, 0);
368 tap_set_state(tap_get_end_state());
371 void opendous_path_move(int num_states
, tap_state_t
*path
)
375 for (i
= 0; i
< num_states
; i
++) {
376 if (path
[i
] == tap_state_transition(tap_get_state(), false))
377 opendous_tap_append_step(0, 0);
378 else if (path
[i
] == tap_state_transition(tap_get_state(), true))
379 opendous_tap_append_step(1, 0);
381 LOG_ERROR("BUG: %s -> %s isn't a valid TAP transition",
382 tap_state_name(tap_get_state()), tap_state_name(path
[i
]));
386 tap_set_state(path
[i
]);
389 tap_set_end_state(tap_get_state());
392 void opendous_runtest(int num_cycles
)
396 tap_state_t saved_end_state
= tap_get_end_state();
398 /* only do a state_move when we're not already in IDLE */
399 if (tap_get_state() != TAP_IDLE
) {
400 opendous_end_state(TAP_IDLE
);
401 opendous_state_move();
404 /* execute num_cycles */
405 for (i
= 0; i
< num_cycles
; i
++)
406 opendous_tap_append_step(0, 0);
408 /* finish in end_state */
409 opendous_end_state(saved_end_state
);
410 if (tap_get_state() != tap_get_end_state())
411 opendous_state_move();
414 void opendous_scan(int ir_scan
, enum scan_type type
, uint8_t *buffer
, int scan_size
, struct scan_command
*command
)
416 tap_state_t saved_end_state
;
418 opendous_tap_ensure_space(1, scan_size
+ 8);
420 saved_end_state
= tap_get_end_state();
422 /* Move to appropriate scan state */
423 opendous_end_state(ir_scan
? TAP_IRSHIFT
: TAP_DRSHIFT
);
425 opendous_state_move();
426 opendous_end_state(saved_end_state
);
429 opendous_tap_append_scan(scan_size
, buffer
, command
);
431 /* We are in Exit1, go to Pause */
432 opendous_tap_append_step(0, 0);
434 tap_set_state(ir_scan
? TAP_IRPAUSE
: TAP_DRPAUSE
);
436 if (tap_get_state() != tap_get_end_state())
437 opendous_state_move();
440 void opendous_reset(int trst
, int srst
)
442 LOG_DEBUG("trst: %i, srst: %i", trst
, srst
);
444 /* Signals are active low */
447 opendous_simple_command(JTAG_CMD_SET_SRST
, 1);
449 opendous_simple_command(JTAG_CMD_SET_SRST
, 0);
452 opendous_simple_command(JTAG_CMD_SET_TRST
, 1);
454 opendous_simple_command(JTAG_CMD_SET_TRST
, 0);
459 opendous_simple_command(JTAG_CMD_SET_SRST_TRST
, srst
| trst
);
462 void opendous_simple_command(uint8_t command
, uint8_t _data
)
466 DEBUG_JTAG_IO("0x%02x 0x%02x", command
, _data
);
468 usb_out_buffer
[0] = (uint16_t) 2;
469 usb_out_buffer
[2] = command
;
470 usb_out_buffer
[3] = _data
;
472 result
= opendous_usb_message(opendous_jtag_handle
, 4, 1);
474 LOG_ERROR("opendous command 0x%02x failed (%d)", command
, result
);
477 int opendous_get_status(void)
482 int opendous_get_version_info(void)
487 /***************************************************************************/
488 /* Estick tap functions */
490 static int tap_length
;
491 static uint8_t tms_buffer
[OPENDOUS_TAP_BUFFER_SIZE
];
492 static uint8_t tdo_buffer
[OPENDOUS_TAP_BUFFER_SIZE
];
494 struct pending_scan_result
{
495 int first
; /* First bit position in tdo_buffer to read */
496 int length
; /* Number of bits to read */
497 struct scan_command
*command
; /* Corresponding scan command */
501 static int pending_scan_results_length
;
502 static struct pending_scan_result pending_scan_results_buffer
[MAX_PENDING_SCAN_RESULTS
];
506 void opendous_tap_init(void)
509 pending_scan_results_length
= 0;
512 void opendous_tap_ensure_space(int scans
, int bits
)
514 int available_scans
= MAX_PENDING_SCAN_RESULTS
- pending_scan_results_length
;
516 if (scans
> available_scans
)
517 opendous_tap_execute();
520 void opendous_tap_append_step(int tms
, int tdi
)
523 unsigned char _tms
= tms
? 1 : 0;
524 unsigned char _tdi
= tdi
? 1 : 0;
526 int tap_index
= tap_length
/ 4;
527 int bits
= (tap_length
% 4) * 2;
529 if (tap_length
< OPENDOUS_TAP_BUFFER_SIZE
) {
531 tms_buffer
[tap_index
] = 0;
533 tms_buffer
[tap_index
] |= (_tdi
<< bits
)|(_tms
<< (bits
+ 1)) ;
536 LOG_ERROR("opendous_tap_append_step, overflow");
539 void opendous_tap_append_scan(int length
, uint8_t *buffer
, struct scan_command
*command
)
541 DEBUG_JTAG_IO("append scan, length = %d", length
);
543 struct pending_scan_result
*pending_scan_result
= &pending_scan_results_buffer
[pending_scan_results_length
];
546 pending_scan_result
->first
= tap_length
;
547 pending_scan_result
->length
= length
;
548 pending_scan_result
->command
= command
;
549 pending_scan_result
->buffer
= buffer
;
551 for (i
= 0; i
< length
; i
++)
552 opendous_tap_append_step((i
< length
-1 ? 0 : 1), (buffer
[i
/ 8] >> (i
% 8)) & 1);
553 pending_scan_results_length
++;
556 /* Pad and send a tap sequence to the device, and receive the answer.
557 * For the purpose of padding we assume that we are in idle or pause state. */
558 int opendous_tap_execute(void)
560 int byte_length
, byte_length_out
;
565 if (tap_length
> 0) {
567 /* memset(tdo_buffer,0,OPENDOUS_TAP_BUFFER_SIZE); */
568 /* LOG_INFO("OPENDOUS tap execute %d",tap_length); */
569 byte_length
= (tap_length
+ 3) / 4;
570 byte_length_out
= (tap_length
+ 7) / 8;
572 #ifdef _DEBUG_USB_COMMS_
573 LOG_DEBUG("opendous is sending %d bytes", byte_length
);
577 for (j
= 0, i
= 0; j
< byte_length
;) {
580 int transmit
= byte_length
- j
;
581 if (transmit
> OPENDOUS_MAX_TAP_TRANSMIT
) {
582 transmit
= OPENDOUS_MAX_TAP_TRANSMIT
;
583 recieve
= (OPENDOUS_MAX_TAP_TRANSMIT
) / 2;
584 usb_out_buffer
[2] = JTAG_CMD_TAP_OUTPUT
;
586 usb_out_buffer
[2] = JTAG_CMD_TAP_OUTPUT
| ((tap_length
% 4) << 4);
587 recieve
= (transmit
+ 1) / 2;
589 usb_out_buffer
[0] = (transmit
+ 1) & 0xff;
590 usb_out_buffer
[1] = ((transmit
+ 1) >> 8) & 0xff;
592 memmove(usb_out_buffer
+ 3, tms_buffer
+ j
, transmit
);
593 result
= opendous_usb_message(opendous_jtag_handle
, 3 + transmit
, recieve
);
594 if (result
!= recieve
) {
595 LOG_ERROR("opendous_tap_execute, wrong result %d, expected %d", result
, recieve
);
596 return ERROR_JTAG_QUEUE_FAILED
;
599 memmove(tdo_buffer
+ i
, usb_in_buffer
, recieve
);
604 result
= byte_length_out
;
605 #ifdef _DEBUG_USB_COMMS_
606 LOG_DEBUG("opendous tap result %d", result
);
607 opendous_debug_buffer(tdo_buffer
, result
);
610 /* LOG_INFO("eStick tap execute %d",tap_length); */
611 for (i
= 0; i
< pending_scan_results_length
; i
++) {
613 struct pending_scan_result
*pending_scan_result
= &pending_scan_results_buffer
[i
];
614 uint8_t *buffer
= pending_scan_result
->buffer
;
615 int length
= pending_scan_result
->length
;
616 int first
= pending_scan_result
->first
;
617 struct scan_command
*command
= pending_scan_result
->command
;
620 buf_set_buf(tdo_buffer
, first
, buffer
, 0, length
);
622 DEBUG_JTAG_IO("pending scan result, length = %d", length
);
624 #ifdef _DEBUG_USB_COMMS_
625 opendous_debug_buffer(buffer
, byte_length_out
);
628 if (jtag_read_buffer(buffer
, command
) != ERROR_OK
) {
630 return ERROR_JTAG_QUEUE_FAILED
;
633 if (pending_scan_result
->buffer
!= NULL
)
634 free(pending_scan_result
->buffer
);
643 /*****************************************************************************/
644 /* Estick USB low-level functions */
646 struct opendous_jtag
*opendous_usb_open(void)
648 struct opendous_jtag
*result
;
650 struct jtag_libusb_device_handle
*devh
;
651 if (jtag_libusb_open(vids
, pids
, &devh
) != ERROR_OK
)
654 jtag_libusb_set_configuration(devh
, 0);
655 jtag_libusb_claim_interface(devh
, 0);
657 result
= (struct opendous_jtag
*) malloc(sizeof(struct opendous_jtag
));
658 result
->usb_handle
= devh
;
662 void opendous_usb_close(struct opendous_jtag
*opendous_jtag
)
664 jtag_libusb_close(opendous_jtag
->usb_handle
);
668 /* Send a message and receive the reply. */
669 int opendous_usb_message(struct opendous_jtag
*opendous_jtag
, int out_length
, int in_length
)
673 result
= opendous_usb_write(opendous_jtag
, out_length
);
674 if (result
== out_length
) {
675 result
= opendous_usb_read(opendous_jtag
);
676 if (result
== in_length
)
679 LOG_ERROR("usb_bulk_read failed (requested=%d, result=%d)", in_length
, result
);
683 LOG_ERROR("usb_bulk_write failed (requested=%d, result=%d)", out_length
, result
);
688 /* Write data from out_buffer to USB. */
689 int opendous_usb_write(struct opendous_jtag
*opendous_jtag
, int out_length
)
693 if (out_length
> OPENDOUS_OUT_BUFFER_SIZE
) {
694 LOG_ERROR("opendous_jtag_write illegal out_length=%d (max=%d)", out_length
, OPENDOUS_OUT_BUFFER_SIZE
);
698 #ifdef _DEBUG_USB_COMMS_
699 LOG_DEBUG("%s: USB write begin", opendous_get_time(time_str
));
701 result
= jtag_libusb_bulk_write(opendous_jtag
->usb_handle
, OPENDOUS_WRITE_ENDPOINT
, \
702 (char *)usb_out_buffer
, out_length
, OPENDOUS_USB_TIMEOUT
);
703 #ifdef _DEBUG_USB_COMMS_
704 LOG_DEBUG("%s: USB write end: %d bytes", opendous_get_time(time_str
), result
);
707 DEBUG_JTAG_IO("opendous_usb_write, out_length = %d, result = %d", out_length
, result
);
709 #ifdef _DEBUG_USB_COMMS_
710 opendous_debug_buffer(usb_out_buffer
, out_length
);
715 /* Read data from USB into in_buffer. */
716 int opendous_usb_read(struct opendous_jtag
*opendous_jtag
)
718 #ifdef _DEBUG_USB_COMMS_
719 LOG_DEBUG("%s: USB read begin", opendous_get_time(time_str
));
721 int result
= jtag_libusb_bulk_read(opendous_jtag
->usb_handle
, OPENDOUS_READ_ENDPOINT
,
722 (char *)usb_in_buffer
, OPENDOUS_IN_BUFFER_SIZE
, OPENDOUS_USB_TIMEOUT
);
723 #ifdef _DEBUG_USB_COMMS_
724 LOG_DEBUG("%s: USB read end: %d bytes", opendous_get_time(time_str
), result
);
726 DEBUG_JTAG_IO("opendous_usb_read, result = %d", result
);
728 #ifdef _DEBUG_USB_COMMS_
729 opendous_debug_buffer(usb_in_buffer
, result
);
734 #ifdef _DEBUG_USB_COMMS_
735 #define BYTES_PER_LINE 16
737 void opendous_debug_buffer(uint8_t *buffer
, int length
)
744 for (i
= 0; i
< length
; i
+= BYTES_PER_LINE
) {
745 snprintf(line
, 5, "%04x", i
);
746 for (j
= i
; j
< i
+ BYTES_PER_LINE
&& j
< length
; j
++) {
747 snprintf(s
, 4, " %02x", buffer
[j
]);
750 LOG_DEBUG("%s", line
);
754 char *opendous_get_time(char *str
)
756 struct timeb timebuffer
;
760 timeline
= ctime(&(timebuffer
.time
));
761 snprintf(str
, 49, "%.8s.%hu", &timeline
[11], timebuffer
.millitm
);
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)