diff options
author | David Brownell <dbrownell@users.sourceforge.net> | 2010-07-02 16:45:28 -0400 |
---|---|---|
committer | David Brownell <db@helium.(none)> | 2010-07-02 16:45:28 -0400 |
commit | 93f2afa45f4cfcb8afd08dae5a17996dba5c7a9c (patch) | |
tree | 0c03935bd09e77c5edd98e1b356f0ffbc3df239b | |
parent | deb176d33514eb6b702b14043c338b2d0053f11d (diff) | |
download | openocd_libswd-93f2afa45f4cfcb8afd08dae5a17996dba5c7a9c.tar.gz openocd_libswd-93f2afa45f4cfcb8afd08dae5a17996dba5c7a9c.tar.bz2 openocd_libswd-93f2afa45f4cfcb8afd08dae5a17996dba5c7a9c.tar.xz openocd_libswd-93f2afa45f4cfcb8afd08dae5a17996dba5c7a9c.zip |
initial "transport" framework
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)>
-rw-r--r-- | NEWS | 3 | ||||
-rw-r--r-- | doc/openocd.texi | 44 | ||||
-rw-r--r-- | src/jtag/Makefile.am | 2 | ||||
-rw-r--r-- | src/jtag/adapter.c | 27 | ||||
-rw-r--r-- | src/jtag/core.c | 61 | ||||
-rw-r--r-- | src/jtag/drivers/ft2232.c | 37 | ||||
-rw-r--r-- | src/jtag/jtag.h | 2 | ||||
-rw-r--r-- | src/jtag/transport.c | 373 | ||||
-rw-r--r-- | src/jtag/transport.h | 80 | ||||
-rw-r--r-- | src/openocd.c | 34 |
10 files changed, 633 insertions, 30 deletions
@@ -17,6 +17,9 @@ JTAG Layer: 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). diff --git a/doc/openocd.texi b/doc/openocd.texi index a3ca1247..a765727c 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -2096,6 +2096,14 @@ target. 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. @@ -2428,7 +2436,41 @@ Turn power switch to target on/off. 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 diff --git a/src/jtag/Makefile.am b/src/jtag/Makefile.am index 910affc1..59cd8fff 100644 --- a/src/jtag/Makefile.am +++ b/src/jtag/Makefile.am @@ -58,6 +58,7 @@ libjtag_la_SOURCES = \ interface.c \ interfaces.c \ tcl.c \ + transport.c \ $(DRIVERFILES) noinst_HEADERS = \ @@ -67,6 +68,7 @@ noinst_HEADERS = \ interfaces.h \ minidriver.h \ jtag.h \ + transport.h \ minidriver/minidriver_imp.h \ minidummy/jtag_minidriver.h diff --git a/src/jtag/adapter.c b/src/jtag/adapter.c index 50e2a022..15b3ddc2 100644 --- a/src/jtag/adapter.c +++ b/src/jtag/adapter.c @@ -35,6 +35,7 @@ #include "minidriver.h" #include "interface.h" #include "interfaces.h" +#include "transport.h" #ifdef HAVE_STRINGS_H #include <strings.h> @@ -92,6 +93,25 @@ static int default_srst_asserted(int *srst_asserted) 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) @@ -452,6 +472,13 @@ static const struct command_registration interface_command_handlers[] = { .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, .mode = COMMAND_ANY, diff --git a/src/jtag/core.c b/src/jtag/core.c index 782f10f7..1643d9b6 100644 --- a/src/jtag/core.c +++ b/src/jtag/core.c @@ -33,11 +33,15 @@ #include "jtag.h" #include "interface.h" +#include "transport.h" #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; @@ -1348,6 +1352,21 @@ int adapter_init(struct command_context *cmd_ctx) 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); @@ -1706,3 +1725,45 @@ unsigned jtag_get_ntrst_assert_width(void) { 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; +} diff --git a/src/jtag/drivers/ft2232.c b/src/jtag/drivers/ft2232.c index f315d699..f02ae626 100644 --- a/src/jtag/drivers/ft2232.c +++ b/src/jtag/drivers/ft2232.c @@ -81,6 +81,7 @@ /* project specific includes */ #include <jtag/interface.h> +#include <jtag/transport.h> #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; + const char **transports; }; /* 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); +/* 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", @@ -235,10 +244,12 @@ static const struct ft2232_layout ft2232_layouts[] = { .name = "evb_lm3s811", .init = lm3s811_jtag_init, .reset = ftx23_reset, + .transports = jtag_and_swd, }, { .name = "luminary_icdi", .init = icdi_jtag_init, .reset = ftx23_reset, + .transports = jtag_and_swd, }, { .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. */ -static inline void ftx232_init_head(void) +static inline void ftx232_dbus_init(void) { 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. */ -static int ftx232_init_tail(void) +static int ftx232_dbus_write(void) { 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. */ - ftx232_init_head(); + ftx232_dbus_init(); nTRST = 0x10; nTRSTnOE = 0x10; nSRST = 0x40; nSRSTnOE = 0x40; - return ftx232_init_tail(); + return ftx232_dbus_write(); } 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. @@ -2478,12 +2489,12 @@ static int lm3s811_jtag_init(void) low_output = 0x88; low_direction = 0x8b; - return ftx232_init_tail(); + return ftx232_dbus_write(); } 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. @@ -2495,18 +2506,18 @@ static int icdi_jtag_init(void) low_output = 0x88; low_direction = 0xcb; - return ftx232_init_tail(); + return ftx232_dbus_write(); } static int signalyzer_init(void) { - ftx232_init_head(); + ftx232_dbus_init(); nTRST = 0x10; nTRSTnOE = 0x10; nSRST = 0x20; nSRSTnOE = 0x20; - return ftx232_init_tail(); + return ftx232_dbus_write(); } 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; - 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); } } diff --git a/src/jtag/jtag.h b/src/jtag/jtag.h index 97ceb013..3b0a145b 100644 --- a/src/jtag/jtag.h +++ b/src/jtag/jtag.h @@ -689,4 +689,6 @@ void jtag_poll_set_enabled(bool value); * level APIs that are used in inner loops. */ #include <jtag/minidriver.h> +bool transport_is_jtag(void); + #endif /* JTAG_H */ diff --git a/src/jtag/transport.c b/src/jtag/transport.c new file mode 100644 index 00000000..cee8ffb3 --- /dev/null +++ b/src/jtag/transport.c @@ -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 index 00000000..d2d38ec2 --- /dev/null +++ b/src/jtag/transport.h @@ -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); diff --git a/src/openocd.c b/src/openocd.c index 96de50c8..bba1e0bf 100644 --- a/src/openocd.c +++ b/src/openocd.c @@ -31,10 +31,9 @@ #include "openocd.h" #include <jtag/driver.h> #include <jtag/jtag.h> +#include <jtag/transport.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> @@ -120,22 +119,24 @@ COMMAND_HANDLER(handle_init_command) /* we must be able to set up the debug adapter */ return retval; } + 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); - 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) @@ -227,16 +228,13 @@ struct command_context *setup_command_handler(Jim_Interp *interp) &server_register_commands, &gdb_register_commands, &log_register_commands, + &transport_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, - NULL }; for (unsigned i = 0; NULL != command_registrants[i]; i++) { |