diff --git a/src/command.c b/src/command.c index caa2ea6..1fbb2be 100644 --- a/src/command.c +++ b/src/command.c @@ -20,8 +20,6 @@ /* This file implements a basic command interpreter for GDB 'monitor' * commands. - * - * TODO: Add a mechanism for target driver so register new commands. */ #include @@ -37,15 +35,15 @@ #include "adiv5.h" -static void cmd_version(void); -static void cmd_help(void); +static bool cmd_version(void); +static bool cmd_help(void); -static void cmd_jtag_scan(void); -static void cmd_swdp_scan(void); -static void cmd_targets(void); -static void cmd_morse(void); +static bool cmd_jtag_scan(void); +static bool cmd_swdp_scan(void); +static bool cmd_targets(void); +static bool cmd_morse(void); #ifdef PLATFORM_HAS_TRACESWO -static void cmd_traceswo(void); +static bool cmd_traceswo(void); #endif const struct command_s cmd_list[] = { @@ -64,6 +62,7 @@ const struct command_s cmd_list[] = { int command_process(char *cmd) { + struct target_command_s *tc; const struct command_s *c; int argc = 0; const char **argv; @@ -83,32 +82,47 @@ int command_process(char *cmd) /* Accept a partial match as GDB does. * So 'mon ver' will match 'monitor version' */ - if(!strncmp(argv[0], c->cmd, strlen(argv[0]))) { - c->handler(argc, argv); - return 0; - } + if(!strncmp(argv[0], c->cmd, strlen(argv[0]))) + return !c->handler(cur_target, argc, argv); } + for (tc = cur_target->commands; tc; tc = tc->next) + for(c = tc->cmds; c->cmd; c++) + if(!strncmp(argv[0], c->cmd, strlen(argv[0]))) + return !c->handler(cur_target, argc, argv); + return -1; } -void cmd_version(void) +bool cmd_version(void) { gdb_out("Black Magic Probe (Firmware 1.5" VERSION_SUFFIX ", build " BUILDDATE ")\n"); gdb_out("Copyright (C) 2011 Black Sphere Technologies Ltd.\n"); gdb_out("License GPLv3+: GNU GPL version 3 or later " "\n\n"); + + return true; } -void cmd_help(void) +bool cmd_help(void) { + struct target_command_s *tc; const struct command_s *c; + gdb_out("General commands:\n"); for(c = cmd_list; c->cmd; c++) - gdb_outf("%s -- %s\n", c->cmd, c->help); + gdb_outf("\t%s -- %s\n", c->cmd, c->help); + + for (tc = cur_target->commands; tc; tc = tc->next) { + gdb_outf("%s specific commands:\n", tc->specific_name); + for(c = tc->cmds; c->cmd; c++) + gdb_outf("\t%s -- %s\n", c->cmd, c->help); + } + + return true; } -void cmd_jtag_scan(void) +bool cmd_jtag_scan(void) { gdb_outf("Target voltage: %s\n", platform_target_voltage()); @@ -116,11 +130,11 @@ void cmd_jtag_scan(void) if(devs < 0) { gdb_out("JTAG device scan failed!\n"); - return; + return false; } if(devs == 0) { gdb_out("JTAG scan found no devices!\n"); - return; + return false; } gdb_outf("Device IR Len IDCODE Description\n"); for(int i = 0; i < jtag_dev_count; i++) @@ -129,30 +143,33 @@ void cmd_jtag_scan(void) jtag_devs[i].descr); gdb_out("\n"); cmd_targets(); + return true; } -void cmd_swdp_scan(void) +bool cmd_swdp_scan(void) { gdb_outf("Target voltage: %s\n", platform_target_voltage()); if(adiv5_swdp_scan() < 0) { gdb_out("SW-DP scan failed!\n"); - return; + return false; } gdb_outf("SW-DP detected IDCODE: 0x%08X\n", adiv5_dp_list->idcode); cmd_targets(); + return true; + } -void cmd_targets(void) +bool cmd_targets(void) { struct target_s *t; int i; if(!target_list) { gdb_out("No usable targets found.\n"); - return; + return false; } gdb_out("Available Targets:\n"); @@ -160,20 +177,24 @@ void cmd_targets(void) for(t = target_list, i = 1; t; t = t->next, i++) gdb_outf("%2d %c %s\n", i, t==cur_target?'*':' ', t->driver); + + return true; } -void cmd_morse(void) +bool cmd_morse(void) { if(morse_msg) gdb_outf("%s\n", morse_msg); + return true; } #ifdef PLATFORM_HAS_TRACESWO -static void cmd_traceswo(void) +static bool cmd_traceswo(void) { extern char serial_no[9]; traceswo_init(); gdb_outf("%s:%02X:%02X\n", serial_no, 5, 0x85); + return true; } #endif diff --git a/src/gdb_main.c b/src/gdb_main.c index 316a186..dc00e2e 100644 --- a/src/gdb_main.c +++ b/src/gdb_main.c @@ -330,9 +330,13 @@ handle_q_packet(char *packet, int len) unhexify(data, packet+6, datalen); data[datalen] = 0; /* add terminating null */ - if(command_process(data) < 0) - gdb_putpacket("", 0); - else gdb_putpacket("OK", 2); + int c = command_process(data); + if(c < 0) + gdb_putpacketz(""); + else if(c == 0) + gdb_putpacketz("OK"); + else + gdb_putpacketz("E"); } else if (!strncmp (packet, "qSupported", 10)) { /* Query supported protocol features */ diff --git a/src/include/command.h b/src/include/command.h index 34db13d..a44ed13 100644 --- a/src/include/command.h +++ b/src/include/command.h @@ -22,9 +22,10 @@ #define __COMMAND_H #include "general.h" +#include "target.h" int command_process(char *cmd); -typedef void (*cmd_handler)(int argc, const char **argv); +typedef bool (*cmd_handler)(target *t, int argc, const char **argv); struct command_s { const char *cmd; diff --git a/src/include/general.h b/src/include/general.h index 65ec2af..b0721ac 100644 --- a/src/include/general.h +++ b/src/include/general.h @@ -29,6 +29,7 @@ #endif #include +#include #endif diff --git a/src/include/target.h b/src/include/target.h index 5f3a5ab..dc602aa 100644 --- a/src/include/target.h +++ b/src/include/target.h @@ -27,9 +27,6 @@ typedef struct target_s target; -target *target_new(unsigned size); -void target_list_free(void); - /* Halt/resume functions */ #define target_attach(target) \ (target)->attach(target) @@ -164,13 +161,25 @@ struct target_s { const uint8_t *src, int len); const char *driver; + struct target_command_s *commands; int size; struct target_s *next; + +}; + +struct target_command_s { + const char *specific_name; + const struct command_s *cmds; + struct target_command_s *next; }; extern target *target_list, *cur_target, *last_target; +target *target_new(unsigned size); +void target_list_free(void); +void target_add_commands(target *t, const struct command_s *cmds, const char *name); + /* Probe for various targets. * Actual functions implemented in their respective drivers. */ diff --git a/src/target.c b/src/target.c index 1c70340..4f2917f 100644 --- a/src/target.c +++ b/src/target.c @@ -38,11 +38,32 @@ target *target_new(unsigned size) void target_list_free(void) { + struct target_command_s *tc; + while(target_list) { target *t = target_list->next; + while (target_list->commands) { + tc = target_list->commands->next; + free(target_list->commands); + target_list->commands = tc; + } free(target_list); target_list = t; } last_target = cur_target = NULL; } +void target_add_commands(target *t, const struct command_s *cmds, const char *name) +{ + struct target_command_s *tc; + if (t->commands) { + for (tc = t->commands; tc->next; tc = tc->next); + tc = tc->next = malloc(sizeof(*tc)); + } else { + t->commands = tc = malloc(sizeof(*tc)); + } + tc->specific_name = name; + tc->cmds = cmds; + tc->next = NULL; +} +