diff --git a/idzhook/_com10.c b/idzhook/_com10.c new file mode 100644 index 0000000..02055f9 --- /dev/null +++ b/idzhook/_com10.c @@ -0,0 +1,75 @@ +#include + +#include +#include + +#include "aimeio/aimeio.h" + +#include "board/sg-led.h" +#include "board/sg-nfc.h" +#include "board/sg-reader.h" + +#include "divahook/_com10.h" + +#include "hook/iohook.h" + +static HRESULT com10_handle_irp(struct irp *irp); +static HRESULT com10_mifare_poll(void *ctx, uint32_t *uid); +static HRESULT com10_mifare_read_luid( + void *ctx, + uint32_t uid, + uint8_t *luid, + size_t nbytes); +static void com10_led_set_color(void *ctx, uint8_t r, uint8_t g, uint8_t b); + +static const struct sg_nfc_ops com10_nfc_ops = { + .mifare_poll = com10_mifare_poll, + .mifare_read_luid = com10_mifare_read_luid, +}; + +static const struct sg_led_ops com10_led_ops = { + .set_color = com10_led_set_color, +}; + +static struct sg_reader com10_reader; + +HRESULT com10_hook_init(void) +{ + HRESULT hr; + + hr = aime_io_init(); + + if (FAILED(hr)) { + return hr; + } + + sg_reader_init(&com10_reader, 10, &com10_nfc_ops, &com10_led_ops, NULL); + + return iohook_push_handler(com10_handle_irp); +} + +static HRESULT com10_handle_irp(struct irp *irp) +{ + assert(irp != NULL); + + return sg_reader_handle_irp(&com10_reader, irp); +} + +static HRESULT com10_mifare_poll(void *ctx, uint32_t *uid) +{ + return aime_io_mifare_poll(0, uid); +} + +static HRESULT com10_mifare_read_luid( + void *ctx, + uint32_t uid, + uint8_t *luid, + size_t luid_size) +{ + return aime_io_mifare_read_luid(0, uid, luid, luid_size); +} + +static void com10_led_set_color(void *ctx, uint8_t r, uint8_t g, uint8_t b) +{ + aime_io_led_set_color(0, r, g, b); +} diff --git a/idzhook/_com10.h b/idzhook/_com10.h new file mode 100644 index 0000000..2bedc59 --- /dev/null +++ b/idzhook/_com10.h @@ -0,0 +1,5 @@ +#pragma once + +#include + +HRESULT com10_hook_init(void); diff --git a/idzhook/dllmain.c b/idzhook/dllmain.c new file mode 100644 index 0000000..5e6402c --- /dev/null +++ b/idzhook/dllmain.c @@ -0,0 +1,82 @@ +#include + +#include +#include + +#include "amex/ds.h" +#include "amex/eeprom.h" +#include "amex/gpio.h" +#include "amex/jvs.h" +#include "amex/sram.h" + +#include "hook/process.h" + +#include "hooklib/serial.h" + +#include "idzhook/_com10.h" +#include "idzhook/jvs.h" + +#include "platform/hwmon.h" +#include "platform/nusec.h" + +#include "util/clock.h" +#include "util/dprintf.h" +#include "util/gfx.h" +#include "util/spike.h" + +static process_entry_t idz_startup; + +static DWORD CALLBACK idz_pre_startup(void) +{ + dprintf("--- Begin idz_pre_startup ---\n"); + + /* Hook Win32 APIs */ + + clock_hook_init(); + serial_hook_init(); + + /* Initialize platform API emulation */ + + hwmon_hook_init(); + nusec_hook_init(); + + /* Initialize AMEX emulation */ + + ds_hook_init(); + eeprom_hook_init(); + gpio_hook_init(); + jvs_hook_init(); + sram_hook_init(); + + /* Initialize Initial D Zero I/O board emulation */ + + com10_hook_init(); + idz_jvs_init(); + + /* Initialize debug helpers */ + + spike_hook_init("idzspike.txt"); + + dprintf("--- End idz_pre_startup ---\n"); + + /* Jump to EXE start address */ + + return idz_startup(); +} + +BOOL WINAPI DllMain(HMODULE mod, DWORD cause, void *ctx) +{ + HRESULT hr; + + if (cause != DLL_PROCESS_ATTACH) { + return TRUE; + } + + hr = process_hijack_startup(idz_pre_startup, &idz_startup); + + if (!SUCCEEDED(hr)) { + dprintf("Failed to hijack process startup: %x\n", (int) hr); + } + + return SUCCEEDED(hr); +} diff --git a/idzhook/idzhook.def b/idzhook/idzhook.def new file mode 100644 index 0000000..02950f4 --- /dev/null +++ b/idzhook/idzhook.def @@ -0,0 +1 @@ +LIBRARY idzhook diff --git a/idzhook/jvs.c b/idzhook/jvs.c new file mode 100644 index 0000000..8297338 --- /dev/null +++ b/idzhook/jvs.c @@ -0,0 +1,144 @@ +#include +#include + +#include +#include +#include +#include + +#include "amex/jvs.h" + +#include "board/io3.h" + +#include "idzhook/jvs.h" + +#include "jvs/jvs-bus.h" + +#include "util/dprintf.h" + +static void idz_jvs_read_switches(void *ctx, struct io3_switch_state *out); +static uint16_t idz_jvs_read_analog(void *ctx, uint8_t analog_no); +static uint16_t idz_jvs_consume_coins(void *ctx, uint8_t slot_no); + +static const struct io3_ops idz_jvs_io3_ops = { + .read_switches = idz_jvs_read_switches, + .read_analog = idz_jvs_read_analog, + .consume_coins = idz_jvs_consume_coins, +}; + +static struct io3 idz_jvs_io3; +static bool idz_jvs_coin; + +void idz_jvs_init(void) +{ + io3_init(&idz_jvs_io3, NULL, &idz_jvs_io3_ops, NULL); + jvs_attach(&idz_jvs_io3.jvs); +} + +static void idz_jvs_read_switches(void *ctx, struct io3_switch_state *out) +{ + XINPUT_STATE xi; + WORD xb; + + assert(out != NULL); + + memset(&xi, 0, sizeof(xi)); + XInputGetState(0, &xi); + xb = xi.Gamepad.wButtons; + + /* Update gameplay buttons (P2 JVS input is not even polled) */ + + if (xb & XINPUT_GAMEPAD_START) { + out->p1 |= 1 << 15; + } + + if (xb & XINPUT_GAMEPAD_DPAD_UP) { + out->p1 |= 1 << 13; + } + + if (xb & XINPUT_GAMEPAD_DPAD_DOWN) { + out->p1 |= 1 << 12; + } + + if (xb & XINPUT_GAMEPAD_DPAD_LEFT) { + out->p1 |= 1 << 11; + } + + if (xb & XINPUT_GAMEPAD_DPAD_RIGHT) { + out->p1 |= 1 << 10; + } + + if (xb & XINPUT_GAMEPAD_BACK) { + out->p1 |= 1 << 9; + } + + /* Update test/service buttons */ + + if (GetAsyncKeyState('1')) { + out->system = 0x80; + } else { + out->system = 0; + } + + if (GetAsyncKeyState('2')) { + out->p1 |= 1 << 14; + } +} + +static uint16_t idz_jvs_read_analog(void *ctx, uint8_t analog_no) +{ + XINPUT_STATE xi; + int tmp; + + if (analog_no > 2) { + return 0; + } + + memset(&xi, 0, sizeof(xi)); + XInputGetState(0, &xi); + + switch (analog_no) { + case 0: + /* Wheel */ + tmp = xi.Gamepad.sThumbLX; + + if (abs(tmp) > XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE) { + return tmp + 0x8000; + } else { + return 0x8000; + } + + case 1: + /* Accel */ + return xi.Gamepad.bRightTrigger << 8; + + case 2: + /* Brake */ + return xi.Gamepad.bLeftTrigger << 8; + + default: + return 0; + } +} + +static uint16_t idz_jvs_consume_coins(void *ctx, uint8_t slot_no) +{ + if (slot_no > 0) { + return 0; + } + + if (GetAsyncKeyState('3')) { + if (idz_jvs_coin) { + return 0; + } else { + dprintf("IDZero JVS: Coin drop\n"); + idz_jvs_coin = true; + + return 1; + } + } else { + idz_jvs_coin = false; + + return 0; + } +} diff --git a/idzhook/jvs.h b/idzhook/jvs.h new file mode 100644 index 0000000..be29753 --- /dev/null +++ b/idzhook/jvs.h @@ -0,0 +1,3 @@ +#pragma once + +void idz_jvs_init(void); diff --git a/idzhook/meson.build b/idzhook/meson.build new file mode 100644 index 0000000..5da0017 --- /dev/null +++ b/idzhook/meson.build @@ -0,0 +1,27 @@ +shared_library( + 'idzhook', + name_prefix : '', + include_directories : inc, + implicit_include_directories : false, + vs_module_defs : 'idzhook.def', + c_pch : '../precompiled.h', + dependencies : [ + capnhook.get_variable('hook_dep'), + capnhook.get_variable('hooklib_dep'), + xinput_lib, + ], + link_with : [ + aimeio_dll, + amex_lib, + board_lib, + jvs_lib, + platform_lib, + util_lib, + ], + sources : [ + '_com10.c', + 'dllmain.c', + 'jvs.c', + 'jvs.h', + ], +) diff --git a/meson.build b/meson.build index d74e52e..2df19dd 100644 --- a/meson.build +++ b/meson.build @@ -39,5 +39,6 @@ subdir('util') subdir('aimeio') subdir('cardhook') subdir('chunihook') +subdir('idzhook') subdir('minihook') subdir('zinput')