fgo: working FTDI hook by @OLEG

from: 88a0026f0b
This commit is contained in:
Dniel97 2023-11-22 21:40:10 +01:00
parent b9fd59fd70
commit d86baab852
Signed by untrusted user: Dniel97
GPG Key ID: 6180B3C768FB2E08
9 changed files with 341 additions and 20 deletions

View File

@ -1,6 +1,6 @@
# Segatools # Segatools
Version: `2023-07-14` Version: `2023-11-22`
Loaders and hardware emulators for SEGA games that run on the Nu and ALLS platforms. Loaders and hardware emulators for SEGA games that run on the Nu and ALLS platforms.
@ -12,19 +12,22 @@ Loaders and hardware emulators for SEGA games that run on the Nu and ALLS platfo
* [Chunithm Star (Plus)](doc/chunihook.md) * [Chunithm Star (Plus)](doc/chunihook.md)
* [Chunithm Amazon (Plus)](doc/chunihook.md) * [Chunithm Amazon (Plus)](doc/chunihook.md)
* [Chunithm Crystal (Plus)](doc/chunihook.md) * [Chunithm Crystal (Plus)](doc/chunihook.md)
* Chunithm SUN
* Initial D * Initial D
* [Initial D Arcade Stage Zero](doc/idzhook.md) * [Initial D Arcade Stage Zero](doc/idzhook.md)
* Initial D The Arcade * Initial D THE ARCADE
* SEGA World Drivers Championship * SEGA World Drivers Championship
* SEGA World Drivers Championship 2019 * up to SEGA World Drivers Championship 2019
* Fate/Grand Order
* Fate/Grand Order Arcade
* ONGEKI * ONGEKI
* bright MEMORY * up to bright MEMORY
* maimai DX * maimai DX
* maimai DX FESTiVAL * up to maimai DX FESTiVAL PLUS
* Card Maker * Card Maker
* Card Maker 1.35 * up to Card Maker 1.35
* Wacca * Wacca
* Wacca Lilly R (WIP) * up to WACCA Reverse
## End-users ## End-users

View File

@ -55,12 +55,13 @@ rotate180=1
; 837-15345 RFID deck reader emulation setting. ; 837-15345 RFID deck reader emulation setting.
enable=1 enable=1
[ftdi]
; FTDI serial to usb adapter emulation for CABINET LED.
enable=1
[ledstrip] [ledstrip]
; 837-15093-06 LED strip emulation setting. ; 837-15093-06 LED strip emulation setting.
enable=1 enable=1
; FTDI board currently not working properly. Use com0com (Create a virtual pair
; for 21 and 51) or use any USB to Serial Adapter.
port=21
; ----------------------------------------------------------------------------- ; -----------------------------------------------------------------------------
; Input settings ; Input settings

View File

