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