update files to correct FSF address
[openocd.git] / src / jtag / drivers / versaloon / usbtoxxx / usbtoxxx.c
1 /***************************************************************************
2 * Copyright (C) 2009 - 2010 by Simon Qian <SimonQian@SimonQian.com> *
3 * *
4 * This program is free software; you can redistribute it and/or modify *
5 * it under the terms of the GNU General Public License as published by *
6 * the Free Software Foundation; either version 2 of the License, or *
7 * (at your option) any later version. *
8 * *
9 * This program is distributed in the hope that it will be useful, *
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
12 * GNU General Public License for more details. *
13 * *
14 * You should have received a copy of the GNU General Public License *
15 * along with this program; if not, write to the *
16 * Free Software Foundation, Inc., *
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. *
18 ***************************************************************************/
19
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23
24 #include <string.h>
25
26 #include "../versaloon_include.h"
27 #include "../versaloon.h"
28 #include "../versaloon_internal.h"
29 #include "usbtoxxx.h"
30 #include "usbtoxxx_internal.h"
31
32 #define N_A "n/a"
33
34 const char *types_name[96] = {
35 "usbtousart", "usbtospi", "usbtoi2c", "usbtogpio", "usbtocan", "usbtopwm",
36 "usbtoadc", "usbtodac",
37 "usbtomicrowire", "usbtoswim", "usbtodusi", N_A, N_A, N_A, "usbtopower", "usbtodelay",
38 N_A, N_A, N_A, N_A, N_A, N_A, N_A, N_A, N_A,
39 N_A, N_A, N_A, N_A, N_A, N_A, N_A,
40 "usbtojtagll", "usbtojtaghl", "usbtoissp", "usbtoc2", "usbtosbw",
41 "usbtolpcicp", "usbtoswd", "usbtojtagraw",
42 "usbtobdm", N_A, N_A, N_A, N_A, N_A, N_A, N_A,
43 N_A, N_A, N_A, N_A, N_A, N_A, N_A, N_A,
44 "usbtomsp430jtag", N_A, N_A, N_A, N_A, N_A, N_A, N_A,
45 "usbtopower", "usbtodelay", "usbtopoll", N_A, N_A, N_A, N_A, N_A,
46 N_A, N_A, N_A, N_A, N_A, N_A, N_A, "usbtoall"
47 };
48
49 uint8_t usbtoxxx_abilities[USB_TO_XXX_ABILITIES_LEN];
50
51 #define usbtoxxx_get_type_name(type) \
52 types_name[((type) - VERSALOON_USB_TO_XXX_CMD_START) \
53 % (sizeof(types_name) / sizeof(types_name[0]))]
54
55 static uint8_t type_pre;
56 static uint16_t usbtoxxx_buffer_index;
57 static uint16_t usbtoxxx_current_cmd_index;
58 static uint8_t *usbtoxxx_buffer;
59
60 uint16_t collect_index;
61 uint8_t collect_cmd;
62 static uint8_t poll_nesting;
63
64 struct usbtoxxx_context_t {
65 uint8_t type_pre;
66 uint8_t *usbtoxxx_buffer;
67 uint16_t usbtoxxx_current_cmd_index;
68 uint16_t usbtoxxx_buffer_index;
69 uint16_t versaloon_pending_idx;
70 };
71 static struct usbtoxxx_context_t poll_context;
72
73 static void usbtoxxx_save_context(struct usbtoxxx_context_t *c)
74 {
75 c->type_pre = type_pre;
76 c->usbtoxxx_buffer = usbtoxxx_buffer;
77 c->usbtoxxx_buffer_index = usbtoxxx_buffer_index;
78 c->usbtoxxx_current_cmd_index = usbtoxxx_current_cmd_index;
79 c->versaloon_pending_idx = versaloon_pending_idx;
80 }
81
82 static void usbtoxxx_pop_context(struct usbtoxxx_context_t *c)
83 {
84 type_pre = c->type_pre;
85 usbtoxxx_buffer = c->usbtoxxx_buffer;
86 usbtoxxx_buffer_index = c->usbtoxxx_buffer_index;
87 usbtoxxx_current_cmd_index = c->usbtoxxx_current_cmd_index;
88 versaloon_pending_idx = c->versaloon_pending_idx;
89 }
90
91 RESULT usbtoxxx_validate_current_command_type(void)
92 {
93 if (type_pre > 0) {
94 /* not the first command */
95 if (NULL == usbtoxxx_buffer) {
96 LOG_BUG(ERRMSG_INVALID_BUFFER, TO_STR(usbtoxxx_buffer));
97 return ERRCODE_INVALID_BUFFER;
98 }
99
100 usbtoxxx_buffer[0] = type_pre;
101 SET_LE_U16(&usbtoxxx_buffer[1], usbtoxxx_current_cmd_index);
102
103 usbtoxxx_buffer_index += usbtoxxx_current_cmd_index;
104 } else {
105 /* first command */
106 usbtoxxx_buffer_index = 3;
107 }
108
109 /* prepare for next command */
110 usbtoxxx_current_cmd_index = 3;
111 usbtoxxx_buffer = versaloon_buf + usbtoxxx_buffer_index;
112
113 collect_index = 0;
114 collect_cmd = 0;
115
116 return ERROR_OK;
117 }
118
119 RESULT usbtoxxx_execute_command(void)
120 {
121 uint16_t i;
122 uint16_t inlen;
123 RESULT result = ERROR_OK;
124
125 if (poll_nesting) {
126 LOG_BUG(ERRMSG_INVALID_USAGE, "USB_TO_POLL");
127 versaloon_free_want_pos();
128 return ERROR_FAIL;
129 }
130
131 if (ERROR_OK != usbtoxxx_validate_current_command_type()) {
132 LOG_BUG(ERRMSG_FAILURE_OPERATION, "validate previous commands");
133 versaloon_free_want_pos();
134 return ERRCODE_FAILURE_OPERATION;
135 }
136 if (3 == usbtoxxx_buffer_index) {
137 versaloon_free_want_pos();
138 return ERROR_OK;
139 }
140
141 versaloon_buf[0] = USB_TO_ALL;
142 SET_LE_U16(&versaloon_buf[1], usbtoxxx_buffer_index);
143
144 if (ERROR_OK != versaloon_send_command(usbtoxxx_buffer_index, &inlen)) {
145 versaloon_free_want_pos();
146 return ERROR_FAIL;
147 }
148
149 /* process return data */
150 usbtoxxx_buffer_index = 0;
151 for (i = 0; i < versaloon_pending_idx; i++) {
152 /* check result */
153 if ((0 == i) || !((versaloon_pending[i].collect)
154 && (versaloon_pending[i - 1].collect)
155 && (versaloon_pending[i].cmd
156 == versaloon_pending[i - 1].cmd))) {
157 if (USB_TO_XXX_CMD_NOT_SUPPORT
158 == versaloon_buf[usbtoxxx_buffer_index]) {
159 LOG_ERROR(ERRMSG_NOT_SUPPORT_BY,
160 usbtoxxx_get_type_name(versaloon_pending[i].type),
161 "current dongle");
162 result = ERROR_FAIL;
163 break;
164 } else if (USB_TO_XXX_OK != versaloon_buf[usbtoxxx_buffer_index]) {
165 LOG_ERROR("%s command 0x%02x failed with 0x%02x",
166 usbtoxxx_get_type_name(versaloon_pending[i].type),
167 versaloon_pending[i].cmd,
168 versaloon_buf[usbtoxxx_buffer_index]);
169 result = ERROR_FAIL;
170 break;
171 }
172 usbtoxxx_buffer_index++;
173 }
174
175 /* get result data */
176 if (versaloon_pending[i].pos != NULL) {
177 uint8_t processed = 0;
178
179 if (versaloon_pending[i].callback != NULL) {
180 versaloon_pending[i].callback(&versaloon_pending[i],
181 versaloon_buf + usbtoxxx_buffer_index, &processed);
182 }
183 if (!processed) {
184 struct versaloon_want_pos_t *tmp;
185
186 tmp = versaloon_pending[i].pos;
187 while (tmp != NULL) {
188 if ((tmp->buff != NULL) && (tmp->size > 0)) {
189 memcpy(tmp->buff,
190 versaloon_buf + usbtoxxx_buffer_index
191 + tmp->offset,
192 tmp->size);
193 }
194 struct versaloon_want_pos_t *free_tmp;
195 free_tmp = tmp;
196 tmp = tmp->next;
197 free(free_tmp);
198 }
199 versaloon_pending[i].pos = NULL;
200 }
201 } else if ((versaloon_pending[i].want_data_size > 0)
202 && (versaloon_pending[i].data_buffer != NULL)) {
203 uint8_t processed = 0;
204
205 if (versaloon_pending[i].callback != NULL) {
206 versaloon_pending[i].callback(&versaloon_pending[i],
207 versaloon_buf + usbtoxxx_buffer_index, &processed);
208 }
209 if (!processed) {
210 memcpy(versaloon_pending[i].data_buffer,
211 versaloon_buf + usbtoxxx_buffer_index
212 + versaloon_pending[i].want_data_pos,
213 versaloon_pending[i].want_data_size);
214 }
215 }
216 usbtoxxx_buffer_index += versaloon_pending[i].actual_data_size;
217 if (usbtoxxx_buffer_index > inlen) {
218 LOG_BUG("%s command 0x%02x process error",
219 usbtoxxx_get_type_name(versaloon_pending[i].type),
220 versaloon_pending[i].cmd);
221 result = ERROR_FAIL;
222 break;
223 }
224 }
225
226 /* data is not the right size */
227 if (inlen != usbtoxxx_buffer_index) {
228 LOG_ERROR(ERRMSG_INVALID_TARGET, "length of return data");
229 result = ERROR_FAIL;
230 }
231
232 if (versaloon_pending_idx > 0)
233 versaloon_pending_idx = 0;
234 else {
235 /* no receive data, avoid collision */
236 sleep_ms(10);
237 }
238
239 type_pre = 0;
240 collect_cmd = 0;
241 collect_index = 0;
242 versaloon_free_want_pos();
243 return result;
244 }
245
246 RESULT usbtoxxx_init(void)
247 {
248 versaloon_pending_idx = 0;
249
250 if ((ERROR_OK != usbtoinfo_get_abilities(usbtoxxx_abilities)) ||
251 (ERROR_OK != usbtoxxx_execute_command()))
252 return ERROR_FAIL;
253 LOG_INFO("USB_TO_XXX abilities: 0x%08X:0x%08X:0x%08X",
254 GET_LE_U32(&usbtoxxx_abilities[0]),
255 GET_LE_U32(&usbtoxxx_abilities[4]),
256 GET_LE_U32(&usbtoxxx_abilities[8]));
257 return ERROR_OK;
258 }
259
260 RESULT usbtoxxx_fini(void)
261 {
262 usbtoxxx_buffer = NULL;
263 type_pre = 0;
264 return ERROR_OK;
265 }
266
267 bool usbtoxxx_interface_supported(uint8_t cmd)
268 {
269 if ((cmd < VERSALOON_USB_TO_XXX_CMD_START) ||
270 (cmd > VERSALOON_USB_TO_XXX_CMD_END))
271 return false;
272
273 cmd -= VERSALOON_USB_TO_XXX_CMD_START;
274 return (usbtoxxx_abilities[cmd / 8] & (1 << (cmd % 8))) > 0;
275 }
276
277 RESULT usbtoxxx_ensure_buffer_size(uint16_t cmdlen)
278 {
279 /* check free space, commit if not enough */
280 if (((usbtoxxx_buffer_index + usbtoxxx_current_cmd_index + cmdlen)
281 >= versaloon_buf_size)
282 || (versaloon_pending_idx >= VERSALOON_MAX_PENDING_NUMBER)) {
283 struct usbtoxxx_context_t context_tmp;
284 uint8_t poll_nesting_tmp = 0;
285
286 memset(&context_tmp, 0, sizeof(context_tmp));
287 if (poll_nesting) {
288 if (0 == poll_context.type_pre) {
289 LOG_BUG("USB_TO_POLL toooooo long");
290 return ERROR_OK;
291 }
292
293 usbtoxxx_save_context(&context_tmp);
294 usbtoxxx_pop_context(&poll_context);
295 poll_nesting_tmp = poll_nesting;
296 poll_nesting = 0;
297 }
298
299 if (usbtoxxx_execute_command() != ERROR_OK)
300 return ERROR_FAIL;
301
302 if (poll_nesting_tmp) {
303 uint16_t newlen, oldlen;
304
305 newlen = context_tmp.versaloon_pending_idx
306 - poll_context.versaloon_pending_idx;
307 memcpy(&versaloon_pending[0],
308 &versaloon_pending[poll_context.versaloon_pending_idx],
309 sizeof(versaloon_pending[0]) * newlen);
310 context_tmp.versaloon_pending_idx = newlen;
311 oldlen = poll_context.usbtoxxx_buffer_index
312 + poll_context.usbtoxxx_current_cmd_index;
313 newlen = context_tmp.usbtoxxx_buffer_index
314 + context_tmp.usbtoxxx_current_cmd_index;
315 memcpy(versaloon_buf + 3, versaloon_buf + oldlen, newlen - oldlen);
316 oldlen -= 3;
317 context_tmp.usbtoxxx_buffer -= oldlen;
318 context_tmp.usbtoxxx_buffer_index -= oldlen;
319 usbtoxxx_pop_context(&context_tmp);
320 poll_nesting = poll_nesting_tmp;
321 }
322 }
323 return ERROR_OK;
324 }
325
326 RESULT usbtoxxx_add_command(uint8_t type, uint8_t cmd, uint8_t *cmdbuf,
327 uint16_t cmdlen, uint16_t retlen, uint8_t *wantbuf,
328 uint16_t wantpos, uint16_t wantlen, uint8_t collect)
329 {
330 uint16_t len_tmp;
331
332 /* 3 more bytes by usbtoxxx_validate_current_command_type */
333 /* 3 more bytes when ((0 == collect_index) || (collect_cmd != cmd)) */
334 if (ERROR_OK != usbtoxxx_ensure_buffer_size(cmdlen + 6))
335 return ERROR_FAIL;
336
337 if ((type_pre != type) || (NULL == usbtoxxx_buffer)) {
338 if (ERROR_OK != usbtoxxx_validate_current_command_type()) {
339 LOG_BUG(ERRMSG_FAILURE_OPERATION, "validate previous commands");
340 return ERRCODE_FAILURE_OPERATION;
341 }
342 type_pre = type;
343 }
344
345 if ((0 == collect_index) || (collect_cmd != cmd)) {
346 usbtoxxx_buffer[usbtoxxx_current_cmd_index++] = cmd;
347
348 if (collect) {
349 collect_index = usbtoxxx_current_cmd_index;
350 collect_cmd = cmd;
351 } else {
352 collect_index = 0;
353 collect_cmd = 0;
354 }
355 SET_LE_U16(&usbtoxxx_buffer[usbtoxxx_current_cmd_index], cmdlen);
356 usbtoxxx_current_cmd_index += 2;
357 } else {
358 len_tmp = GET_LE_U16(&usbtoxxx_buffer[collect_index]) + cmdlen;
359 SET_LE_U16(&usbtoxxx_buffer[collect_index], len_tmp);
360 }
361
362 if (cmdbuf != NULL) {
363 memcpy(usbtoxxx_buffer + usbtoxxx_current_cmd_index, cmdbuf, cmdlen);
364 usbtoxxx_current_cmd_index += cmdlen;
365 }
366
367 return versaloon_add_pending(type, cmd, retlen, wantpos, wantlen,
368 wantbuf, collect);
369 }
370
371 RESULT usbtoinfo_get_abilities(uint8_t abilities[USB_TO_XXX_ABILITIES_LEN])
372 {
373 if (ERROR_OK != usbtoxxx_ensure_buffer_size(3))
374 return ERROR_FAIL;
375
376 if (ERROR_OK != usbtoxxx_validate_current_command_type()) {
377 LOG_BUG(ERRMSG_FAILURE_OPERATION, "validate previous commands");
378 return ERRCODE_FAILURE_OPERATION;
379 }
380 type_pre = USB_TO_INFO;
381
382 return versaloon_add_pending(USB_TO_INFO, 0, USB_TO_XXX_ABILITIES_LEN, 0,
383 USB_TO_XXX_ABILITIES_LEN, abilities, 0);
384 }
385
386 RESULT usbtopoll_start(uint16_t retry_cnt, uint16_t interval_us)
387 {
388 if (ERROR_OK != usbtoxxx_ensure_buffer_size(3 + 5))
389 return ERROR_FAIL;
390 if (!poll_nesting)
391 usbtoxxx_save_context(&poll_context);
392
393 if (ERROR_OK != usbtoxxx_validate_current_command_type()) {
394 LOG_BUG(ERRMSG_FAILURE_OPERATION, "validate previous commands");
395 return ERRCODE_FAILURE_OPERATION;
396 }
397 poll_nesting++;
398 type_pre = USB_TO_POLL;
399
400 usbtoxxx_buffer[usbtoxxx_current_cmd_index++] = USB_TO_POLL_START;
401 SET_LE_U16(&usbtoxxx_buffer[usbtoxxx_current_cmd_index], retry_cnt);
402 usbtoxxx_current_cmd_index += 2;
403 SET_LE_U16(&usbtoxxx_buffer[usbtoxxx_current_cmd_index], interval_us);
404 usbtoxxx_current_cmd_index += 2;
405
406 return versaloon_add_pending(USB_TO_POLL, 0, 0, 0, 0, NULL, 0);
407 }
408
409 RESULT usbtopoll_end(void)
410 {
411 if (!poll_nesting) {
412 LOG_BUG(ERRMSG_FAILURE_OPERATION, "check poll nesting");
413 return ERRCODE_FAILURE_OPERATION;
414 }
415 if (ERROR_OK != usbtoxxx_ensure_buffer_size(3 + 1))
416 return ERROR_FAIL;
417
418 if (ERROR_OK != usbtoxxx_validate_current_command_type()) {
419 LOG_BUG(ERRMSG_FAILURE_OPERATION, "validate previous commands");
420 return ERRCODE_FAILURE_OPERATION;
421 }
422
423 poll_nesting--;
424 type_pre = USB_TO_POLL;
425
426 usbtoxxx_buffer[usbtoxxx_current_cmd_index++] = USB_TO_POLL_END;
427
428 return versaloon_add_pending(USB_TO_POLL, 0, 0, 0, 0, NULL, 0);
429 }
430
431 RESULT usbtopoll_checkok(uint8_t equ, uint16_t offset, uint8_t size,
432 uint32_t mask, uint32_t value)
433 {
434 uint8_t i;
435
436 if (size > 4) {
437 LOG_BUG(ERRMSG_INVALID_PARAMETER, __func__);
438 return ERRCODE_INVALID_PARAMETER;
439 }
440 if (!poll_nesting) {
441 LOG_BUG(ERRMSG_FAILURE_OPERATION, "check poll nesting");
442 return ERRCODE_FAILURE_OPERATION;
443 }
444 if (ERROR_OK != usbtoxxx_ensure_buffer_size(3 + 4 + 2 * size))
445 return ERROR_FAIL;
446
447 if (ERROR_OK != usbtoxxx_validate_current_command_type()) {
448 LOG_BUG(ERRMSG_FAILURE_OPERATION, "validate previous commands");
449 return ERRCODE_FAILURE_OPERATION;
450 }
451
452 type_pre = USB_TO_POLL;
453
454 usbtoxxx_buffer[usbtoxxx_current_cmd_index++] = USB_TO_POLL_CHECKOK;
455 SET_LE_U16(&usbtoxxx_buffer[usbtoxxx_current_cmd_index], offset);
456 usbtoxxx_current_cmd_index += 2;
457 usbtoxxx_buffer[usbtoxxx_current_cmd_index++] = size;
458 usbtoxxx_buffer[usbtoxxx_current_cmd_index++] = equ;
459 for (i = 0; i < size; i++)
460 usbtoxxx_buffer[usbtoxxx_current_cmd_index++] = (mask >> (8 * i)) & 0xFF;
461 for (i = 0; i < size; i++)
462 usbtoxxx_buffer[usbtoxxx_current_cmd_index++] = (value >> (8 * i)) & 0xFF;
463
464 return ERROR_OK;
465 }
466
467 RESULT usbtopoll_checkfail(uint8_t equ, uint16_t offset, uint8_t size,
468 uint32_t mask, uint32_t value)
469 {
470 uint8_t i;
471
472 if (size > 4) {
473 LOG_BUG(ERRMSG_INVALID_PARAMETER, __func__);
474 return ERRCODE_INVALID_PARAMETER;
475 }
476 if (!poll_nesting) {
477 LOG_BUG(ERRMSG_FAILURE_OPERATION, "check poll nesting");
478 return ERRCODE_FAILURE_OPERATION;
479 }
480 if (ERROR_OK != usbtoxxx_ensure_buffer_size(3 + 4 + 2 * size))
481 return ERROR_FAIL;
482
483 if (ERROR_OK != usbtoxxx_validate_current_command_type()) {
484 LOG_BUG(ERRMSG_FAILURE_OPERATION, "validate previous commands");
485 return ERRCODE_FAILURE_OPERATION;
486 }
487
488 type_pre = USB_TO_POLL;
489
490 usbtoxxx_buffer[usbtoxxx_current_cmd_index++] = USB_TO_POLL_CHECKFAIL;
491 SET_LE_U16(&usbtoxxx_buffer[usbtoxxx_current_cmd_index], offset);
492 usbtoxxx_current_cmd_index += 2;
493 usbtoxxx_buffer[usbtoxxx_current_cmd_index++] = size;
494 usbtoxxx_buffer[usbtoxxx_current_cmd_index++] = equ;
495 for (i = 0; i < size; i++)
496 usbtoxxx_buffer[usbtoxxx_current_cmd_index++] = (mask >> (8 * i)) & 0xFF;
497 for (i = 0; i < size; i++)
498 usbtoxxx_buffer[usbtoxxx_current_cmd_index++] = (value >> (8 * i)) & 0xFF;
499
500 return ERROR_OK;
501 }
502
503 RESULT usbtopoll_verifybuff(uint16_t offset, uint16_t size, uint8_t *buff)
504 {
505 if (!poll_nesting) {
506 LOG_BUG(ERRMSG_FAILURE_OPERATION, "check poll nesting");
507 return ERRCODE_FAILURE_OPERATION;
508 }
509 if (ERROR_OK != usbtoxxx_ensure_buffer_size(3 + 5 + size))
510 return ERROR_FAIL;
511
512 if (ERROR_OK != usbtoxxx_validate_current_command_type()) {
513 LOG_BUG(ERRMSG_FAILURE_OPERATION, "validate previous commands");
514 return ERRCODE_FAILURE_OPERATION;
515 }
516
517 type_pre = USB_TO_POLL;
518
519 usbtoxxx_buffer[usbtoxxx_current_cmd_index++] = USB_TO_POLL_VERIFYBUFF;
520 SET_LE_U16(&usbtoxxx_buffer[usbtoxxx_current_cmd_index], offset);
521 usbtoxxx_current_cmd_index += 2;
522 SET_LE_U16(&usbtoxxx_buffer[usbtoxxx_current_cmd_index], size);
523 usbtoxxx_current_cmd_index += 2;
524 memcpy(&usbtoxxx_buffer[usbtoxxx_current_cmd_index], buff, size);
525 usbtoxxx_current_cmd_index += size;
526
527 return ERROR_OK;
528 }
529
530 RESULT usbtodelay_delay(uint16_t dly)
531 {
532 if (ERROR_OK != usbtoxxx_ensure_buffer_size(3 + 2))
533 return ERROR_FAIL;
534
535 if (ERROR_OK != usbtoxxx_validate_current_command_type()) {
536 LOG_BUG(ERRMSG_FAILURE_OPERATION, "validate previous commands");
537 return ERRCODE_FAILURE_OPERATION;
538 }
539 type_pre = USB_TO_DELAY;
540
541 SET_LE_U16(&usbtoxxx_buffer[usbtoxxx_current_cmd_index], dly);
542 usbtoxxx_current_cmd_index += 2;
543
544 return versaloon_add_pending(USB_TO_DELAY, 0, 0, 0, 0, NULL, 0);
545 }
546
547 RESULT usbtodelay_delayms(uint16_t ms)
548 {
549 return usbtodelay_delay(ms | 0x8000);
550 }
551
552 RESULT usbtodelay_delayus(uint16_t us)
553 {
554 return usbtodelay_delay(us & 0x7FFF);
555 }

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)