adapter: switch from struct jtag_interface to adapter_driver
[openocd.git] / src / jtag / drivers / sysfsgpio.c
1 /***************************************************************************
2 * Copyright (C) 2012 by Creative Product Design, marc @ cpdesign.com.au *
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 /* 2014-12: Addition of the SWD protocol support is based on the initial work
19 * on bcm2835gpio.c by Paul Fertser and modifications by Jean-Christian de Rivaz. */
20
21 /**
22 * @file
23 * This driver implements a bitbang jtag interface using gpio lines via
24 * sysfs.
25 * The aim of this driver implementation is use system GPIOs but avoid the
26 * need for a additional kernel driver.
27 * (Note memory mapped IO is another option, however it doesn't mix well with
28 * the kernel gpiolib driver - which makes sense I guess.)
29 *
30 * A gpio is required for tck, tms, tdi and tdo. One or both of srst and trst
31 * must be also be specified. The required jtag gpios are specified via the
32 * sysfsgpio_jtag_nums command or the relevant sysfsgpio_XXX_num commang.
33 * The srst and trst gpios are set via the sysfsgpio_srst_num and
34 * sysfsgpio_trst_num respectively. GPIO numbering follows the kernel
35 * convention of starting from 0.
36 *
37 * The gpios should not be in use by another entity, and must not be requested
38 * by a kernel driver without also being exported by it (otherwise they can't
39 * be exported by sysfs).
40 *
41 * The sysfs gpio interface can only manipulate one gpio at a time, so the
42 * bitbang write handler remembers the last state for tck, tms, tdi to avoid
43 * superfluous writes.
44 * For speed the sysfs "value" entry is opened at init and held open.
45 * This results in considerable gains over open-write-close (45s vs 900s)
46 *
47 * Further work could address:
48 * -srst and trst open drain/ push pull
49 * -configurable active high/low for srst & trst
50 */
51 #ifdef HAVE_CONFIG_H
52 #include "config.h"
53 #endif
54
55 #include <helper/time_support.h>
56 #include <jtag/interface.h>
57 #include "bitbang.h"
58
59 /*
60 * Helper func to determine if gpio number valid
61 *
62 * Assume here that there will be less than 10000 gpios on a system
63 */
64 static int is_gpio_valid(int gpio)
65 {
66 return gpio >= 0 && gpio < 10000;
67 }
68
69 /*
70 * Helper func to open, write to and close a file
71 * name and valstr must be null terminated.
72 *
73 * Returns negative on failure.
74 */
75 static int open_write_close(const char *name, const char *valstr)
76 {
77 int ret;
78 int fd = open(name, O_WRONLY);
79 if (fd < 0)
80 return fd;
81
82 ret = write(fd, valstr, strlen(valstr));
83 close(fd);
84
85 return ret;
86 }
87
88 /*
89 * Helper func to unexport gpio from sysfs
90 */
91 static void unexport_sysfs_gpio(int gpio)
92 {
93 char gpiostr[5];
94
95 if (!is_gpio_valid(gpio))
96 return;
97
98 snprintf(gpiostr, sizeof(gpiostr), "%d", gpio);
99 if (open_write_close("/sys/class/gpio/unexport", gpiostr) < 0)
100 LOG_ERROR("Couldn't unexport gpio %d", gpio);
101
102 return;
103 }
104
105 /*
106 * Exports and sets up direction for gpio.
107 * If the gpio is an output, it is initialized according to init_high,
108 * otherwise it is ignored.
109 *
110 * If the gpio is already exported we just show a warning and continue; if
111 * openocd happened to crash (or was killed by user) then the gpios will not
112 * have been cleaned up.
113 */
114 static int setup_sysfs_gpio(int gpio, int is_output, int init_high)
115 {
116 struct timeval timeout, now;
117 char buf[40];
118 char gpiostr[5];
119 int ret;
120
121 if (!is_gpio_valid(gpio))
122 return ERROR_OK;
123
124 snprintf(gpiostr, sizeof(gpiostr), "%d", gpio);
125 ret = open_write_close("/sys/class/gpio/export", gpiostr);
126 if (ret < 0) {
127 if (errno == EBUSY) {
128 LOG_WARNING("gpio %d is already exported", gpio);
129 } else {
130 LOG_ERROR("Couldn't export gpio %d", gpio);
131 perror("sysfsgpio: ");
132 return ERROR_FAIL;
133 }
134 }
135
136 gettimeofday(&timeout, NULL);
137 timeval_add_time(&timeout, 0, 500000);
138
139 snprintf(buf, sizeof(buf), "/sys/class/gpio/gpio%d/direction", gpio);
140 for (;;) {
141 ret = open_write_close(buf, is_output ? (init_high ? "high" : "low") : "in");
142 if (ret >= 0 || errno != EACCES)
143 break;
144 gettimeofday(&now, NULL);
145 if (timeval_compare(&now, &timeout) >= 0)
146 break;
147 jtag_sleep(10000);
148 }
149 if (ret < 0) {
150 LOG_ERROR("Couldn't set direction for gpio %d", gpio);
151 perror("sysfsgpio: ");
152 unexport_sysfs_gpio(gpio);
153 return ERROR_FAIL;
154 }
155
156 snprintf(buf, sizeof(buf), "/sys/class/gpio/gpio%d/value", gpio);
157 for (;;) {
158 ret = open(buf, O_RDWR | O_NONBLOCK | O_SYNC);
159 if (ret >= 0 || errno != EACCES)
160 break;
161 gettimeofday(&now, NULL);
162 if (timeval_compare(&now, &timeout) >= 0)
163 break;
164 jtag_sleep(10000);
165 }
166 if (ret < 0) {
167 LOG_ERROR("Couldn't open value for gpio %d", gpio);
168 perror("sysfsgpio: ");
169 unexport_sysfs_gpio(gpio);
170 }
171
172 return ret;
173 }
174
175 /* gpio numbers for each gpio. Negative values are invalid */
176 static int tck_gpio = -1;
177 static int tms_gpio = -1;
178 static int tdi_gpio = -1;
179 static int tdo_gpio = -1;
180 static int trst_gpio = -1;
181 static int srst_gpio = -1;
182 static int swclk_gpio = -1;
183 static int swdio_gpio = -1;
184
185 /*
186 * file descriptors for /sys/class/gpio/gpioXX/value
187 * Set up during init.
188 */
189 static int tck_fd = -1;
190 static int tms_fd = -1;
191 static int tdi_fd = -1;
192 static int tdo_fd = -1;
193 static int trst_fd = -1;
194 static int srst_fd = -1;
195 static int swclk_fd = -1;
196 static int swdio_fd = -1;
197
198 static int last_swclk;
199 static int last_swdio;
200 static bool last_stored;
201 static bool swdio_input;
202
203 static void sysfsgpio_swdio_drive(bool is_output)
204 {
205 char buf[40];
206 int ret;
207
208 snprintf(buf, sizeof(buf), "/sys/class/gpio/gpio%d/direction", swdio_gpio);
209 ret = open_write_close(buf, is_output ? "high" : "in");
210 if (ret < 0) {
211 LOG_ERROR("Couldn't set direction for gpio %d", swdio_gpio);
212 perror("sysfsgpio: ");
213 }
214
215 last_stored = false;
216 swdio_input = !is_output;
217 }
218
219 static int sysfsgpio_swdio_read(void)
220 {
221 char buf[1];
222
223 /* important to seek to signal sysfs of new read */
224 lseek(swdio_fd, 0, SEEK_SET);
225 int ret = read(swdio_fd, &buf, sizeof(buf));
226
227 if (ret < 0) {
228 LOG_WARNING("reading swdio failed");
229 return 0;
230 }
231
232 return buf[0] != '0';
233 }
234
235 static void sysfsgpio_swdio_write(int swclk, int swdio)
236 {
237 const char one[] = "1";
238 const char zero[] = "0";
239
240 size_t bytes_written;
241
242 if (!swdio_input) {
243 if (!last_stored || (swdio != last_swdio)) {
244 bytes_written = write(swdio_fd, swdio ? &one : &zero, 1);
245 if (bytes_written != 1)
246 LOG_WARNING("writing swdio failed");
247 }
248 }
249
250 /* write swclk last */
251 if (!last_stored || (swclk != last_swclk)) {
252 bytes_written = write(swclk_fd, swclk ? &one : &zero, 1);
253 if (bytes_written != 1)
254 LOG_WARNING("writing swclk failed");
255 }
256
257 last_swdio = swdio;
258 last_swclk = swclk;
259 last_stored = true;
260 }
261
262 /*
263 * Bitbang interface read of TDO
264 *
265 * The sysfs value will read back either '0' or '1'. The trick here is to call
266 * lseek to bypass buffering in the sysfs kernel driver.
267 */
268 static bb_value_t sysfsgpio_read(void)
269 {
270 char buf[1];
271
272 /* important to seek to signal sysfs of new read */
273 lseek(tdo_fd, 0, SEEK_SET);
274 int ret = read(tdo_fd, &buf, sizeof(buf));
275
276 if (ret < 0) {
277 LOG_WARNING("reading tdo failed");
278 return 0;
279 }
280
281 return buf[0] == '0' ? BB_LOW : BB_HIGH;
282 }
283
284 /*
285 * Bitbang interface write of TCK, TMS, TDI
286 *
287 * Seeing as this is the only function where the outputs are changed,
288 * we can cache the old value to avoid needlessly writing it.
289 */
290 static int sysfsgpio_write(int tck, int tms, int tdi)
291 {
292 if (swd_mode) {
293 sysfsgpio_swdio_write(tck, tdi);
294 return ERROR_OK;
295 }
296
297 const char one[] = "1";
298 const char zero[] = "0";
299
300 static int last_tck;
301 static int last_tms;
302 static int last_tdi;
303
304 static int first_time;
305 size_t bytes_written;
306
307 if (!first_time) {
308 last_tck = !tck;
309 last_tms = !tms;
310 last_tdi = !tdi;
311 first_time = 1;
312 }
313
314 if (tdi != last_tdi) {
315 bytes_written = write(tdi_fd, tdi ? &one : &zero, 1);
316 if (bytes_written != 1)
317 LOG_WARNING("writing tdi failed");
318 }
319
320 if (tms != last_tms) {
321 bytes_written = write(tms_fd, tms ? &one : &zero, 1);
322 if (bytes_written != 1)
323 LOG_WARNING("writing tms failed");
324 }
325
326 /* write clk last */
327 if (tck != last_tck) {
328 bytes_written = write(tck_fd, tck ? &one : &zero, 1);
329 if (bytes_written != 1)
330 LOG_WARNING("writing tck failed");
331 }
332
333 last_tdi = tdi;
334 last_tms = tms;
335 last_tck = tck;
336
337 return ERROR_OK;
338 }
339
340 /*
341 * Bitbang interface to manipulate reset lines SRST and TRST
342 *
343 * (1) assert or (0) deassert reset lines
344 */
345 static int sysfsgpio_reset(int trst, int srst)
346 {
347 LOG_DEBUG("sysfsgpio_reset");
348 const char one[] = "1";
349 const char zero[] = "0";
350 size_t bytes_written;
351
352 /* assume active low */
353 if (srst_fd >= 0) {
354 bytes_written = write(srst_fd, srst ? &zero : &one, 1);
355 if (bytes_written != 1)
356 LOG_WARNING("writing srst failed");
357 }
358
359 /* assume active low */
360 if (trst_fd >= 0) {
361 bytes_written = write(trst_fd, trst ? &zero : &one, 1);
362 if (bytes_written != 1)
363 LOG_WARNING("writing trst failed");
364 }
365
366 return ERROR_OK;
367 }
368
369 COMMAND_HANDLER(sysfsgpio_handle_jtag_gpionums)
370 {
371 if (CMD_ARGC == 4) {
372 COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], tck_gpio);
373 COMMAND_PARSE_NUMBER(int, CMD_ARGV[1], tms_gpio);
374 COMMAND_PARSE_NUMBER(int, CMD_ARGV[2], tdi_gpio);
375 COMMAND_PARSE_NUMBER(int, CMD_ARGV[3], tdo_gpio);
376 } else if (CMD_ARGC != 0) {
377 return ERROR_COMMAND_SYNTAX_ERROR;
378 }
379
380 command_print(CMD,
381 "SysfsGPIO nums: tck = %d, tms = %d, tdi = %d, tdo = %d",
382 tck_gpio, tms_gpio, tdi_gpio, tdo_gpio);
383
384 return ERROR_OK;
385 }
386
387 COMMAND_HANDLER(sysfsgpio_handle_jtag_gpionum_tck)
388 {
389 if (CMD_ARGC == 1)
390 COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], tck_gpio);
391
392 command_print(CMD, "SysfsGPIO num: tck = %d", tck_gpio);
393 return ERROR_OK;
394 }
395
396 COMMAND_HANDLER(sysfsgpio_handle_jtag_gpionum_tms)
397 {
398 if (CMD_ARGC == 1)
399 COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], tms_gpio);
400
401 command_print(CMD, "SysfsGPIO num: tms = %d", tms_gpio);
402 return ERROR_OK;
403 }
404
405 COMMAND_HANDLER(sysfsgpio_handle_jtag_gpionum_tdo)
406 {
407 if (CMD_ARGC == 1)
408 COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], tdo_gpio);
409
410 command_print(CMD, "SysfsGPIO num: tdo = %d", tdo_gpio);
411 return ERROR_OK;
412 }
413
414 COMMAND_HANDLER(sysfsgpio_handle_jtag_gpionum_tdi)
415 {
416 if (CMD_ARGC == 1)
417 COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], tdi_gpio);
418
419 command_print(CMD, "SysfsGPIO num: tdi = %d", tdi_gpio);
420 return ERROR_OK;
421 }
422
423 COMMAND_HANDLER(sysfsgpio_handle_jtag_gpionum_srst)
424 {
425 if (CMD_ARGC == 1)
426 COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], srst_gpio);
427
428 command_print(CMD, "SysfsGPIO num: srst = %d", srst_gpio);
429 return ERROR_OK;
430 }
431
432 COMMAND_HANDLER(sysfsgpio_handle_jtag_gpionum_trst)
433 {
434 if (CMD_ARGC == 1)
435 COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], trst_gpio);
436
437 command_print(CMD, "SysfsGPIO num: trst = %d", trst_gpio);
438 return ERROR_OK;
439 }
440
441 COMMAND_HANDLER(sysfsgpio_handle_swd_gpionums)
442 {
443 if (CMD_ARGC == 2) {
444 COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], swclk_gpio);
445 COMMAND_PARSE_NUMBER(int, CMD_ARGV[1], swdio_gpio);
446 } else if (CMD_ARGC != 0) {
447 return ERROR_COMMAND_SYNTAX_ERROR;
448 }
449
450 command_print(CMD,
451 "SysfsGPIO nums: swclk = %d, swdio = %d",
452 swclk_gpio, swdio_gpio);
453
454 return ERROR_OK;
455 }
456
457 COMMAND_HANDLER(sysfsgpio_handle_swd_gpionum_swclk)
458 {
459 if (CMD_ARGC == 1)
460 COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], swclk_gpio);
461
462 command_print(CMD, "SysfsGPIO num: swclk = %d", swclk_gpio);
463 return ERROR_OK;
464 }
465
466 COMMAND_HANDLER(sysfsgpio_handle_swd_gpionum_swdio)
467 {
468 if (CMD_ARGC == 1)
469 COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], swdio_gpio);
470
471 command_print(CMD, "SysfsGPIO num: swdio = %d", swdio_gpio);
472 return ERROR_OK;
473 }
474
475 static const struct command_registration sysfsgpio_command_handlers[] = {
476 {
477 .name = "sysfsgpio_jtag_nums",
478 .handler = &sysfsgpio_handle_jtag_gpionums,
479 .mode = COMMAND_CONFIG,
480 .help = "gpio numbers for tck, tms, tdi, tdo. (in that order)",
481 .usage = "[tck tms tdi tdo]",
482 },
483 {
484 .name = "sysfsgpio_tck_num",
485 .handler = &sysfsgpio_handle_jtag_gpionum_tck,
486 .mode = COMMAND_CONFIG,
487 .help = "gpio number for tck.",
488 .usage = "[tck]",
489 },
490 {
491 .name = "sysfsgpio_tms_num",
492 .handler = &sysfsgpio_handle_jtag_gpionum_tms,
493 .mode = COMMAND_CONFIG,
494 .help = "gpio number for tms.",
495 .usage = "[tms]",
496 },
497 {
498 .name = "sysfsgpio_tdo_num",
499 .handler = &sysfsgpio_handle_jtag_gpionum_tdo,
500 .mode = COMMAND_CONFIG,
501 .help = "gpio number for tdo.",
502 .usage = "[tdo]",
503 },
504 {
505 .name = "sysfsgpio_tdi_num",
506 .handler = &sysfsgpio_handle_jtag_gpionum_tdi,
507 .mode = COMMAND_CONFIG,
508 .help = "gpio number for tdi.",
509 .usage = "[tdi]",
510 },
511 {
512 .name = "sysfsgpio_srst_num",
513 .handler = &sysfsgpio_handle_jtag_gpionum_srst,
514 .mode = COMMAND_CONFIG,
515 .help = "gpio number for srst.",
516 .usage = "[srst]",
517 },
518 {
519 .name = "sysfsgpio_trst_num",
520 .handler = &sysfsgpio_handle_jtag_gpionum_trst,
521 .mode = COMMAND_CONFIG,
522 .help = "gpio number for trst.",
523 .usage = "[trst]",
524 },
525 {
526 .name = "sysfsgpio_swd_nums",
527 .handler = &sysfsgpio_handle_swd_gpionums,
528 .mode = COMMAND_CONFIG,
529 .help = "gpio numbers for swclk, swdio. (in that order)",
530 .usage = "[swclk swdio]",
531 },
532 {
533 .name = "sysfsgpio_swclk_num",
534 .handler = &sysfsgpio_handle_swd_gpionum_swclk,
535 .mode = COMMAND_CONFIG,
536 .help = "gpio number for swclk.",
537 .usage = "[swclk]",
538 },
539 {
540 .name = "sysfsgpio_swdio_num",
541 .handler = &sysfsgpio_handle_swd_gpionum_swdio,
542 .mode = COMMAND_CONFIG,
543 .help = "gpio number for swdio.",
544 .usage = "[swdio]",
545 },
546 COMMAND_REGISTRATION_DONE
547 };
548
549 static int sysfsgpio_init(void);
550 static int sysfsgpio_quit(void);
551
552 static const char * const sysfsgpio_transports[] = { "jtag", "swd", NULL };
553
554 static struct jtag_interface sysfsgpio_interface = {
555 .supported = DEBUG_CAP_TMS_SEQ,
556 .execute_queue = bitbang_execute_queue,
557 };
558
559 struct adapter_driver sysfsgpio_adapter_driver = {
560 .name = "sysfsgpio",
561 .transports = sysfsgpio_transports,
562 .commands = sysfsgpio_command_handlers,
563
564 .init = sysfsgpio_init,
565 .quit = sysfsgpio_quit,
566 .reset = sysfsgpio_reset,
567
568 .jtag_ops = &sysfsgpio_interface,
569 .swd_ops = &bitbang_swd,
570 };
571
572 static struct bitbang_interface sysfsgpio_bitbang = {
573 .read = sysfsgpio_read,
574 .write = sysfsgpio_write,
575 .swdio_read = sysfsgpio_swdio_read,
576 .swdio_drive = sysfsgpio_swdio_drive,
577 .blink = 0
578 };
579
580 /* helper func to close and cleanup files only if they were valid/ used */
581 static void cleanup_fd(int fd, int gpio)
582 {
583 if (gpio >= 0) {
584 if (fd >= 0)
585 close(fd);
586
587 unexport_sysfs_gpio(gpio);
588 }
589 }
590
591 static void cleanup_all_fds(void)
592 {
593 cleanup_fd(tck_fd, tck_gpio);
594 cleanup_fd(tms_fd, tms_gpio);
595 cleanup_fd(tdi_fd, tdi_gpio);
596 cleanup_fd(tdo_fd, tdo_gpio);
597 cleanup_fd(trst_fd, trst_gpio);
598 cleanup_fd(srst_fd, srst_gpio);
599 cleanup_fd(swclk_fd, swclk_gpio);
600 cleanup_fd(swdio_fd, swdio_gpio);
601 }
602
603 static bool sysfsgpio_jtag_mode_possible(void)
604 {
605 if (!is_gpio_valid(tck_gpio))
606 return 0;
607 if (!is_gpio_valid(tms_gpio))
608 return 0;
609 if (!is_gpio_valid(tdi_gpio))
610 return 0;
611 if (!is_gpio_valid(tdo_gpio))
612 return 0;
613 return 1;
614 }
615
616 static bool sysfsgpio_swd_mode_possible(void)
617 {
618 if (!is_gpio_valid(swclk_gpio))
619 return 0;
620 if (!is_gpio_valid(swdio_gpio))
621 return 0;
622 return 1;
623 }
624
625 static int sysfsgpio_init(void)
626 {
627 bitbang_interface = &sysfsgpio_bitbang;
628
629 LOG_INFO("SysfsGPIO JTAG/SWD bitbang driver");
630
631 if (sysfsgpio_jtag_mode_possible()) {
632 if (sysfsgpio_swd_mode_possible())
633 LOG_INFO("JTAG and SWD modes enabled");
634 else
635 LOG_INFO("JTAG only mode enabled (specify swclk and swdio gpio to add SWD mode)");
636 } else if (sysfsgpio_swd_mode_possible()) {
637 LOG_INFO("SWD only mode enabled (specify tck, tms, tdi and tdo gpios to add JTAG mode)");
638 } else {
639 LOG_ERROR("Require tck, tms, tdi and tdo gpios for JTAG mode and/or swclk and swdio gpio for SWD mode");
640 return ERROR_JTAG_INIT_FAILED;
641 }
642
643
644 /*
645 * Configure TDO as an input, and TDI, TCK, TMS, TRST, SRST
646 * as outputs. Drive TDI and TCK low, and TMS/TRST/SRST high.
647 * For SWD, SWCLK and SWDIO are configures as output high.
648 */
649 if (tck_gpio >= 0) {
650 tck_fd = setup_sysfs_gpio(tck_gpio, 1, 0);
651 if (tck_fd < 0)
652 goto out_error;
653 }
654
655 if (tms_gpio >= 0) {
656 tms_fd = setup_sysfs_gpio(tms_gpio, 1, 1);
657 if (tms_fd < 0)
658 goto out_error;
659 }
660
661 if (tdi_gpio >= 0) {
662 tdi_fd = setup_sysfs_gpio(tdi_gpio, 1, 0);
663 if (tdi_fd < 0)
664 goto out_error;
665 }
666
667 if (tdo_gpio >= 0) {
668 tdo_fd = setup_sysfs_gpio(tdo_gpio, 0, 0);
669 if (tdo_fd < 0)
670 goto out_error;
671 }
672
673 /* assume active low*/
674 if (trst_gpio >= 0) {
675 trst_fd = setup_sysfs_gpio(trst_gpio, 1, 1);
676 if (trst_fd < 0)
677 goto out_error;
678 }
679
680 /* assume active low*/
681 if (srst_gpio >= 0) {
682 srst_fd = setup_sysfs_gpio(srst_gpio, 1, 1);
683 if (srst_fd < 0)
684 goto out_error;
685 }
686
687 if (swclk_gpio >= 0) {
688 swclk_fd = setup_sysfs_gpio(swclk_gpio, 1, 0);
689 if (swclk_fd < 0)
690 goto out_error;
691 }
692
693 if (swdio_gpio >= 0) {
694 swdio_fd = setup_sysfs_gpio(swdio_gpio, 1, 0);
695 if (swdio_fd < 0)
696 goto out_error;
697 }
698
699 if (sysfsgpio_swd_mode_possible()) {
700 if (swd_mode)
701 bitbang_swd_switch_seq(JTAG_TO_SWD);
702 else
703 bitbang_swd_switch_seq(SWD_TO_JTAG);
704 }
705
706 return ERROR_OK;
707
708 out_error:
709 cleanup_all_fds();
710 return ERROR_JTAG_INIT_FAILED;
711 }
712
713 static int sysfsgpio_quit(void)
714 {
715 cleanup_all_fds();
716 return ERROR_OK;
717 }
718

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)