comments for Luminary ICDI layout
[fw/openocd] / src / jtag / drivers / ft2232.c
index 831a5dca79163977c7219324f2128b3999ff8ebd..4dcc045cccdeda67b4a0e2859e0cd1e5c056818a 100644 (file)
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/
 
-/* This code uses information contained in the MPSSE specification which was
+/**
+ * @file
+ * JTAG adapters based on the FT2232 full and high speed USB parts are
+ * popular low cost JTAG debug solutions.  Many FT2232 based JTAG adapters
+ * are discrete, but development boards may integrate them as alternatives
+ * to more capable (and expensive) third party JTAG pods.
+ *
+ * JTAG uses only one of the two communications channels ("MPSSE engines")
+ * on these devices.  Adapters based on FT4232 parts have four ports/channels
+ * (A/B/C/D), instead of just two (A/B).
+ *
+ * Especially on development boards integrating one of these chips (as
+ * opposed to discrete pods/dongles), the additional channels can be used
+ * for a variety of purposes, but OpenOCD only uses one channel at a time.
+ *
+ *  - As a USB-to-serial adapter for the target's console UART ...
+ *    which may be able to support ROM boot loaders that load initial
+ *    firmware images to flash (or SRAM).
+ *
+ *  - On systems which support ARM's SWD in addition to JTAG, or instead
+ *    of it, that second port can be used for reading SWV/SWO trace data.
+ *
+ *  - Additional JTAG links, e.g. to a CPLD or * FPGA.
+ *
+ * FT2232 based JTAG adapters are "dumb" not "smart", because most JTAG
+ * request/response interactions involve round trips over the USB link.
+ * A "smart" JTAG adapter has intelligence close to the scan chain, so it
+ * can for example poll quickly for a status change (usually taking on the
+ * order of microseconds not milliseconds) before beginning a queued
+ * transaction which require the previous one to have completed.
+ *
+ * There are dozens of adapters of this type, differing in details which
+ * this driver needs to understand.  Those "layout" details are required
+ * as part of FT2232 driver configuration.
+ *
+ * This code uses information contained in the MPSSE specification which was
  * found here:
  * http://www.ftdichip.com/Documents/AppNotes/AN2232C-01_MPSSE_Cmnd.pdf
  * Hereafter this is called the "MPSSE Spec".
  *
  * The datasheet for the ftdichip.com's FT2232D part is here:
  * http://www.ftdichip.com/Documents/DataSheets/DS_FT2232D.pdf
+ *
+ * Also note the issue with code 0x4b (clock data to TMS) noted in
+ * http://developer.intra2net.com/mailarchive/html/libftdi/2009/msg00292.html
+ * which can affect longer JTAG state paths.
  */
 
 #ifdef HAVE_CONFIG_H
@@ -42,7 +81,7 @@
 
 /* project specific includes */
 #include <jtag/interface.h>
-#include <jtag/commands.h>
+#include <jtag/transport.h>
 #include <helper/time_support.h>
 
 #if IS_CYGWIN == 1
 /* FT2232 access library includes */
 #if BUILD_FT2232_FTD2XX == 1
 #include <ftd2xx.h>
+
+enum ftdi_interface
+{
+    INTERFACE_ANY = 0,
+    INTERFACE_A   = 1,
+    INTERFACE_B   = 2,
+    INTERFACE_C   = 3,
+    INTERFACE_D   = 4
+};
+
 #elif BUILD_FT2232_LIBFTDI == 1
 #include <ftdi.h>
 #endif
@@ -105,7 +154,6 @@ static int ft2232_stableclocks(int num_cycles, struct jtag_command* cmd);
 static char *       ft2232_device_desc_A = NULL;
 static char*        ft2232_device_desc = NULL;
 static char*        ft2232_serial  = NULL;
-static char*        ft2232_layout  = NULL;
 static uint8_t         ft2232_latency = 2;
 static unsigned                ft2232_max_tck = FTDI_2232C_MAX_TCK;
 
@@ -119,11 +167,14 @@ struct ft2232_layout {
        int (*init)(void);
        void (*reset)(int trst, int srst);
        void (*blink)(void);
+       int channel;
 };
 
 /* init procedures for supported layouts */
 static int usbjtag_init(void);
 static int jtagkey_init(void);
+static int lm3s811_jtag_init(void);
+static int icdi_jtag_init(void);
 static int olimex_jtag_init(void);
 static int flyswatter_init(void);
 static int turtle_init(void);
@@ -133,11 +184,13 @@ static int axm0432_jtag_init(void);
 static int sheevaplug_init(void);
 static int icebear_jtag_init(void);
 static int cortino_jtag_init(void);
+static int signalyzer_init(void);
 static int signalyzer_h_init(void);
 static int ktlink_init(void);
+static int redbee_init(void);
 
 /* reset procedures for supported layouts */
-static void usbjtag_reset(int trst, int srst);
+static void ftx23_reset(int trst, int srst);
 static void jtagkey_reset(int trst, int srst);
 static void olimex_jtag_reset(int trst, int srst);
 static void flyswatter_reset(int trst, int srst);
@@ -149,6 +202,7 @@ static void sheevaplug_reset(int trst, int srst);
 static void icebear_jtag_reset(int trst, int srst);
 static void signalyzer_h_reset(int trst, int srst);
 static void ktlink_reset(int trst, int srst);
+static void redbee_reset(int trst, int srst);
 
 /* blink procedures for layouts that support a blinking led */
 static void olimex_jtag_blink(void);
@@ -157,35 +211,121 @@ static void turtle_jtag_blink(void);
 static void signalyzer_h_blink(void);
 static void ktlink_blink(void);
 