@ -32,6 +32,7 @@ void ftdi_config_load(struct ftdi_config *cfg, const wchar_t *filename)
assert(filename != NULL); assert(filename != NULL);
cfg->enable = GetPrivateProfileIntW(L"ftdi", L"enable", 1, filename); cfg->enable = GetPrivateProfileIntW(L"ftdi", L"enable", 1, filename);
cfg->port_no = GetPrivateProfileIntW(L"ftdi", L"port", 17, filename);
} }
void led1509306_config_load(struct led1509306_config *cfg, const wchar_t *filename) void led1509306_config_load(struct led1509306_config *cfg, const wchar_t *filename)
@ -45,7 +46,7 @@ void led1509306_config_load(struct led1509306_config *cfg, const wchar_t *filena
memset(cfg->chip_number, ' ', sizeof(cfg->chip_number)); memset(cfg->chip_number, ' ', sizeof(cfg->chip_number));
cfg->enable = GetPrivateProfileIntW(L"ledstrip", L"enable", 1, filename); cfg->enable = GetPrivateProfileIntW(L"ledstrip", L"enable", 1, filename);
cfg->port_no = GetPrivateProfileIntW(L"ledstrip", L"port", 21, filename); cfg->port_no = GetPrivateProfileIntW(L"ledstrip", L"port", 17, filename);
cfg->fw_ver = GetPrivateProfileIntW(L"ledstrip", L"fw_ver", 0xA0, filename); cfg->fw_ver = GetPrivateProfileIntW(L"ledstrip", L"fw_ver", 0xA0, filename);
cfg->fw_sum = GetPrivateProfileIntW(L"ledstrip", L"fw_sum", 0xaa53, filename); cfg->fw_sum = GetPrivateProfileIntW(L"ledstrip", L"fw_sum", 0xaa53, filename);

View File

@ -129,7 +129,7 @@ static struct card_collection* cards_ptr;
static uint8_t current_card_idx = 0; static uint8_t current_card_idx = 0;
static bool read_pending = false; static bool read_pending = false;
HRESULT deck_hook_init(const struct deck_config *cfg, int port) HRESULT deck_hook_init(const struct deck_config *cfg, unsigned int port_no)
{ {
assert(cfg != NULL); assert(cfg != NULL);
@ -139,7 +139,7 @@ HRESULT deck_hook_init(const struct deck_config *cfg, int port)
InitializeCriticalSection(&deck_lock); InitializeCriticalSection(&deck_lock);
uart_init(&deck_uart, port); uart_init(&deck_uart, port_no);
deck_uart.written.bytes = deck_written_bytes; deck_uart.written.bytes = deck_written_bytes;
deck_uart.written.nbytes = sizeof(deck_written_bytes); deck_uart.written.nbytes = sizeof(deck_written_bytes);
deck_uart.readable.bytes = deck_readable_bytes; deck_uart.readable.bytes = deck_readable_bytes;
@ -398,6 +398,8 @@ static HRESULT deck_frame_decode(struct iobuf *dest, struct iobuf *src) {
assert(src->bytes != NULL || src->nbytes == 0); assert(src->bytes != NULL || src->nbytes == 0);
assert(src->pos <= src->nbytes); assert(src->pos <= src->nbytes);
deck_frame_sync(src);
dest->pos = 0; dest->pos = 0;
escape = false; escape = false;

View File

@ -8,4 +8,4 @@ struct deck_config {
bool enable; bool enable;
}; };
HRESULT deck_hook_init(const struct deck_config *cfg, int port); HRESULT deck_hook_init(const struct deck_config *cfg, unsigned int port_no);

View File

@ -90,13 +90,11 @@ static DWORD CALLBACK fgo_pre_startup(void)
goto fail; goto fail;
} }
/*
hr = ftdi_hook_init(&fgo_hook_cfg.ftdi); hr = ftdi_hook_init(&fgo_hook_cfg.ftdi);
if (FAILED(hr)) { if (FAILED(hr)) {
goto fail; goto fail;
} }
*/
hr = led1509306_hook_init(&fgo_hook_cfg.led1509306); hr = led1509306_hook_init(&fgo_hook_cfg.led1509306);

View File

@ -8,15 +8,22 @@
The game queries the presence of the FTDI board itself, followed by a The game queries the presence of the FTDI board itself, followed by a
registry check to see which port number is assigned to the FTDI board. registry check to see which port number is assigned to the FTDI board.
If these fail, the "CABINET LED" check on startup will always return "NG". If these fail, the "CABINET LED" check on startup will always return "NG".
Credits:
OLEG
*/ */
#include <windows.h> #include <windows.h>
#include <setupapi.h>
#include <stdint.h>
#include <assert.h> #include <assert.h>
#include <stdio.h>
#include "fgohook/ftdi.h" #include "fgohook/ftdi.h"
#include "hook/iohook.h" #include "hook/iohook.h"
#include "hook/table.h"
#include "hooklib/setupapi.h" #include "hooklib/setupapi.h"
@ -24,10 +31,97 @@
static struct ftdi_config ftdi_cfg; static struct ftdi_config ftdi_cfg;
static HANDLE ftdi_fd;
HRESULT ftdi_hook_init(const struct ftdi_config *cfg) static BOOL WINAPI hook_SetupDiGetDeviceRegistryPropertyA(
{ HDEVINFO DeviceInfoSet,
PSP_DEVINFO_DATA DeviceInfoData,
uint32_t Property,
uint32_t *PropertyRegDataType,
void *PropertyBuffer,
uint32_t PropertyBufferSize,
uint32_t *RequiredSize
);
static HKEY WINAPI hook_SetupDiOpenDevRegKey(
HDEVINFO DeviceInfoSet,
PSP_DEVINFO_DATA DeviceInfoData,
uint32_t Scope,
uint32_t HwProfile,
uint32_t KeyType,
REGSAM samDesired
);
static LSTATUS WINAPI hook_RegQueryValueExA(
HKEY handle,
const char *name,
void *reserved,
uint32_t *type,
void *bytes,
uint32_t *nbytes);
static LSTATUS WINAPI hook_RegCloseKey(HKEY handle);
static BOOL (WINAPI *next_SetupDiGetDeviceRegistryPropertyA)(
HDEVINFO DeviceInfoSet,
PSP_DEVINFO_DATA DeviceInfoData,
uint32_t Property,
uint32_t *PropertyRegDataType,
void *PropertyBuffer,
uint32_t PropertyBufferSize,
uint32_t *RequiredSize
);
static HKEY (WINAPI *next_SetupDiOpenDevRegKey)(
HDEVINFO DeviceInfoSet,
PSP_DEVINFO_DATA DeviceInfoData,
uint32_t Scope,
uint32_t HwProfile,
uint32_t KeyType,
REGSAM samDesired
);
static LSTATUS (WINAPI *next_RegQueryValueExA)(
HKEY handle,
const char *name,
void *reserved,
uint32_t *type,
void *bytes,
uint32_t *nbytes);
static LSTATUS (WINAPI *next_RegCloseKey)(HKEY handle);
static const struct hook_symbol setupapi_syms[] = {
{
.name = "SetupDiGetDeviceRegistryPropertyA",
.patch = hook_SetupDiGetDeviceRegistryPropertyA,
.link = (void *) &next_SetupDiGetDeviceRegistryPropertyA,
}, {
.name = "SetupDiOpenDevRegKey",
.patch = hook_SetupDiOpenDevRegKey,
.link = (void *) &next_SetupDiOpenDevRegKey,
}
};
static const struct hook_symbol reg_syms[] = {
{
.name = "RegQueryValueExA",
.patch = hook_RegQueryValueExA,
.link = (void *) &next_RegQueryValueExA,
}, {
.name = "RegCloseKey",
.patch = hook_RegCloseKey,
.link = (void *) &next_RegCloseKey,
}
};
#define device_fake_key 0xDEADBEEF
static HANDLE ftdi_fd;
static char port_name[8];
HRESULT ftdi_hook_init(const struct ftdi_config *cfg) {
HRESULT hr; HRESULT hr;
assert(cfg != NULL); assert(cfg != NULL);
@ -36,6 +130,18 @@ HRESULT ftdi_hook_init(const struct ftdi_config *cfg)
return S_FALSE; return S_FALSE;
} }
hook_table_apply(
NULL,
"setupapi.dll",
setupapi_syms,
_countof(setupapi_syms));
hook_table_apply(
NULL,
"advapi32.dll",
reg_syms,
_countof(reg_syms));
memcpy(&ftdi_cfg, cfg, sizeof(*cfg)); memcpy(&ftdi_cfg, cfg, sizeof(*cfg));
hr = iohook_open_nul_fd(&ftdi_fd); hr = iohook_open_nul_fd(&ftdi_fd);
@ -50,6 +156,68 @@ HRESULT ftdi_hook_init(const struct ftdi_config *cfg)
return hr; return hr;
} }
sprintf(port_name, "COM%d", cfg->port_no);
dprintf("FTDI: Hook enabled.\n"); dprintf("FTDI: Hook enabled.\n");
return S_OK; return S_OK;
} }
static BOOL WINAPI hook_SetupDiGetDeviceRegistryPropertyA(
HDEVINFO DeviceInfoSet,
PSP_DEVINFO_DATA DeviceInfoData,
uint32_t Property,
uint32_t *PropertyRegDataType,
void *PropertyBuffer,
uint32_t PropertyBufferSize,
uint32_t *RequiredSize
) {
if (!PropertyBuffer || PropertyBufferSize == 0) {
*RequiredSize = 16;
SetLastError(ERROR_INSUFFICIENT_BUFFER);
return FALSE;
}
*PropertyRegDataType = 1;
return TRUE;
}
static HKEY WINAPI hook_SetupDiOpenDevRegKey(
HDEVINFO DeviceInfoSet,
PSP_DEVINFO_DATA DeviceInfoData,
uint32_t Scope,
uint32_t HwProfile,
uint32_t KeyType,
REGSAM samDesired
) {
return (HKEY) device_fake_key;
}
static LSTATUS WINAPI hook_RegCloseKey(HKEY handle) {
if (handle == (HKEY) device_fake_key)
return ERROR_SUCCESS;
return next_RegCloseKey(handle);
}
static LSTATUS WINAPI hook_RegQueryValueExA(
HKEY handle,
const char *name,
void *reserved,
uint32_t *type,
void *bytes,
uint32_t *nbytes) {
if (handle == (HKEY) device_fake_key && !strcmp(name, "PortName")) {
strcpy(bytes, port_name);
*nbytes = 5;
*type = 1;
return ERROR_SUCCESS;
}
return next_RegQueryValueExA(
handle,
name,
reserved,
type,
bytes,
nbytes);
}

