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

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)