- convert all files to unix line-ending
[fw/openocd] / src / jtag / ft2232.c
index 2a8c7387aab7099360dff52adacdc83ce2ba71b9..d5c4af25421d994a49ab21696b754e905b0a56fd 100644 (file)
@@ -73,12 +73,17 @@ int ft2232_handle_device_desc_command(struct command_context_s *cmd_ctx, char *c
 int ft2232_handle_serial_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
 int ft2232_handle_layout_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
 int ft2232_handle_vid_pid_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
+int ft2232_handle_latency_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
 
 char *ft2232_device_desc = NULL;
 char *ft2232_serial = NULL;
 char *ft2232_layout = NULL;
-u16 ft2232_vid = 0x0403;
-u16 ft2232_pid = 0x6010;
+unsigned char ft2232_latency = 2;
+
+#define MAX_USB_IDS    8
+/* vid = pid = 0 marks the end of the list */
+static u16 ft2232_vid[MAX_USB_IDS+1] = { 0x0403, 0 };
+static u16 ft2232_pid[MAX_USB_IDS+1] = { 0x6010, 0 };
 
 typedef struct ft2232_layout_s
 {
@@ -92,16 +97,23 @@ typedef struct ft2232_layout_s
 int usbjtag_init(void);
 int jtagkey_init(void);
 int olimex_jtag_init(void);
-int m5960_init(void);
+int flyswatter_init(void);
+int turtle_init(void);
+int comstick_init(void);
+int stm32stick_init(void);
 
 /* reset procedures for supported layouts */
 void usbjtag_reset(int trst, int srst);
 void jtagkey_reset(int trst, int srst);
 void olimex_jtag_reset(int trst, int srst);
-void m5960_reset(int trst, int srst);
+void flyswatter_reset(int trst, int srst);
+void turtle_reset(int trst, int srst);
+void comstick_reset(int trst, int srst);
+void stm32stick_reset(int trst, int srst);
 
 /* blink procedures for layouts that support a blinking led */
 void olimex_jtag_blink(void);
+void turtle_jtag_blink(void);
 
 ft2232_layout_t ft2232_layouts[] =
 {
@@ -112,7 +124,10 @@ ft2232_layout_t ft2232_layouts[] =
        {"signalyzer", usbjtag_init, usbjtag_reset, NULL},
        {"evb_lm3s811", usbjtag_init, usbjtag_reset, NULL},
        {"olimex-jtag", olimex_jtag_init, olimex_jtag_reset, olimex_jtag_blink},
-       {"m5960", m5960_init, m5960_reset, NULL},
+       {"flyswatter", flyswatter_init, flyswatter_reset, NULL},
+       {"turtelizer2", turtle_init, turtle_reset, turtle_jtag_blink},
+       {"comstick", comstick_init, comstick_reset, NULL},
+       {"stm32stick", stm32stick_init, stm32stick_reset, NULL},
        {NULL, NULL, NULL},
 };
 
@@ -145,8 +160,6 @@ jtag_interface_t ft2232_interface =
        
        .execute_queue = ft2232_execute_queue,
        
-       .support_pathmove = 1,
-       
        .speed = ft2232_speed,
        .register_commands = ft2232_register_commands,
        .init = ft2232_init,
@@ -195,7 +208,8 @@ int ft2232_read(u8* buf, int size, u32* bytes_read)
 
        while ((*bytes_read < size) && timeout--)
        {
-               if ((status = FT_Read(ftdih, buf, size, &dw_bytes_read)) != FT_OK)
+               if ((status = FT_Read(ftdih, buf + *bytes_read, size - 
+                       *bytes_read, &dw_bytes_read)) != FT_OK)         
                {
                        *bytes_read = 0; 
                        ERROR("FT_Read returned: %lu", status);
@@ -236,7 +250,7 @@ int ft2232_speed(int speed)
        u32 bytes_written;
 
        buf[0] = 0x86; /* command "set divisor" */
-       buf[1] = speed & 0xff; /* valueL (0=6MHz, 1=3MHz, 2=1.5MHz, ...*/
+       buf[1] = speed & 0xff; /* valueL (0=6MHz, 1=3MHz, 2=2.0MHz, ...*/
        buf[2] = (speed >> 8) & 0xff; /* valueH */
        
        DEBUG("%2.2x %2.2x %2.2x", buf[0], buf[1], buf[2]);
@@ -245,6 +259,8 @@ int ft2232_speed(int speed)
                ERROR("couldn't set FT2232 TCK speed");
                return retval;
        }
+
+       jtag_speed = speed;
        
        return ERROR_OK;
 }
@@ -259,10 +275,12 @@ int ft2232_register_commands(struct command_context_s *cmd_ctx)
                COMMAND_CONFIG, NULL);
        register_command(cmd_ctx, NULL, "ft2232_vid_pid", ft2232_handle_vid_pid_command,
                                         COMMAND_CONFIG, NULL);
+       register_command(cmd_ctx, NULL, "ft2232_latency", ft2232_handle_latency_command,
+                                        COMMAND_CONFIG, NULL);
        return ERROR_OK;
 }
 
