From 00320d87ecbbc2946ed16453305cfb3df2626fa9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois?= Date: Sun, 24 May 2026 10:48:01 +0200 Subject: [PATCH] script: add jtag_close to release the current probe Lets a session hand a probe back (frees its USB handle) without opening another, e.g. to flash two FPGAs on different probes in turn: jtag_close, then jtag_open the next one and jtag_autoinit. Mirrors the DeInit teardown jtagcore_loaddriver already does when switching drivers. Also fix the help printer: no-arg commands (whose params slot is "") printed an empty body because "" was treated as the terminator. Params are now optional and the description always shows. Co-Authored-By: Claude Opus 4.7 --- README.md | 2 +- modules/script/script.c | 55 +++++++++++++++++++++++++++++++++-------- 2 files changed, 46 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 7e58113..ca306cc 100644 --- a/README.md +++ b/README.md @@ -107,7 +107,7 @@ the full walkthrough (probe → proxy → flash) lives in | Category | Commands | |----------|----------| | Script control | `set`, `print`, `print_env_var`, `if`, `goto`, `call`, `return`, `rand`, `init_array`, `system`, `pause` | -| Probe / chain | `jtag_probes`, `jtag_open`, `jtag_scan`, `jtag_autoinit`, `jtag_ndev`, `jtag_devices` | +| Probe / chain | `jtag_probes`, `jtag_open`, `jtag_close`, `jtag_scan`, `jtag_autoinit`, `jtag_ndev`, `jtag_devices` | | BSDL / pins | `jtag_bsdl`, `jtag_pins`, `jtag_mode`, `jtag_pin_dir`, `jtag_pin_set`, `jtag_pin_get`, `jtag_push_pop` | | I²C / MDIO / SPI over BS pins (EXTEST) | `jtag_i2c_scl`, `jtag_i2c_sda`, `jtag_i2c_rd`, `jtag_i2c_wr`, `jtag_mdio_mdc`, `jtag_mdio_io`, `jtag_mdio_rd`, `jtag_mdio_wr`, `jtag_spi_cs/mosi/miso/clk`, `jtag_spi_xfer` | | FPGA registry | `fpga_list`, `fpga_info` | diff --git a/modules/script/script.c b/modules/script/script.c index 3b47a85..c393ec5 100644 --- a/modules/script/script.c +++ b/modules/script/script.c @@ -1157,18 +1157,19 @@ static int cmd_help(script_ctx *ctx, char *line) not_found = 0; ctx->script_printf(ctx, MSG_NONE, "Documentation of command '%s' :\n", cmdlist[i].command); ctx->script_printf(ctx, MSG_NONE, "---------------------------------------------------\n"); - j = 0; - while (strcmp(cmdlist[i].help[j], "")) { - if (j == 0) { - ctx->script_printf(ctx, MSG_NONE, "Parameters :\n"); - ctx->script_printf(ctx, MSG_NONE, " %s\n", cmdlist[i].help[j]); - } else { - if (j == 1) { - ctx->script_printf(ctx, MSG_NONE, "Description :\n"); - } + // help[0] is the parameter list ("" when the command takes + // none); description lines follow, terminated by "". + if (cmdlist[i].help[0][0]) { + ctx->script_printf(ctx, MSG_NONE, "Parameters :\n"); + ctx->script_printf(ctx, MSG_NONE, " %s\n", cmdlist[i].help[0]); + } + j = 1; + if (strcmp(cmdlist[i].help[j], "")) { + ctx->script_printf(ctx, MSG_NONE, "Description :\n"); + while (strcmp(cmdlist[i].help[j], "")) { ctx->script_printf(ctx, MSG_NONE, " %s\n", cmdlist[i].help[j]); + j++; } - j++; } break; } @@ -1855,6 +1856,39 @@ static int cmd_open_probe(script_ctx *ctx, char *line) } } +const char *cmd_close_probe_help[] = { + "", // Arguments "1(type) ..." + "Release the currently open probe, freeing its USB handle.", + "Use it to hand the probe to another tool, or before driving a", + "second target on a different probe: jtag_close, then jtag_open the", + "other one and jtag_autoinit to rescan. (Opening another probe also", + "releases the current one, so jtag_close is only needed to fully let", + "go without immediately reopening.)", + "" +}; +static int cmd_close_probe(script_ctx *ctx, char *line) +{ + jtag_core *jc; + + (void)line; + jc = (jtag_core *)ctx->app_ctx; + + if (jc->io_functions.drv_DeInit) + { + // Same teardown jtagcore_loaddriver does before switching drivers: + // call the driver's DeInit, then forget its function table so the + // chain looks probe-less until the next jtag_open. + jc->io_functions.drv_DeInit(jc); + memset(&jc->io_functions, 0, sizeof(jc->io_functions)); + ctx->script_printf(ctx, MSG_INFO_0, "Probe released.\n"); + } + else + { + ctx->script_printf(ctx, MSG_INFO_0, "No probe is open.\n"); + } + return JTAG_CORE_NO_ERROR; +} + const char *cmd_load_bsdl_help[] = { "(string) (int)", "Load/attach a bsdl file to a device into the chain.", @@ -3333,6 +3367,7 @@ cmd_list script_commands_list[] = {"init_array", cmd_initarray, cmd_initarray_help}, {"jtag_probes", cmd_print_probes_list, cmd_print_probes_list_help}, {"jtag_open", cmd_open_probe, cmd_open_probe_help}, + {"jtag_close", cmd_close_probe, cmd_close_probe_help}, {"jtag_autoinit", cmd_autoinit, cmd_autoinit_help}, {"jtag_scan", cmd_init_and_scan, cmd_init_and_scan_help}, {"jtag_ndev", cmd_print_nb_dev, cmd_print_nb_dev_help},