OpenOCD
transport.c
Go to the documentation of this file.
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 
3 /*
4  * Copyright (c) 2010 by David Brownell
5  */
6 
7 #ifdef HAVE_CONFIG_H
8 #include "config.h"
9 #endif
10 
33 #include <helper/log.h>
34 #include <helper/replacements.h>
35 #include <transport/transport.h>
36 
37 extern struct command_context *global_cmd_ctx;
38 
39 /*-----------------------------------------------------------------------*/
40 
41 /*
42  * Infrastructure internals
43  */
44 
46 static struct transport *transport_list;
47 
53 static const char * const *allowed_transports;
54 
56 static struct transport *session;
57 
58 static int transport_select(struct command_context *ctx, const char *name)
59 {
60  /* name may only identify a known transport;
61  * caller guarantees session's transport isn't yet set.*/
62  for (struct transport *t = transport_list; t; t = t->next) {
63  if (strcmp(t->name, name) == 0) {
64  int retval = t->select(ctx);
65  /* select() registers commands specific to this
66  * transport, and may also reset the link, e.g.
67  * forcing it to JTAG or SWD mode.
68  */
69  if (retval == ERROR_OK)
70  session = t;
71  else
72  LOG_ERROR("Error selecting '%s' as transport", t->name);
73  return retval;
74  }
75  }
76 
77  LOG_ERROR("No transport named '%s' is available.", name);
78  return ERROR_FAIL;
79 }
80 
86 int allow_transports(struct command_context *ctx, const char * const *vector)
87 {
88  /* NOTE: caller is required to provide only a list
89  * of *valid* transport names
90  *
91  * REVISIT should we validate that? and insist there's
92  * at least one non-NULL element in that list?
93  *
94  * ... allow removals, e.g. external strapping prevents use
95  * of one transport; C code should be definitive about what
96  * can be used when all goes well.
97  */
98  if (allowed_transports || session) {
99  LOG_ERROR("Can't modify the set of allowed transports.");
100  return ERROR_FAIL;
101  }
102 
103  allowed_transports = vector;
104 
105  /* autoselect if there's no choice ... */
106  if (!vector[1]) {
107  LOG_INFO("only one transport option; autoselecting '%s'", vector[0]);
108  return transport_select(ctx, vector[0]);
109  }
110 
111  return ERROR_OK;
112 }
113 
129 int transport_register(struct transport *new_transport)
130 {
131  struct transport *t;
132 
133  for (t = transport_list; t; t = t->next) {
134  if (strcmp(t->name, new_transport->name) == 0) {
135  LOG_ERROR("transport name already used");
136  return ERROR_FAIL;
137  }
138  }
139 
140  if (!new_transport->select || !new_transport->init)
141  LOG_ERROR("invalid transport %s", new_transport->name);
142 
143  /* splice this into the list */
144  new_transport->next = transport_list;
145  transport_list = new_transport;
146  LOG_DEBUG("register '%s'", new_transport->name);
147 
148  return ERROR_OK;
149 }
150 
158 {
159  /* REVISIT -- constify */
160  return session;
161 }
162 
163 /*-----------------------------------------------------------------------*/
164 
165 /*
166  * Infrastructure for Tcl interface to transports.
167  */
168 
169 COMMAND_HANDLER(handle_transport_init)
170 {
171  LOG_DEBUG("%s", __func__);
172  if (!session) {
173  LOG_ERROR("session transport was not selected. Use 'transport select <transport>'");
174 
175  /* no session transport configured, print transports then fail */
176  LOG_ERROR("Transports available:");
177  const char * const *vector = allowed_transports;
178  while (*vector) {
179  LOG_ERROR("%s", *vector);
180  vector++;
181  }
182  return ERROR_FAIL;
183  }
184 
185  return session->init(CMD_CTX);
186 }
187 
188 COMMAND_HANDLER(handle_transport_list)
189 {
190  if (CMD_ARGC != 0)
192 
193  command_print(CMD, "The following transports are available:");
194 
195  for (struct transport *t = transport_list; t; t = t->next)
196  command_print(CMD, "\t%s", t->name);
197 
198  return ERROR_OK;
199 }
200 
207 COMMAND_HANDLER(handle_transport_select)
208 {
209  if (CMD_ARGC > 1)
211 
212  if (CMD_ARGC == 0) {
213  /* autoselect if necessary, then return/display current config */
214  if (!session) {
215  if (!allowed_transports) {
216  command_print(CMD, "Debug adapter does not support any transports? Check config file order.");
217  return ERROR_FAIL;
218  }
219  LOG_INFO("auto-selecting first available session transport \"%s\". "
220  "To override use 'transport select <transport>'.", allowed_transports[0]);
221  int retval = transport_select(CMD_CTX, allowed_transports[0]);
222  if (retval != ERROR_OK)
223  return retval;
224  }
225  command_print(CMD, "%s", session->name);
226  return ERROR_OK;
227  }
228 
229  /* assign transport */
230  if (session) {
231  if (!strcmp(session->name, CMD_ARGV[0])) {
232  LOG_WARNING("Transport \"%s\" was already selected", session->name);
233  return ERROR_OK;
234  }
235  command_print(CMD, "Can't change session's transport after the initial selection was made");
236  return ERROR_FAIL;
237  }
238 
239  /* Is this transport supported by our debug adapter?
240  * Example, "JTAG-only" means SWD is not supported.
241  *
242  * NOTE: requires adapter to have been set up, with
243  * transports declared via C.
244  */
245  if (!allowed_transports) {
246  command_print(CMD, "Debug adapter doesn't support any transports?");
247  return ERROR_FAIL;
248  }
249 
250  for (unsigned int i = 0; allowed_transports[i]; i++) {
251  if (!strcmp(allowed_transports[i], CMD_ARGV[0])) {
252  int retval = transport_select(CMD_CTX, CMD_ARGV[0]);
253  if (retval != ERROR_OK)
254  return retval;
255  return ERROR_OK;
256  }
257  }
258 
259  command_print(CMD, "Debug adapter doesn't support '%s' transport", CMD_ARGV[0]);
260  return ERROR_FAIL;
261 }
262 
263 static const struct command_registration transport_commands[] = {
264  {
265  .name = "init",
266  .handler = handle_transport_init,
267  /* this would be COMMAND_CONFIG ... except that
268  * it needs to trigger event handlers that may
269  * require COMMAND_EXEC ...
270  */
271  .mode = COMMAND_ANY,
272  .help = "Initialize this session's transport",
273  .usage = ""
274  },
275  {
276  .name = "list",
277  .handler = handle_transport_list,
278  .mode = COMMAND_ANY,
279  .help = "list all built-in transports",
280  .usage = ""
281  },
282  {
283  .name = "select",
284  .handler = handle_transport_select,
285  .mode = COMMAND_ANY,
286  .help = "Select this session's transport",
287  .usage = "[transport_name]",
288  },
290 };
291 
292 static const struct command_registration transport_group[] = {
293  {
294  .name = "transport",
295  .mode = COMMAND_ANY,
296  .help = "Transport command group",
297  .chain = transport_commands,
298  .usage = ""
299  },
301 };
302 
304 {
305  return register_commands(ctx, NULL, transport_group);
306 }
const char * name
Definition: armv4_5.c:76
void command_print(struct command_invocation *cmd, const char *format,...)
Definition: command.c:443
#define CMD
Use this macro to access the command being handled, rather than accessing the variable directly.
Definition: command.h:141
#define CMD_ARGV
Use this macro to access the arguments for the command being handled, rather than accessing the varia...
Definition: command.h:156
#define ERROR_COMMAND_SYNTAX_ERROR
Definition: command.h:402
#define CMD_ARGC
Use this macro to access the number of arguments for the command being handled, rather than accessing...
Definition: command.h:151
#define CMD_CTX
Use this macro to access the context of the command being handled, rather than accessing the variable...
Definition: command.h:146
#define COMMAND_REGISTRATION_DONE
Use this as the last entry in an array of command_registration records.
Definition: command.h:253
static int register_commands(struct command_context *cmd_ctx, const char *cmd_prefix, const struct command_registration *cmds)
Register one or more commands in the specified context, as children of parent (or top-level commends,...
Definition: command.h:274
@ COMMAND_ANY
Definition: command.h:42
#define LOG_WARNING(expr ...)
Definition: log.h:130
#define ERROR_FAIL
Definition: log.h:174
#define LOG_ERROR(expr ...)
Definition: log.h:133
#define LOG_INFO(expr ...)
Definition: log.h:127
#define LOG_DEBUG(expr ...)
Definition: log.h:110
#define ERROR_OK
Definition: log.h:168
const char * name
Definition: command.h:235
const char * usage
a string listing the options and arguments, required or optional
Definition: command.h:241
Wrapper for transport lifecycle operations.
Definition: transport.h:35
int(* select)(struct command_context *ctx)
When a transport is selected, this method registers its commands and activates the transport (e....
Definition: transport.h:51
int(* init)(struct command_context *ctx)
server startup uses this method to validate transport configuration.
Definition: transport.h:58
struct transport * next
Transports are stored in a singly linked list.
Definition: transport.h:71
const char * name
Each transport has a unique name, used to select it from among the alternatives.
Definition: transport.h:41
static const struct command_registration transport_group[]
Definition: transport.c:292
struct command_context * global_cmd_ctx
Definition: openocd.c:233
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...
Definition: transport.c:86
static struct transport * transport_list
List of transports known to OpenOCD.
Definition: transport.c:46
static int transport_select(struct command_context *ctx, const char *name)
Definition: transport.c:58
COMMAND_HANDLER(handle_transport_init)
Definition: transport.c:169
static const char *const * allowed_transports
NULL-terminated Vector of names of transports which the currently selected debug adapter supports.
Definition: transport.c:53
static const struct command_registration transport_commands[]
Definition: transport.c:263
int transport_register_commands(struct command_context *ctx)
Definition: transport.c:303
static struct transport * session
Definition: transport.c:56
struct transport * get_current_transport(void)
Returns the transport currently being used by this debug or programming session.
Definition: transport.c:157
int transport_register(struct transport *new_transport)
Registers a transport.
Definition: transport.c:129
#define NULL
Definition: usb.h:16