-void ft2232_end_state(state)
+void ft2232_end_state(enum tap_state state)
 {
        if (tap_move_map[state] != -1)
                end_state = state;
@@ -395,7 +413,12 @@ int ft2232_send_and_recv(jtag_command_t *first, jtag_command_t *last)
 
        ft2232_expect_read = 0;
        ft2232_read_pointer = 0;
-
+       
+       /* return ERROR_OK, unless a jtag_read_buffer returns a failed check
+        * that wasn't handled by a caller-provided error handler
+        */ 
+       retval = ERROR_OK;
+       
        cmd = first;
        while (cmd != last)
        {
@@ -408,7 +431,8 @@ int ft2232_send_and_recv(jtag_command_t *first, jtag_command_t *last)
                                        scan_size = jtag_scan_size(cmd->cmd.scan);
                                        buffer = calloc(CEIL(scan_size, 8), 1);
                                        ft2232_read_scan(type, buffer, scan_size);
-                                       jtag_read_buffer(buffer, cmd->cmd.scan);
+                                       if (jtag_read_buffer(buffer, cmd->cmd.scan) != ERROR_OK)
+                                               retval = ERROR_JTAG_QUEUE_FAILED;
                                        free(buffer);
                                }
                                break;
@@ -420,7 +444,7 @@ int ft2232_send_and_recv(jtag_command_t *first, jtag_command_t *last)
        
        ft2232_buffer_size = 0;
 
-       return ERROR_OK;
+       return retval;
 }
 
 void ft2232_add_pathmove(pathmove_command_t *cmd)
@@ -974,7 +998,7 @@ void olimex_jtag_reset(int trst, int srst)
     DEBUG("trst: %i, srst: %i, high_output: 0x%2.2x, high_direction: 0x%2.2x", trst, srst, high_output, high_direction);
 }
 
