From 112348ce3852cd5e2ef30f69b85a07b5a1082d09 Mon Sep 17 00:00:00 2001 From: Hay1tsme Date: Fri, 31 Jan 2025 06:07:46 -0500 Subject: [PATCH] JVS reader OK, fastio progress --- board/j9100628a.c | 485 +++++++++++++++++++++++++++++++++++++++++++ board/j9100628a.h | 25 +++ board/meson.build | 2 + doc/config/common.md | 29 +++ idmac/fastio.c | 61 +++++- idmac/fastio.h | 18 +- idmac/idmac.c | 11 +- idmac/jvs.c | 59 ++++-- jvs/jvs-bus.h | 1 + jvs/jvs-cmd.h | 26 ++- platform/cert.c | 15 ++ sivahook/fastio.c | 29 ++- sivahook/fastio.h | 2 +- sivahook/reader.c | 36 ++-- sivahook/unity.c | 1 + sivaio/config.c | 2 +- 16 files changed, 726 insertions(+), 76 deletions(-) create mode 100644 board/j9100628a.c create mode 100644 board/j9100628a.h diff --git a/board/j9100628a.c b/board/j9100628a.c new file mode 100644 index 0000000..10da0b5 --- /dev/null +++ b/board/j9100628a.c @@ -0,0 +1,485 @@ +#include + +#include +#include +#include +#include +#include + +#include "board/j9100628a.h" + +#include "jvs/jvs-bus.h" +#include "jvs/jvs-cmd.h" +#include "jvs/jvs-util.h" + +#include "util/dprintf.h" +#include "util/dump.h" + +static const uint8_t j9100628a_ident[] = "taito;JVS-Reader;Ver1.00;JPN,Multipurpose"; + +static uint8_t j9100628a_features[] = { + /* Feature : 0x01 : Players and switches + Param1 : 1 : Number of players + Param2 : 18 : Number of switches per player + Param3 : 0 : N/A */ + + 0x01, + 0x01, + 0x18, + 0x00, + + /* Feature : 0x02 : Coin slots + Param1 : 2 : Number of coin slots + Param2 : 0 : N/A + Param3 : 0 : N/A */ + + 0x02, + 0x00, + 0x00, + 0x00, + + /* Feature : 0x03 : Analog inputs + Param1 : 8 : Number of ADC channels + Param2 : 10 : Effective bits of resolution per ADC + Param3 : 0 : N/A */ + + 0x03, + 0x00, + 0x00, + 0x00, + + /* Feature : 0x04 : Rotary Input + Param1 : 4 : Number of Rotary channels + Param2 : 0 : N/A + Param3 : 0 : N/A */ + + 0x04, + 0x00, + 0x00, + 0x00, + + /* Feature : 0x12 : GPIO outputs + Param1 : 3 : Number of ports (8 bits per port) + Param2 : 0 : N/A + Param3 : 0 : N/A + */ + + 0x12, + 0x00, + 0x00, + 0x00, + + /* Feature : 0x13 : Analog outputs + Param1 : 2 : Number of channels + Param2 : 0 : N/A + Param3 : 0 : N/A + */ + + 0x13, + 0x00, + 0x00, + 0x00, + + /* Feature : 0x14 : Character Output + Param1 : 0x50 : Width + Param2 : 0x19 : Height + Param3 : 0 : Type + */ + 0x14, + 0x50, + 0x19, + 0x00, + + /* Feature : 0x00 : End of capabilities */ + + 0x00, +}; + +static void j9100628a_transact( + struct jvs_node *node, + const void *bytes, + size_t nbytes, + struct iobuf *resp); + +static bool j9100628a_sense(struct jvs_node *node); + +static HRESULT j9100628a_cmd( + void *ctx, + struct const_iobuf *req, + struct iobuf *resp); + +static HRESULT j9100628a_cmd_reset(struct j9100628a *j9100628a, struct const_iobuf *req_buf); +static HRESULT j9100628a_cmd_assign_addr(struct j9100628a *j9100628a, struct const_iobuf *req_buf, struct iobuf *resp_buf); +static HRESULT j9100628a_cmd_read_id(struct j9100628a *j9100628a, struct const_iobuf *req_buf, struct iobuf *resp_buf); +static HRESULT j9100628a_cmd_get_cmd_version(struct j9100628a *j9100628a, struct const_iobuf *req_buf, struct iobuf *resp_buf); +static HRESULT j9100628a_cmd_get_jvs_version(struct j9100628a *j9100628a, struct const_iobuf *req_buf, struct iobuf *resp_buf); +static HRESULT j9100628a_cmd_get_comm_version(struct j9100628a *j9100628a, struct const_iobuf *req_buf, struct iobuf *resp_buf); +static HRESULT j9100628a_cmd_get_features(struct j9100628a *j9100628a, struct const_iobuf *req_buf, struct iobuf *resp_buf); +static HRESULT j9100628a_cmd_read_misc_switches(struct j9100628a *j9100628a, struct const_iobuf *req_buf, struct iobuf *resp_buf); +static HRESULT j9100628a_cmd_read_dip_switches(struct j9100628a *j9100628a, struct const_iobuf *req_buf, struct iobuf *resp_buf); +static HRESULT j9100628a_cmd_write_gpio(struct j9100628a *j9100628a, struct const_iobuf *req_buf, struct iobuf *resp_buf); + +void j9100628a_init( + struct j9100628a *j9100628a, + struct jvs_node *next, + const struct j9100628a_ops *ops, + void *ops_ctx) +{ + assert(j9100628a != NULL); + assert(ops != NULL); + + j9100628a->jvs.next = next; + j9100628a->jvs.transact = j9100628a_transact; + j9100628a->jvs.sense = j9100628a_sense; + j9100628a->jvs.sense_out = true; + j9100628a->addr = 0xFF; + j9100628a->ops = ops; + j9100628a->ops_ctx = ops_ctx; +} + +struct jvs_node *j9100628a_to_jvs_node(struct j9100628a *j9100628a) +{ + assert(j9100628a != NULL); + + return &j9100628a->jvs; +} + +static void j9100628a_transact( + struct jvs_node *node, + const void *bytes, + size_t nbytes, + struct iobuf *resp) +{ + struct j9100628a *j9100628a; + + assert(node != NULL); + assert(bytes != NULL); + assert(resp != NULL); + + j9100628a = CONTAINING_RECORD(node, struct j9100628a, jvs); + + jvs_crack_request(bytes, nbytes, resp, j9100628a->addr, j9100628a_cmd, j9100628a); +} + +static bool j9100628a_sense(struct jvs_node *node) +{ + struct j9100628a *j9100628a; + + assert(node != NULL); + + j9100628a = CONTAINING_RECORD(node, struct j9100628a, jvs); + + return j9100628a->addr == 0xFF; +} + +static HRESULT j9100628a_cmd( + void *ctx, + struct const_iobuf *req, + struct iobuf *resp) +{ + struct j9100628a *j9100628a; + + j9100628a = ctx; + + switch (req->bytes[req->pos]) { + case JVS_CMD_RESET: + return j9100628a_cmd_reset(j9100628a, req); + + case JVS_CMD_ASSIGN_ADDR: + return j9100628a_cmd_assign_addr(j9100628a, req, resp); + + case JVS_CMD_READ_ID: + return j9100628a_cmd_read_id(j9100628a, req, resp); + + case JVS_CMD_GET_CMD_VERSION: + return j9100628a_cmd_get_cmd_version(j9100628a, req, resp); + + case JVS_CMD_GET_JVS_VERSION: + return j9100628a_cmd_get_jvs_version(j9100628a, req, resp); + + case JVS_CMD_GET_COMM_VERSION: + return j9100628a_cmd_get_comm_version(j9100628a, req, resp); + + case JVS_CMD_GET_FEATURES: + return j9100628a_cmd_get_features(j9100628a, req, resp); + + case JVS_CMD_READ_MISC_SWITCHES: + return j9100628a_cmd_read_misc_switches(j9100628a, req, resp); + + case JVS_CMD_TYPEX_READ_DIPSW: + return j9100628a_cmd_read_dip_switches(j9100628a, req, resp); + + case JVS_CMD_TYPEX_POLL_AMIC: + // FIXME: seperate func + return j9100628a_cmd_read_dip_switches(j9100628a, req, resp); + + case JVS_CMD_WRITE_GPIO: + return j9100628a_cmd_write_gpio(j9100628a, req, resp); + + default: + dprintf("J9100628A: Node %02x: Unhandled command byte %02x\n", + j9100628a->addr, + req->bytes[req->pos]); + + return E_NOTIMPL; + } + + return S_OK; +} + +static HRESULT j9100628a_cmd_reset(struct j9100628a *j9100628a, 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("J9100628A: Reset (param %02x)\n", req.unknown); + j9100628a->addr = 0xFF; + j9100628a->jvs.sense_out = false; // ? + + if (j9100628a->ops->reset != NULL) { + j9100628a->ops->reset(j9100628a->ops_ctx); + } + + /* No ack for this since it really is addressed to everybody */ + + return S_OK; +} + +static HRESULT j9100628a_cmd_assign_addr( + struct j9100628a *j9100628a, + 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(j9100628a->jvs.next); + dprintf("J9100628A: Assign addr %02x sense %i\n", req.addr, sense); + + if (sense) { + /* That address is for somebody else */ + return S_OK; + } + + j9100628a->addr = req.addr; + j9100628a->jvs.sense_out = true; + + return iobuf_write_8(resp_buf, 0x01); +} + +static HRESULT j9100628a_cmd_read_id(struct j9100628a *j9100628a, 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("JVS I/O: 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, j9100628a_ident, sizeof(j9100628a_ident)); +} + +static HRESULT j9100628a_cmd_get_cmd_version(struct j9100628a *j9100628a, 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("JVS I/O: 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 j9100628a_cmd_get_jvs_version(struct j9100628a *j9100628a, 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("JVS I/O: 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 j9100628a_cmd_get_comm_version(struct j9100628a *j9100628a, 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("JVS I/O: 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 j9100628a_cmd_get_features(struct j9100628a *j9100628a, 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("JVS I/O: Get reader features\n"); + + hr = iobuf_write_8(resp_buf, 0x01); /* Write report byte */ + + if (FAILED(hr)) { + return hr; + } + + return iobuf_write(resp_buf, j9100628a_features, sizeof(j9100628a_features)); +} + +static HRESULT j9100628a_cmd_read_misc_switches(struct j9100628a *j9100628a, 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; + } + + hr = iobuf_write_8(resp_buf, 0x01); /* Write report byte */ + + if (FAILED(hr)) { + return hr; + } + + return iobuf_write_8(resp_buf, 0x00); /* Write switch byte */ +} + +static HRESULT j9100628a_cmd_read_dip_switches(struct j9100628a *j9100628a, 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; + } + + hr = iobuf_write_8(resp_buf, 0x01); /* Write report byte */ + + if (FAILED(hr)) { + return hr; + } + + return iobuf_write_8(resp_buf, 0x00); /* Write switch byte */ +} + +static HRESULT j9100628a_cmd_write_gpio( + struct j9100628a *j9100628a, + struct const_iobuf *req_buf, + struct iobuf *resp_buf) +{ + uint8_t cmd; + uint8_t nbytes; + uint8_t bytes[3]; + HRESULT hr; + + /* Read request header */ + + hr = iobuf_read_8(req_buf, &cmd); + + if (FAILED(hr)) { + return hr; + } + + hr = iobuf_read_8(req_buf, &nbytes); + + if (FAILED(hr)) { + return hr; + } + + if (nbytes > 3) { + dprintf("J9100628A: Invalid GPIO write size %i\n", nbytes); + hr = iobuf_write_8(resp_buf, 0x02); + + if (FAILED(hr)) { + return hr; + } + + return E_FAIL; + } + + /* Read payload */ + + memset(bytes, 0, sizeof(bytes)); + hr = iobuf_read(req_buf, bytes, nbytes); + + if (FAILED(hr)) { + return hr; + } + + if (j9100628a->ops->write_led != NULL) { + j9100628a->ops->write_led( + j9100628a->ops_ctx, + bytes[0] | (bytes[1] << 8) | (bytes[2] << 16)); + } + + /* Write report byte */ + + return iobuf_write_8(resp_buf, 0x01); +} diff --git a/board/j9100628a.h b/board/j9100628a.h new file mode 100644 index 0000000..cf887bb --- /dev/null +++ b/board/j9100628a.h @@ -0,0 +1,25 @@ +#pragma once +#include + +#include "jvs/jvs-bus.h" + +struct j9100628a_ops { + void (*reset)(void *ctx); + void (*write_led)(void *ctx, uint32_t state); + void (*poll_card)(void *ctx, char *serial); +}; + +struct j9100628a { + struct jvs_node jvs; + uint8_t addr; + const struct j9100628a_ops *ops; + void *ops_ctx; +}; + +void j9100628a_init( + struct j9100628a *j9100628a, + struct jvs_node *next, + const struct j9100628a_ops *ops, + void *ops_ctx); + +struct jvs_node *j9100628a_to_jvs_node(struct j9100628a *j9100628a); diff --git a/board/meson.build b/board/meson.build index 379f77d..2cb30e6 100644 --- a/board/meson.build +++ b/board/meson.build @@ -15,6 +15,8 @@ board_lib = static_library( 'guid.h', 'io3.c', 'io3.h', + 'j9100628a.c', + 'j9100628a.h', 'io4.c', 'io4.h', 'sg-cmd.c', diff --git a/doc/config/common.md b/doc/config/common.md index 00e29d8..460461e 100644 --- a/doc/config/common.md +++ b/doc/config/common.md @@ -231,3 +231,32 @@ If 1, hook the iDmacDrvxx.dll functions, otherwise create a fake device. Set to 1 if you're using the stub included with this hook as a substitute for the real DLL. Both hooking methods lead to the same place, so it doesn't matter too much what you use. + +## `[cert]` +### `enable` + +Default: 1 + +If 1, hooks functions related to server and client certificate processing. + +### `server_cert` + +Default: `cert/Server.pfx` + +Location of the PKCS #12 file containing the certificates used to verify the server + +### `client_cert` + +Default: `` + +Location of the PKCS #12 containing the certificates used by the client to do mTLS. If +your data already came with a cert and the server you're connecting to doesn't use mTLS +you can leave this blank to let the game use it's own (TODO verify) + +### `insecure` + +Default: 0 + +If 1, overrides `WinHttpSetOption`s `WINHTTP_OPTION_SECURITY_FLAGS` behavior to ignore almost all SSL errors. +Useful for testing or if your server sysadmin is lazy. Should be disabled otherwise. + \ No newline at end of file diff --git a/idmac/fastio.c b/idmac/fastio.c index 669f99e..78d62af 100644 --- a/idmac/fastio.c +++ b/idmac/fastio.c @@ -1,6 +1,63 @@ +#include +#include + #include "idmac/fastio.h" +#include "util/dprintf.h" + +static struct fastio_node fio_main; +static struct fastio_node fio_sub; HRESULT fastio_hook_init(fastio_provider_t main, fastio_provider_t sub) { - return S_OK; -} \ No newline at end of file + struct fastio_node fio; + HRESULT hr = S_OK; + + dprintf("FastIO: Init main %p sub %p\n", main, sub); + + if (main != NULL) { + fio_main.board_no = 0; // Maybe 0 should be the PCB itself and connected IO boards start at 1? + hr = main(&fio_main); + } + + if (FAILED(hr)) { + return hr; + } + + if (sub != NULL) { + // TODO: Unsure if "sub" is treated as input from another box, or just a 2nd link in the chain + //fio.next = (struct fastio_node *) malloc(sizeof(struct fastio_node)); + hr = sub(&fio_sub); + } + + return hr; +} + + +/// Itterate over the chain of connected boards and return a pointer to the board with the requested number +void fastio_match_board_number(uint8_t board_no, struct fastio_node root, struct fastio_node *board) +{ + assert(&root != NULL); + + board = &root; + while (board->next != NULL && board->next->board_no != board_no) { + board = board->next; + } + + if (board->board_no != board_no) { + // We've exhausted our boards, give a warning and set boards to NULL + dprintf("FastIO: Could not find board number %d\n", board_no); + board = NULL; + } +} + +void fastio_digital_read(void* ctx, uint8_t board_no, uint32_t *out) +{ + struct fastio_node *req_board = NULL; + fastio_match_board_number(board_no, fio_main, req_board); + + // If we fail to find, or the board we found doesn't have the handler we need, + // quietly return with out unmodified + if (req_board != NULL && req_board->digital_in != NULL) { + fio_main.digital_in(ctx, out); + } +} diff --git a/idmac/fastio.h b/idmac/fastio.h index 41e89e0..1dbe578 100644 --- a/idmac/fastio.h +++ b/idmac/fastio.h @@ -2,19 +2,23 @@ #include #include +#pragma pack(push, 1) struct fastio_node { struct fastio_node *next; + uint8_t board_no; // Unlike JVS, FastIO comms are done on the game side through // DMA register reads and writes, meaning we need to have // indivitual functions here instead of just "transact" - void (*digital_in)(uint16_t *out); // Digital button inputs - void (*analog_in)(uint16_t *out); // Analog stick inputs (WIP) - void (*coins_in)(uint8_t slot, uint16_t *out); // Number of unprocessed coins - void (*digital_out)(uint16_t channel, uint16_t val); // Digital outputs - void (*analog_out)(uint16_t channel, uint16_t val); // Analog outputs (WIP) - void (*coins_out)(uint8_t slot, uint16_t removed); // Remove coins from the count + void (*digital_in)(void* ctx, uint32_t *out); // Digital button inputs + void (*analog_in)(void* ctx, uint16_t *out); // Analog stick inputs (WIP) + void (*coins_in)(void* ctx, uint8_t slot, uint32_t *out); // Number of unprocessed coins + void (*digital_out)(void* ctx, uint16_t channel, uint16_t val); // Digital outputs + void (*analog_out)(void* ctx, uint16_t channel, uint16_t val); // Analog outputs (WIP) + void (*coins_out)(void* ctx, uint8_t slot, uint16_t removed); // Remove coins from the count }; +#pragma pack(pop) -typedef HRESULT (*fastio_provider_t)(struct fastio_node **root); +typedef HRESULT (*fastio_provider_t)(struct fastio_node *root); HRESULT fastio_hook_init(fastio_provider_t main, fastio_provider_t sub); +void fastio_digital_read(void* ctx, uint8_t board_no, uint32_t *out); diff --git a/idmac/idmac.c b/idmac/idmac.c index b0448fe..3329351 100644 --- a/idmac/idmac.c +++ b/idmac/idmac.c @@ -172,7 +172,11 @@ HRESULT idmac_hook_init(const struct idmac_config *cfg, struct idmac_hardware *h return hr; } - fastio_hook_init(hardware->fastio_main, hardware->fastio_sub); + hr = fastio_hook_init(hardware->fastio_main, hardware->fastio_sub); + + if (FAILED(hr)) { + return hr; + } idmac_hook_table_apply(NULL); @@ -312,9 +316,10 @@ static int hook_iDmacDrvRegisterRead(HANDLE a1, DWORD register_id, DWORD* regist case 0x4004: *register_val = -2; break; // Status case 0x4120: // JVS Buttons - if (GetAsyncKeyState(VK_DELETE) & 0x8000) { + /*if (GetAsyncKeyState(VK_DELETE) & 0x8000) { *register_val = 0x40; // Test - } + }*/ + fastio_digital_read(NULL, 0, (uint32_t *)register_val); break; case 0x4124: break; // Analog 1 diff --git a/idmac/jvs.c b/idmac/jvs.c index d76fabb..73a2cce 100644 --- a/idmac/jvs.c +++ b/idmac/jvs.c @@ -35,8 +35,16 @@ static CRITICAL_SECTION jvs_lock; static struct uart jvs_uart; static uint8_t jvs_written_bytes[516]; static uint8_t jvs_readable_bytes[516]; +static uint8_t temp_bytes[516]; static struct jvs_node *jvs_root; static jvs_provider_t jvs_provider; +static struct iobuf tmp = { + .nbytes = 516, + .pos = 0, + .bytes = temp_bytes +}; +static bool last = false; +static uint8_t num_cts = 0; HRESULT jvs_hook_init(const struct jvs_config *cfg, jvs_provider_t provider) { @@ -100,35 +108,40 @@ static HRESULT jvs_handle_irp_locked(struct irp *irp) } } + if (irp->op == IRP_OP_IOCTL) { + switch (irp->ioctl) { + case IOCTL_SERIAL_GET_MODEMSTATUS: + //jvs_uart.cts_on = jvs_root->sense_out; + //dprintf("JVS: Set CTS to %X\n", jvs_root->sense_out); + jvs_uart.cts_on = jvs_root->sense_out; + break; + case IOCTL_SERIAL_GET_COMMSTATUS: + //dprintf("JVS: Set cbInQue to %d\n", (int)tmp.pos); + jvs_uart.readable.pos = tmp.pos; + default: break; + } + } + + if (irp->op == IRP_OP_READ) { + if (irp->read.nbytes > 1) { + //dprintf("JVS: Readable buffer is %d / %d\n", (int)irp->read.nbytes, (int)tmp.pos); + iobuf_write(&irp->read, tmp.bytes, tmp.pos); + tmp.pos = 0; + } else { + dprintf("JVS: Readable buffer is 1!\n"); + } + } + hr = uart_handle_irp(&jvs_uart, irp); if (FAILED(hr) || irp->op != IRP_OP_WRITE) { return hr; } - jvs_bus_transact(jvs_root, irp->write.bytes, irp->write.nbytes, &irp->read); + //jvs_bus_transact(jvs_root, irp->write.bytes, irp->write.nbytes, &irp->read); + jvs_bus_transact(jvs_root, irp->write.bytes, irp->write.nbytes, &tmp); -#if 1 - dprintf("JVS Port: Inbound frame:\n"); - dump_iobuf(&irp->read); - dprintf("\n"); -#endif + jvs_uart.written.pos = 0; - if (irp->read.pos == 0) { - /* The un-acked JVS reset command must return ERROR_NO_DATA_DETECTED, - and this error must always be returned asynchronously. And since - async I/O comes from the NT kernel, we have to return that win32 - error as the equivalent NTSTATUS. */ - - if (irp->ovl == NULL || irp->ovl->hEvent == NULL) { - return HRESULT_FROM_WIN32(ERROR_NO_DATA_DETECTED); - } - - irp->ovl->Internal = STATUS_NO_DATA_DETECTED; - SetEvent(irp->ovl->hEvent); - - return HRESULT_FROM_WIN32(ERROR_IO_PENDING); - } else { - return S_OK; - } + return S_OK; } diff --git a/jvs/jvs-bus.h b/jvs/jvs-bus.h index 820ba20..0f58f7a 100644 --- a/jvs/jvs-bus.h +++ b/jvs/jvs-bus.h @@ -13,6 +13,7 @@ struct jvs_node { size_t nbytes, struct iobuf *resp); bool (*sense)(struct jvs_node *node); + bool sense_out; }; void jvs_bus_transact( diff --git a/jvs/jvs-cmd.h b/jvs/jvs-cmd.h index 0197c9f..efbb476 100644 --- a/jvs/jvs-cmd.h +++ b/jvs/jvs-cmd.h @@ -1,17 +1,21 @@ #pragma once enum { - JVS_CMD_READ_ID = 0x10, - JVS_CMD_GET_CMD_VERSION = 0x11, - JVS_CMD_GET_JVS_VERSION = 0x12, - JVS_CMD_GET_COMM_VERSION = 0x13, - JVS_CMD_GET_FEATURES = 0x14, - JVS_CMD_READ_SWITCHES = 0x20, - JVS_CMD_READ_COIN = 0x21, - JVS_CMD_READ_ANALOGS = 0x22, - JVS_CMD_WRITE_GPIO = 0x32, - JVS_CMD_RESET = 0xF0, - JVS_CMD_ASSIGN_ADDR = 0xF1, + JVS_CMD_TYPEX_READ_DIPSW = 0x01, + JVS_CMD_READ_ID = 0x10, + JVS_CMD_GET_CMD_VERSION = 0x11, + JVS_CMD_GET_JVS_VERSION = 0x12, + JVS_CMD_GET_COMM_VERSION = 0x13, + JVS_CMD_GET_FEATURES = 0x14, + JVS_CMD_READ_SWITCHES = 0x20, + JVS_CMD_READ_COIN = 0x21, + JVS_CMD_READ_ANALOGS = 0x22, + JVS_CMD_READ_MISC_SWITCHES = 0x26, + JVS_CMD_WRITE_GPIO = 0x32, + JVS_CMD_TYPEX_POLL_AMIC = 0x61, + JVS_CMD_TYPEX_POLL_CARD = 0x66, + JVS_CMD_RESET = 0xF0, + JVS_CMD_ASSIGN_ADDR = 0xF1, }; #pragma pack(push, 1) diff --git a/platform/cert.c b/platform/cert.c index 974c86e..758e045 100644 --- a/platform/cert.c +++ b/platform/cert.c @@ -14,6 +14,21 @@ #include "util/dprintf.h" #include "util/str.h" +/* + * There are 2 certs we care about within this hook, the client cert, + * and server cert. The client cert is usually stored in a p12 file and + * identifies the game cabinet, and what nesica plan the game should use + * for billing. It's used in mTLS so the server can verify the client. + * The server cert is used for SSL cert pinning so the client can verify + * the server. Unless the server you're connecting to requires a proper + * mTLS setup, you can pretty safely disregard the client cert as long as + * it exists and the game can find it. The server cert is traditionally + * gotten around by adding the server's CA cert to the PCs root store, but + * that sucks for UX and is generally not a good idea, so this hook aims + * to replace (or disable the need for, if able) the server cert without + * having to mess with CA stores. +*/ + static CRITICAL_SECTION cert_lock; static wchar_t path[MAX_PATH]; diff --git a/sivahook/fastio.c b/sivahook/fastio.c index 4012f1b..157f51a 100644 --- a/sivahook/fastio.c +++ b/sivahook/fastio.c @@ -10,18 +10,21 @@ #include "util/dprintf.h" -static void fastio_digital_read(void *ctx, struct io3_switch_state *out); -static void fastio_coin_read( +static void siva_fastio_digital_read(void *ctx, uint32_t *out); +static void siva_fastio_coin_read( void *ctx, uint8_t slot_no, - uint16_t *out); + uint32_t *out); -HRESULT siva_fastio_init(struct fastio_node **out) +HRESULT siva_fastio_init(struct fastio_node *out) { HRESULT hr; assert(out != NULL); + out->digital_in = siva_fastio_digital_read; + out->coins_in = siva_fastio_coin_read; + dprintf("Siva Nesica Fastio: Init\n"); siva_dll.init(); @@ -29,9 +32,15 @@ HRESULT siva_fastio_init(struct fastio_node **out) return S_OK; } -static void fastio_digital_read(void *ctx, struct io3_switch_state *out) {} -static void fastio_coin_read( - void *ctx, - uint8_t slot_no, - uint16_t *out) - {} \ No newline at end of file +static void siva_fastio_digital_read(void *ctx, uint32_t *out) +{ + +} + +static void siva_fastio_coin_read( + void *ctx, + uint8_t slot_no, + uint32_t *out) +{ + +} \ No newline at end of file diff --git a/sivahook/fastio.h b/sivahook/fastio.h index 20e37e3..03257ef 100644 --- a/sivahook/fastio.h +++ b/sivahook/fastio.h @@ -22,4 +22,4 @@ enum SIVA_SWITCH { SYS_COIN = 0x000001, }; -HRESULT siva_fastio_init(struct fastio_node **out); +HRESULT siva_fastio_init(struct fastio_node *out); diff --git a/sivahook/reader.c b/sivahook/reader.c index 57c051a..ffe818c 100644 --- a/sivahook/reader.c +++ b/sivahook/reader.c @@ -3,25 +3,22 @@ #include "jvs/jvs-bus.h" #include "idmac/jvs.h" -#include "board/io3.h" +#include "board/j9100628a.h" #include "sivahook/reader.h" #include "sivahook/siva-dll.h" #include "util/dprintf.h" -static void reader_jvs_read_switches(void *ctx, struct io3_switch_state *out); -static void reader_jvs_read_coin_counter( - void *ctx, - uint8_t slot_no, - uint16_t *out); +static void reader_jvs_write_led(void *ctx, uint32_t state); +static void reader_jvs_poll_card(void *ctx, char *serial); -static const struct io3_ops siva_jvs_reader_ops = { - .read_switches = reader_jvs_read_switches, - .read_coin_counter = reader_jvs_read_coin_counter, +static const struct j9100628a_ops siva_jvs_reader_ops = { + .write_led = reader_jvs_write_led, + .poll_card = reader_jvs_poll_card, }; -static struct io3 siva_jvs_reader; +static struct j9100628a siva_jvs_reader; HRESULT siva_reader_init(struct jvs_node **out) { @@ -31,15 +28,18 @@ HRESULT siva_reader_init(struct jvs_node **out) dprintf("Siva Nesica Reader: Init\n"); - io3_init(&siva_jvs_reader, NULL, &siva_jvs_reader_ops, NULL); - *out = io3_to_jvs_node(&siva_jvs_reader); + j9100628a_init(&siva_jvs_reader, NULL, &siva_jvs_reader_ops, NULL); + *out = j9100628a_to_jvs_node(&siva_jvs_reader); return S_OK; } -static void reader_jvs_read_switches(void *ctx, struct io3_switch_state *out) {} -static void reader_jvs_read_coin_counter( - void *ctx, - uint8_t slot_no, - uint16_t *out) - {} \ No newline at end of file +static void reader_jvs_write_led(void *ctx, uint32_t state) +{ + +} + +static void reader_jvs_poll_card(void *ctx, char *serial) +{ + +} diff --git a/sivahook/unity.c b/sivahook/unity.c index bfedf79..69918b3 100644 --- a/sivahook/unity.c +++ b/sivahook/unity.c @@ -120,6 +120,7 @@ static HMODULE WINAPI my_LoadLibraryW(const wchar_t *name) dns_hook_apply_hooks(result); netenv_hook_apply(result); idmac_hook_table_apply(result); + iohook_apply_hooks(result); serial_hook_apply_hooks(result); clock_hook_insert_hooks(result); } diff --git a/sivaio/config.c b/sivaio/config.c index aa2cbf3..e19f954 100644 --- a/sivaio/config.c +++ b/sivaio/config.c @@ -12,7 +12,7 @@ void siva_io_config_load(struct siva_input_config *cfg, const wchar_t *filename) cfg->service = GetPrivateProfileIntW(L"jvs", L"service", VK_DELETE, filename); cfg->coin = GetPrivateProfileIntW(L"jvs", L"coin", VK_INSERT, filename); - cfg->is_xinput = GetPrivateProfileIntW(L"deck", L"deck", 0, filename); + cfg->is_xinput = GetPrivateProfileIntW(L"deck", L"controller_type", 0, filename); cfg->xinput_player = GetPrivateProfileIntW(L"deck", L"controller_num", 0, filename); cfg->btn_l = GetPrivateProfileIntW(L"deck", L"left_button", 'C', filename);