From 4c2c941a1ce326cf6443630c0e1017d421c88e27 Mon Sep 17 00:00:00 2001 From: Tau Date: Sun, 6 Jun 2021 09:38:20 -0400 Subject: [PATCH] Load and bind divaio at runtime --- divahook/config.c | 18 +++++++ divahook/config.h | 5 ++ divahook/diva-dll.c | 121 +++++++++++++++++++++++++++++++++++++++++++ divahook/diva-dll.h | 25 +++++++++ divahook/dllmain.c | 7 +++ divahook/jvs.c | 12 +++-- divahook/meson.build | 2 + divahook/slider.c | 19 ++++--- 8 files changed, 199 insertions(+), 10 deletions(-) create mode 100644 divahook/diva-dll.c create mode 100644 divahook/diva-dll.h diff --git a/divahook/config.c b/divahook/config.c index 7c21e46..29ca5c8 100644 --- a/divahook/config.c +++ b/divahook/config.c @@ -1,5 +1,6 @@ #include #include +#include #include "amex/amex.h" #include "amex/config.h" @@ -12,6 +13,22 @@ #include "platform/config.h" #include "platform/platform.h" +void diva_dll_config_load( + struct diva_dll_config *cfg, + const wchar_t *filename) +{ + assert(cfg != NULL); + assert(filename != NULL); + + GetPrivateProfileStringW( + L"divaio", + L"path", + L"", + cfg->path, + _countof(cfg->path), + filename); +} + void slider_config_load(struct slider_config *cfg, const wchar_t *filename) { assert(cfg != NULL); @@ -30,5 +47,6 @@ void diva_hook_config_load( platform_config_load(&cfg->platform, filename); amex_config_load(&cfg->amex, filename); aime_config_load(&cfg->aime, filename); + diva_dll_config_load(&cfg->dll, filename); slider_config_load(&cfg->slider, filename); } diff --git a/divahook/config.h b/divahook/config.h index 3e484d5..a327f47 100644 --- a/divahook/config.h +++ b/divahook/config.h @@ -6,6 +6,7 @@ #include "board/sg-reader.h" +#include "divahook/diva-dll.h" #include "divahook/slider.h" #include "platform/platform.h" @@ -14,9 +15,13 @@ struct diva_hook_config { struct platform_config platform; struct amex_config amex; struct aime_config aime; + struct diva_dll_config dll; struct slider_config slider; }; +void diva_dll_config_load( + struct diva_dll_config *cfg, + const wchar_t *filename); void slider_config_load(struct slider_config *cfg, const wchar_t *filename); void diva_hook_config_load( struct diva_hook_config *cfg, diff --git a/divahook/diva-dll.c b/divahook/diva-dll.c new file mode 100644 index 0000000..c871dd9 --- /dev/null +++ b/divahook/diva-dll.c @@ -0,0 +1,121 @@ +#include + +#include +#include + +#include "divahook/diva-dll.h" + +#include "util/dll-bind.h" +#include "util/dprintf.h" + +const struct dll_bind_sym diva_dll_syms[] = { + { + .sym = "diva_io_jvs_init", + .off = offsetof(struct diva_dll, jvs_init), + }, { + .sym = "diva_io_jvs_poll", + .off = offsetof(struct diva_dll, jvs_poll), + }, { + .sym = "diva_io_jvs_read_coin_counter", + .off = offsetof(struct diva_dll, jvs_read_coin_counter), + }, { + .sym = "diva_io_jvs_set_coin_blocker", + .off = offsetof(struct diva_dll, jvs_set_coin_blocker), + }, { + .sym = "diva_io_slider_init", + .off = offsetof(struct diva_dll, slider_init), + }, { + .sym = "diva_io_slider_start", + .off = offsetof(struct diva_dll, slider_start), + }, { + .sym = "diva_io_slider_stop", + .off = offsetof(struct diva_dll, slider_stop), + }, { + .sym = "diva_io_slider_set_leds", + .off = offsetof(struct diva_dll, slider_set_leds), + } +}; + +struct diva_dll diva_dll; + +// Copypasta DLL binding and diagnostic message boilerplate. +// Not much of this lends itself to being easily factored out. Also there +// will be a lot of API-specific branching code here eventually as new API +// versions get defined, so even though these functions all look the same +// now this won't remain the case forever. + +HRESULT diva_dll_init(const struct diva_dll_config *cfg, HINSTANCE self) +{ + uint16_t (*get_api_version)(void); + const struct dll_bind_sym *sym; + HINSTANCE owned; + HINSTANCE src; + HRESULT hr; + + assert(cfg != NULL); + assert(self != NULL); + + if (cfg->path[0] != L'\0') { + owned = LoadLibraryW(cfg->path); + + if (owned == NULL) { + hr = HRESULT_FROM_WIN32(GetLastError()); + dprintf("Diva IO: Failed to load IO DLL: %x: %S\n", + hr, + cfg->path); + + goto end; + } + + dprintf("Diva IO: Using custom IO DLL: %S\n", cfg->path); + src = owned; + } else { + owned = NULL; + src = self; + } + + get_api_version = (void *) GetProcAddress(src, "diva_io_get_api_version"); + + if (get_api_version != NULL) { + diva_dll.api_version = get_api_version(); + } else { + diva_dll.api_version = 0x0100; + dprintf("Custom IO DLL does not expose diva_io_get_api_version, " + "assuming API version 1.0.\n" + "Please ask the developer to update their DLL.\n"); + } + + if (diva_dll.api_version >= 0x0200) { + hr = E_NOTIMPL; + dprintf("Diva IO: Custom IO DLL implements an unsupported " + "API version (%#04x). Please update Segatools.\n", + diva_dll.api_version); + + goto end; + } + + sym = diva_dll_syms; + hr = dll_bind(&diva_dll, src, &sym, _countof(diva_dll_syms)); + + if (FAILED(hr)) { + if (src != self) { + dprintf("Diva IO: Custom IO DLL does not provide function " + "\"%s\". Please contact your IO DLL's developer for " + "further assistance.\n", + sym->sym); + + goto end; + } else { + dprintf("Internal error: could not reflect \"%s\"\n", sym->sym); + } + } + + owned = NULL; + +end: + if (owned != NULL) { + FreeLibrary(owned); + } + + return hr; +} diff --git a/divahook/diva-dll.h b/divahook/diva-dll.h new file mode 100644 index 0000000..fe78ff2 --- /dev/null +++ b/divahook/diva-dll.h @@ -0,0 +1,25 @@ +#pragma once + +#include + +#include "divaio/divaio.h" + +struct diva_dll { + uint16_t api_version; + HRESULT (*jvs_init)(void); + void (*jvs_poll)(uint8_t *opbtn, uint8_t *beams); + void (*jvs_read_coin_counter)(uint16_t *total); + void (*jvs_set_coin_blocker)(bool open); + HRESULT (*slider_init)(void); + void (*slider_start)(diva_io_slider_callback_t callback); + void (*slider_stop)(void); + void (*slider_set_leds)(const uint8_t *rgb); +}; + +struct diva_dll_config { + wchar_t path[MAX_PATH]; +}; + +extern struct diva_dll diva_dll; + +HRESULT diva_dll_init(const struct diva_dll_config *cfg, HINSTANCE self); diff --git a/divahook/dllmain.c b/divahook/dllmain.c index 067b9c0..fd6ad9b 100644 --- a/divahook/dllmain.c +++ b/divahook/dllmain.c @@ -7,6 +7,7 @@ #include "board/sg-reader.h" #include "divahook/config.h" +#include "divahook/diva-dll.h" #include "divahook/jvs.h" #include "divahook/slider.h" @@ -50,6 +51,12 @@ static DWORD CALLBACK diva_pre_startup(void) goto fail; } + hr = diva_dll_init(&diva_hook_cfg.dll, diva_hook_mod); + + if (FAILED(hr)) { + goto fail; + } + hr = amex_hook_init(&diva_hook_cfg.amex, diva_jvs_init); if (FAILED(hr)) { diff --git a/divahook/jvs.c b/divahook/jvs.c index ebfaaae..14d222d 100644 --- a/divahook/jvs.c +++ b/divahook/jvs.c @@ -9,7 +9,7 @@ #include "board/io3.h" -#include "divaio/divaio.h" +#include "divahook/diva-dll.h" #include "jvs/jvs-bus.h" @@ -33,9 +33,10 @@ HRESULT diva_jvs_init(struct jvs_node **out) HRESULT hr; assert(out != NULL); + assert(diva_dll.jvs_init != NULL); dprintf("JVS I/O: Starting Diva backend DLL\n"); - hr = diva_io_jvs_init(); + hr = diva_dll.jvs_init(); if (FAILED(hr)) { dprintf("JVS I/O: Backend error, I/O disconnected: %x\n", (int) hr); @@ -55,11 +56,12 @@ static void diva_jvs_read_switches(void *ctx, struct io3_switch_state *out) uint8_t gamebtn; assert(out != NULL); + assert(diva_dll.jvs_poll != NULL); opbtn = 0; gamebtn = 0; - diva_io_jvs_poll(&opbtn, &gamebtn); + diva_dll.jvs_poll(&opbtn, &gamebtn); if (gamebtn & 0x01) { out->p1 |= 1 << 6; @@ -97,9 +99,11 @@ static void diva_jvs_read_coin_counter( uint8_t slot_no, uint16_t *out) { + assert(diva_dll.jvs_read_coin_counter != NULL); + if (slot_no > 0) { return; } - diva_io_jvs_read_coin_counter(out); + diva_dll.jvs_read_coin_counter(out); } diff --git a/divahook/meson.build b/divahook/meson.build index 6310141..20c1ff2 100644 --- a/divahook/meson.build +++ b/divahook/meson.build @@ -22,6 +22,8 @@ shared_library( sources : [ 'config.c', 'config.h', + 'diva-dll.c', + 'diva-dll.h', 'dllmain.c', 'jvs.c', 'jvs.h', diff --git a/divahook/slider.c b/divahook/slider.c index 33a569e..8294923 100644 --- a/divahook/slider.c +++ b/divahook/slider.c @@ -8,10 +8,9 @@ #include "board/slider-cmd.h" #include "board/slider-frame.h" +#include "divahook/diva-dll.h" #include "divahook/slider.h" -#include "divaio/divaio.h" - #include "hook/iobuf.h" #include "hook/iohook.h" @@ -80,9 +79,11 @@ static HRESULT slider_handle_irp_locked(struct irp *irp) struct iobuf req_iobuf; HRESULT hr; + assert(diva_dll.slider_init != NULL); + if (irp->op == IRP_OP_OPEN) { dprintf("Diva slider: Starting backend DLL\n"); - hr = diva_io_slider_init(); + hr = diva_dll.slider_init(); if (FAILED(hr)) { dprintf("Diva slider: Backend DLL error: %x\n", (int) hr); @@ -207,8 +208,10 @@ static HRESULT slider_req_get_board_info(void) static HRESULT slider_req_auto_scan_start(void) { + assert(diva_dll.slider_start != NULL); + dprintf("Diva slider: Start slider thread\n"); - diva_io_slider_start(slider_res_auto_scan); + diva_dll.slider_start(slider_res_auto_scan); /* This message is not acknowledged */ @@ -219,6 +222,8 @@ static HRESULT slider_req_auto_scan_stop(void) { struct slider_hdr resp; + assert(diva_dll.slider_stop != NULL); + dprintf("Diva slider: Stop slider thread\n"); /* IO DLL worker thread might attempt to invoke the callback (which needs @@ -227,7 +232,7 @@ static HRESULT slider_req_auto_scan_stop(void) situation. */ LeaveCriticalSection(&slider_lock); - diva_io_slider_stop(); + diva_dll.slider_stop(); EnterCriticalSection(&slider_lock); resp.sync = SLIDER_FRAME_SYNC; @@ -239,8 +244,10 @@ static HRESULT slider_req_auto_scan_stop(void) static HRESULT slider_req_set_led(const struct slider_req_set_led *req) { + assert(diva_dll.slider_set_leds != NULL); + /* This message is not acknowledged */ - diva_io_slider_set_leds(req->payload.rgb); + diva_dll.slider_set_leds(req->payload.rgb); return S_OK; }