-void m5960_reset(int trst, int srst)
+void flyswatter_reset(int trst, int srst)
 {
        if (trst == 1)
        {
@@ -999,7 +1023,88 @@ void m5960_reset(int trst, int srst)
     BUFFER_ADD = 0x80;
     BUFFER_ADD = low_output;
     BUFFER_ADD = low_direction;
-    DEBUG("trst: %i, srst: %i, high_output: 0x%2.2x, high_direction: 0x%2.2x", trst, srst, high_output, high_direction);
+    DEBUG("trst: %i, srst: %i, low_output: 0x%2.2x, low_direction: 0x%2.2x", trst, srst, low_output, low_direction);
+}
+
+void turtle_reset(int trst, int srst)
+{
+       trst = trst;
+       
+       if (srst == 1)
+       {
+               low_output |= nSRST;
+       }
+       else if (srst == 0)
+       {
+               low_output &= ~nSRST;
+       }
+       
+       /* command "set data bits low byte" */
+       BUFFER_ADD = 0x80;
+       BUFFER_ADD = low_output;
+       BUFFER_ADD = low_direction;
+       DEBUG("srst: %i, low_output: 0x%2.2x, low_direction: 0x%2.2x", srst, low_output, low_direction);
+}
+
+void comstick_reset(int trst, int srst)
+{
+       if (trst == 1)
+       {
+               cur_state = TAP_TLR;
+               high_output &= ~nTRST;
+       }
+       else if (trst == 0)
+       {
+               high_output |= nTRST;
+       }
+
+    if (srst == 1)
+    {
+        high_output &= ~nSRST;
+    }
+    else if (srst == 0)
+    {
+        high_output |= nSRST;
+    }
+       
+       /* command "set data bits high byte" */
+       BUFFER_ADD = 0x82;
+       BUFFER_ADD = high_output;
+       BUFFER_ADD = high_direction;
+       DEBUG("trst: %i, srst: %i, high_output: 0x%2.2x, high_direction: 0x%2.2x", trst, srst, high_output, high_direction);
+}
+
+void stm32stick_reset(int trst, int srst)
+{
+       if (trst == 1)
+       {
+               cur_state = TAP_TLR;
+               high_output &= ~nTRST;
+       }
+       else if (trst == 0)
+       {
+               high_output |= nTRST;
+       }
+
+    if (srst == 1)
+    {
+        low_output &= ~nSRST;
+    }
+    else if (srst == 0)
+    {
+        low_output |= nSRST;
+    }
+       
+       /* command "set data bits low byte" */
+       BUFFER_ADD = 0x80;
+       BUFFER_ADD = low_output;
+       BUFFER_ADD = low_direction;
+       
+       /* command "set data bits high byte" */
+       BUFFER_ADD = 0x82;
+       BUFFER_ADD = high_output;
+       BUFFER_ADD = high_direction;
+       DEBUG("trst: %i, srst: %i, high_output: 0x%2.2x, high_direction: 0x%2.2x", trst, srst, high_output, high_direction);
 }
 
 int ft2232_execute_queue()
@@ -1012,6 +1117,12 @@ int ft2232_execute_queue()
        int i;
        int predicted_size = 0;
        int require_send = 0;
+       int retval;
+       
+       /* return ERROR_OK, unless ft2232_send_and_recv reports a failed check
+        * that wasn't handled by a caller-provided error handler
+        */ 
+       retval = ERROR_OK;
 
        ft2232_buffer_size = 0;
        ft2232_expect_read = 0;
@@ -1033,7 +1144,8 @@ int ft2232_execute_queue()
                                predicted_size = 3;
                                if (ft2232_buffer_size + predicted_size + 1 > FT2232_BUFFER_SIZE)
                                {
-                                       ft2232_send_and_recv(first_unsent, cmd);
+                                       if (ft2232_send_and_recv(first_unsent, cmd) != ERROR_OK)
+                                               retval = ERROR_JTAG_QUEUE_FAILED;
                                        require_send = 0;
                                        first_unsent = cmd;
                                }
@@ -1057,7 +1169,8 @@ int ft2232_execute_queue()
                                        predicted_size += 3;
                                if (ft2232_buffer_size + predicted_size + 1 > FT2232_BUFFER_SIZE)
                                {
-                                       ft2232_send_and_recv(first_unsent, cmd);
+                                       if (ft2232_send_and_recv(first_unsent, cmd) != ERROR_OK)
+                                               retval = ERROR_JTAG_QUEUE_FAILED;
                                        require_send = 0;
                                        first_unsent = cmd;
                                }
@@ -1108,7 +1221,8 @@ int ft2232_execute_queue()
                                predicted_size = 3;
                                if (ft2232_buffer_size + predicted_size + 1 > FT2232_BUFFER_SIZE)
                                {
-                                       ft2232_send_and_recv(first_unsent, cmd);
+                                       if (ft2232_send_and_recv(first_unsent, cmd) != ERROR_OK)
+                                               retval = ERROR_JTAG_QUEUE_FAILED;
                                        require_send = 0;
                                        first_unsent = cmd;
                                }
@@ -1132,7 +1246,8 @@ int ft2232_execute_queue()
                                predicted_size = 3 * CEIL(cmd->cmd.pathmove->num_states, 7);
                                if (ft2232_buffer_size + predicted_size + 1 > FT2232_BUFFER_SIZE)
                                {
-                                       ft2232_send_and_recv(first_unsent, cmd);
+                                       if (ft2232_send_and_recv(first_unsent, cmd) != ERROR_OK)
+                                               retval = ERROR_JTAG_QUEUE_FAILED;
                                        require_send = 0;
                                        first_unsent = cmd;
                                }
@@ -1151,7 +1266,8 @@ int ft2232_execute_queue()
                                        DEBUG("oversized ft2232 scan (predicted_size > FT2232_BUFFER_SIZE)");
                                        /* unsent commands before this */
                                        if (first_unsent != cmd)
-                                               ft2232_send_and_recv(first_unsent, cmd);
+                                               if (ft2232_send_and_recv(first_unsent, cmd) != ERROR_OK)
+                                                       retval = ERROR_JTAG_QUEUE_FAILED;
                                        
                                        /* current command */
                                        if (cmd->cmd.scan->end_state != -1)
@@ -1166,7 +1282,8 @@ int ft2232_execute_queue()
                                else if (ft2232_buffer_size + predicted_size + 1 > FT2232_BUFFER_SIZE)
                                {
                                        DEBUG("ft2232 buffer size reached, sending queued commands (first_unsent: %p, cmd: %p)", first_unsent, cmd);
-                                       ft2232_send_and_recv(first_unsent, cmd);
+                                       if (ft2232_send_and_recv(first_unsent, cmd) != ERROR_OK)
+                                               retval = ERROR_JTAG_QUEUE_FAILED;
                                        require_send = 0;
                                        first_unsent = cmd;
                                }
@@ -1183,7 +1300,8 @@ int ft2232_execute_queue()
 #endif
                                break;
                        case JTAG_SLEEP:
-                               ft2232_send_and_recv(first_unsent, cmd);
+                               if (ft2232_send_and_recv(first_unsent, cmd) != ERROR_OK)
+                                       retval = ERROR_JTAG_QUEUE_FAILED;
                                first_unsent = cmd->next;
                                jtag_sleep(cmd->cmd.sleep->us);
 #ifdef _DEBUG_JTAG_IO_                         
@@ -1198,60 +1316,29 @@ int ft2232_execute_queue()
        }
 
        if (require_send > 0)
