From 520ccb014df12b1fc2e5e0245003c0beb1decb4c Mon Sep 17 00:00:00 2001 From: Hay1tsme Date: Thu, 12 Mar 2026 15:06:13 -0400 Subject: [PATCH] change how dongle is attached for games that care --- board/config.c | 7 + board/config.h | 2 + board/dongle.c | 451 +++++++++++++++++++++++++++++++++++++++++++++ board/dongle.h | 25 +++ board/meson.build | 2 + gchook/dllmain.c | 1 - gchook/reader.c | 5 +- idmac/idmac.h | 1 - sivahook/dllmain.c | 1 - 9 files changed, 491 insertions(+), 4 deletions(-) create mode 100644 board/dongle.c create mode 100644 board/dongle.h diff --git a/board/config.c b/board/config.c index 0d8e9e5..5515e92 100644 --- a/board/config.c +++ b/board/config.c @@ -35,3 +35,10 @@ void k9101258_config_load(struct usbio_config *cfg, const wchar_t *filename) cfg->enabled = GetPrivateProfileIntW(L"usbio", L"enable", 1, filename); } + +void dongle_config_load(struct dongle_config *cfg, const wchar_t *filename) +{ + assert(cfg != NULL); + assert(filename != NULL); + GetPrivateProfileStringW(L"reader", L"card_serial", L"702039200000000", cfg->serial, _countof(cfg->serial), filename); +} diff --git a/board/config.h b/board/config.h index 5e7b51e..d29f9be 100644 --- a/board/config.h +++ b/board/config.h @@ -4,9 +4,11 @@ #include #include "board/io4.h" +#include "board/dongle.h" #include "board/k92x0249.h" #include "board/k9101258.h" void io4_config_load(struct io4_config *cfg, const wchar_t *filename); void k92x0249_config_load(struct k92x0249_config *cfg, const wchar_t *filename); void k9101258_config_load(struct usbio_config *cfg, const wchar_t *filename); +void dongle_config_load(struct dongle_config *cfg, const wchar_t *filename); diff --git a/board/dongle.c b/board/dongle.c new file mode 100644 index 0000000..43390d2 --- /dev/null +++ b/board/dongle.c @@ -0,0 +1,451 @@ +#include + +#include +#include +#include +#include +#include + +#include "board/dongle.h" +#include "board/config.h" + +#include "jvs/jvs-bus.h" +#include "jvs/jvs-cmd.h" +#include "jvs/jvs-util.h" + +#include "util/dprintf.h" +#include "util/dump.h" + +// JVS card reader, A/B/C vairants + +static const uint8_t dongle_ident[] = "TAITO CORP.;RFID CTRL P.C.B.;Ver1.11;"; +static const uint8_t card_uid[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x00 }; +static const uint8_t card_id[] = { + 0x01, 0x2E, 0x4C, 0xE4, 0x00, 0x01, 0x00, 0x01, + 0x00, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; +static struct dongle_config cfg; + +static uint8_t dongle_features[] = { + // Misc. SW + 0x07, + 0x00, + 0x08, + 0x00, + + // GPIO Out + 0x12, + 0x08, + 0x00, + 0x00, + + // End + 0x00, +}; + +static void dongle_transact( + struct jvs_node *node, + const void *bytes, + size_t nbytes, + struct iobuf *resp); + +static bool dongle_sense(struct jvs_node *node); + +static HRESULT dongle_cmd( + void *ctx, + struct const_iobuf *req, + struct iobuf *resp); + +static HRESULT dongle_cmd_reset(struct dongle *dongle, struct const_iobuf *req_buf); +static HRESULT dongle_cmd_assign_addr(struct dongle *dongle, struct const_iobuf *req_buf, struct iobuf *resp_buf); +static HRESULT dongle_cmd_read_id(struct dongle *dongle, struct const_iobuf *req_buf, struct iobuf *resp_buf); +static HRESULT dongle_cmd_get_cmd_version(struct dongle *dongle, struct const_iobuf *req_buf, struct iobuf *resp_buf); +static HRESULT dongle_cmd_get_jvs_version(struct dongle *dongle, struct const_iobuf *req_buf, struct iobuf *resp_buf); +static HRESULT dongle_cmd_get_comm_version(struct dongle *dongle, struct const_iobuf *req_buf, struct iobuf *resp_buf); +static HRESULT dongle_cmd_get_features(struct dongle *dongle, struct const_iobuf *req_buf, struct iobuf *resp_buf); +static HRESULT dongle_cmd_write_gpio1(struct dongle *dongle, struct const_iobuf *req_buf, struct iobuf *resp_buf); +static HRESULT dongle_cmd_read_misc_switches(struct dongle *dongle, struct const_iobuf *req_buf, struct iobuf *resp_buf); +static HRESULT dongle_cmd_taito_nesica_read(struct dongle *dongle, struct const_iobuf *req_buf, struct iobuf *resp_buf); +static HRESULT dongle_cmd_taito_aic_read(struct dongle *dongle, struct const_iobuf *req_buf, struct iobuf *resp_buf); + +void dongle_init( + struct dongle *dongle, + struct jvs_node *next, + void *ops_ctx) +{ + assert(dongle != NULL); + + dongle_config_load(&cfg, L".\\taitools.ini"); + + dongle->jvs.next = next; + dongle->jvs.transact = dongle_transact; + dongle->jvs.sense = dongle_sense; + dongle->jvs.sense_out = true; + dongle->addr = 0xFF; + dongle->state = IDLE; + dongle->ops_ctx = ops_ctx; +} + +struct jvs_node *dongle_to_jvs_node(struct dongle *dongle) +{ + assert(dongle != NULL); + + return &dongle->jvs; +} + +static void dongle_transact( + struct jvs_node *node, + const void *bytes, + size_t nbytes, + struct iobuf *resp) +{ + struct dongle *dongle; + + assert(node != NULL); + assert(bytes != NULL); + assert(resp != NULL); + + dongle = CONTAINING_RECORD(node, struct dongle, jvs); + + jvs_crack_request(bytes, nbytes, resp, dongle->addr, dongle_cmd, dongle); +} + +static bool dongle_sense(struct jvs_node *node) +{ + struct dongle *dongle; + + assert(node != NULL); + + dongle = CONTAINING_RECORD(node, struct dongle, jvs); + + return dongle->addr == 0xFF; +} + +static HRESULT dongle_cmd( + void *ctx, + struct const_iobuf *req, + struct iobuf *resp) +{ + struct dongle *dongle; + + dongle = (struct dongle *)ctx; + + switch (req->bytes[req->pos]) { + case JVS_CMD_RESET: + return dongle_cmd_reset(dongle, req); + + case JVS_CMD_ASSIGN_ADDR: + return dongle_cmd_assign_addr(dongle, req, resp); + + case JVS_CMD_READ_ID: + return dongle_cmd_read_id(dongle, req, resp); + + case JVS_CMD_GET_CMD_VERSION: + return dongle_cmd_get_cmd_version(dongle, req, resp); + + case JVS_CMD_GET_JVS_VERSION: + return dongle_cmd_get_jvs_version(dongle, req, resp); + + case JVS_CMD_GET_COMM_VERSION: + return dongle_cmd_get_comm_version(dongle, req, resp); + + case JVS_CMD_GET_FEATURES: + return dongle_cmd_get_features(dongle, req, resp); + + case JVS_CMD_WRITE_GPIO1: // Set reader state + return dongle_cmd_write_gpio1(dongle, req, resp); + + case JVS_CMD_READ_MISC_SWITCHES: // Read for old (1.00/0.02) fw + return dongle_cmd_read_misc_switches(dongle, req, resp); + + case JVS_CMD_TAITO_NESICA_READ: // Check reader state for new fw + return dongle_cmd_taito_nesica_read(dongle, req, resp); + + case JVS_CMD_TAITO_AIC_READ: // Check reader state for new fw + return dongle_cmd_taito_aic_read(dongle, req, resp); + + default: + dprintf("DONGLE: Node %02x: Unhandled command byte @ %02X %02x\n", + dongle->addr, + req->pos, + req->bytes[req->pos]); + dump_const_iobuf(req); + + return E_NOTIMPL; + } + + return S_OK; +} + +static HRESULT dongle_cmd_reset(struct dongle *dongle, struct const_iobuf *req_buf) +{ + struct jvs_req_reset req; + HRESULT hr; + + hr = iobuf_read(req_buf, &req, sizeof(req)); + + if (FAILED(hr)) { + return hr; + } + + dprintf("DONGLE: Reset (param %02x)\n", req.unknown); + dongle->addr = 0xFF; + dongle->jvs.sense_out = false; + + /* No ack for this since it really is addressed to everybody */ + + return S_OK; +} + +static HRESULT dongle_cmd_assign_addr( + struct dongle *dongle, + struct const_iobuf *req_buf, + struct iobuf *resp_buf) +{ + struct jvs_req_assign_addr req; + bool sense; + HRESULT hr; + + hr = iobuf_read(req_buf, &req, sizeof(req)); + + if (FAILED(hr)) { + return hr; + } + + sense = jvs_node_sense(dongle->jvs.next); + dprintf("DONGLE: Assign addr %02x sense %i\n", req.addr, sense); + + if (sense) { + /* That address is for somebody else */ + return S_OK; + } + + dongle->addr = req.addr; + dongle->jvs.sense_out = true; + + return iobuf_write_8(resp_buf, 0x01); +} + +static HRESULT dongle_cmd_read_id(struct dongle *dongle, struct const_iobuf *req_buf, struct iobuf *resp_buf) +{ + uint8_t req; + HRESULT hr; + + hr = iobuf_read_8(req_buf, &req); + + if (FAILED(hr)) { + return hr; + } + + dprintf("DONGLE: Read ID\n"); + + /* Write report byte */ + + hr = iobuf_write_8(resp_buf, 0x01); + + if (FAILED(hr)) { + return hr; + } + + /* Write the identification string. The NUL terminator at the end of this C + string is also sent, and it naturally terminates the response chunk. */ + + return iobuf_write(resp_buf, dongle_ident, sizeof(dongle_ident)); +} + +static HRESULT dongle_cmd_get_cmd_version(struct dongle *dongle, struct const_iobuf *req_buf, struct iobuf *resp_buf) +{ + uint8_t req; + uint8_t resp[2]; + HRESULT hr; + + hr = iobuf_read_8(req_buf, &req); + + if (FAILED(hr)) { + return hr; + } + + dprintf("DONGLE: Get command format version\n"); + resp[0] = 0x01; /* Report byte */ + resp[1] = 0x13; /* Command format version BCD */ + + return iobuf_write(resp_buf, resp, sizeof(resp)); +} + +static HRESULT dongle_cmd_get_jvs_version(struct dongle *dongle, struct const_iobuf *req_buf, struct iobuf *resp_buf) +{ + uint8_t req; + uint8_t resp[2]; + HRESULT hr; + + hr = iobuf_read_8(req_buf, &req); + + if (FAILED(hr)) { + return hr; + } + + dprintf("DONGLE: Get JVS format version\n"); + resp[0] = 0x01; /* Report byte */ + resp[1] = 0x30; /* JVS format version BCD */ + + return iobuf_write(resp_buf, resp, sizeof(resp)); +} + +static HRESULT dongle_cmd_get_comm_version(struct dongle *dongle, struct const_iobuf *req_buf, struct iobuf *resp_buf) +{ + uint8_t req; + uint8_t resp[2]; + HRESULT hr; + + hr = iobuf_read_8(req_buf, &req); + + if (FAILED(hr)) { + return hr; + } + + dprintf("DONGLE: Get COMM format version\n"); + resp[0] = 0x01; /* Report byte */ + resp[1] = 0x10; /* COMM format version BCD */ + + return iobuf_write(resp_buf, resp, sizeof(resp)); +} + +static HRESULT dongle_cmd_get_features(struct dongle *dongle, struct const_iobuf *req_buf, struct iobuf *resp_buf) +{ + uint8_t req; + uint8_t resp[2]; + HRESULT hr; + + hr = iobuf_read_8(req_buf, &req); + + if (FAILED(hr)) { + return hr; + } + + dprintf("DONGLE: Get reader features\n"); + + hr = iobuf_write_8(resp_buf, 0x01); /* Write report byte */ + + if (FAILED(hr)) { + return hr; + } + + return iobuf_write(resp_buf, dongle_features, sizeof(dongle_features)); +} + +static HRESULT dongle_cmd_write_gpio1(struct dongle *dongle, struct const_iobuf *req_buf, struct iobuf *resp_buf) +{ + uint8_t unk; + uint8_t num_io; + uint8_t io_state[255]; + HRESULT hr = iobuf_read_8(req_buf, &unk); + if (FAILED(hr)) { + return hr; + } + + hr = iobuf_read_8(req_buf, &num_io); + + if (FAILED(hr)) { + return hr; + } + + hr = iobuf_read(req_buf, io_state, num_io); + + if (FAILED(hr)) { + return hr; + } + + if (dongle->state != io_state[0]) { + dprintf("DONGLE: Update state %02X\n", io_state[0], num_io); + } + + dongle->state = io_state[0]; + return iobuf_write_8(resp_buf, 0x01); /* Write report byte */ +} + +static HRESULT dongle_cmd_read_misc_switches(struct dongle *dongle, struct const_iobuf *req_buf, struct iobuf *resp_buf) +{ + uint8_t cmd; + uint8_t arg; + HRESULT hr; + + hr = iobuf_read_8(req_buf, &cmd); + + if (FAILED(hr)) { + return hr; + } + + hr = iobuf_read_8(req_buf, &arg); + + if (FAILED(hr)) { + return hr; + } + + hr = iobuf_write_8(resp_buf, 0x01); /* Write report byte */ + + if (FAILED(hr)) { + return hr; + } + + return iobuf_write_8(resp_buf, NO_CARD); /* Write status byte */ +} + +static HRESULT dongle_cmd_taito_nesica_read(struct dongle *dongle, struct const_iobuf *req_buf, struct iobuf *resp_buf) +{ + uint8_t cmd; + HRESULT hr = iobuf_read_8(req_buf, &cmd); + + if (FAILED(hr)) { + return hr; + } + + hr = iobuf_write_8(resp_buf, 0x01); /* Write report byte */ + + if (FAILED(hr)) { + return hr; + } + + hr = iobuf_write(resp_buf, card_uid, 8); // AICC: Unused, should be IDm + + if (FAILED(hr)) { + return hr; + } + + return iobuf_write(resp_buf, cfg.serial, 16); // AICC: SPAD0 +} + +static HRESULT dongle_cmd_taito_aic_read(struct dongle *dongle, struct const_iobuf *req_buf, struct iobuf *resp_buf) +{ + uint8_t cmd; + HRESULT hr = iobuf_read_8(req_buf, &cmd); + + if (FAILED(hr)) { + return hr; + } + + hr = iobuf_write_8(resp_buf, 0x01); /* Write report byte */ + + if (FAILED(hr)) { + return hr; + } + + hr = iobuf_write(resp_buf, card_id, 16); // ID + + if (FAILED(hr)) { + return hr; + } + + hr = iobuf_write(resp_buf, "\x00\x01", 2); // CKV + + if (FAILED(hr)) { + return hr; + } + + hr = iobuf_write(resp_buf, "\x02\x00\x00", 3); // WCNT + + if (FAILED(hr)) { + return hr; + } + + return iobuf_write(resp_buf, "12345678", 8); // MAC_A? +} diff --git a/board/dongle.h b/board/dongle.h new file mode 100644 index 0000000..0acda41 --- /dev/null +++ b/board/dongle.h @@ -0,0 +1,25 @@ +#pragma once +#include + +#include "jvs/jvs-bus.h" + +#pragma pack(push,1) +struct dongle { + struct jvs_node jvs; + uint8_t state; + uint8_t addr; + void *ops_ctx; +}; + +struct dongle_config { + wchar_t serial[16]; +}; + +#pragma pack(pop) + +void dongle_init( + struct dongle *dongle, + struct jvs_node *next, + void *ops_ctx); + +struct jvs_node *dongle_to_jvs_node(struct dongle *dongle); diff --git a/board/meson.build b/board/meson.build index 7b87bdb..ab44008 100644 --- a/board/meson.build +++ b/board/meson.build @@ -14,6 +14,8 @@ board_lib = static_library( 'config.h', 'guid.c', 'guid.h', + 'dongle.c', + 'dongle.h', 'io3.c', 'io3.h', 'k92x0249.c', diff --git a/gchook/dllmain.c b/gchook/dllmain.c index 09c50aa..dd8fc3c 100644 --- a/gchook/dllmain.c +++ b/gchook/dllmain.c @@ -57,7 +57,6 @@ static DWORD CALLBACK gc_pre_startup(void) struct idmac_hardware idhw = { .dipsw = 0b0000, - .dongle = NULL, .jvs = gc_reader_init, .fastio_main = gc_fastio_init, .fastio_sub = NULL, diff --git a/gchook/reader.c b/gchook/reader.c index 1f85539..c942718 100644 --- a/gchook/reader.c +++ b/gchook/reader.c @@ -4,6 +4,7 @@ #include "jvs/jvs-bus.h" #include "idmac/jvs.h" #include "board/k92x0249.h" +#include "board/dongle.h" #include "gchook/reader.h" #include "gchook/gc-dll.h" @@ -11,6 +12,7 @@ #include "util/dprintf.h" static struct k92x0249 gc_jvs_reader; +static struct dongle gc_dongle; HRESULT gc_reader_init(struct jvs_node **out) { @@ -20,7 +22,8 @@ HRESULT gc_reader_init(struct jvs_node **out) dprintf("Gc Nesica Reader: Init\n"); - k92x0249_init(&gc_jvs_reader, NULL, NULL); + dongle_init(&gc_dongle, NULL, NULL); + k92x0249_init(&gc_jvs_reader, dongle_to_jvs_node(&gc_dongle), NULL); *out = k92x0249_to_jvs_node(&gc_jvs_reader); return S_OK; diff --git a/idmac/idmac.h b/idmac/idmac.h index aab31b5..4829ece 100644 --- a/idmac/idmac.h +++ b/idmac/idmac.h @@ -16,7 +16,6 @@ struct idmac_config { struct idmac_hardware { uint8_t dipsw; - jvs_provider_t dongle; jvs_provider_t jvs; fastio_provider_t fastio_main; fastio_provider_t fastio_sub; diff --git a/sivahook/dllmain.c b/sivahook/dllmain.c index 5e134e0..31851d4 100644 --- a/sivahook/dllmain.c +++ b/sivahook/dllmain.c @@ -59,7 +59,6 @@ static DWORD CALLBACK siva_pre_startup(void) struct idmac_hardware idhw = { .dipsw = 0b0000, - .dongle = NULL, .jvs = siva_reader_init, .fastio_main = siva_fastio_init, .fastio_sub = NULL,