OpenOCD
transport/transport.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2010 by David Brownell
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8 
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13 
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 #ifdef HAVE_CONFIG_H
19 #include "config.h"
20 #endif
21 
44 #include <helper/log.h>
45 #include <transport/transport.h>
46 
47 extern struct command_context *global_cmd_ctx;
48 
49 /*-----------------------------------------------------------------------*/
50 
51 /*
52  * Infrastructure internals
53  */
54 
56 static struct transport *transport_list;
57 
63 static const char * const *allowed_transports;
64 
66 static struct transport *session;
67 
68 static int transport_select(struct command_context *ctx, const char *name)
69 {
70  /* name may only identify a known transport;
71  * caller guarantees session's transport isn't yet set.*/
72  for (struct transport *t = transport_list; t; t = t->next) {
73  if (strcmp(t->name, name) == 0) {
74  int retval = t->select(ctx);
75  /* select() registers commands specific to this
76  * transport, and may also reset the link, e.g.
77  * forcing it to JTAG or SWD mode.
78  */
79  if (retval == ERROR_OK)
80  session = t;
81  else
82  LOG_ERROR("Error selecting '%s' as transport", t->name);
83  return retval;
84  }
85  }
86 
87  LOG_ERROR("No transport named '%s' is available.", name);
88  return ERROR_FAIL;
89 }
90 
96 int allow_transports(struct command_context *ctx, const char * const *vector)
97 {
98  /* NOTE: caller is required to provide only a list
99  * of *valid* transport names
100  *
101  * REVISIT should we validate that? and insist there's
102  * at least one non-NULL element in that list?
103  *
104  * ... allow removals, e.g. external strapping prevents use
105  * of one transport; C code should be definitive about what
106  * can be used when all goes well.
107  */
108  if (allowed_transports != NULL || session) {
109  LOG_ERROR("Can't modify the set of allowed transports.");
110  return ERROR_FAIL;
111  }
112 
113  allowed_transports = vector;
114 
115  /* autoselect if there's no choice ... */
116  if (!vector[1]) {
117  LOG_INFO("only one transport option; autoselect '%s'", vector[0]);
118  return transport_select(ctx, vector[0]);
119  }
120 
121  return ERROR_OK;
122 }
123 
139 int transport_register(struct transport *new_transport)
140 {
141  struct transport *t;
142 
143  for (t = transport_list; t; t = t->next) {
144  if (strcmp(t->name, new_transport->name) == 0) {
145  LOG_ERROR("transport name already used");
146  return ERROR_FAIL;
147  }
148  }
149 
150  if (!new_transport->select || !new_transport->init)
151  LOG_ERROR("invalid transport %s", new_transport->name);
152 
153  /* splice this into the list */
154  new_transport->next = transport_list;
155  transport_list = new_transport;
156  LOG_DEBUG("register '%s'", new_transport->name);
157 
158  return ERROR_OK;
159 }
160 
168 {
169  /* REVISIT -- constify */
170  return session;
171 }
172 
173 /*-----------------------------------------------------------------------*/
174 
175 /*
176  * Infrastructure for Tcl interface to transports.
177  */
178 
186 COMMAND_HELPER(transport_list_parse, char ***vector)
187 {
188  char **argv;
189  unsigned n = CMD_ARGC;
190  unsigned j = 0;
191 
192  *vector = NULL;
193 
194  if (n < 1)
196 
197  /* our return vector must be NULL terminated */
198  argv = calloc(n + 1, sizeof(char *));
199  if (argv == NULL)
200  return ERROR_FAIL;
201 
202  for (unsigned i = 0; i < n; i++) {
203  struct transport *t;
204 
205  for (t = transport_list; t; t = t->next) {
206  if (strcmp(t->name, CMD_ARGV[i]) != 0)
207  continue;
208  argv[j++] = strdup(CMD_ARGV[i]);
209  break;
210  }
211  if (!t) {
212  LOG_ERROR("no such transport '%s'", CMD_ARGV[i]);
213  goto fail;
214  }
215  }
216 
217  *vector = argv;
218  return ERROR_OK;
219 
220 fail:
221  for (unsigned i = 0; i < n; i++)
222  free(argv[i]);
223  free(argv);
224  return ERROR_FAIL;
225 }
226 
227 COMMAND_HANDLER(handle_transport_init)
228 {
229  LOG_DEBUG("%s", __func__);
230  if (!session) {
231  LOG_ERROR("session transport was not selected. Use 'transport select <transport>'");
232 
233  /* no session transport configured, print transports then fail */
234  LOG_ERROR("Transports available:");
235  const char * const *vector = allowed_transports;
236  while (*vector) {
237  LOG_ERROR("%s", *vector);
238  vector++;
239  }
240  return ERROR_FAIL;
241  }
242 
243  return session->init(CMD_CTX);
244 }
245 
246 COMMAND_HANDLER(handle_transport_list)
247 {
248  if (CMD_ARGC != 0)
250 
251  command_print(CMD, "The following transports are available:");
252 
253  for (struct transport *t = transport_list; t; t = t->next)
254  command_print(CMD, "\t%s", t->name);
255 
256  return ERROR_OK;
257 }
258 
265 static int jim_transport_select(Jim_Interp *interp, int argc, Jim_Obj * const *argv)
266 {
267  int res;
268  switch (argc) {
269  case 1: /* autoselect if necessary, then return/display current config */
270  if (!session) {
271  if (!allowed_transports) {
272  LOG_ERROR("Debug adapter does not support any transports? Check config file order.");
273  return JIM_ERR;
274  }
275  LOG_INFO("auto-selecting first available session transport \"%s\". "
276  "To override use 'transport select <transport>'.", allowed_transports[0]);
277  res = transport_select(global_cmd_ctx, allowed_transports[0]);
278  if (res != JIM_OK)
279  return res;
280  }
281  Jim_SetResultString(interp, session->name, -1);
282  return JIM_OK;
283  case 2: /* assign */
284  if (session) {
285  if (!strcmp(session->name, argv[1]->bytes)) {
286  LOG_WARNING("Transport \"%s\" was already selected", session->name);
287  Jim_SetResultString(interp, session->name, -1);
288  return JIM_OK;
289  } else {
290  LOG_ERROR("Can't change session's transport after the initial selection was made");
291  return JIM_ERR;
292  }
293  }
294 
295  /* Is this transport supported by our debug adapter?
296  * Example, "JTAG-only" means SWD is not supported.
297  *
298  * NOTE: requires adapter to have been set up, with
299  * transports declared via C.
300  */
301  if (!allowed_transports) {
302  LOG_ERROR("Debug adapter doesn't support any transports?");
303  return JIM_ERR;
304  }
305 
306  for (unsigned i = 0; allowed_transports[i]; i++) {
307 
308  if (strcmp(allowed_transports[i], argv[1]->bytes) == 0) {
309  if (transport_select(global_cmd_ctx, argv[1]->bytes) == ERROR_OK) {
310  Jim_SetResultString(interp, session->name, -1);
311  return JIM_OK;
312  }
313  return JIM_ERR;
314  }
315  }
316 
317  LOG_ERROR("Debug adapter doesn't support '%s' transport", argv[1]->bytes);
318  return JIM_ERR;
319  default:
320  Jim_WrongNumArgs(interp, 1, argv, "[too many parameters]");
321  return JIM_ERR;
322  }
323 }
324 
325 static const struct command_registration transport_commands[] = {
326  {
327  .name = "init",
328  .handler = handle_transport_init,
329  /* this would be COMMAND_CONFIG ... except that
330  * it needs to trigger event handlers that may
331  * require COMMAND_EXEC ...
332  */
333  .mode = COMMAND_ANY,
334  .help = "Initialize this session's transport",
335  .usage = ""
336  },
337  {
338  .name = "list",
339  .handler = handle_transport_list,
340  .mode = COMMAND_ANY,
341  .help = "list all built-in transports",
342  .usage = ""
343  },
344  {
345  .name = "select",
346  .jim_handler = jim_transport_select,
347  .mode = COMMAND_ANY,
348  .help = "Select this session's transport",
349  .usage = "[transport_name]",
350  },
352 };
353 
354 static const struct command_registration transport_group[] = {
355  {
356  .name = "transport",
357  .mode = COMMAND_ANY,
358  .help = "Transport command group",
359  .chain = transport_commands,
360  .usage = ""
361  },
363 };
364 
366 {
367  return register_commands(ctx, NULL, transport_group);
368 }
static const struct command_registration transport_commands[]
static int jim_transport_select(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
Implements the Tcl "transport select" command, choosing the transport to be used in this debug sessio...
int register_commands(struct command_context *cmd_ctx, struct command *parent, const struct command_registration *cmds)
Register one or more commands in the specified context, as children of parent (or top-level commends...
Definition: command.c:398
const char * name
Definition: armv4_5.c:87
int transport_register_commands(struct command_context *ctx)
Wrapper for transport lifecycle operations.
Definition: transport.h:46
#define ERROR_FAIL
Definition: log.h:153
#define CMD_ARGV
Use this macro to access the arguments for the command being handled, rather than accessing the varia...
Definition: command.h:144
#define CMD_ARGC
Use this macro to access the number of arguments for the command being handled, rather than accessing...
Definition: command.h:139
static int transport_select(struct command_context *ctx, const char *name)
#define CMD
Use this macro to access the command being handled, rather than accessing the variable directly...
Definition: command.h:129
#define LOG_INFO(expr ...)
Definition: log.h:126
static const char *const * allowed_transports
NULL-terminated Vector of names of transports which the currently selected debug adapter supports...
void command_print(struct command_invocation *cmd, const char *format,...)
Definition: command.c:505
struct transport * next
Transports are stored in a singly linked list.
Definition: transport.h:82
static const struct command_registration transport_group[]
#define LOG_ERROR(expr ...)
Definition: log.h:132
int(* select)(struct command_context *ctx)
When a transport is selected, this method registers its commands and activates the transport (e...
Definition: transport.h:62
#define COMMAND_REGISTRATION_DONE
Use this as the last entry in an array of command_registration records.
Definition: command.h:234
#define ERROR_COMMAND_SYNTAX_ERROR
Definition: command.h:328
#define LOG_WARNING(expr ...)
Definition: log.h:129
COMMAND_HELPER(transport_list_parse, char ***vector)
Makes and stores a copy of a set of transports passed as parameters to a command. ...
int(* init)(struct command_context *ctx)
server startup uses this method to validate transport configuration.
Definition: transport.h:69
struct command_context * global_cmd_ctx
Definition: openocd.c:233
const char * name
Definition: command.h:216
#define CMD_CTX
Use this macro to access the context of the command being handled, rather than accessing the variable...
Definition: command.h:134
struct transport * get_current_transport(void)
Returns the transport currently being used by this debug or programming session.
const char * usage
a string listing the options and arguments, required or optional
Definition: command.h:222
#define ERROR_OK
Definition: log.h:147
const char * name
Each transport has a unique name, used to select it from among the alternatives.
Definition: transport.h:52
static struct transport * transport_list
List of transports known to OpenOCD.
COMMAND_HANDLER(handle_transport_init)
int transport_register(struct transport *new_transport)
Registers a transport.
#define NULL
Definition: usb.h:27
#define LOG_DEBUG(expr ...)
Definition: log.h:118
int allow_transports(struct command_context *ctx, const char *const *vector)
Called by debug adapter drivers, or affiliated Tcl config scripts, to declare the set of transports s...
static struct transport * session