-               ft2232_send_and_recv(first_unsent, cmd);
+               if (ft2232_send_and_recv(first_unsent, cmd) != ERROR_OK)
+                       retval = ERROR_JTAG_QUEUE_FAILED;
 
-       return ERROR_OK;
+       return retval;
 }
 
-int ft2232_init(void)
-{
-       u8 latency_timer;
-       u8 buf[1];
-       int retval;
-       u32 bytes_written;
-       
 #if BUILD_FT2232_FTD2XX == 1
+static int ft2232_init_ftd2xx(u16 vid, u16 pid, int more, int *try_more)
+{
        FT_STATUS status;
        DWORD openex_flags = 0;
        char *openex_string = NULL;
-#endif
-
-       ft2232_layout_t *cur_layout = ft2232_layouts;
-       
-       if ((ft2232_layout == NULL) || (ft2232_layout[0] == 0))
-       {
-               ft2232_layout = "usbjtag";
-               WARNING("No ft2232 layout specified, using default 'usbjtag'");
-       }
-       
-       while (cur_layout->name)
-       {
-               if (strcmp(cur_layout->name, ft2232_layout) == 0)
-               {
-                       layout = cur_layout;
-                       break;
-               }
-               cur_layout++;
-       }
+       u8 latency_timer;
 
-       if (!layout)
-       {
-               ERROR("No matching layout found for %s", ft2232_layout);
-               return ERROR_JTAG_INIT_FAILED;
-       }
-       
-#if BUILD_FT2232_FTD2XX == 1
-       DEBUG("'ft2232' interface using FTD2XX with '%s' layout", ft2232_layout);
-#elif BUILD_FT2232_LIBFTDI == 1
-       DEBUG("'ft2232' interface using libftdi with '%s' layout", ft2232_layout);
-#endif
+       DEBUG("'ft2232' interface using FTD2XX with '%s' layout (%4.4x:%4.4x)",
+           ft2232_layout, vid, pid);
 
-#if BUILD_FT2232_FTD2XX == 1
 #if IS_WIN32 == 0
        /* Add non-standard Vid/Pid to the linux driver */
-       if ((status = FT_SetVIDPID(ft2232_vid, ft2232_pid)) != FT_OK)
+       if ((status = FT_SetVIDPID(vid, pid)) != FT_OK)
        {
-               WARNING("couldn't add %4.4x:%4.4x", ft2232_vid, ft2232_pid);
+               WARNING("couldn't add %4.4x:%4.4x",
+                   vid, pid);
        }
 #endif
 
@@ -1283,6 +1370,12 @@ int ft2232_init(void)
        {
                DWORD num_devices;
                
+               if (more) {
+                       WARNING("unable to open ftdi device (trying more): %lu",
+                           status);
+                       *try_more = 1;
+                       return ERROR_JTAG_INIT_FAILED;
+               }
                ERROR("unable to open ftdi device: %lu", status);
                status = FT_ListDevices(&num_devices, NULL, FT_LIST_NUMBER_ONLY);
                if (status == FT_OK)
@@ -1309,12 +1402,12 @@ int ft2232_init(void)
                }
                else
                {
-                       printf("ListDevices: NONE\n");
+                       ERROR("ListDevices: NONE\n");
                }
                return ERROR_JTAG_INIT_FAILED;
        }
 
-       if ((status = FT_SetLatencyTimer(ftdih, 2)) != FT_OK)
+       if ((status = FT_SetLatencyTimer(ftdih, ft2232_latency)) != FT_OK)
        {
                ERROR("unable to set latency timer: %lu", status);
                return ERROR_JTAG_INIT_FAILED;
@@ -1341,14 +1434,44 @@ int ft2232_init(void)
                ERROR("unable to enable bit i/o mode: %lu", status);
                return ERROR_JTAG_INIT_FAILED;
        }
-#elif BUILD_FT2232_LIBFTDI == 1
+
+       return ERROR_OK;
+}
+
+static int ft2232_purge_ftd2xx(void)
+{
+       FT_STATUS status;
+
+       if ((status = FT_Purge(ftdih, FT_PURGE_RX | FT_PURGE_TX)) != FT_OK)
+       {
+               ERROR("error purging ftd2xx device: %lu", status);
+               return ERROR_JTAG_INIT_FAILED;
+       }
+
+       return ERROR_OK;
+}
+#endif /* BUILD_FT2232_FTD2XX == 1 */
+
+#if BUILD_FT2232_LIBFTDI == 1
+static int ft2232_init_libftdi(u16 vid, u16 pid, int more, int *try_more)
+{
+       u8 latency_timer;
+
+       DEBUG("'ft2232' interface using libftdi with '%s' layout (%4.4x:%4.4x)",
+           ft2232_layout, vid, pid);
+
        if (ftdi_init(&ftdic) < 0)
                return ERROR_JTAG_INIT_FAILED;
 
        /* context, vendor id, product id */
-       if (ftdi_usb_open_desc(&ftdic, ft2232_vid, ft2232_pid, ft2232_device_desc, ft2232_serial) < 0)
-       {
-               ERROR("unable to open ftdi device: %s", ftdic.error_str);
+       if (ftdi_usb_open_desc(&ftdic, vid, pid, ft2232_device_desc,
+           ft2232_serial) < 0) {
+               if (more)
+                       WARNING("unable to open ftdi device (trying more): %s",
+                            ftdic.error_str);
+               else
+                       ERROR("unable to open ftdi device: %s", ftdic.error_str);
+               *try_more = 1;
                return ERROR_JTAG_INIT_FAILED;
        }
 
@@ -1364,7 +1487,7 @@ int ft2232_init(void)
                return ERROR_JTAG_INIT_FAILED;
        }
 
-       if (ftdi_set_latency_timer(&ftdic, 2) < 0)
+       if (ftdi_set_latency_timer(&ftdic, ft2232_latency) < 0)
        {
                ERROR("unable to set latency timer");
                return ERROR_JTAG_INIT_FAILED;
@@ -1381,7 +1504,77 @@ int ft2232_init(void)
        }
 
        ftdi_set_bitmode(&ftdic, 0x0b, 2); /* ctx, JTAG I/O mask */
+
+       return ERROR_OK;
+}
+
+static int ft2232_purge_libftdi(void)
+{
+       if (ftdi_usb_purge_buffers(&ftdic) < 0)
+       {
+               ERROR("ftdi_purge_buffers: %s", ftdic.error_str);
+               return ERROR_JTAG_INIT_FAILED;
+       }
+
+       return ERROR_OK;
+}
+#endif /* BUILD_FT2232_LIBFTDI == 1 */
+
+int ft2232_init(void)
+{
+       u8 buf[1];
+       int retval;
+       u32 bytes_written;
+       ft2232_layout_t *cur_layout = ft2232_layouts;
+       int i;
+       
+       if ((ft2232_layout == NULL) || (ft2232_layout[0] == 0))
+       {
+               ft2232_layout = "usbjtag";
+               WARNING("No ft2232 layout specified, using default 'usbjtag'");
+       }
+       
+       while (cur_layout->name)
+       {
+               if (strcmp(cur_layout->name, ft2232_layout) == 0)
+               {
+                       layout = cur_layout;
+                       break;
+               }
+               cur_layout++;
+       }
+
+       if (!layout)
+       {
+               ERROR("No matching layout found for %s", ft2232_layout);
+               return ERROR_JTAG_INIT_FAILED;
+       }
+       
+       for (i = 0; 1; i++) {
+               /*
+                * "more indicates that there are more IDs to try, so we should
+                * not print an error for an ID mismatch (but for anything
+                * else, we should).
+                *
+                * try_more indicates that the error code returned indicates an
+                * ID mismatch (and nothing else) and that we should proceeed
+                * with the next ID pair.
+                */
+               int more = ft2232_vid[i+1] || ft2232_pid[i+1];
+               int try_more = 0;
+
+#if BUILD_FT2232_FTD2XX == 1
+               retval = ft2232_init_ftd2xx(ft2232_vid[i], ft2232_pid[i],
+                   more, &try_more);
+#elif BUILD_FT2232_LIBFTDI == 1
+               retval = ft2232_init_libftdi(ft2232_vid[i], ft2232_pid[i],
+                   more, &try_more);
 #endif 
+               if (retval >= 0)
+                       break;
+               if (!more || !try_more)
+                       return retval;
+       }
 
        ft2232_buffer_size = 0;
        ft2232_buffer = malloc(FT2232_BUFFER_SIZE);
@@ -1399,17 +1592,9 @@ int ft2232_init(void)
        }
 
 #if BUILD_FT2232_FTD2XX == 1
