digilent: dlopen libdjtg/libdmgr + implement Detect

Loads the Adept .so files lazily and resolves the symbols we need.
Detect() enumerates devices via DmgrEnumDevices/DmgrGetDvc and exposes
each as a Viveris probe slot. If Adept Runtime is missing, the driver
silently reports 0 probes.
This commit is contained in:
2026-05-23 11:10:58 +02:00
parent 78f6bb9b34
commit 09708177b7

View File

@@ -1,12 +1,15 @@
/*
* Boundary-Scan Explorer - Digilent JTAG-SMT* driver (skeleton)
* Boundary-Scan Explorer - Digilent JTAG-SMT* driver
*
* Step 1: build wiring + driver registration only. Detect() returns 0,
* Init() returns an error. Real implementation lands in subsequent steps.
* Talks to Digilent JTAG modules through libdjtg / libdmgr, loaded via
* dlopen at runtime. No Digilent binary or header is embedded in this
* repository; the typedefs below mirror the public Adept SDK ABI.
*/
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <dlfcn.h>
#include "jtag_core/jtag_core.h"
#include "jtag_core/dbg_logs.h"
@@ -18,56 +21,193 @@
#define MAX_PROBES_DIGILENT 8
/* ------------------------------------------------------------------ */
/* Adept SDK ABI mirrors (no Digilent headers included) */
/* ------------------------------------------------------------------ */
typedef int DJ_BOOL;
typedef uint8_t DJ_BYTE;
typedef uint32_t DJ_DWORD;
typedef int32_t DJ_INT32;
typedef DJ_DWORD DJ_HIF;
typedef DJ_DWORD DJ_DTP;
#define DJ_CCH_DVC_NAME_MAX 64
#define DJ_CCH_CONN_MAX 261 /* MAX_PATH(260) + 1 in dpcdecl.h */
#pragma pack(push, 16)
typedef struct dj_dvc {
char szName[DJ_CCH_DVC_NAME_MAX];
char szConn[DJ_CCH_CONN_MAX];
DJ_DTP dtp;
} DJ_DVC;
#pragma pack(pop)
typedef DJ_BOOL (*pfn_DmgrEnumDevices)(int *pcdvc);
typedef DJ_BOOL (*pfn_DmgrGetDvc)(int idvc, DJ_DVC *pdvc);
typedef DJ_BOOL (*pfn_DmgrOpen)(DJ_HIF *phif, char *szSel);
typedef DJ_BOOL (*pfn_DmgrClose)(DJ_HIF hif);
typedef DJ_BOOL (*pfn_DjtgEnable)(DJ_HIF hif);
typedef DJ_BOOL (*pfn_DjtgDisable)(DJ_HIF hif);
typedef DJ_BOOL (*pfn_DjtgSetSpeed)(DJ_HIF hif, DJ_DWORD frqReq, DJ_DWORD *pfrqSet);
typedef DJ_BOOL (*pfn_DjtgPutTdiBits)(DJ_HIF hif, DJ_BOOL fTms, DJ_BYTE *rgbSnd, DJ_BYTE *rgbRcv, DJ_DWORD cbits, DJ_BOOL fOverlap);
typedef DJ_BOOL (*pfn_DjtgPutTmsBits)(DJ_HIF hif, DJ_BOOL fTdi, DJ_BYTE *rgbSnd, DJ_BYTE *rgbRcv, DJ_DWORD cbits, DJ_BOOL fOverlap);
typedef DJ_BOOL (*pfn_DjtgPutTmsTdiBits)(DJ_HIF hif, DJ_BYTE *rgbSnd, DJ_BYTE *rgbRcv, DJ_DWORD cbitpairs, DJ_BOOL fOverlap);
static struct {
void *libmgr;
void *libjtg;
pfn_DmgrEnumDevices EnumDevices;
pfn_DmgrGetDvc GetDvc;
pfn_DmgrOpen Open;
pfn_DmgrClose Close;
pfn_DjtgEnable Enable;
pfn_DjtgDisable Disable;
pfn_DjtgSetSpeed SetSpeed;
pfn_DjtgPutTdiBits PutTdiBits;
pfn_DjtgPutTmsBits PutTmsBits;
pfn_DjtgPutTmsTdiBits PutTmsTdiBits;
} g_dj;
static int g_dj_loaded = 0; /* 0 = not tried, 1 = ok, -1 = failed */
static int digilent_load(jtag_core *jc)
{
if (g_dj_loaded > 0) return 0;
if (g_dj_loaded < 0) return -1;
g_dj.libmgr = dlopen("libdmgr.so", RTLD_LAZY);
if (!g_dj.libmgr) {
jtagcore_logs_printf(jc, MSG_INFO_1,
"drv_Digilent : libdmgr.so not loadable (Adept Runtime not installed?) : %s\r\n",
dlerror());
g_dj_loaded = -1;
return -1;
}
g_dj.libjtg = dlopen("libdjtg.so", RTLD_LAZY);
if (!g_dj.libjtg) {
jtagcore_logs_printf(jc, MSG_INFO_1,
"drv_Digilent : libdjtg.so not loadable : %s\r\n", dlerror());
dlclose(g_dj.libmgr); g_dj.libmgr = NULL;
g_dj_loaded = -1;
return -1;
}
#define RESOLVE(field, lib, name) \
do { \
g_dj.field = (pfn_##name)dlsym(g_dj.lib, #name); \
if (!g_dj.field) { \
jtagcore_logs_printf(jc, MSG_ERROR, \
"drv_Digilent : dlsym(%s) failed\r\n", #name); \
goto fail; \
} \
} while (0)
RESOLVE(EnumDevices, libmgr, DmgrEnumDevices);
RESOLVE(GetDvc, libmgr, DmgrGetDvc);
RESOLVE(Open, libmgr, DmgrOpen);
RESOLVE(Close, libmgr, DmgrClose);
RESOLVE(Enable, libjtg, DjtgEnable);
RESOLVE(Disable, libjtg, DjtgDisable);
RESOLVE(SetSpeed, libjtg, DjtgSetSpeed);
RESOLVE(PutTdiBits, libjtg, DjtgPutTdiBits);
RESOLVE(PutTmsBits, libjtg, DjtgPutTmsBits);
RESOLVE(PutTmsTdiBits, libjtg, DjtgPutTmsTdiBits);
#undef RESOLVE
g_dj_loaded = 1;
return 0;
fail:
if (g_dj.libjtg) dlclose(g_dj.libjtg);
if (g_dj.libmgr) dlclose(g_dj.libmgr);
memset(&g_dj, 0, sizeof(g_dj));
g_dj_loaded = -1;
return -1;
}
/* ------------------------------------------------------------------ */
/* Probe registry */
/* ------------------------------------------------------------------ */
typedef struct _digilent_drv_desc
{
char drv_id[64];
char drv_id[64]; /* szName from DVC; passed to DmgrOpen as szSel */
char drv_desc[128];
int sub_drv_id;
} digilent_drv_desc;
static digilent_drv_desc subdrv_list[MAX_PROBES_DIGILENT] = {
{"DIGILENT_SMT_PROBE", "DIGILENT JTAG-SMT PROBE", 0},
{"DIGILENT_SMT_PROBE", "DIGILENT JTAG-SMT PROBE", 0},
{"DIGILENT_SMT_PROBE", "DIGILENT JTAG-SMT PROBE", 0},
{"DIGILENT_SMT_PROBE", "DIGILENT JTAG-SMT PROBE", 0},
{"DIGILENT_SMT_PROBE", "DIGILENT JTAG-SMT PROBE", 0},
{"DIGILENT_SMT_PROBE", "DIGILENT JTAG-SMT PROBE", 0},
{"DIGILENT_SMT_PROBE", "DIGILENT JTAG-SMT PROBE", 0},
{"DIGILENT_SMT_PROBE", "DIGILENT JTAG-SMT PROBE", 0},
};
static digilent_drv_desc subdrv_list[MAX_PROBES_DIGILENT];
static int g_dj_num_probes = 0;
static int drv_Digilent_Detect(jtag_core * jc)
/* ------------------------------------------------------------------ */
/* Viveris driver interface */
/* ------------------------------------------------------------------ */
static int drv_Digilent_Detect(jtag_core *jc)
{
/* Step 2 will populate subdrv_list via DmgrEnumDevices. */
return 0;
int cdvc = 0;
int i;
if (digilent_load(jc) < 0) {
g_dj_num_probes = 0;
return 0;
}
if (!g_dj.EnumDevices(&cdvc)) {
jtagcore_logs_printf(jc, MSG_INFO_1,
"drv_Digilent_Detect : DmgrEnumDevices failed\r\n");
g_dj_num_probes = 0;
return 0;
}
if (cdvc > MAX_PROBES_DIGILENT) cdvc = MAX_PROBES_DIGILENT;
for (i = 0; i < cdvc; i++) {
DJ_DVC dvc;
memset(&dvc, 0, sizeof(dvc));
if (!g_dj.GetDvc(i, &dvc)) {
snprintf(subdrv_list[i].drv_id, sizeof(subdrv_list[i].drv_id), "unknown%d", i);
snprintf(subdrv_list[i].drv_desc, sizeof(subdrv_list[i].drv_desc), "Digilent (idx %d - DmgrGetDvc failed)", i);
} else {
snprintf(subdrv_list[i].drv_id, sizeof(subdrv_list[i].drv_id), "%s", dvc.szName);
snprintf(subdrv_list[i].drv_desc, sizeof(subdrv_list[i].drv_desc), "Digilent: %s", dvc.szName);
}
subdrv_list[i].sub_drv_id = i;
}
g_dj_num_probes = cdvc;
jtagcore_logs_printf(jc, MSG_INFO_1,
"drv_Digilent_Detect : %d device(s) found\r\n", cdvc);
return cdvc;
}
static int drv_Digilent_Init(jtag_core * jc, int sub_drv, char * params)
static int drv_Digilent_Init(jtag_core *jc, int sub_drv, char *params)
{
jtagcore_logs_printf(jc, MSG_ERROR,
"drv_Digilent_Init : Digilent backend not yet implemented\r\n");
"drv_Digilent_Init : not yet implemented (step 3)\r\n");
return -1;
}
static int drv_Digilent_DeInit(jtag_core * jc)
static int drv_Digilent_DeInit(jtag_core *jc)
{
return 0;
}
static int drv_Digilent_TMS_xfer(jtag_core * jc, unsigned char * str_out, int size)
static int drv_Digilent_TMS_xfer(jtag_core *jc, unsigned char *str_out, int size)
{
return -1;
}
static int drv_Digilent_TDOTDI_xfer(jtag_core * jc,
unsigned char * str_out,
unsigned char * str_in,
static int drv_Digilent_TDOTDI_xfer(jtag_core *jc,
unsigned char *str_out,
unsigned char *str_in,
int size)
{
return -1;
}
int drv_Digilent_libGetDrv(jtag_core * jc, int sub_drv, unsigned int infotype, void * returnvalue)
int drv_Digilent_libGetDrv(jtag_core *jc, int sub_drv, unsigned int infotype, void *returnvalue)
{
drv_ptr drv_funcs = {
(DRV_DETECT) drv_Digilent_Detect,