+/* common transport support options */
+
+//static const char *jtag_and_swd[] = { "jtag", "swd", NULL };
+
 static const struct ft2232_layout  ft2232_layouts[] =
 {
-       { "usbjtag",              usbjtag_init,              usbjtag_reset,      NULL                    },
-       { "jtagkey",              jtagkey_init,              jtagkey_reset,      NULL                    },
-       { "jtagkey_prototype_v1", jtagkey_init,              jtagkey_reset,      NULL                    },
-       { "oocdlink",             jtagkey_init,              jtagkey_reset,      NULL                    },
-       { "signalyzer",           usbjtag_init,              usbjtag_reset,      NULL                    },
-       { "evb_lm3s811",          usbjtag_init,              usbjtag_reset,      NULL                    },
-       { "luminary_icdi",        usbjtag_init,              usbjtag_reset,      NULL                    },
-       { "olimex-jtag",          olimex_jtag_init,          olimex_jtag_reset,  olimex_jtag_blink       },
-       { "flyswatter",           flyswatter_init,           flyswatter_reset,   flyswatter_jtag_blink   },
-       { "turtelizer2",          turtle_init,               turtle_reset,       turtle_jtag_blink       },
-       { "comstick",             comstick_init,             comstick_reset,     NULL                    },
-       { "stm32stick",           stm32stick_init,           stm32stick_reset,   NULL                    },
-       { "axm0432_jtag",         axm0432_jtag_init,         axm0432_jtag_reset, NULL                    },
-       { "sheevaplug",           sheevaplug_init,           sheevaplug_reset,   NULL                    },
-       { "icebear",              icebear_jtag_init,         icebear_jtag_reset, NULL                    },
-       { "cortino",              cortino_jtag_init,         comstick_reset, NULL                        },
-       { "signalyzer-h",         signalyzer_h_init,         signalyzer_h_reset, signalyzer_h_blink      },
-       { "ktlink",               ktlink_init,               ktlink_reset,       ktlink_blink            },
-       { NULL,                   NULL,                      NULL,               NULL                    },
+       { .name = "usbjtag",
+               .init = usbjtag_init,
+               .reset = ftx23_reset,
+       },
+       { .name = "jtagkey",
+               .init = jtagkey_init,
+               .reset = jtagkey_reset,
+       },
+       { .name = "jtagkey_prototype_v1",
+               .init = jtagkey_init,
+               .reset = jtagkey_reset,
+       },
+       { .name = "oocdlink",
+               .init = jtagkey_init,
+               .reset = jtagkey_reset,
+       },
+       { .name = "signalyzer",
+               .init = signalyzer_init,
+               .reset = ftx23_reset,
+       },
+       { .name = "evb_lm3s811",
+               .init = lm3s811_jtag_init,
+               .reset = ftx23_reset,
+       },
+       { .name = "luminary_icdi",
+               .init = icdi_jtag_init,
+               .reset = ftx23_reset,
+       },
+       { .name = "olimex-jtag",
+               .init = olimex_jtag_init,
+               .reset = olimex_jtag_reset,
+               .blink = olimex_jtag_blink
+       },
+       { .name = "flyswatter",
+               .init = flyswatter_init,
+               .reset = flyswatter_reset,
+               .blink = flyswatter_jtag_blink
+       },
+       { .name = "turtelizer2",
+               .init = turtle_init,
+               .reset = turtle_reset,
+               .blink = turtle_jtag_blink
+       },
+       { .name = "comstick",
+               .init = comstick_init,
+               .reset = comstick_reset,
+       },
+       { .name = "stm32stick",
+               .init = stm32stick_init,
+               .reset = stm32stick_reset,
+       },
+       { .name = "axm0432_jtag",
+               .init = axm0432_jtag_init,
+               .reset = axm0432_jtag_reset,
+       },
+       { .name = "sheevaplug",
+               .init = sheevaplug_init,
+               .reset = sheevaplug_reset,
+       },
+       { .name = "icebear",
+               .init = icebear_jtag_init,
+               .reset = icebear_jtag_reset,
+       },
+       { .name = "cortino",
+               .init = cortino_jtag_init,
+               .reset = comstick_reset,
+       },
+       { .name = "signalyzer-h",
+               .init = signalyzer_h_init,
+               .reset = signalyzer_h_reset,
+               .blink = signalyzer_h_blink
+       },
+       { .name = "ktlink",
+               .init = ktlink_init,
+               .reset = ktlink_reset,
+               .blink = ktlink_blink
+       },
+       { .name = "redbee-econotag",
+               .init = redbee_init,
+               .reset = redbee_reset,
+       },
+       { .name = "redbee-usb",
+               .init = redbee_init,
+               .reset = redbee_reset,
+               .channel = INTERFACE_B,
+       },
+       { .name = NULL, /* END OF TABLE */ },
 };
 
-static uint8_t                  nTRST, nTRSTnOE, nSRST, nSRSTnOE;
+/* bitmask used to drive nTRST; usually a GPIOLx signal */
+static uint8_t                  nTRST;
+static uint8_t                  nTRSTnOE;
+/* bitmask used to drive nSRST; usually a GPIOLx signal */
+static uint8_t                  nSRST;
+static uint8_t                  nSRSTnOE;
 
+/** the layout being used with this debug session */
 static const struct ft2232_layout *layout;
+
+/** default bitmask values ddriven on DBUS: TCK/TDI/TDO/TMS and GPIOL(0..4) */
 static uint8_t                  low_output     = 0x0;
+
+/* note that direction bit == 1 means that signal is an output */
+
+/** default direction bitmask for DBUS: TCK/TDI/TDO/TMS and GPIOL(0..4) */
 static uint8_t                  low_direction  = 0x0;
+/** default value bitmask for CBUS GPIOH(0..4) */
 static uint8_t                  high_output    = 0x0;
+/** default direction bitmask for CBUS GPIOH(0..4) */
 static uint8_t                  high_direction = 0x0;
 
 #if BUILD_FT2232_FTD2XX == 1
@@ -348,7 +488,6 @@ static int ft2232_write(uint8_t* buf, int size, uint32_t* bytes_written)
        else
        {
                *bytes_written = dw_bytes_written;
-               return ERROR_OK;
        }
 #elif BUILD_FT2232_LIBFTDI == 1
        int retval;