View File

@ -8,6 +8,7 @@
struct ftdi_config { struct ftdi_config {
bool enable; bool enable;
uint32_t port_no;
}; };
DEFINE_GUID( DEFINE_GUID(

View File

@ -16,6 +16,7 @@
struct setupapi_class { struct setupapi_class {
const GUID *guid; const GUID *guid;
const wchar_t *path; const wchar_t *path;
char *a_path;
HDEVINFO cur_handle; HDEVINFO cur_handle;
}; };
@ -29,6 +30,12 @@ static HDEVINFO WINAPI my_SetupDiGetClassDevsW(
HWND hwndParent, HWND hwndParent,
DWORD Flags); DWORD Flags);
static HDEVINFO WINAPI my_SetupDiGetClassDevsA(
const GUID *ClassGuid,
char *Enumerator,
HWND hwndParent,
DWORD Flags);
static BOOL WINAPI my_SetupDiEnumDeviceInterfaces( static BOOL WINAPI my_SetupDiEnumDeviceInterfaces(
HDEVINFO DeviceInfoSet, HDEVINFO DeviceInfoSet,
SP_DEVINFO_DATA *DeviceInfoData, SP_DEVINFO_DATA *DeviceInfoData,
@ -44,6 +51,14 @@ static BOOL WINAPI my_SetupDiGetDeviceInterfaceDetailW(
DWORD *RequiredSize, DWORD *RequiredSize,
SP_DEVINFO_DATA *DeviceInfoData); SP_DEVINFO_DATA *DeviceInfoData);
static BOOL WINAPI my_SetupDiGetDeviceInterfaceDetailA(
HDEVINFO DeviceInfoSet,
SP_DEVICE_INTERFACE_DATA *DeviceInterfaceData,
SP_DEVICE_INTERFACE_DETAIL_DATA_A *DeviceInterfaceDetailData,
DWORD DeviceInterfaceDetailDataSize,
DWORD *RequiredSize,
SP_DEVINFO_DATA *DeviceInfoData);
static BOOL WINAPI my_SetupDiDestroyDeviceInfoList(HDEVINFO DeviceInfoSet); static BOOL WINAPI my_SetupDiDestroyDeviceInfoList(HDEVINFO DeviceInfoSet);
/* Links */ /* Links */
@ -54,6 +69,12 @@ static HDEVINFO (WINAPI *next_SetupDiGetClassDevsW)(
HWND hwndParent, HWND hwndParent,
DWORD Flags); DWORD Flags);
static HDEVINFO (WINAPI *next_SetupDiGetClassDevsA)(
const GUID *ClassGuid,
char *Enumerator,
HWND hwndParent,
DWORD Flags);
static BOOL (WINAPI *next_SetupDiEnumDeviceInterfaces)( static BOOL (WINAPI *next_SetupDiEnumDeviceInterfaces)(
HDEVINFO DeviceInfoSet, HDEVINFO DeviceInfoSet,
SP_DEVINFO_DATA *DeviceInfoData, SP_DEVINFO_DATA *DeviceInfoData,
@ -69,6 +90,14 @@ static BOOL (WINAPI *next_SetupDiGetDeviceInterfaceDetailW)(
DWORD *RequiredSize, DWORD *RequiredSize,
SP_DEVINFO_DATA *DeviceInfoData); SP_DEVINFO_DATA *DeviceInfoData);
static BOOL (WINAPI *next_SetupDiGetDeviceInterfaceDetailA)(
HDEVINFO DeviceInfoSet,
SP_DEVICE_INTERFACE_DATA *DeviceInterfaceData,
SP_DEVICE_INTERFACE_DETAIL_DATA_A *DeviceInterfaceDetailData,
DWORD DeviceInterfaceDetailDataSize,
DWORD *RequiredSize,
SP_DEVINFO_DATA *DeviceInfoData);
static BOOL (WINAPI *next_SetupDiDestroyDeviceInfoList)(HDEVINFO DeviceInfoSet); static BOOL (WINAPI *next_SetupDiDestroyDeviceInfoList)(HDEVINFO DeviceInfoSet);
/* Hook tbl */ /* Hook tbl */
@ -78,6 +107,10 @@ static const struct hook_symbol setupapi_syms[] = {
.name = "SetupDiGetClassDevsW", .name = "SetupDiGetClassDevsW",
.patch = my_SetupDiGetClassDevsW, .patch = my_SetupDiGetClassDevsW,
.link = (void *) &next_SetupDiGetClassDevsW, .link = (void *) &next_SetupDiGetClassDevsW,
}, {
.name = "SetupDiGetClassDevsA",
.patch = my_SetupDiGetClassDevsA,
.link = (void *) &next_SetupDiGetClassDevsA,
}, { }, {
.name = "SetupDiEnumDeviceInterfaces", .name = "SetupDiEnumDeviceInterfaces",
.patch = my_SetupDiEnumDeviceInterfaces, .patch = my_SetupDiEnumDeviceInterfaces,
@ -86,6 +119,10 @@ static const struct hook_symbol setupapi_syms[] = {
.name = "SetupDiGetDeviceInterfaceDetailW", .name = "SetupDiGetDeviceInterfaceDetailW",
.patch = my_SetupDiGetDeviceInterfaceDetailW, .patch = my_SetupDiGetDeviceInterfaceDetailW,
.link = (void *) &next_SetupDiGetDeviceInterfaceDetailW, .link = (void *) &next_SetupDiGetDeviceInterfaceDetailW,
}, {
.name = "SetupDiGetDeviceInterfaceDetailA",
.patch = my_SetupDiGetDeviceInterfaceDetailA,
.link = (void *) &next_SetupDiGetDeviceInterfaceDetailA,
}, { }, {
.name = "SetupDiDestroyDeviceInfoList", .name = "SetupDiDestroyDeviceInfoList",
.patch = my_SetupDiDestroyDeviceInfoList, .patch = my_SetupDiDestroyDeviceInfoList,
@ -102,6 +139,7 @@ HRESULT setupapi_add_phantom_dev(const GUID *iface_class, const wchar_t *path)
{ {
struct setupapi_class *class_; struct setupapi_class *class_;
struct setupapi_class *new_array; struct setupapi_class *new_array;
size_t a_path_len;
HRESULT hr; HRESULT hr;
assert(iface_class != NULL); assert(iface_class != NULL);
@ -126,6 +164,11 @@ HRESULT setupapi_add_phantom_dev(const GUID *iface_class, const wchar_t *path)
class_ = &setupapi_classes[setupapi_nclasses++]; class_ = &setupapi_classes[setupapi_nclasses++];
class_->guid = iface_class; class_->guid = iface_class;
class_->path = path; class_->path = path;
a_path_len = wcslen(path) * sizeof(wchar_t) + 1;
class_->a_path = (char*)malloc(a_path_len);
wcstombs(class_->a_path, path, a_path_len);
hr = S_OK; hr = S_OK;
end: end:
@ -189,6 +232,40 @@ static HDEVINFO WINAPI my_SetupDiGetClassDevsW(
return result; return result;
} }
static HDEVINFO WINAPI my_SetupDiGetClassDevsA(
const GUID *ClassGuid,
char *Enumerator,
HWND hwndParent,
DWORD Flags)
{
struct setupapi_class *class_;
HDEVINFO result;
size_t i;
result = next_SetupDiGetClassDevsA(
ClassGuid,
Enumerator,
hwndParent,
Flags);
if (result == INVALID_HANDLE_VALUE || ClassGuid == NULL) {
return result;
}
EnterCriticalSection(&setupapi_lock);
for (i = 0 ; i < setupapi_nclasses ; i++) {
class_ = &setupapi_classes[i];
if (memcmp(ClassGuid, class_->guid, sizeof(*ClassGuid)) == 0) {
class_->cur_handle = result;
}
}
LeaveCriticalSection(&setupapi_lock);
return result;
}
static BOOL WINAPI my_SetupDiEnumDeviceInterfaces( static BOOL WINAPI my_SetupDiEnumDeviceInterfaces(
HDEVINFO DeviceInfoSet, HDEVINFO DeviceInfoSet,
SP_DEVINFO_DATA *DeviceInfoData, SP_DEVINFO_DATA *DeviceInfoData,
@ -322,6 +399,76 @@ pass:
DeviceInfoData); DeviceInfoData);
} }
static BOOL WINAPI my_SetupDiGetDeviceInterfaceDetailA(
HDEVINFO DeviceInfoSet,
SP_DEVICE_INTERFACE_DATA *DeviceInterfaceData,
SP_DEVICE_INTERFACE_DETAIL_DATA_A *DeviceInterfaceDetailData,
DWORD DeviceInterfaceDetailDataSize,
DWORD *RequiredSize,
SP_DEVINFO_DATA *DeviceInfoData)
{
const char *str;
size_t nbytes_str;
size_t nbytes_total;
size_t i;
bool match;
if (DeviceInfoSet == INVALID_HANDLE_VALUE || DeviceInterfaceData == NULL) {
goto pass;
}
EnterCriticalSection(&setupapi_lock);
for (i = 0, match = false; i < setupapi_nclasses && !match; i++) {
if (DeviceInfoSet == setupapi_classes[i].cur_handle &&
DeviceInterfaceData->Reserved == (ULONG_PTR) setupapi_classes[i].path) {
str = setupapi_classes[i].a_path;
match = true;
}
}
LeaveCriticalSection(&setupapi_lock);
if (!match) {
goto pass;
}
nbytes_str = strlen(str) + 1;
nbytes_total = offsetof(SP_DEVICE_INTERFACE_DETAIL_DATA_W, DevicePath);
nbytes_total += nbytes_str;
if (RequiredSize != NULL) {
*RequiredSize = (DWORD) nbytes_total;
}
if ( DeviceInterfaceDetailData == NULL &&
DeviceInterfaceDetailDataSize < nbytes_total) {
SetLastError(ERROR_INSUFFICIENT_BUFFER);
return FALSE;
}
if (DeviceInterfaceDetailData->cbSize!=sizeof(*DeviceInterfaceDetailData)) {
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
memcpy(DeviceInterfaceDetailData->DevicePath, str, nbytes_str);
SetLastError(ERROR_SUCCESS);
return TRUE;
pass:
return next_SetupDiGetDeviceInterfaceDetailA(
DeviceInfoSet,
DeviceInterfaceData,
DeviceInterfaceDetailData,
DeviceInterfaceDetailDataSize,
RequiredSize,
DeviceInfoData);
}
static BOOL WINAPI my_SetupDiDestroyDeviceInfoList(HDEVINFO DeviceInfoSet) static BOOL WINAPI my_SetupDiDestroyDeviceInfoList(HDEVINFO DeviceInfoSet)
{ {
size_t i; size_t i;