From 9ac794e36c9a6f53791d2b76737d52ba57a45b5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois?= Date: Sat, 23 May 2026 11:14:17 +0200 Subject: [PATCH] digilent: implement Init / DeInit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit DmgrOpen + DjtgEnable + DjtgSetSpeed at 4 MHz (Adept rounds to the nearest supported, e.g. 3.75 MHz on SMT2-NC). DeInit does the reverse. An atexit hook also forces Close on process shutdown — leaving an open HIF when libdjtg's C++ static destructors run triggers "pure virtual method called". --- .../drivers/digilent_jtag/digilent_jtag_drv.c | 79 ++++++++++++++++++- 1 file changed, 75 insertions(+), 4 deletions(-) diff --git a/modules/drivers/digilent_jtag/digilent_jtag_drv.c b/modules/drivers/digilent_jtag/digilent_jtag_drv.c index f8a166b..b7cd72e 100644 --- a/modules/drivers/digilent_jtag/digilent_jtag_drv.c +++ b/modules/drivers/digilent_jtag/digilent_jtag_drv.c @@ -7,6 +7,7 @@ */ #include +#include #include #include #include @@ -71,6 +72,21 @@ static struct { static int g_dj_loaded = 0; /* 0 = not tried, 1 = ok, -1 = failed */ +static DJ_HIF g_dj_hif = 0; +static int g_dj_open = 0; + +static void digilent_atexit_close(void) +{ + /* libdjtg/libdmgr are C++ internally — leaving an open HIF when + * their static destructors run triggers "pure virtual method called" + * during process shutdown. Force a clean Close from atexit. */ + if (g_dj_open && g_dj.Disable && g_dj.Close) { + g_dj.Disable(g_dj_hif); + g_dj.Close(g_dj_hif); + g_dj_open = 0; + } +} + static int digilent_load(jtag_core *jc) { if (g_dj_loaded > 0) return 0; @@ -115,6 +131,8 @@ static int digilent_load(jtag_core *jc) RESOLVE(PutTmsTdiBits, libjtg, DjtgPutTmsTdiBits); #undef RESOLVE + atexit(digilent_atexit_close); + g_dj_loaded = 1; return 0; @@ -184,14 +202,67 @@ static int drv_Digilent_Detect(jtag_core *jc) static int drv_Digilent_Init(jtag_core *jc, int sub_drv, char *params) { - jtagcore_logs_printf(jc, MSG_ERROR, - "drv_Digilent_Init : not yet implemented (step 3)\r\n"); - return -1; + DJ_DWORD frq_req = 4000000; /* 4 MHz — safe and fast enough for IDCODE/IR */ + DJ_DWORD frq_set = 0; + + (void)params; + + if (g_dj_loaded != 1) { + jtagcore_logs_printf(jc, MSG_ERROR, + "drv_Digilent_Init : Adept libs not loaded\r\n"); + return JTAG_CORE_BAD_PARAMETER; + } + if (sub_drv < 0 || sub_drv >= g_dj_num_probes) { + jtagcore_logs_printf(jc, MSG_ERROR, + "drv_Digilent_Init : sub_drv %d out of range (have %d)\r\n", + sub_drv, g_dj_num_probes); + return JTAG_CORE_BAD_PARAMETER; + } + + if (g_dj_open) { + g_dj.Disable(g_dj_hif); + g_dj.Close(g_dj_hif); + g_dj_open = 0; + } + + if (!g_dj.Open(&g_dj_hif, subdrv_list[sub_drv].drv_id)) { + jtagcore_logs_printf(jc, MSG_ERROR, + "drv_Digilent_Init : DmgrOpen(\"%s\") failed\r\n", + subdrv_list[sub_drv].drv_id); + return JTAG_CORE_BAD_PARAMETER; + } + + if (!g_dj.Enable(g_dj_hif)) { + jtagcore_logs_printf(jc, MSG_ERROR, + "drv_Digilent_Init : DjtgEnable failed\r\n"); + g_dj.Close(g_dj_hif); + return JTAG_CORE_BAD_PARAMETER; + } + + if (!g_dj.SetSpeed(g_dj_hif, frq_req, &frq_set)) { + jtagcore_logs_printf(jc, MSG_WARNING, + "drv_Digilent_Init : DjtgSetSpeed failed, keeping default speed\r\n"); + } else { + jtagcore_logs_printf(jc, MSG_INFO_0, + "drv_Digilent_Init : JTAG clock = %u Hz (requested %u)\r\n", + (unsigned)frq_set, (unsigned)frq_req); + } + + g_dj_open = 1; + jtagcore_logs_printf(jc, MSG_INFO_0, + "drv_Digilent_Init : opened \"%s\"\r\n", subdrv_list[sub_drv].drv_id); + return JTAG_CORE_NO_ERROR; } static int drv_Digilent_DeInit(jtag_core *jc) { - return 0; + (void)jc; + if (g_dj_open) { + g_dj.Disable(g_dj_hif); + g_dj.Close(g_dj_hif); + g_dj_open = 0; + } + return JTAG_CORE_NO_ERROR; } static int drv_Digilent_TMS_xfer(jtag_core *jc, unsigned char *str_out, int size)