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