initial "transport" framework
authorDavid Brownell <dbrownell@users.sourceforge.net>
Fri, 2 Jul 2010 20:45:28 +0000 (16:45 -0400)
committerDavid Brownell <db@helium.(none)>
Fri, 2 Jul 2010 20:45:28 +0000 (16:45 -0400)
This adds the guts of a transport framework with initialization,
which should work with current JTAG-only configurations (tested
with FT2232).

Each debug adapter can declare the transports it supports, and
exactly one transport is initialized.  (with its commands) in
any given OpenOCD session.

  * Define a new "struct transport with init hooks and a few
 "transport"  subcommands to support it:

     "list" ... list the transports configured (just "jtag" for now)
     "select" ... makes the debug session use that transport
     "init" ... initializes the selected transport (internal)

  * "interface_transports" ... declares transports the current interface
    can support.  (Some will do this from C code instead, when there are
    no hardware versioning (or other) issues to prevent it.

Plus some FT2232 tweaks, including a few to streamline upcoming
support for an SWD transport (initially for Luminary adapters).

Eventually src/jtag should probably become src/transport, moving
jtag-specific stuff  to transport/jtag.

Signed-off-by: David Brownell <db@helium.(none)>
NEWS
doc/openocd.texi
src/jtag/Makefile.am
src/jtag/adapter.c
src/jtag/core.c
src/jtag/drivers/ft2232.c
src/jtag/jtag.h
src/jtag/transport.c [new file with mode: 0644]
src/jtag/transport.h [new file with mode: 0644]
src/openocd.c

diff --git a/NEWS b/NEWS
index db4485dae172db70034a605b551ca33b28e42594..2dd14cc60e2edfc86dd0fc7918346760ada37dad 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -17,6 +17,9 @@ JTAG Layer:
 
 Boundary Scan:
 
 
 Boundary Scan:
 
+Transport framework core ... supporting future work for SWD, SPI, and other
+non-JTAG ways to debug targets or program flash.
+
 Target Layer:
        ARM:
                - basic semihosting support (ARMv7M).
 Target Layer:
        ARM:
                - basic semihosting support (ARMv7M).
index a3ca12475bca36eae98d6096d1816c7cca1f0598..a765727ceb6e858cdc7012f001b3d7cd291baa1f 100644 (file)
@@ -2096,6 +2096,14 @@ target.
 List the debug adapter drivers that have been built into
 the running copy of OpenOCD.
 @end deffn
 List the debug adapter drivers that have been built into
 the running copy of OpenOCD.
 @end deffn
+@deffn Command {interface transports} transport_name+
+Specifies the transports supported by this debug adapter.
+The adapter driver builds-in similar knowledge; use this only
+when external configuration (such as jumpering) changes what
+the hardware can support.
+@end deffn
+
+
 
 @deffn Command {adapter_name}
 Returns the name of the debug adapter driver being used.
 
 @deffn Command {adapter_name}
 Returns the name of the debug adapter driver being used.
@@ -2428,7 +2436,41 @@ Turn power switch to target on/off.
 No arguments: print status.
 @end deffn
 
 No arguments: print status.
 @end deffn
 
-@end deffn
+@section Transport Configuration
+As noted earlier, depending on the version of OpenOCD you use,
+and the debug adapter you are using,
+several transports may be available to
+communicate with debug targets (or perhaps to program flash memory).
+@deffn Command {transport list}
+displays the names of the transports supported by this
+version of OpenOCD.
+@end deffn
+
+@deffn Command {transport select} transport_name
+Select which of the supported transports to use in this OpenOCD session.
+The transport must be supported by the debug adapter hardware  and by the
+version of OPenOCD you are using (including the adapter's driver).
+No arguments: print selected transport..
+@end deffn
+
+@subsection JTAG Transport
+JTAG is the original transport supported by OpenOCD, and most
+of the OpenOCD commands support it.
+JTAG transports expose a chain of one or more Test Access Points (TAPs),
+each of which must be explicitly declared.
+JTAG supports both debugging and boundary scan testing.
+Flash programming support is built on top of debug support.
+@subsection SWD ransport
+SWD (Serial Wire Debug) is an ARM-specific transport which exposes one
+Debug Access Point (DAP, which must be explicitly declared.
+(SWD uses fewer signal wires than JTAG.)
+SWD is debug-oriented, and does not support  boundary scan testing.
+Flash programming support is built on top of debug support.
+(Some processors support both JTAG and SWD.)
+@subsection SPI ransport
+The Serial Peripheral Interface (SPI) is a general purpose transport
+which uses four wire signaling.  Some processors use it as part of a
+solution for flash programming.
 
 @anchor{JTAG Speed}
 @section JTAG Speed
 
 @anchor{JTAG Speed}
 @section JTAG Speed
index 910affc1aa7e13a9683d4e6479552b54d66aa2dc..59cd8ffffd06b85192f95ab2773d2f5f1f57c255 100644 (file)
@@ -58,6 +58,7 @@ libjtag_la_SOURCES = \
        interface.c \
        interfaces.c \
        tcl.c \
        interface.c \
        interfaces.c \
        tcl.c \
+       transport.c \
        $(DRIVERFILES)
 
 noinst_HEADERS = \
        $(DRIVERFILES)
 
 noinst_HEADERS = \
@@ -67,6 +68,7 @@ noinst_HEADERS = \
        interfaces.h \
        minidriver.h \
        jtag.h \
        interfaces.h \
        minidriver.h \
        jtag.h \
+       transport.h \
        minidriver/minidriver_imp.h \
        minidummy/jtag_minidriver.h
 
        minidriver/minidriver_imp.h \
        minidummy/jtag_minidriver.h
 
index 50e2a02285f73caa84dce724a9f5bed029411848..15b3ddc2c90c7a32ae93e18a3d2540b5a47d03a2 100644 (file)
@@ -35,6 +35,7 @@
 #include "minidriver.h"
 #include "interface.h"
 #include "interfaces.h"
 #include "minidriver.h"
 #include "interface.h"
 #include "interfaces.h"
+#include "transport.h"
 
 #ifdef HAVE_STRINGS_H
 #include <strings.h>
 
 #ifdef HAVE_STRINGS_H
 #include <strings.h>
@@ -92,6 +93,25 @@ static int default_srst_asserted(int *srst_asserted)
        return ERROR_OK;
 }
 
        return ERROR_OK;
 }
 
+COMMAND_HANDLER(interface_transport_command)
+{
+       char **transports;
+       int retval;
+
+       retval = CALL_COMMAND_HANDLER(transport_list_parse, &transports);
+       if (retval != ERROR_OK) {
+               return retval;
+
+       retval = allow_transports(CMD_CTX, (const char **)transports);
+       if (retval != ERROR_OK) {
+               for (unsigned i = 0; transports[i]; i++)
+                       free(transports[i]);
+               free(transports);
+       }
+       }
+       return retval;
+}
+
 COMMAND_HANDLER(handle_interface_list_command)
 {
        if (strcmp(CMD_NAME, "interface_list") == 0 && CMD_ARGC > 0)
 COMMAND_HANDLER(handle_interface_list_command)
 {
        if (strcmp(CMD_NAME, "interface_list") == 0 && CMD_ARGC > 0)
@@ -451,6 +471,13 @@ static const struct command_registration interface_command_handlers[] = {
                .help = "Select a debug adapter interface (driver)",
                .usage = "driver_name",
        },
                .help = "Select a debug adapter interface (driver)",
                .usage = "driver_name",
        },
+       {
+               .name = "interface_transports",
+               .handler = interface_transport_command,
+               .mode = COMMAND_CONFIG,
+               .help = "Declare transports the interface supports.",
+               .usage = "transport ... ",
+       },
        {
                .name = "interface_list",
                .handler = handle_interface_list_command,
        {
                .name = "interface_list",
                .handler = handle_interface_list_command,
index 782f10f78d7e29dffd6344b3cb62054821f92739..1643d9b64e4827756d499e41902d29c6c4c79c61 100644 (file)
 
 #include "jtag.h"
 #include "interface.h"
 
 #include "jtag.h"
 #include "interface.h"
+#include "transport.h"
 
 #ifdef HAVE_STRINGS_H
 #include <strings.h>
 #endif
 
 
 #ifdef HAVE_STRINGS_H
 #include <strings.h>
 #endif
 
+/* SVF and XSVF are higher level JTAG command sets (for boundary scan) */
+#include "svf/svf.h"
+#include "xsvf/xsvf.h"
 
 /// The number of JTAG queue flushes (for profiling and debugging purposes).
 static int jtag_flush_queue_count;
 
 /// The number of JTAG queue flushes (for profiling and debugging purposes).
 static int jtag_flush_queue_count;
@@ -1348,6 +1352,21 @@ int adapter_init(struct command_context *cmd_ctx)
                return ERROR_JTAG_INIT_FAILED;
        }
 
                return ERROR_JTAG_INIT_FAILED;
        }
 
+       /* LEGACY SUPPORT ... adapter drivers  must declare what
+        * transports they allow.  Until they all do so, assume
+        * the legacy drivers are JTAG-only
+        */
+       if (!transports_are_declared()) {
+               static const char *jtag_only[] = { "jtag", NULL, };
+               LOG_ERROR("Adapter driver '%s' did not declare "
+                       "which transports it allows; assuming"
+                       "JTAG-only", jtag->name);
+               int retval = allow_transports(cmd_ctx, jtag_only);
+               if (retval != ERROR_OK)
+                       return retval;
+       }
+
+
        int requested_khz = jtag_get_speed_khz();
        int actual_khz = requested_khz;
        int retval = jtag_get_speed_readable(&actual_khz);
        int requested_khz = jtag_get_speed_khz();
        int actual_khz = requested_khz;
        int retval = jtag_get_speed_readable(&actual_khz);
@@ -1706,3 +1725,45 @@ unsigned jtag_get_ntrst_assert_width(void)
 {
        return jtag_ntrst_assert_width;
 }
 {
        return jtag_ntrst_assert_width;
 }
+
+static int jtag_select(struct command_context *ctx)
+{
+       int retval;
+
+       /* NOTE:  interface init must already have been done.
+        * That works with only C code ... no Tcl glue required.
+        */
+
+
+       retval = jtag_register_commands(ctx);
+
+       if (retval != ERROR_OK)
+               return retval;
+
+       retval = svf_register_commands(ctx);
+
+       if (retval != ERROR_OK)
+               return retval;
+
+       return xsvf_register_commands(ctx);
+}
+
+static struct transport jtag_transport = {
+       .name = "jtag",
+       .select = jtag_select,
+       .init = jtag_init,
+};
+
+static void jtag_constructor(void) __attribute__((constructor));
+static void jtag_constructor(void)
+{
+       transport_register(&jtag_transport);
+}
+
+/** Returns true if the current debug session
+ * is using JTAG as its transport.
+ */
+bool transport_is_jtag(void)
+{
+       return get_current_transport() == &jtag_transport;
+}
index f315d69970bf3205675833d9267720bb7eea78d3..f02ae626130ccfc544451cb582d75384fb4f82d0 100644 (file)
@@ -81,6 +81,7 @@
 
 /* project specific includes */
 #include <jtag/interface.h>
 
 /* project specific includes */
 #include <jtag/interface.h>
+#include <jtag/transport.h>
 #include <helper/time_support.h>
 
 #if IS_CYGWIN == 1
 #include <helper/time_support.h>
 
 #if IS_CYGWIN == 1
@@ -167,6 +168,7 @@ struct ft2232_layout {
        void (*reset)(int trst, int srst);
        void (*blink)(void);
        int channel;
        void (*reset)(int trst, int srst);
        void (*blink)(void);
        int channel;
+       const char **transports;
 };
 
 /* init procedures for supported layouts */
 };
 
 /* init procedures for supported layouts */
@@ -210,6 +212,13 @@ static void turtle_jtag_blink(void);
 static void signalyzer_h_blink(void);
 static void ktlink_blink(void);
 
 static void signalyzer_h_blink(void);
 static void ktlink_blink(void);
 
+/* common transport support options */
+static const char *jtag_only[] = { "jtag", NULL };
+
+
+//static const char *jtag_and_swd[] = { "jtag", "swd", NULL };
+#define jtag_and_swd NULL
+
 static const struct ft2232_layout  ft2232_layouts[] =
 {
        { .name = "usbjtag",
 static const struct ft2232_layout  ft2232_layouts[] =
 {
        { .name = "usbjtag",
@@ -235,10 +244,12 @@ static const struct ft2232_layout  ft2232_layouts[] =
        { .name = "evb_lm3s811",
                .init = lm3s811_jtag_init,
                .reset = ftx23_reset,
        { .name = "evb_lm3s811",
                .init = lm3s811_jtag_init,
                .reset = ftx23_reset,
+               .transports = jtag_and_swd,
        },
        { .name = "luminary_icdi",
                .init = icdi_jtag_init,
                .reset = ftx23_reset,
        },
        { .name = "luminary_icdi",
                .init = icdi_jtag_init,
                .reset = ftx23_reset,
+               .transports = jtag_and_swd,
        },
        { .name = "olimex-jtag",
                .init = olimex_jtag_init,
        },
        { .name = "olimex-jtag",
                .init = olimex_jtag_init,
@@ -2393,7 +2404,7 @@ static int ft2232_init(void)
 /** Updates defaults for DBUS signals:  the four JTAG signals
  * (TCK, TDI, TDO, TMS) and * the four GPIOL signals.
  */
 /** Updates defaults for DBUS signals:  the four JTAG signals
  * (TCK, TDI, TDO, TMS) and * the four GPIOL signals.
  */
-static inline void ftx232_init_head(void)
+static inline void ftx232_dbus_init(void)
 {
        low_output    = 0x08;
        low_direction = 0x0b;
 {
        low_output    = 0x08;
        low_direction = 0x0b;
@@ -2403,7 +2414,7 @@ static inline void ftx232_init_head(void)
  * the four GPIOL signals.  Initialization covers value and direction,
  * as customized for each layout.
  */
  * the four GPIOL signals.  Initialization covers value and direction,
  * as customized for each layout.
  */
-static int ftx232_init_tail(void)
+static int ftx232_dbus_write(void)
 {
        uint8_t  buf[3];
        uint32_t bytes_written;
 {
        uint8_t  buf[3];
        uint32_t bytes_written;
@@ -2452,19 +2463,19 @@ static int usbjtag_init(void)
         * NOTE:  This is now _specific_ to the "usbjtag" layout.
         * Don't try cram any more layouts into this.
         */
         * NOTE:  This is now _specific_ to the "usbjtag" layout.
         * Don't try cram any more layouts into this.
         */
-       ftx232_init_head();
+       ftx232_dbus_init();
 
        nTRST    = 0x10;
        nTRSTnOE = 0x10;
        nSRST    = 0x40;
        nSRSTnOE = 0x40;
 
 
        nTRST    = 0x10;
        nTRSTnOE = 0x10;
        nSRST    = 0x40;
        nSRSTnOE = 0x40;
 
-       return ftx232_init_tail();
+       return ftx232_dbus_write();
 }
 
 static int lm3s811_jtag_init(void)
 {
 }
 
 static int lm3s811_jtag_init(void)
 {
-       ftx232_init_head();
+       ftx232_dbus_init();
 
        /* There are multiple revisions of LM3S811 eval boards:
         * - Rev B (and older?) boards have no SWO trace support.
 
        /* There are multiple revisions of LM3S811 eval boards:
         * - Rev B (and older?) boards have no SWO trace support.
@@ -2478,12 +2489,12 @@ static int lm3s811_jtag_init(void)
        low_output    = 0x88;
        low_direction = 0x8b;
 
        low_output    = 0x88;
        low_direction = 0x8b;
 
-       return ftx232_init_tail();
+       return ftx232_dbus_write();
 }
 
 static int icdi_jtag_init(void)
 {
 }
 
 static int icdi_jtag_init(void)
 {
-       ftx232_init_head();
+       ftx232_dbus_init();
 
        /* Most Luminary eval boards support SWO trace output,
         * and should use this "luminary_icdi" layout.
 
        /* Most Luminary eval boards support SWO trace output,
         * and should use this "luminary_icdi" layout.
@@ -2495,18 +2506,18 @@ static int icdi_jtag_init(void)
        low_output    = 0x88;
        low_direction = 0xcb;
 
        low_output    = 0x88;
        low_direction = 0xcb;
 
-       return ftx232_init_tail();
+       return ftx232_dbus_write();
 }
 
 static int signalyzer_init(void)
 {
 }
 
 static int signalyzer_init(void)
 {
-       ftx232_init_head();
+       ftx232_dbus_init();
 
        nTRST    = 0x10;
        nTRSTnOE = 0x10;
        nSRST    = 0x20;
        nSRSTnOE = 0x20;
 
        nTRST    = 0x10;
        nTRSTnOE = 0x10;
        nSRST    = 0x20;
        nSRSTnOE = 0x20;
-       return ftx232_init_tail();
+       return ftx232_dbus_write();
 }
 
 static int axm0432_jtag_init(void)
 }
 
 static int axm0432_jtag_init(void)
@@ -3195,7 +3206,11 @@ COMMAND_HANDLER(ft2232_handle_layout_command)
        for (const struct ft2232_layout *l = ft2232_layouts; l->name; l++) {
                if (strcmp(l->name, CMD_ARGV[0]) == 0) {
                        layout = l;
        for (const struct ft2232_layout *l = ft2232_layouts; l->name; l++) {
                if (strcmp(l->name, CMD_ARGV[0]) == 0) {
                        layout = l;
-                       return ERROR_OK;
+                       /* This may also select the transport
+                        * if we only suppport one of them.
+                        */
+                       return allow_transports(CMD_CTX,
+                               l->transports ? : jtag_only);
                }
        }
 
                }
        }
 
index 97ceb013538d6dcc124ecb6dbe5b609c07b7502a..3b0a145bb47af4413284824c01b35ad94f2d52bf 100644 (file)
@@ -689,4 +689,6 @@ void jtag_poll_set_enabled(bool value);
  * level APIs that are used in inner loops. */
 #include <jtag/minidriver.h>
 
  * level APIs that are used in inner loops. */
 #include <jtag/minidriver.h>
 
+bool transport_is_jtag(void);
+
 #endif /* JTAG_H */
 #endif /* JTAG_H */
diff --git a/src/jtag/transport.c b/src/jtag/transport.c
new file mode 100644 (file)
index 0000000..cee8ffb
--- /dev/null
@@ -0,0 +1,373 @@
+/*
+ * Copyright (c) 2010 by David Brownell
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+/** @file
+ * Infrastructure for specifying and managing the transport protocol
+ * used in a given debug or programming session.
+ *
+ * Examples of "debug-capable" transports are JTAG or SWD.
+ * Additionally, JTAG supports boundary scan testing.
+ *
+ * Examples of "programming-capable" transports include SPI or UART;
+ * those are used (often mediated by a ROM bootloader) for ISP style
+ * programming, to perform an initial load of code into flash, or
+ * sometimes into SRAM.  Target code could use "variant" options to
+ * decide how to use such protocols.  For example, Cortex-M3 cores
+ * from TI/Luminary and from NXP use different protocols for for
+ * UART or SPI based firmware loading.
+ *
+ * As a rule, there are protocols layered on top of the transport.
+ * For example, different chip families use JTAG in different ways
+ * for debugging.  Also, each family that supports programming over
+ * a UART link for initial firmware loading tends to define its own
+ * messaging and error handling.
+ */
+
+#include <helper/log.h>
+
+#include "transport.h"
+
+/*-----------------------------------------------------------------------*/
+
+/*
+ * Infrastructure internals
+ */
+
+/** List of transports known to OpenOCD. */
+static struct transport *transport_list;
+
+/**
+ * NULL-terminated Vector of names of transports which the
+ * currently selected debug adapter supports.  This is declared
+ * by the time that adapter is fully set up.
+ */
+static const char **allowed_transports;
+
+/** * The transport being used for the current OpenOCD session.  */
+static struct transport *session;
+
+static  int transport_select(struct command_context *ctx, const char *name)
+{
+       /* name may only identify a known transport;
+        * caller guarantees session's transport isn't yet set.*/
+       for (struct transport *t = transport_list; t; t = t->next) {
+                       if (strcmp(t->name, name) == 0) {
+                               int retval = t->select(ctx);
+                       /* select() registers commands specific to this
+                        * transport, and may also reset the link, e.g.
+                        * forcing it to JTAG or SWD mode.
+                        */
+                       if (retval == ERROR_OK)
+                               session = t;
+                       else
+                               LOG_ERROR("Error %d selecting '%s' as "
+                                       "transport", retval, t->name);
+                       return retval;
+               }
+       }
+
+       LOG_ERROR("No transport named '%s' is available.", name);
+       return ERROR_FAIL;
+}
+
+/**
+ * Called by debug adapter drivers, or affiliated Tcl config scripts,
+ * to declare the set of transports supported by an adapter.  When
+ * there is only one member of that set, it is automatically selected.
+ */
+int allow_transports(struct command_context *ctx, const char **vector)
+{
+       /* NOTE:  caller is required to provide only a list
+        * of *valid* transport names
+        *
+        * REVISIT should we validate that?  and insist there's
+        * at least one non-NULL element in that list?
+        */
+       if (allowed_transports != NULL || session) {
+               LOG_ERROR("Can't modify the set of allowed transports.");
+               return ERROR_FAIL;
+       }
+
+
+       allowed_transports = vector;
+
+       /* autoselect if there's no choice ... */
+       if (!vector[1]) {
+               LOG_INFO("only one transport option; autoselect '%s'",
+                               vector[0]);
+               return transport_select(ctx, vector [0]);
+       } else {
+               while (*vector)
+                       LOG_DEBUG("allow transport '%s'", *vector++);
+               return ERROR_OK;
+       }
+}
+
+
+/**
+ * Used to verify corrrect adapter driver initialization.
+ *
+ * @returns true iff the adapter declared one or more transports.
+ */
+bool transports_are_declared(void)
+{
+       return allowed_transports != NULL;
+}
+
+/**
+ * Registers a transport.  There are general purpose transports
+ * (such as JTAG), as well as relatively proprietary ones which are
+ * specific to a given chip (or chip family).
+ *
+ * Code implementing a transport needs to register it before it can
+ * be selected and then activated.  This is a dynamic process, so
+ * that chips (and families) can define transports as needed (without
+ * nneeding error-prone static tables).
+ *
+ * @param new_transport the transport being registered.  On a
+ * successful return, this memory is owned by the transport framework.
+ *
+ * @returns ERROR_OK on success, else a fault code.
+ */
+int transport_register(struct transport *new_transport)
+{
+       struct transport *t;
+
+       for (t = transport_list; t; t = t->next) {
+               if (strcmp(t->name, new_transport->name) == 0) {
+                       LOG_ERROR("transport name already used");
+                       return ERROR_FAIL;
+               }
+       }
+
+       if (!new_transport->select || !new_transport->init) {
+               LOG_ERROR("invalid transport %s", new_transport->name);
+       }
+
+       /* splice this into the list */
+       new_transport->next = transport_list;
+       transport_list = new_transport;
+       LOG_DEBUG("register '%s'", t->name);
+
+       return ERROR_OK;
+}
+
+/**
+ * Returns the transport currently being used by this debug or
+ * programming session.
+ *
+ * @returns handle to the read-only transport entity.
+ */
+struct transport *get_current_transport(void)
+{
+
+       /* REVISIT -- constify */
+       return session;
+}
+
+
+/*-----------------------------------------------------------------------*/
+
+/*
+ * Infrastructure for Tcl interface to transports.
+ */
+
+/**
+ * Makes and stores a copy of a set of transports passed as
+ * parameters to a command.
+ *
+ * @param vector where the resulting copy is stored, as an argv-style
+ *     NULL-terminated vector.
+ */
+COMMAND_HELPER(transport_list_parse, char ***vector)
+{
+       char **argv;
+       unsigned n = CMD_ARGC;
+       unsigned j = 0;
+
+       *vector = NULL;
+
+       if (n < 1)
+               return ERROR_COMMAND_SYNTAX_ERROR;
+
+       /* our return vector must be NULL terminated */
+       argv = (char **) calloc(n + 1, sizeof(char *));
+       if (argv == NULL)
+               return ERROR_FAIL;
+
+       for (unsigned i = 0; i < n; i++) {
+               struct transport *t;
+
+               for (t = transport_list; t; t = t->next) {
+                       if (strcmp(t->name, CMD_ARGV[i]) != 0)
+                               continue;
+                       argv[j++] = strdup(CMD_ARGV[i]);
+                       break;
+               }
+               if (!t) {
+                       LOG_ERROR("no such transport '%s'", CMD_ARGV[i]);
+                       goto fail;
+               }
+       }
+
+       *vector = argv;
+       return ERROR_OK;
+
+fail:
+       for (unsigned i = 0; i < n; i++)
+               free(argv[i]);
+       free(argv);
+       return ERROR_FAIL;
+}
+
+COMMAND_HANDLER(handle_transport_init)
+{
+       LOG_DEBUG("%s", __func__);
+       if (!session) {
+               LOG_ERROR("session's transport is not selected.");
+               return ERROR_FAIL;
+       }
+
+       return session->init(CMD_CTX);
+}
+
+COMMAND_HANDLER(handle_transport_list)
+{
+       if (CMD_ARGC != 0)
+               return ERROR_COMMAND_SYNTAX_ERROR;
+
+       command_print(CMD_CTX, "The following transports are available:");
+
+       for (struct transport *t = transport_list; t; t = t->next)
+               command_print(CMD_CTX, "\t%s", t->name);
+
+       return ERROR_OK;
+}
+
+/**
+ * Implements the Tcl "transport select" command, choosing the
+ * transport to be used in this debug session from among the
+ * set supported by the debug adapter being used.
+ */
+COMMAND_HANDLER(handle_transport_select)
+{
+       int retval = ERROR_OK;;
+
+       switch (CMD_ARGC) {
+       case 0:                 /* "select" */
+               if (session) {
+                       goto show;
+               }
+               LOG_ERROR("session's transport is not selected.");
+               return ERROR_FAIL;
+
+       case 1:                 /* "select FOO" */
+               if(strcmp(session->name, CMD_ARGV[0]) == 0) {
+                       /* NOP */
+                       LOG_DEBUG("transport '%s' is already selected",
+                                       CMD_ARGV[0]);
+                       return ERROR_OK;
+               } else {
+
+               /* we can't change this session's transport after-the-fact */
+               if (session) {
+                       LOG_ERROR("session's transport is already selected.");
+                       return ERROR_FAIL;
+               }
+               }
+               break;
+
+       default:                /* select FOO BAR */
+               /* we only select *one* transport per session */
+               LOG_ERROR("may only select one transport!");
+               return ERROR_COMMAND_SYNTAX_ERROR;
+       }
+
+       /* Is this transport supported by our debug adapter?
+        * Example, "JTAG-only" means SWD is not supported.
+        *
+        * NOTE:  requires adapter to have been set up, including
+        * declaring transport via C code or Tcl script.
+        */
+       if (!allowed_transports) {
+               LOG_ERROR("Debug adapter doesn't support any transports?");
+               return ERROR_FAIL;
+       }
+       for (unsigned i = 0; allowed_transports[i]; i++) {
+
+               if (strcmp(allowed_transports[i], CMD_ARGV[0]) == 0)
+                       return transport_select(CMD_CTX, CMD_ARGV[0]);
+       }
+
+       LOG_ERROR("Debug adapter doesn't support '%s' "
+                       "transport?", CMD_ARGV[0]);
+       return ERROR_FAIL;
+
+
+show:
+       /* report the current transport selection */
+       command_print(CMD_CTX, "%s", session->name);
+       return retval;
+}
+
+static const struct command_registration transport_commands[] = {
+       {
+               .name = "init",
+               .handler = handle_transport_init,
+               /* this would be COMMAND_CONFIG ... except that
+                * it needs to trigger event handlers that may
+                * require COMMAND_EXEC ...
+                */
+               .mode = COMMAND_ANY,
+               .help = "Initialize this session's transport",
+       },
+       {
+               .name = "list",
+               .handler = handle_transport_list,
+               .mode = COMMAND_ANY,
+               .help = "list all built-in transports",
+       },
+       {
+               .name = "select",
+               .handler = handle_transport_select,
+               .mode = COMMAND_ANY,
+               .help = "Select this session's transport",
+               .usage = "[transport_name]",
+       },
+       COMMAND_REGISTRATION_DONE
+};
+
+static const struct command_registration transport_group[] = {
+       {
+               .name = "transport",
+               .mode = COMMAND_ANY,
+               .help = "Transport command group",
+               .chain = transport_commands,
+       },
+       COMMAND_REGISTRATION_DONE
+};
+
+
+int transport_register_commands(struct command_context *ctx)
+{
+       return register_commands(ctx, NULL, transport_group);
+}
diff --git a/src/jtag/transport.h b/src/jtag/transport.h
new file mode 100644 (file)
index 0000000..d2d38ec
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2010 by David Brownell
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "helper/command.h"
+
+/**
+ * Wrapper for transport lifecycle operations.
+ *
+ * OpenOCD talks to targets through some kind of debugging
+ * or programming adapter, using some protocol that probably
+ * has target-specific aspects.
+ *
+ * A "transport" reflects electrical protocol to the target,
+ * e..g jtag, swd, spi, uart, ... NOT the messaging protocols
+ * layered over it (e.g. JTAG has eICE, CoreSight, Nexus, OnCE,
+ * and more).
+ *
+ * In addition to the lifecycle operations packaged by this
+ * structure, a transport also involves  an interface supported
+ * by debug adapters and used by components such as debug targets.
+ * For non-debug transports,  there may be interfaces used to
+ * write to flash chips.
+ */
+struct transport {
+       /**
+        * Each transport has a unique name, used to select it
+        * from among the alternatives.  Examples might include
+        * "jtag", * "swd", "AVR_ISP" and more.
+        */
+       const char *name;
+
+       /**
+        * When a transport is selected, this method registers
+        * its commands and activates the transport (e.g. resets
+        * the link).
+        *
+        * After those commands are registered, they will often
+        * be used for further configuration of the debug link.
+        */
+       int (*select)(struct command_context *ctx);
+
+       /**
+        * server startup uses this method to validate transport
+        * configuration.  (For example, with JTAG this interrogates
+        * the scan chain against the list of expected TAPs.)
+        */
+       int (*init)(struct command_context *ctx);
+
+       /**
+        * Transports are stored in a singly linked list.
+        */
+       struct transport *next;
+};
+
+int transport_register(struct transport *new_transport);
+
+struct transport *get_current_transport(void);
+
+int transport_register_commands(struct command_context *ctx);
+
+COMMAND_HELPER(transport_list_parse, char ***vector);
+
+int allow_transports(struct command_context *ctx, const char **vector);
+
+bool transports_are_declared(void);
index 96de50c80cf701923f0572ee5b55b58e4f1fa814..bba1e0bf9cbc28c4cd629277e014410a7961f102 100644 (file)
 #include "openocd.h"
 #include <jtag/driver.h>
 #include <jtag/jtag.h>
 #include "openocd.h"
 #include <jtag/driver.h>
 #include <jtag/jtag.h>
+#include <jtag/transport.h>
 #include <helper/ioutil.h>
 #include <helper/configuration.h>
 #include <helper/ioutil.h>
 #include <helper/configuration.h>
-#include <xsvf/xsvf.h>
-#include <svf/svf.h>
 #include <flash/nor/core.h>
 #include <flash/nand/core.h>
 #include <pld/pld.h>
 #include <flash/nor/core.h>
 #include <flash/nand/core.h>
 #include <pld/pld.h>
@@ -120,22 +119,24 @@ COMMAND_HANDLER(handle_init_command)
                /* we must be able to set up the debug adapter */
                return retval;
        }
                /* we must be able to set up the debug adapter */
                return retval;
        }
+
        LOG_DEBUG("Debug Adapter init complete");
 
        LOG_DEBUG("Debug Adapter init complete");
 
-       /* Try to initialize & examine the JTAG chain at this point,
-        * but continue startup regardless.  Note that platforms
-        * need to be able to provide JTAG event handlers that use
-        * a variety of JTAG operations in order to do that...
+       /* "transport init" verifies the expected devices are present;
+        * for JTAG, it checks the list of configured TAPs against
+        * what's discoverable, possibly with help from the platform's
+        * JTAG event handlers.  (which require COMMAND_EXEC)
         */
        command_context_mode(CMD_CTX, COMMAND_EXEC);
         */
        command_context_mode(CMD_CTX, COMMAND_EXEC);
-       if (command_run_line(CMD_CTX, "jtag init") == ERROR_OK)
-       {
-               LOG_DEBUG("Examining targets...");
-               if (target_examine() != ERROR_OK)
-                       LOG_DEBUG("target examination failed");
-       }
-       else
-               LOG_WARNING("jtag initialization failed; try 'jtag init' again.");
+
+       retval = command_run_line(CMD_CTX, "transport init");
+       if (ERROR_OK != retval)
+               return ERROR_FAIL;
+
+       LOG_DEBUG("Examining targets...");
+       if (target_examine() != ERROR_OK)
+               LOG_DEBUG("target examination failed");
+
        command_context_mode(CMD_CTX, COMMAND_CONFIG);
 
        if (command_run_line(CMD_CTX, "flash init") != ERROR_OK)
        command_context_mode(CMD_CTX, COMMAND_CONFIG);
 
        if (command_run_line(CMD_CTX, "flash init") != ERROR_OK)
@@ -227,16 +228,13 @@ struct command_context *setup_command_handler(Jim_Interp *interp)
                &server_register_commands,
                &gdb_register_commands,
                &log_register_commands,
                &server_register_commands,
                &gdb_register_commands,
                &log_register_commands,
+               &transport_register_commands,
                &interface_register_commands,
                &interface_register_commands,
-               &jtag_register_commands,
-               &xsvf_register_commands,
-               &svf_register_commands,
                &target_register_commands,
                &flash_register_commands,
                &nand_register_commands,
                &pld_register_commands,
                &mflash_register_commands,
                &target_register_commands,
                &flash_register_commands,
                &nand_register_commands,
                &pld_register_commands,
                &mflash_register_commands,
-               NULL
        };
        for (unsigned i = 0; NULL != command_registrants[i]; i++)
        {
        };
        for (unsigned i = 0; NULL != command_registrants[i]; i++)
        {

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)