@@ -361,9 +500,15 @@ static int ft2232_write(uint8_t* buf, int size, uint32_t* bytes_written)
        else
        {
                *bytes_written = retval;
-               return ERROR_OK;
        }
 #endif
+
+       if (*bytes_written != (uint32_t)size)
+       {
+               return ERROR_JTAG_DEVICE_ERROR;
+       }
+
+       return ERROR_OK;
 }
 
 static int ft2232_read(uint8_t* buf, uint32_t size, uint32_t* bytes_read)
@@ -437,8 +582,9 @@ static int ft2232h_ft4232h_adaptive_clocking(bool enable)
        LOG_DEBUG("%2.2x", buf);
 
        uint32_t bytes_written;
-       int retval = ft2232_write(&buf, 1, &bytes_written);
-       if ((ERROR_OK != retval) || (bytes_written != 1))
+       int retval;
+
+       if ((retval = ft2232_write(&buf, sizeof(buf), &bytes_written)) != ERROR_OK)
        {
                LOG_ERROR("couldn't write command to %s adaptive clocking"
                        , enable ? "enable" : "disable");
@@ -457,8 +603,8 @@ static int ft2232h_ft4232h_clk_divide_by_5(bool enable)
 {
        uint32_t bytes_written;
        uint8_t buf = enable ?  0x8b : 0x8a;
-       int retval = ft2232_write(&buf, 1, &bytes_written);
-       if ((ERROR_OK != retval) || (bytes_written != 1))
+
+       if (ft2232_write(&buf, sizeof(buf), &bytes_written) != ERROR_OK)
        {
                LOG_ERROR("couldn't write command to %s clk divide by 5"
                        , enable ? "enable" : "disable");
@@ -495,7 +641,7 @@ static int ft2232_speed(int speed)
        buf[2] = (speed >> 8) & 0xff;   /* valueH */
 
        LOG_DEBUG("%2.2x %2.2x %2.2x", buf[0], buf[1], buf[2]);
-       if (((retval = ft2232_write(buf, 3, &bytes_written)) != ERROR_OK) || (bytes_written != 3))
+       if ((retval = ft2232_write(buf, sizeof(buf), &bytes_written)) != ERROR_OK)
        {
                LOG_ERROR("couldn't set FT2232 TCK speed");
                return retval;
@@ -605,7 +751,7 @@ static void ft2232_debug_dump_buffer(void)
 
        for (i = 0; i < ft2232_buffer_size; i++)
        {
-               line_p += snprintf(line_p, 256 - (line_p - line), "%2.2x ", ft2232_buffer[i]);
+               line_p += snprintf(line_p, sizeof(line) - (line_p - line), "%2.2x ", ft2232_buffer[i]);
                if (i % 16 == 15)
                {
                        LOG_DEBUG("%s", line);
@@ -1220,7 +1366,8 @@ static int ft2232_predict_scan_in(int scan_size, enum scan_type type)
        return predicted_size;
 }
 
-static void usbjtag_reset(int trst, int srst)
+/* semi-generic FT2232/FT4232 reset code */
+static void ftx23_reset(int trst, int srst)
 {
        enum reset_types jtag_reset_config = jtag_get_reset_config();
        if (trst == 1)
@@ -1491,6 +1638,36 @@ static void sheevaplug_reset(int trst, int srst)
        LOG_DEBUG("trst: %i, srst: %i, high_output: 0x%2.2x, high_direction: 0x%2.2x", trst, srst, high_output, high_direction);
 }
 
+static void redbee_reset(int trst, int srst)
+{
+       if (trst == 1)
+       {
+               tap_set_state(TAP_RESET);
+               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 low byte" */
+       buffer_write(0x82);
+       buffer_write(high_output);
+       buffer_write(high_direction);
+       LOG_DEBUG("trst: %i, srst: %i, high_output: 0x%2.2x, "
+                       "high_direction: 0x%2.2x", trst, srst, high_output,
+                       high_direction);
+}
+
 static int ft2232_execute_runtest(struct jtag_command *cmd)
 {
        int retval;
@@ -1592,6 +1769,72 @@ static int ft2232_execute_statemove(struct jtag_command *cmd)
        return retval;
 }
 
+/**
+ * Clock a bunch of TMS (or SWDIO) transitions, to change the JTAG
+ * (or SWD) state machine.
+ */
+static int ft2232_execute_tms(struct jtag_command *cmd)
+{
+       int             retval = ERROR_OK;
+       unsigned        num_bits = cmd->cmd.tms->num_bits;
+       const uint8_t   *bits = cmd->cmd.tms->bits;
+       unsigned        count;
+
+       DEBUG_JTAG_IO("TMS: %d bits", num_bits);
+
+       /* only send the maximum buffer size that FT2232C can handle */
+       count = 3 * DIV_ROUND_UP(num_bits, 4);
+       if (ft2232_buffer_size + 3*count + 1 > FT2232_BUFFER_SIZE) {
+               if (ft2232_send_and_recv(first_unsent, cmd) != ERROR_OK)
+                       retval = ERROR_JTAG_QUEUE_FAILED;
+
+               require_send = 0;
+               first_unsent = cmd;
+       }
+
+       /* Shift out in batches of at most 6 bits; there's a report of an
+        * FT2232 bug in this area, where shifting exactly 7 bits can make
+        * problems with TMS signaling for the last clock cycle:
+        *
+        *    http://developer.intra2net.com/mailarchive/html/
+        *              libftdi/2009/msg00292.html
+        *
+        * Command 0x4b is: "Clock Data to TMS/CS Pin (no Read)"
+        *
+        * Note that pathmoves in JTAG are not often seven bits, so that
+        * isn't a particularly likely situation outside of "special"
+        * signaling such as switching between JTAG and SWD modes.
+        */
+       while (num_bits) {
+               if (num_bits <= 6) {
+                       buffer_write(0x4b);
+                       buffer_write(num_bits - 1);
+                       buffer_write(*bits & 0x3f);
+                       break;
+               }
+
+               /* Yes, this is lazy ... we COULD shift out more data
+                * bits per operation, but doing it in nybbles is easy
+                */
+               buffer_write(0x4b);
+               buffer_write(3);
+               buffer_write(*bits & 0xf);
+               num_bits -= 4;
+
+               count  = (num_bits > 4) ? 4 : num_bits;
+
+               buffer_write(0x4b);
+               buffer_write(count - 1);
+               buffer_write((*bits >> 4) & 0xf);
+               num_bits -= count;
+
+               bits++;
+       }
+
+       require_send = 1;
+       return retval;
+}
+
 static int ft2232_execute_pathmove(struct jtag_command *cmd)
 {
        int     predicted_size = 0;
@@ -1744,20 +1987,23 @@ static int ft2232_execute_stableclocks(struct jtag_command *cmd)
 static int ft2232_execute_command(struct jtag_command *cmd)
 {
        int retval;
-       retval = ERROR_OK;
 
        switch (cmd->type)
        {
        case JTAG_RESET:        retval = ft2232_execute_reset(cmd); break;
        case JTAG_RUNTEST:      retval = ft2232_execute_runtest(cmd); break;
-       case JTAG_STATEMOVE: retval = ft2232_execute_statemove(cmd); break;
+       case JTAG_TLR_RESET: retval = ft2232_execute_statemove(cmd); break;
        case JTAG_PATHMOVE:     retval = ft2232_execute_pathmove(cmd); break;
        case JTAG_SCAN:         retval = ft2232_execute_scan(cmd); break;
        case JTAG_SLEEP:        retval = ft2232_execute_sleep(cmd); break;
        case JTAG_STABLECLOCKS: retval = ft2232_execute_stableclocks(cmd); break;
+       case JTAG_TMS:
+               retval = ft2232_execute_tms(cmd);
+               break;
        default:
                LOG_ERROR("BUG: unknown JTAG command type encountered");
-               exit(-1);
+               retval = ERROR_JTAG_QUEUE_FAILED;
+               break;
        }
        return retval;
 }
@@ -1814,7 +2060,12 @@ static int ft2232_init_ftd2xx(uint16_t vid, uint16_t pid, int more, int* try_mor
        char*   openex_string = NULL;
        uint8_t latency_timer;
 
-       LOG_DEBUG("'ft2232' interface using FTD2XX with '%s' layout (%4.4x:%4.4x)", ft2232_layout, vid, pid);
+       if (layout == NULL) {
+               LOG_WARNING("No ft2232 layout specified'");
+               return ERROR_JTAG_INIT_FAILED;
+       }
+
+       LOG_DEBUG("'ft2232' interface using FTD2XX with '%s' layout (%4.4x:%4.4x)", layout->name, vid, pid);
 
 #if IS_WIN32 == 0
        /* Add non-standard Vid/Pid to the linux driver */
@@ -1977,17 +2228,25 @@ static int ft2232_purge_ftd2xx(void)
 #endif /* BUILD_FT2232_FTD2XX == 1 */
 
 #if BUILD_FT2232_LIBFTDI == 1
-static int ft2232_init_libftdi(uint16_t vid, uint16_t pid, int more, int* try_more)
+static int ft2232_init_libftdi(uint16_t vid, uint16_t pid, int more, int* try_more, int channel)
 {
        uint8_t latency_timer;
 
+       if (layout == NULL) {
+               LOG_WARNING("No ft2232 layout specified'");
+               return ERROR_JTAG_INIT_FAILED;
+       }
+
        LOG_DEBUG("'ft2232' interface using libftdi with '%s' layout (%4.4x:%4.4x)",
-                       ft2232_layout, vid, pid);
+                       layout->name, vid, pid);
 
        if (ftdi_init(&ftdic) < 0)
                return ERROR_JTAG_INIT_FAILED;
 
-       if (ftdi_set_interface(&ftdic, INTERFACE_A) < 0)
+       /* default to INTERFACE_A */
+       if(channel == INTERFACE_ANY) { channel = INTERFACE_A; }
+
+       if (ftdi_set_interface(&ftdic, channel) < 0)
        {
                LOG_ERROR("unable to select FT2232 channel A: %s", ftdic.error_str);
                return ERROR_JTAG_INIT_FAILED;
@@ -2059,8 +2318,6 @@ static int ft2232_init(void)
        uint8_t  buf[1];
        int retval;
        uint32_t bytes_written;
-       const struct ft2232_layout* cur_layout = ft2232_layouts;
-       int i;
 
        if (tap_get_tms_path_len(TAP_IRPAUSE,TAP_IRPAUSE) == 7)
        {
@@ -2071,29 +2328,12 @@ static int ft2232_init(void)
                LOG_DEBUG("ft2232 interface using shortest path jtag state transitions");
 
        }
-       if ((ft2232_layout == NULL) || (ft2232_layout[0] == 0))
-       {
-               ft2232_layout = "usbjtag";
-               LOG_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)
-       {
-               LOG_ERROR("No matching layout found for %s", ft2232_layout);
+       if (layout == NULL) {
+               LOG_WARNING("No ft2232 layout specified'");
                return ERROR_JTAG_INIT_FAILED;
        }
 
-       for (i = 0; 1; i++)
+       for (int i = 0; 1; i++)
        {
                /*
                 * "more indicates that there are more IDs to try, so we should
@@ -2112,7 +2352,7 @@ static int ft2232_init(void)
                                more, &try_more);
 #elif BUILD_FT2232_LIBFTDI == 1
                retval = ft2232_init_libftdi(ft2232_vid[i], ft2232_pid[i],
-                               more, &try_more);
+                                            more, &try_more, layout->channel);
 #endif
                if (retval >= 0)
                        break;
@@ -2143,7 +2383,7 @@ static int ft2232_init(void)
        ft2232_speed(jtag_get_speed());
 
        buf[0] = 0x85; /* Disconnect TDI/DO to TDO/DI for Loopback */
-       if (((retval = ft2232_write(buf, 1, &bytes_written)) != ERROR_OK) || (bytes_written != 1))
+       if ((retval = ft2232_write(buf, 1, &bytes_written)) != ERROR_OK)
        {
                LOG_ERROR("couldn't write to FT2232 to disable loopback");
                return ERROR_JTAG_INIT_FAILED;
@@ -2158,51 +2398,23 @@ static int ft2232_init(void)
        return ERROR_OK;
 }
 
-static int usbjtag_init(void)
+/** Updates defaults for DBUS signals:  the four JTAG signals
+ * (TCK, TDI, TDO, TMS) and * the four GPIOL signals.
+ */
+static inline void ftx232_dbus_init(void)
 {
-       uint8_t  buf[3];
-       uint32_t bytes_written;
-
        low_output    = 0x08;
        low_direction = 0x0b;
+}
 
-       if (strcmp(ft2232_layout, "usbjtag") == 0)
-       {
-               nTRST    = 0x10;
-               nTRSTnOE = 0x10;
-               nSRST    = 0x40;
-               nSRSTnOE = 0x40;
-       }
-       else if (strcmp(ft2232_layout, "signalyzer") == 0)
-       {
-               nTRST    = 0x10;
-               nTRSTnOE = 0x10;
-               nSRST    = 0x20;
-               nSRSTnOE = 0x20;
-       }
-       else if (strcmp(ft2232_layout, "evb_lm3s811") == 0)
-       {
-               nTRST = 0x0;
-               nTRSTnOE = 0x00;
-               nSRST = 0x20;
-               nSRSTnOE = 0x20;
-               low_output    = 0x88;
-               low_direction = 0x8b;
-       }
-       else if (strcmp(ft2232_layout, "luminary_icdi") == 0)
-       {
-               nTRST = 0x0;
-               nTRSTnOE = 0x00;
-               nSRST = 0x20;
-               nSRSTnOE = 0x20;
-               low_output    = 0x88;
-               low_direction = 0xcb;
-       }
-       else
-       {
-               LOG_ERROR("BUG: usbjtag_init called for unknown layout '%s'", ft2232_layout);
-               return ERROR_JTAG_INIT_FAILED;
-       }
+/** Initializes DBUS signals:  the four JTAG signals (TCK, TDI, TDO, TMS),
+ * the four GPIOL signals.  Initialization covers value and direction,
+ * as customized for each layout.
+ */
+static int ftx232_dbus_write(void)
+{
+       uint8_t  buf[3];
+       uint32_t bytes_written;
 
        enum reset_types jtag_reset_config = jtag_get_reset_config();
        if (jtag_reset_config & RESET_TRST_OPEN_DRAIN)
@@ -2233,15 +2445,99 @@ static int usbjtag_init(void)
        buf[2] = low_direction; /* dir (output = 1), TCK/TDI/TMS = out, TDO = in */
        LOG_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))
+       if (ft2232_write(buf, sizeof(buf), &bytes_written) != ERROR_OK)
        {
-               LOG_ERROR("couldn't initialize FT2232 with 'USBJTAG' layout");
+               LOG_ERROR("couldn't initialize FT2232 DBUS");
                return ERROR_JTAG_INIT_FAILED;
        }
 
        return ERROR_OK;
 }
 
+static int usbjtag_init(void)
+{
+       /*
+        * NOTE:  This is now _specific_ to the "usbjtag" layout.
+        * Don't try cram any more layouts into this.
+        */
+       ftx232_dbus_init();
+
+       nTRST    = 0x10;
+       nTRSTnOE = 0x10;
+       nSRST    = 0x40;
+       nSRSTnOE = 0x40;
+
+       return ftx232_dbus_write();
+}
+
+static int lm3s811_jtag_init(void)
+{
+       ftx232_dbus_init();
+
+       /* There are multiple revisions of LM3S811 eval boards:
+        * - Rev B (and older?) boards have no SWO trace support.
+        * - Rev C boards add ADBUS_6 DBG_ENn and BDBUS_4 SWO_EN;
+        *   they should use the "luminary_icdi" layout instead.
+        */
+       nTRST = 0x0;
+       nTRSTnOE = 0x00;
+       nSRST = 0x20;
+       nSRSTnOE = 0x20;
+       low_output    = 0x88;
+       low_direction = 0x8b;
+
+       return ftx232_dbus_write();
+}
+
+static int icdi_jtag_init(void)
+{
+       ftx232_dbus_init();
+
+       /* Most Luminary eval boards support SWO trace output,
+        * and should use this "luminary_icdi" layout.
+        *
+        * DBUS 0..3 are used for JTAG as usual.  GPIOs are used
+        * to switch between JTAG and SWD, or switch the ft2232 UART
+        * between (i) the target UART or (ii) SWO trace data.
+        *
+        * We come up in JTAG mode and may switch to SWD later (with
+        * SWO/trace option if SWD is active).
+        *
+        * DBUS == GPIO-Lx
+        * CBUS == GPIO-Hx
+        */
+
+
+#define ICDI_JTAG_EN (1 << 7)          /* ADBUS 7 (a.k.a. DBGMOD) */
+#define ICDI_DBG_ENn (1 << 6)          /* ADBUS 6 */
+#define ICDI_SRST (1 << 5)             /* ADBUS 5 */
+#define ICDI_TDI (1 << 2)              /* ADBUS 2 (INPUT) */
+
+#define ICDI_SWO_EN (1 << 4)           /* BDBUS 4 */
+#define ICDI_TX_SWO (1 << 1)           /* BDBUS 1 */
+
+       nTRST = 0x0;
+       nTRSTnOE = 0x00;
+       nSRST = ICDI_SRST;
+       nSRSTnOE = 0x20;
+
+       low_output    = 0x08 | ICDI_JTAG_EN;
+       low_direction = 0xcb | ICDI_JTAG_EN;
+
+       return ftx232_dbus_write();
+}
+
+static int signalyzer_init(void)
+{
+       ftx232_dbus_init();
+
+       nTRST    = 0x10;
+       nTRSTnOE = 0x10;
+       nSRST    = 0x20;
+       nSRSTnOE = 0x20;
+       return ftx232_dbus_write();
+}
+
 static int axm0432_jtag_init(void)
 {
        uint8_t  buf[3];
@@ -2256,7 +2552,7 @@ static int axm0432_jtag_init(void)
        buf[2] = low_direction; /* dir (output = 1), TCK/TDI/TMS = out, TDO = in, nOE = out */
        LOG_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))
+       if (ft2232_write(buf, sizeof(buf), &bytes_written) != ERROR_OK)
        {
                LOG_ERROR("couldn't initialize FT2232 with 'JTAGkey' layout");
                return ERROR_JTAG_INIT_FAILED;
@@ -2303,7 +2599,7 @@ static int axm0432_jtag_init(void)
        buf[2] = high_direction;    /* all outputs (xRST and xRSTnOE) */
        LOG_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))
+       if (ft2232_write(buf, sizeof(buf), &bytes_written) != ERROR_OK)
        {
                LOG_ERROR("couldn't initialize FT2232 with 'Dicarlo' layout");
                return ERROR_JTAG_INIT_FAILED;
@@ -2312,6 +2608,71 @@ static int axm0432_jtag_init(void)
        return ERROR_OK;
 }
 
+static int redbee_init(void)
+{
+       uint8_t  buf[3];
+       uint32_t bytes_written;
+
+       low_output    = 0x08;
+       low_direction = 0x2b;
+
+       /* initialize low byte for jtag */
+       /* command "set data bits low byte" */
+       buf[0] = 0x80;
+       /* value (TMS = 1,TCK = 0, TDI = 0, nOE = 0) */
+       buf[2] = low_direction;
+       /* dir (output = 1), TCK/TDI/TMS = out, TDO = in, nOE = out */
+       buf[1] = low_output;
+       LOG_DEBUG("%2.2x %2.2x %2.2x", buf[0], buf[1], buf[2]);
+
+       if (ft2232_write(buf, sizeof(buf), &bytes_written) != ERROR_OK)
+       {
+               LOG_ERROR("couldn't initialize FT2232 with 'redbee' layout");
+               return ERROR_JTAG_INIT_FAILED;
+       }
+
+       nTRST    = 0x08;
+       nTRSTnOE = 0x0;     /* No output enable for TRST*/
+       nSRST    = 0x04;
+       nSRSTnOE = 0x0;     /* No output enable for SRST*/
+
+       high_output    = 0x0;
+       high_direction = 0x0c;
+
+       enum reset_types jtag_reset_config = jtag_get_reset_config();
+       if (jtag_reset_config & RESET_TRST_OPEN_DRAIN)
+       {
+               LOG_ERROR("can't set nTRSTOE to push-pull on redbee");
+       }
+       else
+       {
+               high_output |= nTRST;
+       }
+
+       if (jtag_reset_config & RESET_SRST_PUSH_PULL)
+       {
+               LOG_ERROR("can't set nSRST to push-pull on redbee");
+       }
+       else
+       {
+               high_output |= nSRST;
+       }
+
+       /* initialize high port */
+       buf[0] = 0x82;              /* command "set data bits high byte" */
+       buf[1] = high_output;       /* value */
+       buf[2] = high_direction;    /* all outputs (xRST and xRSTnOE) */
+       LOG_DEBUG("%2.2x %2.2x %2.2x", buf[0], buf[1], buf[2]);
+
+       if (ft2232_write(buf, sizeof(buf), &bytes_written) != ERROR_OK)
+       {
+               LOG_ERROR("couldn't initialize FT2232 with 'redbee' layout");
+               return ERROR_JTAG_INIT_FAILED;
+       }
+
+       return ERROR_OK;
+}
+
 static int jtagkey_init(void)
 {
        uint8_t  buf[3];
@@ -2326,7 +2687,7 @@ static int jtagkey_init(void)
        buf[2] = low_direction; /* dir (output = 1), TCK/TDI/TMS = out, TDO = in, nOE = out */
        LOG_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))
+       if (ft2232_write(buf, sizeof(buf), &bytes_written) != ERROR_OK)
        {
                LOG_ERROR("couldn't initialize FT2232 with 'JTAGkey' layout");
                return ERROR_JTAG_INIT_FAILED;
@@ -2385,7 +2746,7 @@ static int jtagkey_init(void)
        buf[2] = high_direction;    /* all outputs (xRST and xRSTnOE) */
        LOG_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))
+       if (ft2232_write(buf, sizeof(buf), &bytes_written) != ERROR_OK)
        {
                LOG_ERROR("couldn't initialize FT2232 with 'JTAGkey' layout");
                return ERROR_JTAG_INIT_FAILED;
@@ -2408,7 +2769,7 @@ static int olimex_jtag_init(void)
        buf[2] = low_direction; /* dir (output = 1), TCK/TDI/TMS = out, TDO = in, nOE = out */
        LOG_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))
+       if (ft2232_write(buf, sizeof(buf), &bytes_written) != ERROR_OK)
        {
                LOG_ERROR("couldn't initialize FT2232 with 'Olimex' layout");
                return ERROR_JTAG_INIT_FAILED;
@@ -2452,7 +2813,7 @@ static int olimex_jtag_init(void)
        buf[2] = high_direction;    /* all outputs (xRST and xRSTnOE) */
        LOG_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))
+       if (ft2232_write(buf, sizeof(buf), &bytes_written) != ERROR_OK)
        {
                LOG_ERROR("couldn't initialize FT2232 with 'Olimex' layout");
                return ERROR_JTAG_INIT_FAILED;
@@ -2475,7 +2836,7 @@ static int flyswatter_init(void)
        buf[2] = low_direction; /* dir (output = 1), TCK/TDI/TMS = out, TDO = in, nOE[12]=out, n[ST]srst = out */
        LOG_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))
+       if (ft2232_write(buf, sizeof(buf), &bytes_written) != ERROR_OK)
        {
                LOG_ERROR("couldn't initialize FT2232 with 'flyswatter' layout");
                return ERROR_JTAG_INIT_FAILED;
@@ -2498,7 +2859,7 @@ static int flyswatter_init(void)
        buf[2] = high_direction;    /* all outputs (xRST and xRSTnOE) */
        LOG_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))
+       if (ft2232_write(buf, sizeof(buf), &bytes_written) != ERROR_OK)
        {
                LOG_ERROR("couldn't initialize FT2232 with 'flyswatter' layout");
                return ERROR_JTAG_INIT_FAILED;
@@ -2521,7 +2882,7 @@ static int turtle_init(void)
        buf[2] = low_direction; /* dir (output = 1), TCK/TDI/TMS = out, TDO = in, nOE = out */
        LOG_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))
