Files
TeamTofuShop_taitools/idmac/idmac.c
T
2026-03-12 12:02:59 -04:00

468 lines
16 KiB
C

#include <windows.h>
#include <assert.h>
#include <stdlib.h>
#include <winioctl.h>
#include "idmac/idmac.h"
#include "idmac/jvs.h"
#include "hook/table.h"
#include "hook/iohook.h"
#include "util/dprintf.h"
#include "util/str.h"
#define IDMAC_IOCTL_DMA_READ CTL_CODE(0xC350, 0x800, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IDMAC_IOCTL_DMA_WRITE CTL_CODE(0xC350, 0x801, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IDMAC_IOCTL_REGISTER_READ CTL_CODE(0xC350, 0x802, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IDMAC_IOCTL_REGISTER_WRITE CTL_CODE(0xC350, 0x803, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IDMAC_IOCTL_REGISTER_BUFFER_READ CTL_CODE(0xC350, 0x804, METHOD_OUT_DIRECT, FILE_ANY_ACCESS)
#define IDMAC_IOCTL_REGISTER_BUFFER_WRITE CTL_CODE(0xC350, 0x805, METHOD_OUT_DIRECT, FILE_ANY_ACCESS)
#define IDMAC_IOCTL_MEMORY_READ CTL_CODE(0xC350, 0x806, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IDMAC_IOCTL_MEMORY_WRITE CTL_CODE(0xC350, 0x807, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IDMAC_IOCTL_MEMORY_BUFFER_READ CTL_CODE(0xC350, 0x808, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IDMAC_IOCTL_MEMORY_BUFFER_WRITE CTL_CODE(0xC350, 0x809, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IDMAC_IOCTL_MEMORY_READ_EXT CTL_CODE(0xC350, 0x820, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IDMAC_IOCTL_MEMORY_WRITE_EXT CTL_CODE(0xC350, 0x821, METHOD_BUFFERED, FILE_ANY_ACCESS)
static uint8_t dipsw = 0;
static HANDLE idmac_fd;
static HRESULT idmac_handle_irp(struct irp *irp);
static HRESULT idmac_handle_open(struct irp *irp);
static HRESULT idmac_handle_close(struct irp *irp);
static HRESULT idmac_handle_ioctl(struct irp *irp);
static DWORD hook_iDmacDrvOpen(int dev_num, DWORD *dev_handle, DWORD *err);
static DWORD hook_iDmacDrvClose(HANDLE a1, DWORD *lp);
static int hook_iDmacDrvDmaRead(HANDLE a1, void *lp, int ucb, unsigned int *err);
static int hook_iDmacDrvDmaWrite(HANDLE a1, void *lp, int ucb, unsigned int *err);
static int hook_iDmacDrvRegisterRead(HANDLE a1, DWORD register_id, DWORD* lp, unsigned int *err);
static int hook_iDmacDrvRegisterWrite(HANDLE a1, DWORD register_id, int a3, DWORD *lp);
static int hook_iDmacDrvRegisterBufferRead(HANDLE a1, DWORD BytesReturned, LPVOID lp, UINT_PTR ucb, DWORD *a5);
static int hook_iDmacDrvRegisterBufferWrite(HANDLE a1, DWORD BytesReturned, void *lp, UINT_PTR ucb, DWORD *a5);
static int hook_iDmacDrvMemoryRead(HANDLE a1, DWORD BytesReturned, LPVOID lp, DWORD *a4);
static int hook_iDmacDrvMemoryWrite(HANDLE a1, DWORD BytesReturned, int a3, DWORD *lp);
static int hook_iDmacDrvMemoryBufferRead(HANDLE a1, DWORD BytesReturned, LPVOID lp, UINT_PTR ucb, DWORD *a5);
static int hook_iDmacDrvMemoryBufferWrite(HANDLE a1, unsigned int a2, void *lp, UINT_PTR ucb, DWORD *a5);
static int hook_iDmacDrvMemoryReadExt(HANDLE a1, DWORD BytesReturned, unsigned int a3, LPVOID lp, int nOutBufferSize, DWORD *a6);
static int hook_iDmacDrvMemoryWriteExt(HANDLE a1, int a2, unsigned int a3, void *Source, rsize_t DestinationSize, unsigned int *lp);
static DWORD (*next_iDmacDrvOpen)(int dev_num, DWORD *dev_handle, DWORD *err);
static DWORD (*next_iDmacDrvClose)(HANDLE a1, DWORD *lp);
static int (*next_iDmacDrvDmaRead)(HANDLE a1, void *lp, int ucb, unsigned int *err);
static int (*next_iDmacDrvDmaWrite)(HANDLE a1, void *lp, int ucb, unsigned int *err);
static int (*next_iDmacDrvRegisterRead)(HANDLE a1, DWORD BytesReturned, LPVOID lp, unsigned int *err);
static int (*next_iDmacDrvRegisterWrite)(HANDLE a1, DWORD BytesReturned, int a3, DWORD *lp);
static int (*next_iDmacDrvRegisterBufferRead)(HANDLE a1, DWORD BytesReturned, LPVOID lp, UINT_PTR ucb, DWORD *a5);
static int (*next_iDmacDrvRegisterBufferWrite)(HANDLE a1, DWORD BytesReturned, void *lp, UINT_PTR ucb, DWORD *a5);
static int (*next_iDmacDrvMemoryRead)(HANDLE a1, DWORD BytesReturned, LPVOID lp, DWORD *a4);
static int (*next_iDmacDrvMemoryWrite)(HANDLE a1, DWORD BytesReturned, int a3, DWORD *lp);
static int (*next_iDmacDrvMemoryBufferRead)(HANDLE a1, DWORD BytesReturned, LPVOID lp, UINT_PTR ucb, DWORD *a5);
static int (*next_iDmacDrvMemoryBufferWrite)(HANDLE a1, unsigned int a2, void *lp, UINT_PTR ucb, DWORD *a5);
static int (*next_iDmacDrvMemoryReadExt)(HANDLE a1, DWORD BytesReturned, unsigned int a3, LPVOID lp, int nOutBufferSize, DWORD *a6);
static int (*next_iDmacDrvMemoryWriteExt)(HANDLE a1, int a2, unsigned int a3, void *Source, rsize_t DestinationSize, unsigned int *lp);
static const struct hook_symbol idmac_hooks[] = {
{
.name = "iDmacDrvOpen",
.ordinal = 1,
.patch = hook_iDmacDrvOpen,
.link = (void **) &next_iDmacDrvOpen,
},{
.name = "iDmacDrvClose",
.ordinal = 2,
.patch = hook_iDmacDrvClose,
.link = (void **) &next_iDmacDrvClose,
},{
.name = "iDmacDrvDmaRead",
.ordinal = 3,
.patch = hook_iDmacDrvDmaRead,
.link = (void **) &next_iDmacDrvDmaRead,
},{
.name = "iDmacDrvDmaWrite",
.ordinal = 4,
.patch = hook_iDmacDrvDmaWrite,
.link = (void **) &next_iDmacDrvDmaWrite,
},{
.name = "iDmacDrvRegisterRead",
.ordinal = 5,
.patch = hook_iDmacDrvRegisterRead,
.link = (void **) &next_iDmacDrvRegisterRead,
},{
.name = "iDmacDrvRegisterWrite",
.ordinal = 6,
.patch = hook_iDmacDrvRegisterWrite,
.link = (void **) &next_iDmacDrvRegisterWrite,
},{
.name = "iDmacDrvRegisterBufferRead",
.ordinal = 7,
.patch = hook_iDmacDrvRegisterBufferRead,
.link = (void **) &next_iDmacDrvRegisterBufferRead,
},{
.name = "iDmacDrvRegisterBufferWrite",
.ordinal = 8,
.patch = hook_iDmacDrvRegisterBufferWrite,
.link = (void **) &next_iDmacDrvRegisterBufferWrite,
},{
.name = "iDmacDrvMemoryRead",
.ordinal = 9,
.patch = hook_iDmacDrvMemoryRead,
.link = (void **) &next_iDmacDrvMemoryRead,
},{
.name = "iDmacDrvMemoryWrite",
.ordinal = 10,
.patch = hook_iDmacDrvMemoryWrite,
.link = (void **) &next_iDmacDrvMemoryWrite,
},{
.name = "iDmacDrvMemoryBufferRead",
.ordinal = 11,
.patch = hook_iDmacDrvMemoryBufferRead,
.link = (void **) &next_iDmacDrvMemoryBufferRead,
},{
.name = "iDmacDrvMemoryBufferWrite",
.ordinal = 12,
.patch = hook_iDmacDrvMemoryBufferWrite,
.link = (void **) &next_iDmacDrvMemoryBufferWrite,
},{
.name = "iDmacDrvMemoryReadExt",
.ordinal = 13,
.patch = hook_iDmacDrvMemoryReadExt,
.link = (void **) &next_iDmacDrvMemoryReadExt,
},{
.name = "iDmacDrvMemoryWriteExt",
.ordinal = 14,
.patch = hook_iDmacDrvMemoryWriteExt,
.link = (void **) &next_iDmacDrvMemoryWriteExt,
},
};
void idmac_hook_table_apply(HMODULE target)
{
hook_table_apply(
target,
"iDmacDrv64.dll",
idmac_hooks,
_countof(idmac_hooks)
);
hook_table_apply(
target,
"iDmacDrv32.dll",
idmac_hooks,
_countof(idmac_hooks)
);
}
HRESULT idmac_hook_init(const struct idmac_config *cfg, struct idmac_hardware *hardware)
{
HRESULT hr;
assert(cfg != NULL);
dprintf("iDmac: Init\n");
dipsw = hardware->dipsw & 0x0F;
if (cfg->dipsw >> 4) {
dipsw = cfg->dipsw & 0x0F;
}
hr = jvs_hook_init(&cfg->jvs, hardware->jvs);
if (FAILED(hr)) {
return hr;
}
hr = fastio_hook_init(hardware->fastio_main, hardware->fastio_sub);
if (FAILED(hr)) {
return hr;
}
idmac_hook_table_apply(NULL);
hr = iohook_open_nul_fd(&idmac_fd);
if (FAILED(hr)) {
return hr;
}
hr = iohook_push_handler(idmac_handle_irp);
if (FAILED(hr)) {
return hr;
}
return S_OK;
}
static HRESULT idmac_handle_irp(struct irp *irp)
{
assert(irp != NULL);
if (irp->op != IRP_OP_OPEN && irp->fd != idmac_fd) {
return iohook_invoke_next(irp);
}
switch (irp->op) {
case IRP_OP_OPEN: return idmac_handle_open(irp);
case IRP_OP_CLOSE: return idmac_handle_close(irp);
case IRP_OP_IOCTL: return idmac_handle_ioctl(irp);
default: return HRESULT_FROM_WIN32(ERROR_INVALID_FUNCTION);
}
}
static HRESULT idmac_handle_open(struct irp *irp)
{
if (!wstr_ieq(irp->open_filename, L"\\\\.\\iDmacDrv0")) {
return iohook_invoke_next(irp);
}
dprintf("iDmac: Opened handle\n");
irp->fd = idmac_fd;
return S_OK;
}
static HRESULT idmac_handle_close(struct irp *irp)
{
dprintf("iDmac: Closed handle\n");
return S_OK;
}
static HRESULT idmac_handle_ioctl(struct irp *irp)
{
switch (irp->ioctl) {
/*case IDMAC_IOCTL_DMA_READ:
return hook_iDmacDrvDmaRead(irp);
case IDMAC_IOCTL_DMA_WRITE:
return hook_iDmacDrvDmaWrite(irp);
case IDMAC_IOCTL_REGISTER_READ:
return hook_iDmacDrvRegisterRead(irp);
case IDMAC_IOCTL_REGISTER_WRITE:
return hook_iDmacDrvRegisterWrite(irp);
case IDMAC_IOCTL_REGISTER_BUFFER_READ:
return hook_iDmacDrvRegisterBufferRead(irp);
case IDMAC_IOCTL_REGISTER_BUFFER_WRITE:
return hook_iDmacDrvRegisterBufferWrite(irp);
case IDMAC_IOCTL_MEMORY_READ:
return hook_iDmacDrvMemoryRead(irp);
case IDMAC_IOCTL_MEMORY_WRITE:
return hook_iDmacDrvMemoryWrite(irp);
case IDMAC_IOCTL_MEMORY_BUFFER_READ:
return hook_iDmacDrvMemoryBufferRead(irp);
case IDMAC_IOCTL_MEMORY_BUFFER_WRITE:
return hook_iDmacDrvMemoryBufferWrite(irp);
case IDMAC_IOCTL_MEMORY_READ_EXT:
return hook_iDmacDrvMemoryReadExt(irp);
case IDMAC_IOCTL_MEMORY_WRITE_EXT:
return hook_iDmacDrvMemoryWriteExt(irp);*/
default:
dprintf("iDmac: Unknown ioctl %#08x, write %i read %i\n",
irp->ioctl,
(int) irp->write.nbytes,
(int) irp->read.nbytes);
return HRESULT_FROM_WIN32(ERROR_INVALID_FUNCTION);
}
}
static DWORD hook_iDmacDrvOpen(int dev_num, DWORD *dev_handle, DWORD *err)
{
dprintf("hook_iDmacDrvOpen: Open device #%X\n", dev_num);
return 0;
}
static DWORD hook_iDmacDrvClose(HANDLE dev_handle, DWORD *lp)
{
dprintf("hook_iDmacDrvClose: Close handle %p\n", dev_handle);
return 0;
}
static int hook_iDmacDrvDmaRead(HANDLE a1, void *lp, int ucb, unsigned int *err)
{
dprintf("hook_iDmacDrvDmaRead: Read %d bytes\n", ucb);
return 0;
}
static int hook_iDmacDrvDmaWrite(HANDLE a1, void *lp, int ucb, unsigned int *err)
{
dprintf("hook_iDmacDrvDmaWrite: Write %d bytes\n", ucb);
return 0;
}
static int hook_iDmacDrvRegisterRead(HANDLE a1, DWORD register_id, DWORD* register_val, unsigned int *err)
{
//dprintf("hook_iDmacDrvRegisterRead: This code should not run!\n");
*register_val = 0;
*err = 0;
switch (register_id) {
case 0x0400: break; // DMA card ID
// Magic values taken from https://github.com/asesidaa/GCLoader-new/blob/main/iDmacDrv32.cpp
// Both of these were set to -2 prior to work with TFFAC...
case 0x4000: *register_val = 0x00FF00FF; break; // Main Status
case 0x4004: *register_val = 0x00FF0000; break; // Sub Status
case 0x4120: // Main Buttons
fastio_digital_read(NULL, 0, (uint32_t *)register_val);
break;
case 0x4124: // Analog 1
fastio_analog_in(NULL, 0, 1, (uint32_t *)register_val);
break;
case 0x4128: // Analog 2
fastio_analog_in(NULL, 0, 2, (uint32_t *)register_val);
break;
case 0x412C: // Analog 3
fastio_analog_in(NULL, 0, 3, (uint32_t *)register_val);
break;
case 0x4140:
fastio_coins_in(NULL, 0, 1, (uint32_t *)register_val);
break; // Coin slot 1
case 0x4144:
fastio_coins_in(NULL, 0, 2, (uint32_t *)register_val);
break; // Coin slot 2
// TODO: Let games specify hub connection
case 0x4150: *register_val = 0x0001823C; break; // FastIO hub port1 status?
case 0x4154: break; // FastIO hub port2 status?
case 0x4158: break; // FastIO hub port3 status?
case 0x415C: break; // FastIO hub port4 status?
case 0x41A0: // Sub buttons
fastio_digital_read(NULL, 1, (uint32_t *)register_val);
break;
case 0x41A4: // sub Analog 1
fastio_analog_in(NULL, 1, 1, (uint32_t *)register_val);
break;
case 0x41A8: // sub Analog 2
fastio_analog_in(NULL, 1, 1, (uint32_t *)register_val);
break;
case 0x41AC: // sub Analog 3
fastio_analog_in(NULL, 1, 1, (uint32_t *)register_val);
break;
case 0x41C0:
fastio_coins_in(NULL, 1, 1, (uint32_t *)register_val);
break; // Sub Coin slot 1
case 0x41C4:
fastio_coins_in(NULL, 1, 2, (uint32_t *)register_val);
break; // Sub Coin slot 2
default:
dprintf("iDmac: Requested read register %04lX\n", register_id);
break;
}
return 0;
}
static int hook_iDmacDrvRegisterWrite(HANDLE a1, DWORD register_id, int a3, DWORD *lp)
{
//dprintf("hook_iDmacDrvRegisterWrite: Write %d to register %04lX\n", a3, register_id);
switch (register_id) {
case 0x4000: // Main reset
fastio_reset(NULL, 0, a3);
break;
case 0x4004: // Sub reset
fastio_reset(NULL, 1, a3);
break;
case 0x4100: // Main GPIO
case 0x4104:
case 0x4108:
case 0x410C:
fastio_gpio_out(NULL, 0, register_id - 0x4100, a3);
break;
case 0x4140: // Main coin slot 1
fastio_coins_out(NULL, 0, 1, a3);
break;
case 0x4144: // Main coin slot 2
fastio_coins_out(NULL, 0, 2, a3);
break;
case 0x4180: // Sub GPIO
case 0x4184:
case 0x4188:
case 0x418C:
fastio_gpio_out(NULL, 1, register_id - 0x4180, a3);
break;
case 0x41C0: // Sub coin slot 1
fastio_coins_out(NULL, 1, 1, a3);
break;
case 0x41C4: // Sub coin slot 2
fastio_coins_out(NULL, 1, 2, a3);
break;
default:
dprintf("iDmac: Requested write register %04lX\n", register_id);
break;
}
return 0;
}
static int hook_iDmacDrvRegisterBufferRead(HANDLE a1, DWORD BytesReturned, LPVOID lp, UINT_PTR ucb, DWORD *a5)
{
//dprintf("hook_iDmacDrvRegisterBufferRead: This code should not run!\n");
return 0;
}
static int hook_iDmacDrvRegisterBufferWrite(HANDLE a1, DWORD BytesReturned, void *lp, UINT_PTR ucb, DWORD *a5)
{
//dprintf("hook_iDmacDrvRegisterBufferWrite: This code should not run!\n");
return 0;
}
static int hook_iDmacDrvMemoryRead(HANDLE a1, DWORD BytesReturned, LPVOID lp, DWORD *a4)
{
//dprintf("hook_iDmacDrvMemoryRead: This code should not run!\n");
return 0;
}
static int hook_iDmacDrvMemoryWrite(HANDLE a1, DWORD BytesReturned, int a3, DWORD *lp)
{
//dprintf("hook_iDmacDrvMemoryWrite: This code should not run!\n");
return 0;
}
static int hook_iDmacDrvMemoryBufferRead(HANDLE a1, DWORD BytesReturned, LPVOID lp, UINT_PTR ucb, DWORD *a5)
{
//dprintf("hook_iDmacDrvMemoryBufferRead: This code should not run!\n");
return 0;
}
static int hook_iDmacDrvMemoryBufferWrite(HANDLE a1, unsigned int a2, void *lp, UINT_PTR ucb, DWORD *a5)
{
//dprintf("hook_iDmacDrvMemoryBufferWrite: This code should not run!\n");
return 0;
}
static int hook_iDmacDrvMemoryReadExt(HANDLE a1, DWORD BytesReturned, unsigned int a3, LPVOID lp, int nOutBufferSize, DWORD *a6)
{
//dprintf("hook_iDmacDrvMemoryReadExt: This code should not run!\n");
return 0;
}
static int hook_iDmacDrvMemoryWriteExt(HANDLE a1, int a2, unsigned int a3, void *Source, rsize_t DestinationSize, unsigned int *lp)
{
//dprintf("hook_iDmacDrvMemoryWriteExt: This code should not run!\n");
return 0;
}