-       if ((status = FT_Purge(ftdih, FT_PURGE_RX | FT_PURGE_TX)) != FT_OK)
-       {
-               ERROR("error purging ftd2xx device: %lu", status);
-               return ERROR_JTAG_INIT_FAILED;
-       }
+       return ft2232_purge_ftd2xx();
 #elif BUILD_FT2232_LIBFTDI == 1
-       if (ftdi_usb_purge_buffers(&ftdic) < 0)
-       {
-               ERROR("ftdi_purge_buffers: %s", ftdic.error_str);
-               return ERROR_JTAG_INIT_FAILED;
-       }
+       return ft2232_purge_libftdi();
 #endif 
 
        return ERROR_OK;
@@ -1636,7 +1821,7 @@ int olimex_jtag_init(void)
        return ERROR_OK;
 }
 
-int m5960_init(void)
+int flyswatter_init(void)
 {
        u8 buf[3];
        u32 bytes_written;
@@ -1652,7 +1837,7 @@ int m5960_init(void)
        
        if (((ft2232_write(buf, 3, &bytes_written)) != ERROR_OK) || (bytes_written != 3))
        {
-               ERROR("couldn't initialize FT2232 with 'm5960' layout"); 
+               ERROR("couldn't initialize FT2232 with 'flyswatter' layout"); 
                return ERROR_JTAG_INIT_FAILED;
        }
        
@@ -1675,7 +1860,133 @@ int m5960_init(void)
        
        if (((ft2232_write(buf, 3, &bytes_written)) != ERROR_OK) || (bytes_written != 3))
        {
-               ERROR("couldn't initialize FT2232 with 'm5960' layout"); 
+               ERROR("couldn't initialize FT2232 with 'flyswatter' layout"); 
+               return ERROR_JTAG_INIT_FAILED;
+       }
+       
+       return ERROR_OK;
+}
+
+int turtle_init(void)
+{
+       u8 buf[3];
+       u32 bytes_written;
+       
+       low_output = 0x08;
+       low_direction = 0x5b;
+       
+       /* initialize low byte for jtag */
+       buf[0] = 0x80; /* command "set data bits low byte" */
+       buf[1] = low_output; /* value (TMS=1,TCK=0, TDI=0, nOE=0) */
+       buf[2] = low_direction; /* dir (output=1), TCK/TDI/TMS=out, TDO=in, nOE=out */
+       DEBUG("%2.2x %2.2x %2.2x", buf[0], buf[1], buf[2]);
+       
+       if (((ft2232_write(buf, 3, &bytes_written)) != ERROR_OK) || (bytes_written != 3))
+       {
+               ERROR("couldn't initialize FT2232 with 'turtelizer2' layout"); 
+               return ERROR_JTAG_INIT_FAILED;
+       }
+       
+       nSRST = 0x40;
+       
+       high_output = 0x00;
+       high_direction = 0x0C;
+       
+       /* initialize high port */
+       buf[0] = 0x82; /* command "set data bits high byte" */
+       buf[1] = high_output;
+       buf[2] = high_direction;
+       DEBUG("%2.2x %2.2x %2.2x", buf[0], buf[1], buf[2]);
+       
+       if (((ft2232_write(buf, 3, &bytes_written)) != ERROR_OK) || (bytes_written != 3))
+       {
+               ERROR("couldn't initialize FT2232 with 'turtelizer2' layout"); 
+               return ERROR_JTAG_INIT_FAILED;
+       }
+       
+       return ERROR_OK;
+}
+
+int comstick_init(void)
+{
+       u8 buf[3];
+       u32 bytes_written;
+       
+       low_output = 0x08;
+       low_direction = 0x0b;
+       
+       /* initialize low byte for jtag */
+       buf[0] = 0x80; /* command "set data bits low byte" */
+       buf[1] = low_output; /* value (TMS=1,TCK=0, TDI=0, nOE=0) */
+       buf[2] = low_direction; /* dir (output=1), TCK/TDI/TMS=out, TDO=in, nOE=out */
+       DEBUG("%2.2x %2.2x %2.2x", buf[0], buf[1], buf[2]);
+       
+       if (((ft2232_write(buf, 3, &bytes_written)) != ERROR_OK) || (bytes_written != 3))
+       {
+               ERROR("couldn't initialize FT2232 with 'comstick' layout"); 
+               return ERROR_JTAG_INIT_FAILED;
+       }
+       
+       nTRST = 0x01;
+       nTRSTnOE = 0x00; /* no output enable for nTRST */
+       nSRST = 0x02;
+       nSRSTnOE = 0x00; /* no output enable for nSRST */
+       
+       high_output = 0x03;
+       high_direction = 0x03;
+       
+       /* initialize high port */
+       buf[0] = 0x82; /* command "set data bits high byte" */
+       buf[1] = high_output;
+       buf[2] = high_direction;
+       DEBUG("%2.2x %2.2x %2.2x", buf[0], buf[1], buf[2]);
+       
+       if (((ft2232_write(buf, 3, &bytes_written)) != ERROR_OK) || (bytes_written != 3))
+       {
+               ERROR("couldn't initialize FT2232 with 'comstick' layout"); 
+               return ERROR_JTAG_INIT_FAILED;
+       }
+       
+       return ERROR_OK;
+}
+
+int stm32stick_init(void)
+{
+       u8 buf[3];
+       u32 bytes_written;
+       
+       low_output = 0x88;
+       low_direction = 0x8b;
+       
+       /* initialize low byte for jtag */
+       buf[0] = 0x80; /* command "set data bits low byte" */
+       buf[1] = low_output; /* value (TMS=1,TCK=0, TDI=0, nOE=0) */
+       buf[2] = low_direction; /* dir (output=1), TCK/TDI/TMS=out, TDO=in, nOE=out */
+       DEBUG("%2.2x %2.2x %2.2x", buf[0], buf[1], buf[2]);
+       
+       if (((ft2232_write(buf, 3, &bytes_written)) != ERROR_OK) || (bytes_written != 3))
+       {
+               ERROR("couldn't initialize FT2232 with 'stm32stick' layout"); 
+               return ERROR_JTAG_INIT_FAILED;
+       }
+               
+       nTRST = 0x01;
+       nTRSTnOE = 0x00; /* no output enable for nTRST */
+       nSRST = 0x80;
+       nSRSTnOE = 0x00; /* no output enable for nSRST */
+       
+       high_output = 0x01;
+       high_direction = 0x03;
+       
+       /* initialize high port */
+       buf[0] = 0x82; /* command "set data bits high byte" */
+       buf[1] = high_output;
+       buf[2] = high_direction;
+       DEBUG("%2.2x %2.2x %2.2x", buf[0], buf[1], buf[2]);
+       
+       if (((ft2232_write(buf, 3, &bytes_written)) != ERROR_OK) || (bytes_written != 3))
+       {
+               ERROR("couldn't initialize FT2232 with 'stm32stick' layout"); 
                return ERROR_JTAG_INIT_FAILED;
        }
        
@@ -1703,6 +2014,26 @@ void olimex_jtag_blink(void)
        BUFFER_ADD = high_direction;
 }
 