+       if (ft2232_write(buf, sizeof(buf), &bytes_written) != ERROR_OK)
        {
                LOG_ERROR("couldn't initialize FT2232 with 'turtelizer2' layout");
                return ERROR_JTAG_INIT_FAILED;
@@ -2538,7 +2899,7 @@ static int turtle_init(void)
        buf[2] = high_direction;
        LOG_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))
+       if (ft2232_write(buf, sizeof(buf), &bytes_written) != ERROR_OK)
        {
                LOG_ERROR("couldn't initialize FT2232 with 'turtelizer2' layout");
                return ERROR_JTAG_INIT_FAILED;
@@ -2561,7 +2922,7 @@ static int comstick_init(void)
        buf[2] = low_direction; /* dir (output = 1), TCK/TDI/TMS = out, TDO = in, nOE = out */
        LOG_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))
+       if (ft2232_write(buf, sizeof(buf), &bytes_written) != ERROR_OK)
        {
                LOG_ERROR("couldn't initialize FT2232 with 'comstick' layout");
                return ERROR_JTAG_INIT_FAILED;
@@ -2581,7 +2942,7 @@ static int comstick_init(void)
        buf[2] = high_direction;
        LOG_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))
+       if (ft2232_write(buf, sizeof(buf), &bytes_written) != ERROR_OK)
        {
                LOG_ERROR("couldn't initialize FT2232 with 'comstick' layout");
                return ERROR_JTAG_INIT_FAILED;
@@ -2604,7 +2965,7 @@ static int stm32stick_init(void)
        buf[2] = low_direction; /* dir (output = 1), TCK/TDI/TMS = out, TDO = in, nOE = out */
        LOG_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))
