diff --git a/board/aime-dll.c b/board/aime-dll.c new file mode 100644 index 00000000..0ada7f4b --- /dev/null +++ b/board/aime-dll.c @@ -0,0 +1,112 @@ +#include + +#include +#include + +#include "board/aime-dll.h" + +#include "util/dll-bind.h" +#include "util/dprintf.h" + +const struct dll_bind_sym aime_dll_syms[] = { + { + .sym = "aime_io_init", + .off = offsetof(struct aime_dll, init), + }, { + .sym = "aime_io_nfc_poll", + .off = offsetof(struct aime_dll, nfc_poll), + }, { + .sym = "aime_io_nfc_get_aime_id", + .off = offsetof(struct aime_dll, nfc_get_aime_id), + }, { + .sym = "aime_io_nfc_get_felica_id", + .off = offsetof(struct aime_dll, nfc_get_felica_id), + }, { + .sym = "aime_io_led_set_color", + .off = offsetof(struct aime_dll, led_set_color), + } +}; + +struct aime_dll aime_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 aime_dll_init(const struct aime_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("NFC Assembly: Failed to load IO DLL: %x: %S\n", + hr, + cfg->path); + + goto end; + } + + dprintf("NFC Assembly: Using custom IO DLL: %S\n", cfg->path); + src = owned; + } else { + owned = NULL; + src = self; + } + + get_api_version = (void *) GetProcAddress(src, "aime_io_get_api_version"); + + if (get_api_version != NULL) { + aime_dll.api_version = get_api_version(); + } else { + aime_dll.api_version = 0x0100; + dprintf("Custom IO DLL does not expose aime_io_get_api_version, " + "assuming API version 1.0.\n" + "Please ask the developer to update their DLL.\n"); + } + + if (aime_dll.api_version >= 0x0200) { + hr = E_NOTIMPL; + dprintf("NFC Assembly: Custom IO DLL implements an unsupported " + "API version (%#04x). Please update Segatools.\n", + aime_dll.api_version); + + goto end; + } + + sym = aime_dll_syms; + hr = dll_bind(&aime_dll, src, &sym, _countof(aime_dll_syms)); + + if (FAILED(hr)) { + if (src != self) { + dprintf("NFC Assembly: 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/board/aime-dll.h b/board/aime-dll.h new file mode 100644 index 00000000..354516be --- /dev/null +++ b/board/aime-dll.h @@ -0,0 +1,25 @@ +#pragma once + +#include + +#include "aimeio/aimeio.h" + +struct aime_dll { + uint16_t api_version; + HRESULT (*init)(void); + HRESULT (*nfc_poll)(uint8_t unit_no); + HRESULT (*nfc_get_aime_id)( + uint8_t unit_no, + uint8_t *luid, + size_t luid_size); + HRESULT (*nfc_get_felica_id)(uint8_t unit_no, uint64_t *IDm); + void (*led_set_color)(uint8_t unit_no, uint8_t r, uint8_t g, uint8_t b); +}; + +struct aime_dll_config { + wchar_t path[MAX_PATH]; +}; + +extern struct aime_dll aime_dll; + +HRESULT aime_dll_init(const struct aime_dll_config *cfg, HINSTANCE self); diff --git a/board/config.c b/board/config.c index 84d89562..e64e28a8 100644 --- a/board/config.c +++ b/board/config.c @@ -3,14 +3,31 @@ #include #include #include +#include +#include "board/aime-dll.h" #include "board/config.h" #include "board/sg-reader.h" +static void aime_dll_config_load(struct aime_dll_config *cfg, const wchar_t *filename) +{ + assert(cfg != NULL); + assert(filename != NULL); + + GetPrivateProfileStringW( + L"aimeio", + L"path", + L"", + cfg->path, + _countof(cfg->path), + filename); +} + void aime_config_load(struct aime_config *cfg, const wchar_t *filename) { assert(cfg != NULL); assert(filename != NULL); + aime_dll_config_load(&cfg->dll, filename); cfg->enable = GetPrivateProfileIntW(L"aime", L"enable", 1, filename); } diff --git a/board/meson.build b/board/meson.build index eb2caa7f..d463d9ae 100644 --- a/board/meson.build +++ b/board/meson.build @@ -10,6 +10,8 @@ board_lib = static_library( iccard_lib, ], sources : [ + 'aime-dll.c', + 'aime-dll.h', 'config.c', 'config.h', 'guid.c', diff --git a/board/sg-reader.c b/board/sg-reader.c index 58745441..dbf0392a 100644 --- a/board/sg-reader.c +++ b/board/sg-reader.c @@ -4,8 +4,7 @@ #include #include -#include "aimeio/aimeio.h" - +#include "board/aime-dll.h" #include "board/sg-led.h" #include "board/sg-nfc.h" #include "board/sg-reader.h" @@ -48,14 +47,24 @@ static struct sg_led sg_reader_led; HRESULT sg_reader_hook_init( const struct aime_config *cfg, - unsigned int port_no) + unsigned int port_no, + HINSTANCE self) { + HRESULT hr; + assert(cfg != NULL); + assert(self != NULL); if (!cfg->enable) { return S_FALSE; } + hr = aime_dll_init(&cfg->dll, self); + + if (FAILED(hr)) { + return hr; + } + sg_nfc_init(&sg_reader_nfc, 0x00, &sg_reader_nfc_ops, NULL); sg_led_init(&sg_reader_led, 0x08, &sg_reader_led_ops, NULL); @@ -111,7 +120,7 @@ static HRESULT sg_reader_handle_irp_locked(struct irp *irp) if (!sg_reader_started) { dprintf("NFC Assembly: Starting backend DLL\n"); - hr = aime_io_init(); + hr = aime_dll.init(); sg_reader_started = true; sg_reader_start_hr = hr; @@ -155,7 +164,7 @@ static HRESULT sg_reader_handle_irp_locked(struct irp *irp) static HRESULT sg_reader_nfc_poll(void *ctx) { - return aime_io_nfc_poll(0); + return aime_dll.nfc_poll(0); } static HRESULT sg_reader_nfc_get_aime_id( @@ -163,15 +172,15 @@ static HRESULT sg_reader_nfc_get_aime_id( uint8_t *luid, size_t luid_size) { - return aime_io_nfc_get_aime_id(0, luid, luid_size); + return aime_dll.nfc_get_aime_id(0, luid, luid_size); } static HRESULT sg_reader_nfc_get_felica_id(void *ctx, uint64_t *IDm) { - return aime_io_nfc_get_felica_id(0, IDm); + return aime_dll.nfc_get_felica_id(0, IDm); } static void sg_reader_led_set_color(void *ctx, uint8_t r, uint8_t g, uint8_t b) { - aime_io_led_set_color(0, r, g, b); + aime_dll.led_set_color(0, r, g, b); } diff --git a/board/sg-reader.h b/board/sg-reader.h index 00b237cd..673a8bda 100644 --- a/board/sg-reader.h +++ b/board/sg-reader.h @@ -4,10 +4,14 @@ #include +#include "board/aime-dll.h" + struct aime_config { + struct aime_dll_config dll; bool enable; }; HRESULT sg_reader_hook_init( const struct aime_config *cfg, - unsigned int port_no); + unsigned int port_no, + HINSTANCE self); diff --git a/chunihook/dllmain.c b/chunihook/dllmain.c index c6f1ed55..5ffa691f 100644 --- a/chunihook/dllmain.c +++ b/chunihook/dllmain.c @@ -87,7 +87,7 @@ static DWORD CALLBACK chuni_pre_startup(void) goto fail; } - hr = sg_reader_hook_init(&chuni_hook_cfg.aime, 12); + hr = sg_reader_hook_init(&chuni_hook_cfg.aime, 12, chuni_hook_mod); if (FAILED(hr)) { goto fail; diff --git a/divahook/dllmain.c b/divahook/dllmain.c index a59a066d..067b9c0b 100644 --- a/divahook/dllmain.c +++ b/divahook/dllmain.c @@ -56,7 +56,7 @@ static DWORD CALLBACK diva_pre_startup(void) goto fail; } - hr = sg_reader_hook_init(&diva_hook_cfg.aime, 10); + hr = sg_reader_hook_init(&diva_hook_cfg.aime, 10, diva_hook_mod); if (FAILED(hr)) { goto fail; diff --git a/idzhook/dllmain.c b/idzhook/dllmain.c index 80ca7ef8..d1dd2086 100644 --- a/idzhook/dllmain.c +++ b/idzhook/dllmain.c @@ -57,7 +57,7 @@ static DWORD CALLBACK idz_pre_startup(void) goto fail; } - hr = sg_reader_hook_init(&idz_hook_cfg.aime, 10); + hr = sg_reader_hook_init(&idz_hook_cfg.aime, 10, idz_hook_mod); if (FAILED(hr)) { goto fail; diff --git a/mu3hook/dllmain.c b/mu3hook/dllmain.c index 5b625062..08ca9895 100644 --- a/mu3hook/dllmain.c +++ b/mu3hook/dllmain.c @@ -50,7 +50,7 @@ static DWORD CALLBACK mu3_pre_startup(void) goto fail; } - hr = sg_reader_hook_init(&mu3_hook_cfg.aime, 1); + hr = sg_reader_hook_init(&mu3_hook_cfg.aime, 1, mu3_hook_mod); if (FAILED(hr)) { goto fail;