X-Git-Url: https://review.openocd.org/gitweb?p=openocd.git;a=blobdiff_plain;f=src%2Ftarget%2Ftarget.c;h=8a7547b8a706a46332928b1bad6c4d81f054883b;hp=9f12704a5c2c767c2b8afe179458cc2eba289e5a;hb=d3c2679bcb8e8ba25e7b6e443b39f57474afc099;hpb=25e7a69e266b7c848af3c88f5743c88120d28d0f diff --git a/src/target/target.c b/src/target/target.c index 9f12704a5c..8a7547b8a7 100644 --- a/src/target/target.c +++ b/src/target/target.c @@ -139,6 +139,7 @@ static struct target_type *target_types[] = { struct target *all_targets; static struct target_event_callback *target_event_callbacks; static struct target_timer_callback *target_timer_callbacks; +LIST_HEAD(target_reset_callback_list); static const int polling_interval = 100; static const Jim_Nvp nvp_assert[] = { @@ -216,6 +217,8 @@ static const Jim_Nvp nvp_target_event[] = { { .value = TARGET_EVENT_GDB_FLASH_ERASE_START, .name = "gdb-flash-erase-start" }, { .value = TARGET_EVENT_GDB_FLASH_ERASE_END , .name = "gdb-flash-erase-end" }, + { .value = TARGET_EVENT_TRACE_CONFIG, .name = "trace-config" }, + { .name = NULL, .value = -1 } }; @@ -280,6 +283,28 @@ const char *target_state_name(struct target *t) return cp; } +const char *target_event_name(enum target_event event) +{ + const char *cp; + cp = Jim_Nvp_value2name_simple(nvp_target_event, event)->name; + if (!cp) { + LOG_ERROR("Invalid target event: %d", (int)(event)); + cp = "(*BUG*unknown*BUG*)"; + } + return cp; +} + +const char *target_reset_mode_name(enum target_reset_mode reset_mode) +{ + const char *cp; + cp = Jim_Nvp_value2name_simple(nvp_reset_modes, reset_mode)->name; + if (!cp) { + LOG_ERROR("Invalid target reset mode: %d", (int)(reset_mode)); + cp = "(*BUG*unknown*BUG*)"; + } + return cp; +} + /* determine the number of the new target */ static int new_target_number(void) { @@ -601,6 +626,10 @@ static int target_process_reset(struct command_context *cmd_ctx, enum target_res return ERROR_FAIL; } + struct target *target; + for (target = all_targets; target; target = target->next) + target_call_reset_callbacks(target, reset_mode); + /* disable polling during reset to make reset event scripts * more predictable, i.e. dr/irscan & pathmove in events will * not have JTAG operations injected into the middle of a sequence. @@ -623,7 +652,6 @@ static int target_process_reset(struct command_context *cmd_ctx, enum target_res /* We want any events to be processed before the prompt */ retval = target_call_timer_callbacks_now(); - struct target *target; for (target = all_targets; target; target = target->next) { target->type->check_reset(target); target->running_alg = false; @@ -659,7 +687,15 @@ static int default_check_reset(struct target *target) int target_examine_one(struct target *target) { - return target->type->examine(target); + target_call_event_callbacks(target, TARGET_EVENT_EXAMINE_START); + + int retval = target->type->examine(target); + if (retval != ERROR_OK) + return retval; + + target_call_event_callbacks(target, TARGET_EVENT_EXAMINE_END); + + return ERROR_OK; } static int jtag_enable_callback(enum jtag_event event, void *priv) @@ -671,15 +707,7 @@ static int jtag_enable_callback(enum jtag_event event, void *priv) jtag_unregister_event_callback(jtag_enable_callback, target); - target_call_event_callbacks(target, TARGET_EVENT_EXAMINE_START); - - int retval = target_examine_one(target); - if (retval != ERROR_OK) - return retval; - - target_call_event_callbacks(target, TARGET_EVENT_EXAMINE_END); - - return retval; + return target_examine_one(target); } /* Targets that correctly implement init + examine, i.e. @@ -700,13 +728,9 @@ int target_examine(void) continue; } - target_call_event_callbacks(target, TARGET_EVENT_EXAMINE_START); - retval = target_examine_one(target); if (retval != ERROR_OK) return retval; - - target_call_event_callbacks(target, TARGET_EVENT_EXAMINE_END); } return retval; } @@ -914,7 +938,7 @@ int target_run_flash_async_algorithm(struct target *target, break; } - if ((rp & (block_size - 1)) || rp < fifo_start_addr || rp >= fifo_end_addr) { + if (((rp - fifo_start_addr) & (block_size - 1)) || rp < fifo_start_addr || rp >= fifo_end_addr) { LOG_ERROR("corrupted fifo read pointer 0x%" PRIx32, rp); break; } @@ -1312,6 +1336,28 @@ int target_register_event_callback(int (*callback)(struct target *target, return ERROR_OK; } +int target_register_reset_callback(int (*callback)(struct target *target, + enum target_reset_mode reset_mode, void *priv), void *priv) +{ + struct target_reset_callback *entry; + + if (callback == NULL) + return ERROR_COMMAND_SYNTAX_ERROR; + + entry = malloc(sizeof(struct target_reset_callback)); + if (entry == NULL) { + LOG_ERROR("error allocating buffer for reset callback entry"); + return ERROR_COMMAND_SYNTAX_ERROR; + } + + entry->callback = callback; + entry->priv = priv; + list_add(&entry->list, &target_reset_callback_list); + + + return ERROR_OK; +} + int target_register_timer_callback(int (*callback)(void *priv), int time_ms, int periodic, void *priv) { struct target_timer_callback **callbacks_p = &target_timer_callbacks; @@ -1330,6 +1376,7 @@ int target_register_timer_callback(int (*callback)(void *priv), int time_ms, int (*callbacks_p)->callback = callback; (*callbacks_p)->periodic = periodic; (*callbacks_p)->time_ms = time_ms; + (*callbacks_p)->removed = false; gettimeofday(&now, NULL); (*callbacks_p)->when.tv_usec = now.tv_usec + (time_ms % 1000) * 1000; @@ -1369,26 +1416,39 @@ int target_unregister_event_callback(int (*callback)(struct target *target, return ERROR_OK; } -int target_unregister_timer_callback(int (*callback)(void *priv), void *priv) +int target_unregister_reset_callback(int (*callback)(struct target *target, + enum target_reset_mode reset_mode, void *priv), void *priv) { - struct target_timer_callback **p = &target_timer_callbacks; - struct target_timer_callback *c = target_timer_callbacks; + struct target_reset_callback *entry; if (callback == NULL) return ERROR_COMMAND_SYNTAX_ERROR; - while (c) { - struct target_timer_callback *next = c->next; + list_for_each_entry(entry, &target_reset_callback_list, list) { + if (entry->callback == callback && entry->priv == priv) { + list_del(&entry->list); + free(entry); + break; + } + } + + return ERROR_OK; +} + +int target_unregister_timer_callback(int (*callback)(void *priv), void *priv) +{ + if (callback == NULL) + return ERROR_COMMAND_SYNTAX_ERROR; + + for (struct target_timer_callback *c = target_timer_callbacks; + c; c = c->next) { if ((c->callback == callback) && (c->priv == priv)) { - *p = next; - free(c); + c->removed = true; return ERROR_OK; - } else - p = &(c->next); - c = next; + } } - return ERROR_OK; + return ERROR_FAIL; } int target_call_event_callbacks(struct target *target, enum target_event event) @@ -1415,6 +1475,19 @@ int target_call_event_callbacks(struct target *target, enum target_event event) return ERROR_OK; } +int target_call_reset_callbacks(struct target *target, enum target_reset_mode reset_mode) +{ + struct target_reset_callback *callback; + + LOG_DEBUG("target reset %i (%s)", reset_mode, + Jim_Nvp_value2name_simple(nvp_reset_modes, reset_mode)->name); + + list_for_each_entry(callback, &target_reset_callback_list, list) + callback->callback(target, reset_mode, callback->priv); + + return ERROR_OK; +} + static int target_timer_callback_periodic_restart( struct target_timer_callback *cb, struct timeval *now) { @@ -1442,31 +1515,44 @@ static int target_call_timer_callback(struct target_timer_callback *cb, static int target_call_timer_callbacks_check_time(int checktime) { + static bool callback_processing; + + /* Do not allow nesting */ + if (callback_processing) + return ERROR_OK; + + callback_processing = true; + keep_alive(); struct timeval now; gettimeofday(&now, NULL); - struct target_timer_callback *callback = target_timer_callbacks; - while (callback) { - /* cleaning up may unregister and free this callback */ - struct target_timer_callback *next_callback = callback->next; + /* Store an address of the place containing a pointer to the + * next item; initially, that's a standalone "root of the + * list" variable. */ + struct target_timer_callback **callback = &target_timer_callbacks; + while (*callback) { + if ((*callback)->removed) { + struct target_timer_callback *p = *callback; + *callback = (*callback)->next; + free(p); + continue; + } - bool call_it = callback->callback && - ((!checktime && callback->periodic) || - now.tv_sec > callback->when.tv_sec || - (now.tv_sec == callback->when.tv_sec && - now.tv_usec >= callback->when.tv_usec)); + bool call_it = (*callback)->callback && + ((!checktime && (*callback)->periodic) || + now.tv_sec > (*callback)->when.tv_sec || + (now.tv_sec == (*callback)->when.tv_sec && + now.tv_usec >= (*callback)->when.tv_usec)); - if (call_it) { - int retval = target_call_timer_callback(callback, &now); - if (retval != ERROR_OK) - return retval; - } + if (call_it) + target_call_timer_callback(*callback, &now); - callback = next_callback; + callback = &(*callback)->next; } + callback_processing = false; return ERROR_OK; } @@ -1716,6 +1802,31 @@ int target_free_working_area(struct target *target, struct working_area *area) return target_free_working_area_restore(target, area, 1); } +void target_quit(void) +{ + struct target_event_callback *pe = target_event_callbacks; + while (pe) { + struct target_event_callback *t = pe->next; + free(pe); + pe = t; + } + target_event_callbacks = NULL; + + struct target_timer_callback *pt = target_timer_callbacks; + while (pt) { + struct target_timer_callback *t = pt->next; + free(pt); + pt = t; + } + target_timer_callbacks = NULL; + + for (struct target *target = all_targets; + target; target = target->next) { + if (target->type->deinit_target) + target->type->deinit_target(target); + } +} + /* free resources and restore memory, if restoring memory fails, * free up resources anyway */ @@ -5333,55 +5444,6 @@ static int jim_target_create(Jim_Interp *interp, int argc, Jim_Obj *const *argv) return target_create(&goi); } -static int jim_target_number(Jim_Interp *interp, int argc, Jim_Obj *const *argv) -{ - Jim_GetOptInfo goi; - Jim_GetOpt_Setup(&goi, interp, argc - 1, argv + 1); - - /* It's OK to remove this mechanism sometime after August 2010 or so */ - LOG_WARNING("don't use numbers as target identifiers; use names"); - if (goi.argc != 1) { - Jim_SetResultFormatted(goi.interp, "usage: target number "); - return JIM_ERR; - } - jim_wide w; - int e = Jim_GetOpt_Wide(&goi, &w); - if (e != JIM_OK) - return JIM_ERR; - - struct target *target; - for (target = all_targets; NULL != target; target = target->next) { - if (target->target_number != w) - continue; - - Jim_SetResultString(goi.interp, target_name(target), -1); - return JIM_OK; - } - { - Jim_Obj *wObj = Jim_NewIntObj(goi.interp, w); - Jim_SetResultFormatted(goi.interp, - "Target: number %#s does not exist", wObj); - Jim_FreeNewObj(interp, wObj); - } - return JIM_ERR; -} - -static int jim_target_count(Jim_Interp *interp, int argc, Jim_Obj *const *argv) -{ - if (argc != 1) { - Jim_WrongNumArgs(interp, 1, argv, ""); - return JIM_ERR; - } - unsigned count = 0; - struct target *target = all_targets; - while (NULL != target) { - target = target->next; - count++; - } - Jim_SetResult(interp, Jim_NewIntObj(interp, count)); - return JIM_OK; -} - static const struct command_registration target_subcommand_handlers[] = { { .name = "init", @@ -5416,21 +5478,6 @@ static const struct command_registration target_subcommand_handlers[] = { .jim_handler = jim_target_names, .help = "Returns the names of all targets as a list of strings", }, - { - .name = "number", - .mode = COMMAND_ANY, - .jim_handler = jim_target_number, - .usage = "number", - .help = "Returns the name of the numbered target " - "(DEPRECATED)", - }, - { - .name = "count", - .mode = COMMAND_ANY, - .jim_handler = jim_target_count, - .help = "Returns the number of targets as an integer " - "(DEPRECATED)", - }, { .name = "smp", .mode = COMMAND_ANY,