+       if (ft2232_write(buf, sizeof(buf), &bytes_written) != ERROR_OK)
        {
                LOG_ERROR("couldn't initialize FT2232 with 'stm32stick' layout");
                return ERROR_JTAG_INIT_FAILED;
@@ -2624,7 +2985,7 @@ static int stm32stick_init(void)
        buf[2] = high_direction;
        LOG_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))
+       if (ft2232_write(buf, sizeof(buf), &bytes_written) != ERROR_OK)
        {
                LOG_ERROR("couldn't initialize FT2232 with 'stm32stick' layout");
                return ERROR_JTAG_INIT_FAILED;
@@ -2647,7 +3008,7 @@ static int sheevaplug_init(void)
        buf[2] = low_direction; /* dir (output = 1), TCK/TDI/TMS = out, TDO = in */
        LOG_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))
+       if (ft2232_write(buf, sizeof(buf), &bytes_written) != ERROR_OK)
        {
                LOG_ERROR("couldn't initialize FT2232 with 'sheevaplug' layout");
                return ERROR_JTAG_INIT_FAILED;
@@ -2675,7 +3036,7 @@ static int sheevaplug_init(void)
        buf[2] = high_direction;   /* all outputs - xRST */
        LOG_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))
+       if (ft2232_write(buf, sizeof(buf), &bytes_written) != ERROR_OK)
        {
                LOG_ERROR("couldn't initialize FT2232 with 'sheevaplug' layout");
                return ERROR_JTAG_INIT_FAILED;
@@ -2698,7 +3059,7 @@ static int cortino_jtag_init(void)
        buf[2] = low_direction; /* dir (output = 1), TCK/TDI/TMS = out, TDO = in, nOE = out */
        LOG_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))
