diff --git a/src/main/hooklib/rs232.c b/src/main/hooklib/rs232.c index ed72280..3ad5148 100644 --- a/src/main/hooklib/rs232.c +++ b/src/main/hooklib/rs232.c @@ -4,6 +4,7 @@ #include #include +#include #include #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; diff --git a/src/main/hooklib/rs232.h b/src/main/hooklib/rs232.h index f0beddf..a32ea15 100644 --- a/src/main/hooklib/rs232.h +++ b/src/main/hooklib/rs232.h @@ -1,6 +1,21 @@ #ifndef HOOKLIB_RS232_H #define HOOKLIB_RS232_H +#include + 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 diff --git a/src/main/iidxhook-util/acio.c b/src/main/iidxhook-util/acio.c index a1bc8c2..0ca919c 100644 --- a/src/main/iidxhook-util/acio.c +++ b/src/main/iidxhook-util/acio.c @@ -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) diff --git a/src/main/iidxhook8/bio2.c b/src/main/iidxhook8/bio2.c index 82c1149..29a3a10 100644 --- a/src/main/iidxhook8/bio2.c +++ b/src/main/iidxhook8/bio2.c @@ -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) diff --git a/src/main/iidxhook8/dllmain.c b/src/main/iidxhook8/dllmain.c index 47178d7..5e90d3b 100644 --- a/src/main/iidxhook8/dllmain.c +++ b/src/main/iidxhook8/dllmain.c @@ -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);