1
0
mirror of https://github.com/djhackersdev/bemanitools.git synced 2025-02-17 11:18:31 +01:00

hooklib: Allow proper passthrough of serial calls to real hardware (#26)

Only enabled / tested on IIDX CB and SDVX5

The point of this, is to allow rs232 hooks for only the descriptors that we hook.
This is because the emulation here is incomplete.
Although the IOCTL's do end up being passed to the real hardware, the game rejects some of the responses and hangs.
By short circuiting out, and calling the real Comm functions instead, it works.
And hence, card-reader passthrough works on IIDX25+/SDVX5+ finally without eamio-real
This commit is contained in:
Will Xyen 2019-09-21 12:57:05 -04:00
parent 1a567aa8ba
commit 89e3bbd2a3
5 changed files with 139 additions and 0 deletions

View File

@ -4,6 +4,7 @@
#include <devioctl.h>
#include <ntddser.h>
#include <stdbool.h>
#include <string.h>
#include "hook/iohook.h"
@ -11,6 +12,7 @@
#include "util/hr.h"
#include "util/log.h"
#include "util/array.h"
/* RS232 API hooks */
@ -29,55 +31,130 @@ static BOOL STDCALL my_SetupComm(HANDLE fd, uint32_t in_q, uint32_t out_q);
static BOOL STDCALL my_SetCommBreak(HANDLE fd);
static BOOL STDCALL my_ClearCommBreak(HANDLE fd);
static BOOL (STDCALL *real_ClearCommError)(
HANDLE fd,
uint32_t *errors,
COMSTAT *status);
static BOOL (STDCALL *real_EscapeCommFunction)(HANDLE fd, uint32_t func);
static BOOL (STDCALL *real_GetCommState)(HANDLE fd, DCB *dcb);
static BOOL (STDCALL *real_PurgeComm)(HANDLE fd, uint32_t flags);
static BOOL (STDCALL *real_SetCommMask)(HANDLE fd, uint32_t mask);
static BOOL (STDCALL *real_SetCommState)(HANDLE fd, const DCB *dcb);
static BOOL (STDCALL *real_SetCommTimeouts)(HANDLE fd, COMMTIMEOUTS *timeouts);
static BOOL (STDCALL *real_SetupComm)(HANDLE fd, uint32_t in_q, uint32_t out_q);
static BOOL (STDCALL *real_SetCommBreak)(HANDLE fd);
static BOOL (STDCALL *real_ClearCommBreak)(HANDLE fd);
static struct hook_symbol rs232_syms[] = {
{
.name = "ClearCommError",
.patch = my_ClearCommError,
.link = (void*) &real_ClearCommError,
},
{
.name = "EscapeCommFunction",
.patch = my_EscapeCommFunction,
.link = (void*) &real_EscapeCommFunction,
},
{
.name = "GetCommState",
.patch = my_GetCommState,
.link = (void*) &real_GetCommState,
},
{
.name = "PurgeComm",
.patch = my_PurgeComm,
.link = (void*) &real_PurgeComm,
},
{
.name = "SetCommMask",
.patch = my_SetCommMask,
.link = (void*) &real_SetCommMask,
},
{
.name = "SetCommState",
.patch = my_SetCommState,
.link = (void*) &real_SetCommState,
},
{
.name = "SetCommTimeouts",
.patch = my_SetCommTimeouts,
.link = (void*) &real_SetCommTimeouts,
},
{
.name = "SetupComm",
.patch = my_SetupComm,
.link = (void*) &real_SetupComm,
},
{
.name = "SetCommBreak",
.patch = my_SetCommBreak,
.link = (void*) &real_SetCommBreak,
},
{
.name = "ClearCommBreak",
.patch = my_ClearCommBreak,
.link = (void*) &real_ClearCommBreak,
},
};
static struct array hooked_port_fds;
static bool rs232_limit_hooks;
static CRITICAL_SECTION hooked_port_fds_cs;
/**
* Some notes:
*
* The point of this, is to allow rs232 hooks for only the descriptors that we hook.
* This is because the emulation here is incomplete.
* Although the IOCTL's do end up being passed to the real hardware, the game rejects some of the responses and hangs.
* By short circuiting out, and calling the real Comm functions instead, it works.
* And hence, card-reader passthrough works on IIDX25+/SDVX5+ finally without eamio-real
*
*/
void rs232_hook_init(void)
{
array_init(&hooked_port_fds);
InitializeCriticalSection(&hooked_port_fds_cs);
hook_table_apply(NULL, "kernel32.dll", rs232_syms, lengthof(rs232_syms));
log_info("IO Hook RS232 ioctl subsystem initialized");
}
void rs232_hook_limit_hooks(void)
{
rs232_limit_hooks = true;
}
static BOOL rs232_check_fd(HANDLE fd) {
HANDLE check;
if (rs232_limit_hooks){
EnterCriticalSection(&hooked_port_fds_cs);
for (size_t i = 0 ; i < hooked_port_fds.nitems ; i++) {
check = *array_item(HANDLE, &hooked_port_fds, i);
if (check == fd) {
LeaveCriticalSection(&hooked_port_fds_cs);
return TRUE;
}
}
LeaveCriticalSection(&hooked_port_fds_cs);
return FALSE;
}
return TRUE;
}
void rs232_hook_add_fd(HANDLE fd)
{
EnterCriticalSection(&hooked_port_fds_cs);
*array_append(HANDLE, &hooked_port_fds) = fd;
LeaveCriticalSection(&hooked_port_fds_cs);
}
static BOOL STDCALL my_ClearCommError(
HANDLE fd,
uint32_t *errors,
@ -87,6 +164,10 @@ static BOOL STDCALL my_ClearCommError(
SERIAL_STATUS llstatus;
HRESULT hr;
if (!rs232_check_fd(fd)) {
return real_ClearCommError(fd, errors, status);
}
memset(&irp, 0, sizeof(irp));
irp.op = IRP_OP_IOCTL;
irp.fd = fd;
@ -180,6 +261,10 @@ static BOOL STDCALL my_EscapeCommFunction(HANDLE fd, uint32_t cmd)
uint32_t ioctl;
HRESULT hr;
if (!rs232_check_fd(fd)) {
return real_EscapeCommFunction(fd, cmd);
}
switch (cmd) {
case CLRBREAK: ioctl = IOCTL_SERIAL_SET_BREAK_OFF; break;
case CLRDTR: ioctl = IOCTL_SERIAL_CLR_DTR; break;
@ -221,6 +306,10 @@ static BOOL STDCALL my_GetCommState(HANDLE fd, DCB *dcb)
SERIAL_LINE_CONTROL line_control;
HRESULT hr;
if (!rs232_check_fd(fd)) {
return real_GetCommState(fd, dcb);
}
/*
* Validate params
*/
@ -393,6 +482,10 @@ static BOOL STDCALL my_PurgeComm(HANDLE fd, uint32_t flags)
struct irp irp;
HRESULT hr;
if (!rs232_check_fd(fd)) {
return real_PurgeComm(fd, flags);
}
memset(&irp, 0, sizeof(irp));
irp.op = IRP_OP_IOCTL;
irp.fd = fd;
@ -415,6 +508,10 @@ static BOOL STDCALL my_SetCommMask(HANDLE fd, uint32_t mask)
struct irp irp;
HRESULT hr;
if (!rs232_check_fd(fd)) {
return real_SetCommMask(fd, mask);
}
memset(&irp, 0, sizeof(irp));
irp.op = IRP_OP_IOCTL;
irp.fd = fd;
@ -440,6 +537,10 @@ static BOOL STDCALL my_SetCommState(HANDLE fd, const DCB *dcb)
SERIAL_LINE_CONTROL line_control;
HRESULT hr;
if (!rs232_check_fd(fd)) {
return real_SetCommState(fd, dcb);
}
if (dcb == NULL) {
log_warning("%s: DCB pointer is NULL", __func__);
SetLastError(ERROR_INVALID_PARAMETER);
@ -616,6 +717,10 @@ static BOOL STDCALL my_SetCommTimeouts(HANDLE fd, COMMTIMEOUTS *src)
SERIAL_TIMEOUTS dest;
HRESULT hr;
if (!rs232_check_fd(fd)) {
return real_SetCommTimeouts(fd, src);
}
dest.ReadIntervalTimeout = src->ReadIntervalTimeout;
dest.ReadTotalTimeoutMultiplier = src->ReadTotalTimeoutMultiplier;
dest.ReadTotalTimeoutConstant = src->ReadTotalTimeoutConstant;
@ -644,6 +749,10 @@ static BOOL STDCALL my_SetupComm(HANDLE fd, uint32_t in_q, uint32_t out_q)
SERIAL_QUEUE_SIZE qs;
HRESULT hr;
if (!rs232_check_fd(fd)) {
return real_SetupComm(fd, in_q, out_q);
}
qs.InSize = in_q;
qs.OutSize = out_q;
@ -668,6 +777,10 @@ static BOOL STDCALL my_SetCommBreak(HANDLE fd)
struct irp irp;
HRESULT hr;
if (!rs232_check_fd(fd)) {
return real_SetCommBreak(fd);
}
memset(&irp, 0, sizeof(irp));
irp.op = IRP_OP_IOCTL;
irp.fd = fd;
@ -687,6 +800,10 @@ static BOOL STDCALL my_ClearCommBreak(HANDLE fd)
struct irp irp;
HRESULT hr;
if (!rs232_check_fd(fd)) {
return real_ClearCommBreak(fd);
}
memset(&irp, 0, sizeof(irp));
irp.op = IRP_OP_IOCTL;
irp.fd = fd;

View File

@ -1,6 +1,21 @@
#ifndef HOOKLIB_RS232_H
#define HOOKLIB_RS232_H
#include <windows.h>
void rs232_hook_init(void);
/**
* Allows limiting the rs232 to only the specified fd's
*/
void rs232_hook_limit_hooks(void);
/**
* Adds the specified fd to the list of descriptors to hook
*
* @param fd descriptor to hook
*/
void rs232_hook_add_fd(HANDLE fd);
#endif

View File

@ -14,6 +14,7 @@
#include "acioemu/icca.h"
#include "hook/iohook.h"
#include "hooklib/rs232.h"
#include "iidxhook-util/acio.h"
@ -41,6 +42,8 @@ void iidxhook_util_acio_init(bool legacy_mode)
ac_io_emu_icca_init(&iidxhook_util_acio_emu_icca[i],
&iidxhook_util_acio_emu, i);
}
rs232_hook_add_fd(iidxhook_util_acio_emu.fd);
}
void iidxhook_util_acio_fini(void)

View File

@ -13,6 +13,7 @@
#include "acioemu/emu.h"
#include "hook/iohook.h"
#include "hooklib/rs232.h"
#include "iidxhook8/bi2a.h"
@ -31,6 +32,8 @@ void bio2_port_init(bool disable_poll_limiter)
// they use the same framing
ac_io_emu_init(&bio2_emu, L"COM4");
bio2_emu_bi2a_init(&bio2_emu, disable_poll_limiter);
rs232_hook_add_fd(bio2_emu.fd);
}
void bio2_port_fini(void)

View File

@ -126,6 +126,7 @@ static bool my_dll_entry_init(char *sidcode, struct property_node *param)
API implementations with real IO devices */
iohook_init(iidxhook_handlers, lengthof(iidxhook_handlers));
rs232_hook_init();
rs232_hook_limit_hooks();
if (!iidxhook8_config_io.disable_bio2_emu) {
bio2_port_init(iidxhook8_config_io.disable_poll_limiter);