]> git.sur5r.net Git - openocd/blob - src/jtag/ftdi2232.c
- Added support for native MinGW builds (thanks to Spencer Oliver and Michael Fischer...
[openocd] / src / jtag / ftdi2232.c
1 /***************************************************************************
2  *   Copyright (C) 2004 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 /* project specific includes */
25 #include "log.h"
26 #include "types.h"
27 #include "jtag.h"
28 #include "configuration.h"
29 #include "command.h"
30
31 /* system includes */
32 #include <string.h>
33 #include <stdlib.h>
34 #include <unistd.h>
35 #include <usb.h>
36 #include <ftdi.h>
37
38 #include <sys/time.h>
39 #include <time.h>
40
41 /* enable this to debug io latency
42  */
43 #if 0
44 #define _DEBUG_USB_IO_
45 #endif
46
47 int ftdi2232_execute_queue(void);
48
49 int ftdi2232_speed(int speed);
50 int ftdi2232_register_commands(struct command_context_s *cmd_ctx);
51 int ftdi2232_init(void);
52 int ftdi2232_quit(void);
53
54 enum { FTDI2232_TRST = 0x10, FTDI2232_SRST = 0x40 };
55 static u8 discrete_output = 0x0 | FTDI2232_TRST | FTDI2232_SRST;
56 static struct ftdi_context ftdic;
57
58 static u8 *ftdi2232_buffer = NULL;
59 static int ftdi2232_buffer_size = 0;
60 static int ftdi2232_read_pointer = 0;
61 static int ftdi2232_expect_read = 0;
62 #define FTDI2232_BUFFER_SIZE    131072
63 #define BUFFER_ADD ftdi2232_buffer[ftdi2232_buffer_size++]
64 #define BUFFER_READ ftdi2232_buffer[ftdi2232_read_pointer++]
65
66 #define FTDI2232_SAVE_SIZE      1024
67
68 int ftdi2232_handle_vid_pid_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
69
70 static u16 ftdi2232_vid = 0x0403;
71 static u16 ftdi2232_pid = 0x6010;
72
73 jtag_interface_t ftdi2232_interface = 
74 {
75         
76         .name = "ftdi2232",
77         
78         .execute_queue = ftdi2232_execute_queue,
79         
80         .support_statemove = 1,
81         
82         .speed = ftdi2232_speed,
83         .register_commands = ftdi2232_register_commands,
84         .init = ftdi2232_init,
85         .quit = ftdi2232_quit,
86 };
87
88 int ftdi2232_speed(int speed)
89 {
90         u8 buf[3];
91
92         buf[0] = 0x86; /* command "set divisor" */
93         buf[1] = speed & 0xff; /* valueL (0=6MHz, 1=3MHz, 2=1.5MHz, ...*/
94         buf[2] = (speed >> 8) & 0xff; /* valueH */
95         
96         DEBUG("%2.2x %2.2x %2.2x", buf[0], buf[1], buf[2]);
97         ftdi_write_data(&ftdic, buf, 3);
98
99         return ERROR_OK;
100 }
101
102 int ftdi2232_register_commands(struct command_context_s *cmd_ctx)
103 {
104         register_command(cmd_ctx, NULL, "ftdi2232_vid_pid", ftdi2232_handle_vid_pid_command,
105                 COMMAND_CONFIG, NULL);
106         
107         return ERROR_OK;
108 }
109
110 void ftdi2232_end_state(state)
111 {
112         if (tap_move_map[state] != -1)
113                 end_state = state;
114         else
115         {
116                 ERROR("BUG: %i is not a valid end state", state);
117                 exit(-1);
118         }
119 }
120
121 void ftdi2232_read_scan(enum scan_type type, u8* buffer, int scan_size)
122 {
123         int num_bytes = ((scan_size + 7) / 8);
124         int bits_left = scan_size;
125         int cur_byte = 0;
126
127         while(num_bytes-- > 1)
128         {
129                 buffer[cur_byte] = BUFFER_READ;
130                 cur_byte++;
131                 bits_left -= 8;
132         }
133
134         buffer[cur_byte] = 0x0;
135
136         if (bits_left > 1)
137         {
138                 buffer[cur_byte] = BUFFER_READ >> 1;
139         }
140
141         buffer[cur_byte] = (buffer[cur_byte] | ((BUFFER_READ & 0x02) << 6)) >> (8 - bits_left);
142
143 }
144
145 void ftdi2232_debug_dump_buffer(void)
146 {
147         int i;
148         for (i = 0; i < ftdi2232_buffer_size; i++)
149         {
150                 printf("%2.2x ", ftdi2232_buffer[i]);
151                 if (i % 16 == 15)
152                         printf("\n");
153         }
154         printf("\n");
155         fflush(stdout);
156 }
157
158 int ftdi2232_send_and_recv(jtag_command_t *first, jtag_command_t *last)
159 {
160         jtag_command_t *cmd;
161         u8 *buffer;
162         int scan_size;
163         enum scan_type type;
164         int retval;
165
166         BUFFER_ADD = 0x87;      /* send immediate command */
167         
168         if (ftdi2232_buffer_size > FTDI2232_SAVE_SIZE)
169         {
170                 ERROR("BUG: ftdi2232_buffer grew beyond %i byte (%i) - this is going to fail", FTDI2232_SAVE_SIZE,  ftdi2232_buffer_size);
171         }
172
173 #ifdef _DEBUG_USB_IO_
174         DEBUG("write buffer (size %i):", ftdi2232_buffer_size);
175         ftdi2232_debug_dump_buffer();
176 #endif
177
178         if ((retval = ftdi_write_data(&ftdic, ftdi2232_buffer, ftdi2232_buffer_size)) < 0)
179         {
180                 ERROR("ftdi_write_data returned %i", retval);
181                 exit(-1);
182         }
183
184         if (ftdi2232_expect_read)
185         {
186                 int timeout = 100;
187                 ftdi2232_buffer_size = 0;
188                 
189                 while ((ftdi2232_buffer_size < ftdi2232_expect_read) && timeout)
190                 {
191                         ftdi2232_buffer_size += ftdi_read_data(&ftdic, ftdi2232_buffer + ftdi2232_buffer_size, FTDI2232_BUFFER_SIZE - ftdi2232_buffer_size);
192                         timeout--;
193                 }
194
195                 if (ftdi2232_expect_read != ftdi2232_buffer_size)
196                 {
197                         ERROR("ftdi2232_expect_read (%i) != ftdi2232_buffer_size (%i) (%i retries)", ftdi2232_expect_read, ftdi2232_buffer_size, 100 - timeout);
198                         ftdi2232_debug_dump_buffer();
199
200                         exit(-1);
201                 }
202
203 #ifdef _DEBUG_USB_IO_
204                 DEBUG("read buffer (%i retries): %i bytes", 100 - timeout, ftdi2232_buffer_size);
205                 ftdi2232_debug_dump_buffer();   
206 #endif
207         }
208
209         ftdi2232_expect_read = 0;
210         ftdi2232_read_pointer = 0;
211
212         cmd = first;
213         while (cmd != last)
214         {
215                 switch (cmd->type)
216                 {
217                         case JTAG_SCAN:
218                                 type = jtag_scan_type(cmd->cmd.scan);
219                                 if (type != SCAN_OUT)
220                                 {
221                                         scan_size = jtag_scan_size(cmd->cmd.scan);
222                                         buffer = calloc(CEIL(scan_size, 8), 1);
223                                         ftdi2232_read_scan(type, buffer, scan_size);
224                                         jtag_read_buffer(buffer, cmd->cmd.scan);
225                                         free(buffer);
226                                 }
227                                 break;
228                         default:
229                                 break;
230                 }
231                 cmd = cmd->next;
232         }
233         
234         ftdi2232_buffer_size = 0;
235
236         return ERROR_OK;
237 }
238
239 void ftdi2232_add_scan(int ir_scan, enum scan_type type, u8 *buffer, int scan_size)
240 {
241         int num_bytes = (scan_size + 7) / 8;
242         int bits_left = scan_size;
243         int cur_byte = 0;
244         int last_bit;
245
246         /* command "Clock Data to TMS/CS Pin (no Read)" */
247         BUFFER_ADD = 0x4b;
248         /* scan 7 bit */
249         BUFFER_ADD = 0x6;
250         /* TMS data bits */
251         if (ir_scan)
252         {
253                 BUFFER_ADD = TAP_MOVE(cur_state, TAP_SI);
254                 cur_state = TAP_SI;
255         }
256         else
257         {
258                 BUFFER_ADD = TAP_MOVE(cur_state, TAP_SD);
259                 cur_state = TAP_SD;
260         }
261         //DEBUG("added TMS scan (no read)");
262
263         /* add command for complete bytes */
264         if (num_bytes > 1)
265         {
266                 if (type == SCAN_IO)
267                 {
268                         /* Clock Data Bytes In and Out LSB First */
269                         BUFFER_ADD = 0x39;
270                         //DEBUG("added TDI bytes (io %i)", num_bytes);
271                 }
272                 else if (type == SCAN_OUT)
273                 {
274                         /* Clock Data Bytes Out on -ve Clock Edge LSB First (no Read) */
275                         BUFFER_ADD = 0x19;
276                         //DEBUG("added TDI bytes (o)");
277                 }
278                 else if (type == SCAN_IN)
279                 {
280                         /* Clock Data Bytes In on +ve Clock Edge LSB First (no Write) */
281                         BUFFER_ADD = 0x28;
282                         //DEBUG("added TDI bytes (i %i)", num_bytes);
283                 }
284                 BUFFER_ADD = (num_bytes-2) & 0xff;
285                 BUFFER_ADD = ((num_bytes-2) >> 8) & 0xff;
286         }
287         if (type != SCAN_IN)
288         {
289                 /* add complete bytes */
290                 while(num_bytes-- > 1)
291                 {
292                         BUFFER_ADD = buffer[cur_byte];
293                         cur_byte++;
294                         bits_left -= 8;
295                 }
296         }
297         if (type == SCAN_IN)
298         {
299                 bits_left -= 8 * (num_bytes - 1);
300         }
301
302         /* the most signifcant bit is scanned during TAP movement */
303         if (type != SCAN_IN)
304                 last_bit = (buffer[cur_byte] >> (bits_left - 1)) & 0x1;
305         else
306                 last_bit = 0;
307
308         /* process remaining bits but the last one */
309         if (bits_left > 1)
310         {
311                 if (type == SCAN_IO)
312                 {
313                         /* Clock Data Bits In and Out LSB First */
314                         BUFFER_ADD = 0x3b;
315                         //DEBUG("added TDI bits (io) %i", bits_left - 1);
316                 }
317                 else if (type == SCAN_OUT)
318                 {
319                         /* Clock Data Bits Out on -ve Clock Edge LSB First (no Read) */
320                         BUFFER_ADD = 0x1b;
321                         //DEBUG("added TDI bits (o)");
322                 }
323                 else if (type == SCAN_IN)
324                 {
325                         /* Clock Data Bits In on +ve Clock Edge LSB First (no Write) */
326                         BUFFER_ADD = 0x2a;
327                         //DEBUG("added TDI bits (i %i)", bits_left - 1);
328                 }
329                 BUFFER_ADD = bits_left - 2;
330                 if (type != SCAN_IN)
331                         BUFFER_ADD = buffer[cur_byte];
332         }
333
334         /* move from Shift-IR/DR to end state */
335         if (type != SCAN_OUT)
336         {
337                 /* Clock Data to TMS/CS Pin with Read */
338                 BUFFER_ADD = 0x6b;
339                 //DEBUG("added TMS scan (read)");
340         }
341         else
342         {
343                 /* Clock Data to TMS/CS Pin (no Read) */
344                 BUFFER_ADD = 0x4b;
345                 //DEBUG("added TMS scan (no read)");
346         }
347         BUFFER_ADD = 0x6;
348         BUFFER_ADD = TAP_MOVE(cur_state, end_state) | (last_bit << 7);
349         cur_state = end_state;
350
351 }
352
353 int ftdi2232_predict_scan_out(int scan_size, enum scan_type type)
354 {
355         int predicted_size = 6;
356         if (type == SCAN_IN)    /* only from device to host */
357         {
358                 predicted_size += (CEIL(scan_size, 8) > 1) ? 3 : 0;
359                 predicted_size += ((scan_size - 1) % 8) ? 2 : 0;
360         }
361         else                                    /* host to device, or bidirectional */
362         {
363                 predicted_size += (CEIL(scan_size, 8) > 1) ? (CEIL(scan_size, 8) + 3 - 1) : 0;
364                 predicted_size += ((scan_size - 1) % 8) ? 3 : 0;
365         }
366
367         return predicted_size;
368 }
369
370 int ftdi2232_predict_scan_in(int scan_size, enum scan_type type)
371 {
372         int predicted_size = 0;
373         
374         if (type != SCAN_OUT)
375         {
376                 /* complete bytes */
377                 predicted_size += (CEIL(scan_size, 8) > 1) ? (CEIL(scan_size, 8) - 1) : 0;
378                 /* remaining bits - 1 */
379                 predicted_size += ((scan_size - 1) % 8) ? 1 : 0;
380                 /* last bit (from TMS scan) */
381                 predicted_size += 1;
382         }
383         
384         //DEBUG("scan_size: %i, predicted_size: %i", scan_size, predicted_size);
385
386         return predicted_size;
387 }
388
389 int ftdi2232_execute_queue()
390 {
391         jtag_command_t *cmd = jtag_command_queue; /* currently processed command */
392         jtag_command_t *first_unsent = cmd;     /* next command that has to be sent */
393         u8 *buffer;
394         int scan_size;  /* size of IR or DR scan */
395         enum scan_type type;
396         int i;
397         int predicted_size = 0;
398         int require_send = 0;
399
400         ftdi2232_buffer_size = 0;
401         ftdi2232_expect_read = 0;
402
403         while (cmd)
404         {
405                 switch(cmd->type)
406                 {
407                         case JTAG_END_STATE:
408                                 if (cmd->cmd.end_state->end_state != -1)
409                                         ftdi2232_end_state(cmd->cmd.end_state->end_state);
410                                 break;
411                         case JTAG_RESET:
412                                 /* only send the maximum buffer size that FT2232C can handle */
413                                 predicted_size = 3;
414                                 if (ftdi2232_buffer_size + predicted_size + 1 > FTDI2232_SAVE_SIZE)
415                                 {
416                                         ftdi2232_send_and_recv(first_unsent, cmd);
417                                         require_send = 0;
418                                         first_unsent = cmd;
419                                 }
420
421                                 if (cmd->cmd.reset->trst == 1)
422                                 {
423                                         cur_state = TAP_TLR;
424                                         discrete_output &= ~FTDI2232_TRST;
425                                 }
426                                 else if (cmd->cmd.reset->trst == 0)
427                                 {
428                                         discrete_output |= FTDI2232_TRST;
429                                 }
430
431                                 if (cmd->cmd.reset->srst == 1)
432                                         discrete_output &= ~FTDI2232_SRST;
433                                 else if (cmd->cmd.reset->srst == 0)
434                                         discrete_output |= FTDI2232_SRST;
435                                 /* command "set data bits low byte" */
436                                 BUFFER_ADD = 0x80;
437                                 /* value (TMS=1,TCK=0, TDI=0, TRST/SRST */
438                                 BUFFER_ADD = 0x08 | discrete_output;
439                                 /* dir (output=1), TCK/TDI/TMS=out, TDO=in, TRST/SRST=out */
440                                 BUFFER_ADD = 0x0b | FTDI2232_SRST | FTDI2232_TRST;
441                                 require_send = 1;
442                                 break;
443                         case JTAG_RUNTEST:
444                                 /* only send the maximum buffer size that FT2232C can handle */
445                                 predicted_size = 0;
446                                 if (cur_state != TAP_RTI)
447                                         predicted_size += 3;
448                                 predicted_size += 3 * CEIL(cmd->cmd.runtest->num_cycles, 7);
449                                 if ((cmd->cmd.runtest->end_state != -1) && (cmd->cmd.runtest->end_state != TAP_RTI))
450                                         predicted_size += 3;
451                                 if ((cmd->cmd.runtest->end_state == -1) && (end_state != TAP_RTI))
452                                         predicted_size += 3;
453                                 if (ftdi2232_buffer_size + predicted_size + 1 > FTDI2232_SAVE_SIZE)
454                                 {
455                                         ftdi2232_send_and_recv(first_unsent, cmd);
456                                         require_send = 0;
457                                         first_unsent = cmd;
458                                 }
459                                 if (cur_state != TAP_RTI)
460                                 {
461                                         /* command "Clock Data to TMS/CS Pin (no Read)" */
462                                         BUFFER_ADD = 0x4b;
463                                         /* scan 7 bit */
464                                         BUFFER_ADD = 0x6;
465                                         /* TMS data bits */
466                                         BUFFER_ADD = TAP_MOVE(cur_state, TAP_RTI);
467                                         cur_state = TAP_RTI;
468                                         require_send = 1;
469                                 }
470                                 i = cmd->cmd.runtest->num_cycles;
471                                 while (i > 0)
472                                 {
473                                         /* command "Clock Data to TMS/CS Pin (no Read)" */
474                                         BUFFER_ADD = 0x4b;
475                                         /* scan 7 bit */
476                                         BUFFER_ADD = (i > 7) ? 6 : (i - 1);
477                                         /* TMS data bits */
478                                         BUFFER_ADD = 0x0;
479                                         cur_state = TAP_RTI;
480                                         i -= (i > 7) ? 7 : i;
481                                         //DEBUG("added TMS scan (no read)");
482                                 }
483                                 if (cmd->cmd.runtest->end_state != -1)
484                                         ftdi2232_end_state(cmd->cmd.runtest->end_state);
485                                 if (cur_state != end_state)
486                                 {
487                                         /* command "Clock Data to TMS/CS Pin (no Read)" */
488                                         BUFFER_ADD = 0x4b;
489                                         /* scan 7 bit */
490                                         BUFFER_ADD = 0x6;
491                                         /* TMS data bits */
492                                         BUFFER_ADD = TAP_MOVE(cur_state, end_state);
493                                         cur_state = end_state;
494                                         //DEBUG("added TMS scan (no read)");
495                                 }
496                                 require_send = 1;
497                                 break;
498                         case JTAG_STATEMOVE:
499                                 /* only send the maximum buffer size that FT2232C can handle */
500                                 predicted_size = 3;
501                                 if (ftdi2232_buffer_size + predicted_size + 1 > FTDI2232_SAVE_SIZE)
502                                 {
503                                         ftdi2232_send_and_recv(first_unsent, cmd);
504                                         require_send = 0;
505                                         first_unsent = cmd;
506                                 }
507                                 if (cmd->cmd.statemove->end_state != -1)
508                                         ftdi2232_end_state(cmd->cmd.statemove->end_state);
509                                 /* command "Clock Data to TMS/CS Pin (no Read)" */
510                                 BUFFER_ADD = 0x4b;
511                                 /* scan 7 bit */
512                                 BUFFER_ADD = 0x6;
513                                 /* TMS data bits */
514                                 BUFFER_ADD = TAP_MOVE(cur_state, end_state);
515                                 //DEBUG("added TMS scan (no read)");
516                                 cur_state = end_state;
517                                 require_send = 1;
518                                 break;
519                         case JTAG_SCAN:
520                                 scan_size = jtag_build_buffer(cmd->cmd.scan, &buffer);
521                                 type = jtag_scan_type(cmd->cmd.scan);
522                                 predicted_size = ftdi2232_predict_scan_out(scan_size, type);
523                                 if (ftdi2232_buffer_size + predicted_size + 1 > FTDI2232_SAVE_SIZE)
524                                 {
525                                         ftdi2232_send_and_recv(first_unsent, cmd);
526                                         require_send = 0;
527                                         first_unsent = cmd;
528                                 }
529                                 ftdi2232_expect_read += ftdi2232_predict_scan_in(scan_size, type);
530                                 //DEBUG("new read size: %i", ftdi2232_expect_read);
531                                 if (cmd->cmd.scan->end_state != -1)
532                                         ftdi2232_end_state(cmd->cmd.scan->end_state);
533                                 ftdi2232_add_scan(cmd->cmd.scan->ir_scan, type, buffer, scan_size);
534                                 require_send = 1;
535                                 if (buffer)
536                                         free(buffer);
537                                 break;
538                         case JTAG_SLEEP:
539                                 jtag_sleep(cmd->cmd.sleep->us);
540                                 break;
541                         default:
542                                 ERROR("BUG: unknown JTAG command type encountered");
543                                 exit(-1);
544                 }
545                 cmd = cmd->next;
546         }
547
548         if (require_send > 0)
549                 ftdi2232_send_and_recv(first_unsent, cmd);
550
551         return ERROR_OK;
552 }
553
554 int ftdi2232_init(void)
555 {
556         if (ftdi_init(&ftdic) < 0)
557                 return ERROR_JTAG_INIT_FAILED;
558
559         /* context, vendor id, product id */
560         if (ftdi_usb_open(&ftdic, ftdi2232_vid, ftdi2232_pid) < 0)
561         {
562                 ERROR("unable to open ftdi device: %s", ftdic.error_str);
563                 return ERROR_JTAG_INIT_FAILED;
564         }
565
566         if (ftdi_usb_reset(&ftdic) < 0)
567         {
568                 ERROR("unable to reset ftdi device");
569                 return ERROR_JTAG_INIT_FAILED;
570         }
571
572         if (ftdi_set_latency_timer(&ftdic, 1) < 0)
573         {
574                 ERROR("unable to set latency timer");
575                 return ERROR_JTAG_INIT_FAILED;
576         }
577
578         ftdi2232_buffer_size = 0;
579         ftdi2232_buffer = malloc(FTDI2232_BUFFER_SIZE);
580
581         ftdic.bitbang_mode = 0; /* Reset controller */
582         ftdi_enable_bitbang(&ftdic, 0x0b | FTDI2232_SRST | FTDI2232_TRST); /* ctx, i/o mask (out=1, in=0) */
583
584         ftdic.bitbang_mode = 2; /* MPSSE mode */
585         ftdi_enable_bitbang(&ftdic, 0x0b | FTDI2232_SRST | FTDI2232_TRST); /* ctx, i/o mask (out=1, in=0) */
586         
587         if (ftdi_usb_purge_buffers(&ftdic) < 0)
588         {
589                 ERROR("ftdi_purge_buffers: %s", ftdic.error_str);
590                 return ERROR_JTAG_INIT_FAILED;
591         }
592
593         /* initialize low byte for jtag */
594         BUFFER_ADD = 0x80; /* command "set data bits low byte" */
595         BUFFER_ADD = 0x08 | FTDI2232_SRST | FTDI2232_TRST; /* value (TMS=1,TCK=0, TDI=0, xRST high) */
596         BUFFER_ADD = 0x0b | FTDI2232_SRST | FTDI2232_TRST; /* dir (output=1), TCK/TDI/TMS=out, TDO=in */
597         BUFFER_ADD = 0x85; /* command "Disconnect TDI/DO to TDO/DI for Loopback" */
598         ftdi2232_debug_dump_buffer();
599         if (ftdi_write_data(&ftdic, ftdi2232_buffer, ftdi2232_buffer_size) != 4)
600                 return ERROR_JTAG_INIT_FAILED;
601
602         ftdi2232_speed(jtag_speed);
603
604         return ERROR_OK;
605 }
606
607 int ftdi2232_quit(void)
608 {
609         ftdi_disable_bitbang(&ftdic);
610         
611         ftdi_usb_close(&ftdic);
612         
613         ftdi_deinit(&ftdic);
614
615         free(ftdi2232_buffer);
616
617         return ERROR_OK;
618 }
619
620 int ftdi2232_handle_vid_pid_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
621 {
622         if (argc >= 2)
623         {
624                 ftdi2232_vid = strtol(args[0], NULL, 0);
625                 ftdi2232_pid = strtol(args[1], NULL, 0);
626         }
627         else
628         {
629                 WARNING("incomplete ftdi2232_vid_pid configuration directive");
630         }
631         
632         return ERROR_OK;
633 }