+void turtle_jtag_blink(void)
+{
+       /* 
+   * Turtelizer2 has two LEDs connected to ACBUS2 and ACBUS3
+        */
+       if (high_output & 0x08)
+       {
+               high_output = 0x04;
+       }
+       else
+       {
+               high_output = 0x08;
+       }
+       
+       BUFFER_ADD = 0x82;
+       BUFFER_ADD = high_output;
+       BUFFER_ADD = high_direction;
+}
+
+
 int ft2232_quit(void)
 {
 #if BUILD_FT2232_FTD2XX == 1
@@ -1718,6 +2049,7 @@ int ft2232_quit(void)
 #endif
 
        free(ft2232_buffer);
+       ft2232_buffer = NULL;
 
        return ERROR_OK;
 }
@@ -1763,15 +2095,45 @@ int ft2232_handle_layout_command(struct command_context_s *cmd_ctx, char *cmd, c
 
 int ft2232_handle_vid_pid_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
 {
-       if (argc >= 2)
+       int i;
+
+       if (argc > MAX_USB_IDS*2) {
+               WARNING("ignoring extra IDs in ft2232_vid_pid "
+                   "(maximum is %d pairs)", MAX_USB_IDS);
+               argc = MAX_USB_IDS*2;
+       }
+       if (argc < 2 || (argc & 1))
        {
-               ft2232_vid = strtol(args[0], NULL, 0);
-               ft2232_pid = strtol(args[1], NULL, 0);
+               WARNING("incomplete ft2232_vid_pid configuration directive");
+               if (argc < 2)
+                       return ERROR_OK;
+       }
+
+       for (i = 0; i+1 < argc; i += 2) {
+               ft2232_vid[i >> 1] = strtol(args[i], NULL, 0);
+               ft2232_pid[i >> 1] = strtol(args[i+1], NULL, 0);
+       }
+       /*
+        * Explicitly terminate, in case there are multiples instances of
+        * ft2232_vid_pid.
+        */
+       ft2232_vid[i >> 1] = ft2232_pid[i >> 1] = 0;
+
+       return ERROR_OK;
+}
+
+int ft2232_handle_latency_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+       if (argc == 1)
+       {
+               ft2232_latency = atoi(args[0]);
        }
        else
        {
-               WARNING("incomplete ft2232_vid_pid configuration directive");
+               ERROR("expected exactly one argument to ft2232_latency <ms>");
        }
        
        return ERROR_OK;
 }
+
+