+       if (ft2232_write(buf, sizeof(buf), &bytes_written) != ERROR_OK)
        {
                LOG_ERROR("couldn't initialize FT2232 with 'cortino' layout");
                return ERROR_JTAG_INIT_FAILED;
@@ -2718,7 +3079,7 @@ static int cortino_jtag_init(void)
        buf[2] = high_direction;
        LOG_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))
+       if (ft2232_write(buf, sizeof(buf), &bytes_written) != ERROR_OK)
        {
                LOG_ERROR("couldn't initialize FT2232 with 'stm32stick' layout");
                return ERROR_JTAG_INIT_FAILED;
@@ -2847,13 +3208,28 @@ COMMAND_HANDLER(ft2232_handle_serial_command)
 
 COMMAND_HANDLER(ft2232_handle_layout_command)
 {
-       if (CMD_ARGC == 0)
-               return ERROR_OK;
+       if (CMD_ARGC != 1) {
+               LOG_ERROR("Need exactly one argument to ft2232_layout");
+               return ERROR_FAIL;
+       }
 
-       ft2232_layout = malloc(strlen(CMD_ARGV[0]) + 1);
-       strcpy(ft2232_layout, CMD_ARGV[0]);
+       if (layout) {
+               LOG_ERROR("already specified ft2232_layout %s",
+                               layout->name);
+               return (strcmp(layout->name, CMD_ARGV[0]) != 0)
+                               ? ERROR_FAIL
+                               : ERROR_OK;
+       }
 
-       return ERROR_OK;
+       for (const struct ft2232_layout *l = ft2232_layouts; l->name; l++) {
+               if (strcmp(l->name, CMD_ARGV[0]) == 0) {
+                       layout = l;
+                       return ERROR_OK;
+               }
+       }
+
+       LOG_ERROR("No FT2232 layout '%s' found", CMD_ARGV[0]);
+       return ERROR_FAIL;
 }
 
 COMMAND_HANDLER(ft2232_handle_vid_pid_command)
@@ -2998,7 +3374,7 @@ static int icebear_jtag_init(void) {
        buf[2] = low_direction;
        LOG_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)) {
+       if (ft2232_write(buf, sizeof(buf), &bytes_written) != ERROR_OK) {
                LOG_ERROR("couldn't initialize FT2232 with 'IceBear' layout (low)");
                return ERROR_JTAG_INIT_FAILED;
        }
@@ -3013,7 +3389,7 @@ static int icebear_jtag_init(void) {
        buf[2] = high_direction;    /* all outputs (xRST and xRSTnOE) */
        LOG_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)) {
+       if (ft2232_write(buf, sizeof(buf), &bytes_written) != ERROR_OK) {
                LOG_ERROR("couldn't initialize FT2232 with 'IceBear' layout (high)");
                return ERROR_JTAG_INIT_FAILED;
        }
@@ -3660,8 +4036,7 @@ static int signalyzer_h_init(void)
        buf[1] = low_output;
        buf[2] = low_direction;
 
-       if (((ft2232_write(buf, 3, &bytes_written)) != ERROR_OK)
-                       || (bytes_written != 3))
+       if (ft2232_write(buf, sizeof(buf), &bytes_written) != ERROR_OK)
        {
                LOG_ERROR("couldn't initialize Signalyzer-H layout");
                return ERROR_JTAG_INIT_FAILED;
@@ -3675,8 +4050,7 @@ static int signalyzer_h_init(void)
                buf[1] = high_output;
                buf[2] = high_direction;
 
-               if ((ft2232_write(buf, 3, &bytes_written) != ERROR_OK)
-                               || (bytes_written != 3))
+               if (ft2232_write(buf, sizeof(buf), &bytes_written) != ERROR_OK)
                {
                        LOG_ERROR("couldn't initialize Signalyzer-H layout");
                        return ERROR_JTAG_INIT_FAILED;
@@ -3690,8 +4064,7 @@ static int signalyzer_h_init(void)
                buf[1] = high_output;
                buf[2] = high_direction;
 
-               if ((ft2232_write(buf, 3, &bytes_written) != ERROR_OK)
-                               || (bytes_written != 3))
+               if (ft2232_write(buf, sizeof(buf), &bytes_written) != ERROR_OK)
                {
                        LOG_ERROR("couldn't initialize Signalyzer-H layout");
                        return ERROR_JTAG_INIT_FAILED;
@@ -3875,7 +4248,7 @@ static int ktlink_init(void)
        buf[2] = low_direction;
        LOG_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))
+       if (ft2232_write(buf, sizeof(buf), &bytes_written) != ERROR_OK)
        {
                LOG_ERROR("couldn't initialize FT2232 with 'ktlink' layout");
                return ERROR_JTAG_INIT_FAILED;
@@ -3913,7 +4286,7 @@ static int ktlink_init(void)
        buf[2] = high_direction;
        LOG_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))
+       if (ft2232_write(buf, sizeof(buf), &bytes_written) != ERROR_OK)
        {
                LOG_ERROR("couldn't initialize FT2232 with 'ktlink' layout");
                return ERROR_JTAG_INIT_FAILED;
@@ -3975,14 +4348,14 @@ static const struct command_registration ft2232_command_handlers[] = {
                .handler = &ft2232_handle_device_desc_command,
                .mode = COMMAND_CONFIG,
                .help = "set the USB device description of the FTDI FT2232 device",
-               .usage = "<description>",
+               .usage = "description_string",
        },
        {
                .name = "ft2232_serial",
                .handler = &ft2232_handle_serial_command,
                .mode = COMMAND_CONFIG,
                .help = "set the serial number of the FTDI FT2232 device",
-               .usage = "<serial#>",
+               .usage = "serial_string",
        },
        {
                .name = "ft2232_layout",
@@ -3990,32 +4363,35 @@ static const struct command_registration ft2232_command_handlers[] = {
                .mode = COMMAND_CONFIG,
                .help = "set the layout of the FT2232 GPIO signals used "
                        "to control output-enables and reset signals",
-               .usage = "<layout>",
+               .usage = "layout_name",
        },
        {
                .name = "ft2232_vid_pid",
                .handler = &ft2232_handle_vid_pid_command,
                .mode = COMMAND_CONFIG,
                .help = "the vendor ID and product ID of the FTDI FT2232 device",
-               .usage = "<vid> <pid> [...]",
+               .usage = "(vid pid)* ",
        },
        {
                .name = "ft2232_latency",
                .handler = &ft2232_handle_latency_command,
                .mode = COMMAND_CONFIG,
                .help = "set the FT2232 latency timer to a new value",
-               .usage = "<vid> <pid> [...]",
+               .usage = "value",
        },
        COMMAND_REGISTRATION_DONE
 };
 
 struct jtag_interface ft2232_interface = {
-               .name = "ft2232",
-               .commands = ft2232_command_handlers,
-               .init = &ft2232_init,
-               .quit = &ft2232_quit,
-               .speed = &ft2232_speed,
-               .speed_div = &ft2232_speed_div,
-               .khz = &ft2232_khz,
-               .execute_queue = &ft2232_execute_queue,
-       };
+       .name = "ft2232",
+       .supported = DEBUG_CAP_TMS_SEQ,
+       .commands = ft2232_command_handlers,
+       .transports = jtag_only,
+
+       .init = ft2232_init,
+       .quit = ft2232_quit,
+       .speed = ft2232_speed,
+       .speed_div = ft2232_speed_div,
+       .khz = ft2232_khz,
+       .execute_queue = ft2232_execute_queue,
+};