c1973a3cfb399c1afac03a8aa9b76f3c1c3486f1
[openocd.git] / src / jtag / ft2232.c
1 /***************************************************************************
2 * Copyright (C) 2004, 2006 by Dominic Rath *
3 * Dominic.Rath@gmx.de *
4 * *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
9 * *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
14 * *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
19 ***************************************************************************/
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23
24 #if IS_CYGWIN == 1
25 #include "windows.h"
26 #undef ERROR
27 #endif
28
29 #include "replacements.h"
30
31 /* project specific includes */
32 #include "log.h"
33 #include "types.h"
34 #include "jtag.h"
35 #include "configuration.h"
36 #include "time_support.h"
37
38 /* system includes */
39 #include <string.h>
40 #include <stdlib.h>
41 #include <unistd.h>
42
43 /* FT2232 access library includes */
44 #if BUILD_FT2232_FTD2XX == 1
45 #include <ftd2xx.h>
46 #elif BUILD_FT2232_LIBFTDI == 1
47 #include <ftdi.h>
48 #endif
49
50 #include <sys/time.h>
51 #include <time.h>
52
53 /* enable this to debug io latency
54 */
55 #if 0
56 #define _DEBUG_USB_IO_
57 #endif
58
59 /* enable this to debug communication
60 */
61 #if 0
62 #define _DEBUG_USB_COMMS_
63 #endif
64
65 int ft2232_execute_queue(void);
66
67 int ft2232_speed(int speed);
68 int ft2232_register_commands(struct command_context_s *cmd_ctx);
69 int ft2232_init(void);
70 int ft2232_quit(void);
71
72 int ft2232_handle_device_desc_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
73 int ft2232_handle_layout_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
74 int ft2232_handle_vid_pid_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
75
76 char *ft2232_device_desc = NULL;
77 char *ft2232_layout = NULL;
78 u16 ft2232_vid = 0x0403;
79 u16 ft2232_pid = 0x6010;
80
81 typedef struct ft2232_layout_s
82 {
83 char* name;
84 int(*init)(void);
85 void(*reset)(int trst, int srst);
86 void(*blink)(void);
87 } ft2232_layout_t;
88
89 /* init procedures for supported layouts */
90 int usbjtag_init(void);
91 int jtagkey_init(void);
92 int olimex_jtag_init(void);
93
94 /* reset procedures for supported layouts */
95 void usbjtag_reset(int trst, int srst);
96 void jtagkey_reset(int trst, int srst);
97 void olimex_jtag_reset(int trst, int srst);
98
99 /* blink procedures for layouts that support a blinking led */
100 void olimex_jtag_blink(void);
101
102 ft2232_layout_t ft2232_layouts[] =
103 {
104 {"usbjtag", usbjtag_init, usbjtag_reset, NULL},
105 {"jtagkey", jtagkey_init, jtagkey_reset, NULL},
106 {"jtagkey_prototype_v1", jtagkey_init, jtagkey_reset, NULL},
107 {"signalyzer", usbjtag_init, usbjtag_reset, NULL},
108 {"olimex-jtag", olimex_jtag_init, olimex_jtag_reset, olimex_jtag_blink},
109 {NULL, NULL, NULL},
110 };
111
112 static u8 nTRST, nTRSTnOE, nSRST, nSRSTnOE;
113
114 static ft2232_layout_t *layout;
115 static u8 low_output = 0x0;
116 static u8 low_direction = 0x0;
117 static u8 high_output = 0x0;
118 static u8 high_direction = 0x0;
119
120 #if BUILD_FT2232_FTD2XX == 1
121 static FT_HANDLE ftdih = NULL;
122 #elif BUILD_FT2232_LIBFTDI == 1
123 static struct ftdi_context ftdic;
124 #endif
125
126 static u8 *ft2232_buffer = NULL;
127 static int ft2232_buffer_size = 0;
128 static int ft2232_read_pointer = 0;
129 static int ft2232_expect_read = 0;
130 #define FT2232_BUFFER_SIZE 131072
131 #define BUFFER_ADD ft2232_buffer[ft2232_buffer_size++]
132 #define BUFFER_READ ft2232_buffer[ft2232_read_pointer++]
133
134 jtag_interface_t ft2232_interface =
135 {
136
137 .name = "ft2232",
138
139 .execute_queue = ft2232_execute_queue,
140
141 .support_pathmove = 1,
142
143 .speed = ft2232_speed,
144 .register_commands = ft2232_register_commands,
145 .init = ft2232_init,
146 .quit = ft2232_quit,
147 };
148
149 int ft2232_write(u8 *buf, int size, u32* bytes_written)
150 {
151 #if BUILD_FT2232_FTD2XX == 1
152 FT_STATUS status;
153 DWORD dw_bytes_written;
154 if ((status = FT_Write(ftdih, buf, size, &dw_bytes_written)) != FT_OK)
155 {
156 *bytes_written = dw_bytes_written;
157 ERROR("FT_Write returned: %i", status);
158 return ERROR_JTAG_DEVICE_ERROR;
159 }
160 else
161 {
162 *bytes_written = dw_bytes_written;
163 return ERROR_OK;
164 }
165 #elif BUILD_FT2232_LIBFTDI == 1
166 int retval;
167 if ((retval = ftdi_write_data(&ftdic, buf, size)) < 0)
168 {
169 *bytes_written = 0;
170 ERROR("ftdi_write_data: %s", ftdi_get_error_string(&ftdic));
171 return ERROR_JTAG_DEVICE_ERROR;
172 }
173 else
174 {
175 *bytes_written = retval;
176 return ERROR_OK;
177 }
178 #endif
179 }
180
181 int ft2232_read(u8* buf, int size, u32* bytes_read)
182 {
183 #if BUILD_FT2232_FTD2XX == 1
184 DWORD dw_bytes_read;
185 FT_STATUS status;
186 if ((status = FT_Read(ftdih, buf, size, &dw_bytes_read)) != FT_OK)
187 {
188 *bytes_read = dw_bytes_read;
189 ERROR("FT_Read returned: %i", status);
190 return ERROR_JTAG_DEVICE_ERROR;
191 }
192 *bytes_read = dw_bytes_read;
193 return ERROR_OK;
194
195 #elif BUILD_FT2232_LIBFTDI == 1
196 int retval;
197 int timeout = 100;
198 *bytes_read = 0;
199
200 while ((*bytes_read < size) && timeout--)
201 {
202 if ((retval = ftdi_read_data(&ftdic, buf + *bytes_read, size - *bytes_read)) < 0)
203 {
204 *bytes_read = 0;
205 ERROR("ftdi_read_data: %s", ftdi_get_error_string(&ftdic));
206 return ERROR_JTAG_DEVICE_ERROR;
207 }
208 *bytes_read += retval;
209 }
210 return ERROR_OK;
211 #endif
212 }
213
214 int ft2232_speed(int speed)
215 {
216 u8 buf[3];
217 int retval;
218 u32 bytes_written;
219
220 buf[0] = 0x86; /* command "set divisor" */
221 buf[1] = speed & 0xff; /* valueL (0=6MHz, 1=3MHz, 2=1.5MHz, ...*/
222 buf[2] = (speed >> 8) & 0xff; /* valueH */
223
224 DEBUG("%2.2x %2.2x %2.2x", buf[0], buf[1], buf[2]);
225 if (((retval = ft2232_write(buf, 3, &bytes_written)) != ERROR_OK) || (bytes_written != 3))
226 {
227 ERROR("couldn't set FT2232 TCK speed");
228 return retval;
229 }
230
231 return ERROR_OK;
232 }
233
234 int ft2232_register_commands(struct command_context_s *cmd_ctx)
235 {
236 register_command(cmd_ctx, NULL, "ft2232_device_desc", ft2232_handle_device_desc_command,
237 COMMAND_CONFIG, NULL);
238 register_command(cmd_ctx, NULL, "ft2232_layout", ft2232_handle_layout_command,
239 COMMAND_CONFIG, NULL);
240 register_command(cmd_ctx, NULL, "ft2232_vid_pid", ft2232_handle_vid_pid_command,
241 COMMAND_CONFIG, NULL);
242 return ERROR_OK;
243 }
244
245 void ft2232_end_state(state)
246 {
247 if (tap_move_map[state] != -1)
248 end_state = state;
249 else
250 {
251 ERROR("BUG: %i is not a valid end state", state);
252 exit(-1);
253 }
254 }
255
256 void ft2232_read_scan(enum scan_type type, u8* buffer, int scan_size)
257 {
258 int num_bytes = ((scan_size + 7) / 8);
259 int bits_left = scan_size;
260 int cur_byte = 0;
261
262 while(num_bytes-- > 1)
263 {
264 buffer[cur_byte] = BUFFER_READ;
265 cur_byte++;
266 bits_left -= 8;
267 }
268
269 buffer[cur_byte] = 0x0;
270
271 if (bits_left > 1)
272 {
273 buffer[cur_byte] = BUFFER_READ >> 1;
274 }
275
276 buffer[cur_byte] = (buffer[cur_byte] | ((BUFFER_READ & 0x02) << 6)) >> (8 - bits_left);
277
278 }
279
280 void ft2232_debug_dump_buffer(void)
281 {
282 int i;
283 char line[256];
284 char *line_p = line;
285
286 for (i = 0; i < ft2232_buffer_size; i++)
287 {
288 line_p += snprintf(line_p, 256 - (line_p - line), "%2.2x ", ft2232_buffer[i]);
289 if (i % 16 == 15)
290 {
291 DEBUG("%s", line);
292 line_p = line;
293 }
294 }
295
296 if (line_p != line)
297 DEBUG("%s", line);
298 }
299
300 int ft2232_send_and_recv(jtag_command_t *first, jtag_command_t *last)
301 {
302 jtag_command_t *cmd;
303 u8 *buffer;
304 int scan_size;
305 enum scan_type type;
306 int retval;
307 u32 bytes_written;
308 u32 bytes_read;
309
310 #ifdef _DEBUG_USB_IO_
311 struct timeval start, inter, inter2, end;
312 struct timeval d_inter, d_inter2, d_end;
313 #endif
314
315 #ifdef _DEBUG_USB_COMMS_
316 DEBUG("write buffer (size %i):", ft2232_buffer_size);
317 ft2232_debug_dump_buffer();
318 #endif
319
320 #ifdef _DEBUG_USB_IO_
321 gettimeofday(&start, NULL);
322 #endif
323
324 if ((retval = ft2232_write(ft2232_buffer, ft2232_buffer_size, &bytes_written)) != ERROR_OK)
325 {
326 ERROR("couldn't write MPSSE commands to FT2232");
327 exit(-1);
328 }
329
330 #ifdef _DEBUG_USB_IO_
331 gettimeofday(&inter, NULL);
332 #endif
333
334 if (ft2232_expect_read)
335 {
336 int timeout = 100;
337 ft2232_buffer_size = 0;
338
339 #ifdef _DEBUG_USB_IO_
340 gettimeofday(&inter2, NULL);
341 #endif
342
343 if ((retval = ft2232_read(ft2232_buffer, ft2232_expect_read, &bytes_read)) != ERROR_OK)
344 {
345 ERROR("couldn't read from FT2232");
346 exit(-1);
347 }
348
349 #ifdef _DEBUG_USB_IO_
350 gettimeofday(&end, NULL);
351
352 timeval_subtract(&d_inter, &inter, &start);
353 timeval_subtract(&d_inter2, &inter2, &start);
354 timeval_subtract(&d_end, &end, &start);
355
356 INFO("inter: %i.%i, inter2: %i.%i end: %i.%i", d_inter.tv_sec, d_inter.tv_usec, d_inter2.tv_sec, d_inter2.tv_usec, d_end.tv_sec, d_end.tv_usec);
357 #endif
358
359
360 ft2232_buffer_size = bytes_read;
361
362 if (ft2232_expect_read != ft2232_buffer_size)
363 {
364 ERROR("ft2232_expect_read (%i) != ft2232_buffer_size (%i) (%i retries)", ft2232_expect_read, ft2232_buffer_size, 100 - timeout);
365 ft2232_debug_dump_buffer();
366
367 exit(-1);
368 }
369
370 #ifdef _DEBUG_USB_COMMS_
371 DEBUG("read buffer (%i retries): %i bytes", 100 - timeout, ft2232_buffer_size);
372 ft2232_debug_dump_buffer();
373 #endif
374 }
375
376 ft2232_expect_read = 0;
377 ft2232_read_pointer = 0;
378
379 cmd = first;
380 while (cmd != last)
381 {
382 switch (cmd->type)
383 {
384 case JTAG_SCAN:
385 type = jtag_scan_type(cmd->cmd.scan);
386 if (type != SCAN_OUT)
387 {
388 scan_size = jtag_scan_size(cmd->cmd.scan);
389 buffer = calloc(CEIL(scan_size, 8), 1);
390 ft2232_read_scan(type, buffer, scan_size);
391 jtag_read_buffer(buffer, cmd->cmd.scan);
392 free(buffer);
393 }
394 break;
395 default:
396 break;
397 }
398 cmd = cmd->next;
399 }
400
401 ft2232_buffer_size = 0;
402
403 return ERROR_OK;
404 }
405
406 void ft2232_add_pathmove(pathmove_command_t *cmd)
407 {
408 int num_states = cmd->num_states;
409 u8 tms_byte;
410 int state_count;
411
412 state_count = 0;
413 while (num_states)
414 {
415 tms_byte = 0x0;
416 int bit_count = 0;
417
418 /* command "Clock Data to TMS/CS Pin (no Read)" */
419 BUFFER_ADD = 0x4b;
420 /* number of states remaining */
421 BUFFER_ADD = (num_states % 7) - 1;
422
423 while (num_states % 7)
424 {
425 if (tap_transitions[cur_state].low == cmd->path[state_count])
426 buf_set_u32(&tms_byte, bit_count++, 1, 0x0);
427 else if (tap_transitions[cur_state].high == cmd->path[state_count])
428 buf_set_u32(&tms_byte, bit_count++, 1, 0x1);
429 else
430 {
431 ERROR("BUG: %s -> %s isn't a valid TAP transition", tap_state_strings[cur_state], tap_state_strings[cmd->path[state_count]]);
432 exit(-1);
433 }
434
435 cur_state = cmd->path[state_count];
436 state_count++;
437 num_states--;
438 }
439
440 BUFFER_ADD = tms_byte;
441 }
442
443 end_state = cur_state;
444 }
445
446 void ft2232_add_scan(int ir_scan, enum scan_type type, u8 *buffer, int scan_size)
447 {
448 int num_bytes = (scan_size + 7) / 8;
449 int bits_left = scan_size;
450 int cur_byte = 0;
451 int last_bit;
452
453 if ((!ir_scan && (cur_state != TAP_SD)) || (ir_scan && (cur_state != TAP_SI)))
454 {
455 /* command "Clock Data to TMS/CS Pin (no Read)" */
456 BUFFER_ADD = 0x4b;
457 /* scan 7 bit */
458 BUFFER_ADD = 0x6;
459 /* TMS data bits */
460 if (ir_scan)
461 {
462 BUFFER_ADD = TAP_MOVE(cur_state, TAP_SI);
463 cur_state = TAP_SI;
464 }
465 else
466 {
467 BUFFER_ADD = TAP_MOVE(cur_state, TAP_SD);
468 cur_state = TAP_SD;
469 }
470 //DEBUG("added TMS scan (no read)");
471 }
472
473 /* add command for complete bytes */
474 if (num_bytes > 1)
475 {
476 if (type == SCAN_IO)
477 {
478 /* Clock Data Bytes In and Out LSB First */
479 BUFFER_ADD = 0x39;
480 //DEBUG("added TDI bytes (io %i)", num_bytes);
481 }
482 else if (type == SCAN_OUT)
483 {
484 /* Clock Data Bytes Out on -ve Clock Edge LSB First (no Read) */
485 BUFFER_ADD = 0x19;
486 //DEBUG("added TDI bytes (o)");
487 }
488 else if (type == SCAN_IN)
489 {
490 /* Clock Data Bytes In on +ve Clock Edge LSB First (no Write) */
491 BUFFER_ADD = 0x28;
492 //DEBUG("added TDI bytes (i %i)", num_bytes);
493 }
494 BUFFER_ADD = (num_bytes-2) & 0xff;
495 BUFFER_ADD = ((num_bytes-2) >> 8) & 0xff;
496 }
497 if (type != SCAN_IN)
498 {
499 /* add complete bytes */
500 while(num_bytes-- > 1)
501 {
502 BUFFER_ADD = buffer[cur_byte];
503 cur_byte++;
504 bits_left -= 8;
505 }
506 }
507 if (type == SCAN_IN)
508 {
509 bits_left -= 8 * (num_bytes - 1);
510 }
511
512 /* the most signifcant bit is scanned during TAP movement */
513 if (type != SCAN_IN)
514 last_bit = (buffer[cur_byte] >> (bits_left - 1)) & 0x1;
515 else
516 last_bit = 0;
517
518 /* process remaining bits but the last one */
519 if (bits_left > 1)
520 {
521 if (type == SCAN_IO)
522 {
523 /* Clock Data Bits In and Out LSB First */
524 BUFFER_ADD = 0x3b;
525 //DEBUG("added TDI bits (io) %i", bits_left - 1);
526 }
527 else if (type == SCAN_OUT)
528 {
529 /* Clock Data Bits Out on -ve Clock Edge LSB First (no Read) */
530 BUFFER_ADD = 0x1b;
531 //DEBUG("added TDI bits (o)");
532 }
533 else if (type == SCAN_IN)
534 {
535 /* Clock Data Bits In on +ve Clock Edge LSB First (no Write) */
536 BUFFER_ADD = 0x2a;
537 //DEBUG("added TDI bits (i %i)", bits_left - 1);
538 }
539 BUFFER_ADD = bits_left - 2;
540 if (type != SCAN_IN)
541 BUFFER_ADD = buffer[cur_byte];
542 }
543
544 /* move from Shift-IR/DR to end state */
545 if (type != SCAN_OUT)
546 {
547 /* Clock Data to TMS/CS Pin with Read */
548 BUFFER_ADD = 0x6b;
549 //DEBUG("added TMS scan (read)");
550 }
551 else
552 {
553 /* Clock Data to TMS/CS Pin (no Read) */
554 BUFFER_ADD = 0x4b;
555 //DEBUG("added TMS scan (no read)");
556 }
557 BUFFER_ADD = 0x6;
558 BUFFER_ADD = TAP_MOVE(cur_state, end_state) | (last_bit << 7);
559 cur_state = end_state;
560
561 }
562
563 int ft2232_predict_scan_out(int scan_size, enum scan_type type)
564 {
565 int predicted_size = 3;
566
567 if (cur_state != TAP_SD)
568 predicted_size += 3;
569
570 if (type == SCAN_IN) /* only from device to host */
571 {
572 /* complete bytes */
573 predicted_size += (CEIL(scan_size, 8) > 1) ? 3 : 0;
574 /* remaining bits - 1 (up to 7) */
575 predicted_size += ((scan_size - 1) % 8) ? 2 : 0;
576 }
577 else /* host to device, or bidirectional */
578 {
579 /* complete bytes */
580 predicted_size += (CEIL(scan_size, 8) > 1) ? (CEIL(scan_size, 8) + 3 - 1) : 0;
581 /* remaining bits -1 (up to 7) */
582 predicted_size += ((scan_size - 1) % 8) ? 3 : 0;
583 }
584
585 return predicted_size;
586 }
587
588 int ft2232_predict_scan_in(int scan_size, enum scan_type type)
589 {
590 int predicted_size = 0;
591
592 if (type != SCAN_OUT)
593 {
594 /* complete bytes */
595 predicted_size += (CEIL(scan_size, 8) > 1) ? (CEIL(scan_size, 8) - 1) : 0;
596 /* remaining bits - 1 */
597 predicted_size += ((scan_size - 1) % 8) ? 1 : 0;
598 /* last bit (from TMS scan) */
599 predicted_size += 1;
600 }
601
602 //DEBUG("scan_size: %i, predicted_size: %i", scan_size, predicted_size);
603
604 return predicted_size;
605 }
606
607 void usbjtag_reset(int trst, int srst)
608 {
609 if (trst == 1)
610 {
611 cur_state = TAP_TLR;
612 if (jtag_reset_config & RESET_TRST_OPEN_DRAIN)
613 low_direction |= nTRSTnOE; /* switch to output pin (output is low) */
614 else
615 low_output &= ~nTRST; /* switch output low */
616 }
617 else if (trst == 0)
618 {
619 if (jtag_reset_config & RESET_TRST_OPEN_DRAIN)
620 low_direction &= ~nTRSTnOE; /* switch to input pin (high-Z + internal and external pullup) */
621 else
622 low_output |= nTRST; /* switch output high */
623 }
624
625 if (srst == 1)
626 {
627 if (jtag_reset_config & RESET_SRST_PUSH_PULL)
628 low_output &= ~nSRST; /* switch output low */
629 else
630 low_direction |= nSRSTnOE; /* switch to output pin (output is low) */
631 }
632 else if (srst == 0)
633 {
634 if (jtag_reset_config & RESET_SRST_PUSH_PULL)
635 low_output |= nSRST; /* switch output high */
636 else
637 low_direction &= ~nSRSTnOE; /* switch to input pin (high-Z) */
638 }
639
640 /* command "set data bits low byte" */
641 BUFFER_ADD = 0x80;
642 BUFFER_ADD = low_output;
643 BUFFER_ADD = low_direction;
644
645 }
646
647 void jtagkey_reset(int trst, int srst)
648 {
649 if (trst == 1)
650 {
651 cur_state = TAP_TLR;
652 if (jtag_reset_config & RESET_TRST_OPEN_DRAIN)
653 high_output &= ~nTRSTnOE;
654 else
655 high_output &= ~nTRST;
656 }
657 else if (trst == 0)
658 {
659 if (jtag_reset_config & RESET_TRST_OPEN_DRAIN)
660 high_output |= nTRSTnOE;
661 else
662 high_output |= nTRST;
663 }
664
665 if (srst == 1)
666 {
667 if (jtag_reset_config & RESET_SRST_PUSH_PULL)
668 high_output &= ~nSRST;
669 else
670 high_output &= ~nSRSTnOE;
671 }
672 else if (srst == 0)
673 {
674 if (jtag_reset_config & RESET_SRST_PUSH_PULL)
675 high_output |= nSRST;
676 else
677 high_output |= nSRSTnOE;
678 }
679
680 /* command "set data bits high byte" */
681 BUFFER_ADD = 0x82;
682 BUFFER_ADD = high_output;
683 BUFFER_ADD = high_direction;
684 DEBUG("trst: %i, srst: %i, high_output: 0x%2.2x, high_direction: 0x%2.2x", trst, srst, high_output, high_direction);
685 }
686
687 void olimex_jtag_reset(int trst, int srst)
688 {
689 if (trst == 1)
690 {
691 cur_state = TAP_TLR;
692 if (jtag_reset_config & RESET_TRST_OPEN_DRAIN)
693 high_output &= ~nTRSTnOE;
694 else
695 high_output &= ~nTRST;
696 }
697 else if (trst == 0)
698 {
699 if (jtag_reset_config & RESET_TRST_OPEN_DRAIN)
700 high_output |= nTRSTnOE;
701 else
702 high_output |= nTRST;
703 }
704
705 if (srst == 1)
706 {
707 high_output |= nSRST;
708 }
709 else if (srst == 0)
710 {
711 high_output &= ~nSRST;
712 }
713
714 /* command "set data bits high byte" */
715 BUFFER_ADD = 0x82;
716 BUFFER_ADD = high_output;
717 BUFFER_ADD = high_direction;
718 DEBUG("trst: %i, srst: %i, high_output: 0x%2.2x, high_direction: 0x%2.2x", trst, srst, high_output, high_direction);
719 }
720
721 int ft2232_execute_queue()
722 {
723 jtag_command_t *cmd = jtag_command_queue; /* currently processed command */
724 jtag_command_t *first_unsent = cmd; /* next command that has to be sent */
725 u8 *buffer;
726 int scan_size; /* size of IR or DR scan */
727 enum scan_type type;
728 int i;
729 int predicted_size = 0;
730 int require_send = 0;
731
732 ft2232_buffer_size = 0;
733 ft2232_expect_read = 0;
734
735 /* blink, if the current layout has that feature */
736 if (layout->blink)
737 layout->blink();
738
739 while (cmd)
740 {
741 switch(cmd->type)
742 {
743 case JTAG_END_STATE:
744 if (cmd->cmd.end_state->end_state != -1)
745 ft2232_end_state(cmd->cmd.end_state->end_state);
746 break;
747 case JTAG_RESET:
748 /* only send the maximum buffer size that FT2232C can handle */
749 predicted_size = 3;
750 if (ft2232_buffer_size + predicted_size + 1 > FT2232_BUFFER_SIZE)
751 {
752 ft2232_send_and_recv(first_unsent, cmd);
753 require_send = 0;
754 first_unsent = cmd;
755 }
756
757 layout->reset(cmd->cmd.reset->trst, cmd->cmd.reset->srst);
758 require_send = 1;
759
760 #ifdef _DEBUG_JTAG_IO_
761 DEBUG("trst: %i, srst: %i", cmd->cmd.reset->trst, cmd->cmd.reset->srst);
762 #endif
763 break;
764 case JTAG_RUNTEST:
765 /* only send the maximum buffer size that FT2232C can handle */
766 predicted_size = 0;
767 if (cur_state != TAP_RTI)
768 predicted_size += 3;
769 predicted_size += 3 * CEIL(cmd->cmd.runtest->num_cycles, 7);
770 if ((cmd->cmd.runtest->end_state != -1) && (cmd->cmd.runtest->end_state != TAP_RTI))
771 predicted_size += 3;
772 if ((cmd->cmd.runtest->end_state == -1) && (end_state != TAP_RTI))
773 predicted_size += 3;
774 if (ft2232_buffer_size + predicted_size + 1 > FT2232_BUFFER_SIZE)
775 {
776 ft2232_send_and_recv(first_unsent, cmd);
777 require_send = 0;
778 first_unsent = cmd;
779 }
780 if (cur_state != TAP_RTI)
781 {
782 /* command "Clock Data to TMS/CS Pin (no Read)" */
783 BUFFER_ADD = 0x4b;
784 /* scan 7 bit */
785 BUFFER_ADD = 0x6;
786 /* TMS data bits */
787 BUFFER_ADD = TAP_MOVE(cur_state, TAP_RTI);
788 cur_state = TAP_RTI;
789 require_send = 1;
790 }
791 i = cmd->cmd.runtest->num_cycles;
792 while (i > 0)
793 {
794 /* command "Clock Data to TMS/CS Pin (no Read)" */
795 BUFFER_ADD = 0x4b;
796 /* scan 7 bit */
797 BUFFER_ADD = (i > 7) ? 6 : (i - 1);
798 /* TMS data bits */
799 BUFFER_ADD = 0x0;
800 cur_state = TAP_RTI;
801 i -= (i > 7) ? 7 : i;
802 //DEBUG("added TMS scan (no read)");
803 }
804 if (cmd->cmd.runtest->end_state != -1)
805 ft2232_end_state(cmd->cmd.runtest->end_state);
806 if (cur_state != end_state)
807 {
808 /* command "Clock Data to TMS/CS Pin (no Read)" */
809 BUFFER_ADD = 0x4b;
810 /* scan 7 bit */
811 BUFFER_ADD = 0x6;
812 /* TMS data bits */
813 BUFFER_ADD = TAP_MOVE(cur_state, end_state);
814 cur_state = end_state;
815 //DEBUG("added TMS scan (no read)");
816 }
817 require_send = 1;
818 #ifdef _DEBUG_JTAG_IO_
819 DEBUG("runtest: %i, end in %i", cmd->cmd.runtest->num_cycles, end_state);
820 #endif
821 break;
822 case JTAG_STATEMOVE:
823 /* only send the maximum buffer size that FT2232C can handle */
824 predicted_size = 3;
825 if (ft2232_buffer_size + predicted_size + 1 > FT2232_BUFFER_SIZE)
826 {
827 ft2232_send_and_recv(first_unsent, cmd);
828 require_send = 0;
829 first_unsent = cmd;
830 }
831 if (cmd->cmd.statemove->end_state != -1)
832 ft2232_end_state(cmd->cmd.statemove->end_state);
833 /* command "Clock Data to TMS/CS Pin (no Read)" */
834 BUFFER_ADD = 0x4b;
835 /* scan 7 bit */
836 BUFFER_ADD = 0x6;
837 /* TMS data bits */
838 BUFFER_ADD = TAP_MOVE(cur_state, end_state);
839 //DEBUG("added TMS scan (no read)");
840 cur_state = end_state;
841 require_send = 1;
842 #ifdef _DEBUG_JTAG_IO_
843 DEBUG("statemove: %i", end_state);
844 #endif
845 break;
846 case JTAG_PATHMOVE:
847 /* only send the maximum buffer size that FT2232C can handle */
848 predicted_size = 3 * CEIL(cmd->cmd.pathmove->num_states, 7);
849 if (ft2232_buffer_size + predicted_size + 1 > FT2232_BUFFER_SIZE)
850 {
851 ft2232_send_and_recv(first_unsent, cmd);
852 require_send = 0;
853 first_unsent = cmd;
854 }
855 ft2232_add_pathmove(cmd->cmd.pathmove);
856 require_send = 1;
857 #ifdef _DEBUG_JTAG_IO_
858 DEBUG("pathmove: %i states, end in %i", cmd->cmd.pathmove->num_states, cmd->cmd.pathmove->path[cmd->cmd.pathmove->num_states - 1]);
859 #endif
860 break;
861 case JTAG_SCAN:
862 scan_size = jtag_build_buffer(cmd->cmd.scan, &buffer);
863 type = jtag_scan_type(cmd->cmd.scan);
864 predicted_size = ft2232_predict_scan_out(scan_size, type);
865 if (ft2232_buffer_size + predicted_size + 1 > FT2232_BUFFER_SIZE)
866 {
867 DEBUG("ftd2xx buffer size reached, sending queued commands (first_unsent: %x, cmd: %x)", first_unsent, cmd);
868 ft2232_send_and_recv(first_unsent, cmd);
869 require_send = 0;
870 first_unsent = cmd;
871 }
872 ft2232_expect_read += ft2232_predict_scan_in(scan_size, type);
873 //DEBUG("new read size: %i", ft2232_expect_read);
874 if (cmd->cmd.scan->end_state != -1)
875 ft2232_end_state(cmd->cmd.scan->end_state);
876 ft2232_add_scan(cmd->cmd.scan->ir_scan, type, buffer, scan_size);
877 require_send = 1;
878 if (buffer)
879 free(buffer);
880 #ifdef _DEBUG_JTAG_IO_
881 DEBUG("%s scan, %i bit, end in %i", (cmd->cmd.scan->ir_scan) ? "IR" : "DR", scan_size, end_state);
882 #endif
883 break;
884 case JTAG_SLEEP:
885 ft2232_send_and_recv(first_unsent, cmd);
886 first_unsent = cmd->next;
887 jtag_sleep(cmd->cmd.sleep->us);
888 #ifdef _DEBUG_JTAG_IO_
889 DEBUG("sleep %i usec", cmd->cmd.sleep->us);
890 #endif
891 break;
892 default:
893 ERROR("BUG: unknown JTAG command type encountered");
894 exit(-1);
895 }
896 cmd = cmd->next;
897 }
898
899 if (require_send > 0)
900 ft2232_send_and_recv(first_unsent, cmd);
901
902 return ERROR_OK;
903 }
904
905 int ft2232_init(void)
906 {
907 u8 latency_timer;
908 u8 buf[1];
909 int retval;
910 u32 bytes_written;
911
912 #if BUILD_FT2232_FTD2XX == 1
913 FT_STATUS status;
914 #endif
915
916 ft2232_layout_t *cur_layout = ft2232_layouts;
917
918 if ((ft2232_layout == NULL) || (ft2232_layout[0] == 0))
919 {
920 ft2232_layout = "usbjtag";
921 WARNING("No ft2232 layout specified, using default 'usbjtag'");
922 }
923
924 while (cur_layout->name)
925 {
926 if (strcmp(cur_layout->name, ft2232_layout) == 0)
927 {
928 layout = cur_layout;
929 break;
930 }
931 cur_layout++;
932 }
933
934 if (!layout)
935 {
936 ERROR("No matching layout found for %s", ft2232_layout);
937 return ERROR_JTAG_INIT_FAILED;
938 }
939
940 #if BUILD_FT2232_FTD2XX == 1
941 DEBUG("'ft2232' interface using FTD2XX with '%s' layout", ft2232_layout);
942 #elif BUILD_FT2232_LIBFTDI == 1
943 DEBUG("'ft2232' interface using libftdi with '%s' layout", ft2232_layout);
944 #endif
945
946 #if BUILD_FT2232_FTD2XX == 1
947 /* Open by device description */
948 if (ft2232_device_desc == NULL)
949 {
950 WARNING("no ftd2xx device description specified, using default 'Dual RS232'");
951 ft2232_device_desc = "Dual RS232";
952 }
953
954 #if IS_WIN32 == 0
955 /* Add non-standard Vid/Pid to the linux driver */
956 if ((status = FT_SetVIDPID(ft2232_vid, ft2232_pid)) != FT_OK)
957 {
958 WARNING("couldn't add %4.4x:%4.4x", ft2232_vid, ft2232_pid);
959 }
960 #endif
961
962 if ((status = FT_OpenEx(ft2232_device_desc, FT_OPEN_BY_DESCRIPTION, &ftdih)) != FT_OK)
963 {
964 DWORD num_devices;
965
966 ERROR("unable to open ftdi device: %i", status);
967 status = FT_ListDevices(&num_devices, NULL, FT_LIST_NUMBER_ONLY);
968 if (status == FT_OK)
969 {
970 char **desc_array = malloc(sizeof(char*) * (num_devices + 1));
971 int i;
972
973 for (i = 0; i < num_devices; i++)
974 desc_array[i] = malloc(64);
975 desc_array[num_devices] = NULL;
976
977 status = FT_ListDevices(desc_array, &num_devices, FT_LIST_ALL | FT_OPEN_BY_DESCRIPTION);
978
979 if (status == FT_OK)
980 {
981 ERROR("ListDevices: %d\n", num_devices);
982 for (i = 0; i < num_devices; i++)
983 ERROR("%i: %s", i, desc_array[i]);
984 }
985
986 for (i = 0; i < num_devices; i++)
987 free(desc_array[i]);
988 free(desc_array);
989 }
990 else
991 {
992 printf("ListDevices: NONE\n");
993 }
994 return ERROR_JTAG_INIT_FAILED;
995 }
996
997 if ((status = FT_SetLatencyTimer(ftdih, 2)) != FT_OK)
998 {
999 ERROR("unable to set latency timer: %i", status);
1000 return ERROR_JTAG_INIT_FAILED;
1001 }
1002
1003 if ((status = FT_GetLatencyTimer(ftdih, &latency_timer)) != FT_OK)
1004 {
1005 ERROR("unable to get latency timer: %i", status);
1006 return ERROR_JTAG_INIT_FAILED;
1007 }
1008 else
1009 {
1010 DEBUG("current latency timer: %i", latency_timer);
1011 }
1012
1013 if ((status = FT_SetTimeouts(ftdih, 5000, 5000)) != FT_OK)
1014 {
1015 ERROR("unable to set timeouts: %i", status);
1016 return ERROR_JTAG_INIT_FAILED;
1017 }
1018
1019 if ((status = FT_SetBitMode(ftdih, 0x0b, 2)) != FT_OK)
1020 {
1021 ERROR("unable to enable bit i/o mode: %i", status);
1022 return ERROR_JTAG_INIT_FAILED;
1023 }
1024 #elif BUILD_FT2232_LIBFTDI == 1
1025 if (ftdi_init(&ftdic) < 0)
1026 return ERROR_JTAG_INIT_FAILED;
1027
1028 /* context, vendor id, product id */
1029 if (ftdi_usb_open(&ftdic, ft2232_vid, ft2232_pid) < 0)
1030 {
1031 ERROR("unable to open ftdi device: %s", ftdic.error_str);
1032 return ERROR_JTAG_INIT_FAILED;
1033 }
1034
1035 if (ftdi_usb_reset(&ftdic) < 0)
1036 {
1037 ERROR("unable to reset ftdi device");
1038 return ERROR_JTAG_INIT_FAILED;
1039 }
1040
1041 if (ftdi_set_latency_timer(&ftdic, 2) < 0)
1042 {
1043 ERROR("unable to set latency timer");
1044 return ERROR_JTAG_INIT_FAILED;
1045 }
1046
1047 if (ftdi_get_latency_timer(&ftdic, &latency_timer) < 0)
1048 {
1049 ERROR("unable to get latency timer");
1050 return ERROR_JTAG_INIT_FAILED;
1051 }
1052 else
1053 {
1054 DEBUG("current latency timer: %i", latency_timer);
1055 }
1056
1057 ftdic.bitbang_mode = 0; /* Reset controller */
1058 ftdi_enable_bitbang(&ftdic, 0x0b); /* ctx, JTAG I/O mask */
1059
1060 ftdic.bitbang_mode = 2; /* MPSSE mode */
1061 ftdi_enable_bitbang(&ftdic, 0x0b); /* ctx, JTAG I/O mask */
1062 #endif
1063
1064 ft2232_buffer_size = 0;
1065 ft2232_buffer = malloc(FT2232_BUFFER_SIZE);
1066
1067 if (layout->init() != ERROR_OK)
1068 return ERROR_JTAG_INIT_FAILED;
1069
1070 ft2232_speed(jtag_speed);
1071
1072 buf[0] = 0x85; /* Disconnect TDI/DO to TDO/DI for Loopback */
1073 if (((retval = ft2232_write(buf, 1, &bytes_written)) != ERROR_OK) || (bytes_written != 1))
1074 {
1075 ERROR("couldn't write to FT2232 to disable loopback");
1076 return ERROR_JTAG_INIT_FAILED;
1077 }
1078
1079 #if BUILD_FT2232_FTD2XX == 1
1080 if ((status = FT_Purge(ftdih, FT_PURGE_RX | FT_PURGE_TX)) != FT_OK)
1081 {
1082 ERROR("error purging ftd2xx device: %i", status);
1083 return ERROR_JTAG_INIT_FAILED;
1084 }
1085 #elif BUILD_FT2232_LIBFTDI == 1
1086 if (ftdi_usb_purge_buffers(&ftdic) < 0)
1087 {
1088 ERROR("ftdi_purge_buffers: %s", ftdic.error_str);
1089 return ERROR_JTAG_INIT_FAILED;
1090 }
1091 #endif
1092
1093 return ERROR_OK;
1094 }
1095
1096 int usbjtag_init(void)
1097 {
1098 u8 buf[3];
1099 u32 bytes_written;
1100
1101 low_output = 0x08;
1102 low_direction = 0x0b;
1103
1104 if (strcmp(ft2232_layout, "usbjtag") == 0)
1105 {
1106 nTRST = 0x10;
1107 nTRSTnOE = 0x10;
1108 nSRST = 0x40;
1109 nSRSTnOE = 0x40;
1110 }
1111 else if (strcmp(ft2232_layout, "signalyzer") == 0)
1112 {
1113 nTRST = 0x10;
1114 nTRSTnOE = 0x10;
1115 nSRST = 0x20;
1116 nSRSTnOE = 0x20;
1117 }
1118 else
1119 {
1120 ERROR("BUG: usbjtag_init called for unknown layout '%s'", ft2232_layout);
1121 return ERROR_JTAG_INIT_FAILED;
1122 }
1123
1124 if (jtag_reset_config & RESET_TRST_OPEN_DRAIN)
1125 {
1126 low_direction &= ~nTRSTnOE; /* nTRST input */
1127 low_output &= ~nTRST; /* nTRST = 0 */
1128 }
1129 else
1130 {
1131 low_direction |= nTRSTnOE; /* nTRST output */
1132 low_output |= nTRST; /* nTRST = 1 */
1133 }
1134
1135 if (jtag_reset_config & RESET_SRST_PUSH_PULL)
1136 {
1137 low_direction |= nSRSTnOE; /* nSRST output */
1138 low_output |= nSRST; /* nSRST = 1 */
1139 }
1140 else
1141 {
1142 low_direction &= ~nSRSTnOE; /* nSRST input */
1143 low_output &= ~nSRST; /* nSRST = 0 */
1144 }
1145
1146 /* initialize low byte for jtag */
1147 buf[0] = 0x80; /* command "set data bits low byte" */
1148 buf[1] = low_output; /* value (TMS=1,TCK=0, TDI=0, xRST high) */
1149 buf[2] = low_direction; /* dir (output=1), TCK/TDI/TMS=out, TDO=in */
1150 DEBUG("%2.2x %2.2x %2.2x", buf[0], buf[1], buf[2]);
1151
1152 if (((ft2232_write(buf, 3, &bytes_written)) != ERROR_OK) || (bytes_written != 3))
1153 {
1154 ERROR("couldn't initialize FT2232 with 'USBJTAG' layout");
1155 return ERROR_JTAG_INIT_FAILED;
1156 }
1157
1158 return ERROR_OK;
1159 }
1160
1161 int jtagkey_init(void)
1162 {
1163 u8 buf[3];
1164 u32 bytes_written;
1165
1166 low_output = 0x08;
1167 low_direction = 0x1b;
1168
1169 /* initialize low byte for jtag */
1170 buf[0] = 0x80; /* command "set data bits low byte" */
1171 buf[1] = low_output; /* value (TMS=1,TCK=0, TDI=0, nOE=0) */
1172 buf[2] = low_direction; /* dir (output=1), TCK/TDI/TMS=out, TDO=in, nOE=out */
1173 DEBUG("%2.2x %2.2x %2.2x", buf[0], buf[1], buf[2]);
1174
1175 if (((ft2232_write(buf, 3, &bytes_written)) != ERROR_OK) || (bytes_written != 3))
1176 {
1177 ERROR("couldn't initialize FT2232 with 'JTAGkey' layout");
1178 return ERROR_JTAG_INIT_FAILED;
1179 }
1180
1181 if (strcmp(layout->name, "jtagkey") == 0)
1182 {
1183 nTRST = 0x01;
1184 nTRSTnOE = 0x4;
1185 nSRST = 0x02;
1186 nSRSTnOE = 0x08;
1187 }
1188 else if (strcmp(layout->name, "jtagkey_prototype_v1") == 0)
1189 {
1190 nTRST = 0x02;
1191 nTRSTnOE = 0x1;
1192 nSRST = 0x08;
1193 nSRSTnOE = 0x04;
1194 }
1195 else
1196 {
1197 ERROR("BUG: jtagkey_init called for non jtagkey layout");
1198 exit(-1);
1199 }
1200
1201 high_output = 0x0;
1202 high_direction = 0x0f;
1203
1204 if (jtag_reset_config & RESET_TRST_OPEN_DRAIN)
1205 {
1206 high_output |= nTRSTnOE;
1207 high_output &= ~nTRST;
1208 }
1209 else
1210 {
1211 high_output &= ~nTRSTnOE;
1212 high_output |= nTRST;
1213 }
1214
1215 if (jtag_reset_config & RESET_SRST_PUSH_PULL)
1216 {
1217 high_output &= ~nSRSTnOE;
1218 high_output |= nSRST;
1219 }
1220 else
1221 {
1222 high_output |= nSRSTnOE;
1223 high_output &= ~nSRST;
1224 }
1225
1226 /* initialize high port */
1227 buf[0] = 0x82; /* command "set data bits high byte" */
1228 buf[1] = high_output; /* value */
1229 buf[2] = high_direction; /* all outputs (xRST and xRSTnOE) */
1230 DEBUG("%2.2x %2.2x %2.2x", buf[0], buf[1], buf[2]);
1231
1232 if (((ft2232_write(buf, 3, &bytes_written)) != ERROR_OK) || (bytes_written != 3))
1233 {
1234 ERROR("couldn't initialize FT2232 with 'JTAGkey' layout");
1235 return ERROR_JTAG_INIT_FAILED;
1236 }
1237
1238 return ERROR_OK;
1239 }
1240
1241 int olimex_jtag_init(void)
1242 {
1243 u8 buf[3];
1244 u32 bytes_written;
1245
1246 low_output = 0x08;
1247 low_direction = 0x1b;
1248
1249 /* initialize low byte for jtag */
1250 buf[0] = 0x80; /* command "set data bits low byte" */
1251 buf[1] = low_output; /* value (TMS=1,TCK=0, TDI=0, nOE=0) */
1252 buf[2] = low_direction; /* dir (output=1), TCK/TDI/TMS=out, TDO=in, nOE=out */
1253 DEBUG("%2.2x %2.2x %2.2x", buf[0], buf[1], buf[2]);
1254
1255 if (((ft2232_write(buf, 3, &bytes_written)) != ERROR_OK) || (bytes_written != 3))
1256 {
1257 ERROR("couldn't initialize FT2232 with 'JTAGkey' layout");
1258 return ERROR_JTAG_INIT_FAILED;
1259 }
1260
1261 nTRST = 0x01;
1262 nTRSTnOE = 0x4;
1263 nSRST = 0x02;
1264 nSRSTnOE = 0x00; /* no output enable for nSRST */
1265
1266 high_output = 0x0;
1267 high_direction = 0x0f;
1268
1269 if (jtag_reset_config & RESET_TRST_OPEN_DRAIN)
1270 {
1271 high_output |= nTRSTnOE;
1272 high_output &= ~nTRST;
1273 }
1274 else
1275 {
1276 high_output &= ~nTRSTnOE;
1277 high_output |= nTRST;
1278 }
1279
1280 if (jtag_reset_config & RESET_SRST_PUSH_PULL)
1281 {
1282 ERROR("can't set nSRST to push-pull on the Olimex ARM-USB-OCD");
1283 }
1284 else
1285 {
1286 high_output &= ~nSRST;
1287 }
1288
1289 /* turn red LED on */
1290 high_output |= 0x08;
1291
1292 /* initialize high port */
1293 buf[0] = 0x82; /* command "set data bits high byte" */
1294 buf[1] = high_output; /* value */
1295 buf[2] = high_direction; /* all outputs (xRST and xRSTnOE) */
1296 DEBUG("%2.2x %2.2x %2.2x", buf[0], buf[1], buf[2]);
1297
1298 if (((ft2232_write(buf, 3, &bytes_written)) != ERROR_OK) || (bytes_written != 3))
1299 {
1300 ERROR("couldn't initialize FT2232 with 'JTAGkey' layout");
1301 return ERROR_JTAG_INIT_FAILED;
1302 }
1303
1304 return ERROR_OK;
1305 }
1306
1307 void olimex_jtag_blink(void)
1308 {
1309 /* Olimex ARM-USB-OCD has a LED connected to ACBUS3
1310 * ACBUS3 is bit 3 of the GPIOH port
1311 */
1312 if (high_output & 0x08)
1313 {
1314 /* set port pin high */
1315 high_output &= 0x07;
1316 }
1317 else
1318 {
1319 /* set port pin low */
1320 high_output |= 0x08;
1321 }
1322
1323 BUFFER_ADD = 0x82;
1324 BUFFER_ADD = high_output;
1325 BUFFER_ADD = high_direction;
1326 }
1327
1328 int ft2232_quit(void)
1329 {
1330 #if BUILD_FT2232_FTD2XX == 1
1331 FT_STATUS status;
1332
1333 status = FT_Close(ftdih);
1334 #elif BUILD_FT2232_LIBFTDI == 1
1335 ftdi_disable_bitbang(&ftdic);
1336
1337 ftdi_usb_close(&ftdic);
1338
1339 ftdi_deinit(&ftdic);
1340 #endif
1341
1342 free(ft2232_buffer);
1343
1344 return ERROR_OK;
1345 }
1346
1347 int ft2232_handle_device_desc_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
1348 {
1349 if (argc == 1)
1350 {
1351 ft2232_device_desc = strdup(args[0]);
1352 }
1353 else
1354 {
1355 ERROR("expected exactly one argument to ft2232_device_desc <description>");
1356 }
1357
1358 return ERROR_OK;
1359 }
1360
1361 int ft2232_handle_layout_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
1362 {
1363 if (argc == 0)
1364 return ERROR_OK;
1365
1366 ft2232_layout = malloc(strlen(args[0]) + 1);
1367 strcpy(ft2232_layout, args[0]);
1368
1369 return ERROR_OK;
1370 }
1371
1372 int ft2232_handle_vid_pid_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
1373 {
1374 if (argc >= 2)
1375 {
1376 ft2232_vid = strtol(args[0], NULL, 0);
1377 ft2232_pid = strtol(args[1], NULL, 0);
1378 }
1379 else
1380 {
1381 WARNING("incomplete ft2232_vid_pid configuration directive");
1382 }
1383
1384 return ERROR_OK;
1385 }