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)>tags/v0.5.0-rc1
@@ -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). | |||
@@ -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 | |||
@@ -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 | |||
@@ -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) | |||
@@ -451,6 +471,13 @@ static const struct command_registration interface_command_handlers[] = { | |||
.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, | |||
@@ -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; | |||
} |
@@ -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); | |||
} | |||
} | |||
@@ -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 */ |
@@ -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); | |||
} |
@@ -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); |
@@ -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++) | |||
{ | |||