diff --git a/README.md b/README.md index 7077fde..d24c497 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Segatools -Version: `2023-07-14` +Version: `2023-11-22` 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 Amazon (Plus)](doc/chunihook.md) * [Chunithm Crystal (Plus)](doc/chunihook.md) + * Chunithm SUN * Initial D * [Initial D Arcade Stage Zero](doc/idzhook.md) - * Initial D The Arcade + * Initial D THE ARCADE * SEGA World Drivers Championship - * SEGA World Drivers Championship 2019 + * up to SEGA World Drivers Championship 2019 +* Fate/Grand Order + * Fate/Grand Order Arcade * ONGEKI - * bright MEMORY + * up to bright MEMORY * maimai DX - * maimai DX FESTiVAL + * up to maimai DX FESTiVAL PLUS * Card Maker - * Card Maker 1.35 + * up to Card Maker 1.35 * Wacca - * Wacca Lilly R (WIP) + * up to WACCA Reverse ## End-users diff --git a/dist/fgo/segatools.ini b/dist/fgo/segatools.ini index 67c0f91..0d99009 100644 --- a/dist/fgo/segatools.ini +++ b/dist/fgo/segatools.ini @@ -55,12 +55,13 @@ rotate180=1 ; 837-15345 RFID deck reader emulation setting. enable=1 +[ftdi] +; FTDI serial to usb adapter emulation for CABINET LED. +enable=1 + [ledstrip] ; 837-15093-06 LED strip emulation setting. 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 diff --git a/fgohook/config.c b/fgohook/config.c index d6971ac..be6bdd0 100644 --- a/fgohook/config.c +++ b/fgohook/config.c @@ -32,6 +32,7 @@ void ftdi_config_load(struct ftdi_config *cfg, const wchar_t *filename) assert(filename != NULL); 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) @@ -45,7 +46,7 @@ void led1509306_config_load(struct led1509306_config *cfg, const wchar_t *filena memset(cfg->chip_number, ' ', sizeof(cfg->chip_number)); 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_sum = GetPrivateProfileIntW(L"ledstrip", L"fw_sum", 0xaa53, filename); diff --git a/fgohook/deck.c b/fgohook/deck.c index e712724..b8e4bed 100644 --- a/fgohook/deck.c +++ b/fgohook/deck.c @@ -129,7 +129,7 @@ static struct card_collection* cards_ptr; static uint8_t current_card_idx = 0; 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); @@ -139,7 +139,7 @@ HRESULT deck_hook_init(const struct deck_config *cfg, int port) InitializeCriticalSection(&deck_lock); - uart_init(&deck_uart, port); + uart_init(&deck_uart, port_no); deck_uart.written.bytes = deck_written_bytes; deck_uart.written.nbytes = sizeof(deck_written_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->pos <= src->nbytes); + deck_frame_sync(src); + dest->pos = 0; escape = false; diff --git a/fgohook/deck.h b/fgohook/deck.h index 32c1ef9..c8e5f6d 100644 --- a/fgohook/deck.h +++ b/fgohook/deck.h @@ -8,4 +8,4 @@ struct deck_config { 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); diff --git a/fgohook/dllmain.c b/fgohook/dllmain.c index 69269b5..2c3af8e 100644 --- a/fgohook/dllmain.c +++ b/fgohook/dllmain.c @@ -90,13 +90,11 @@ static DWORD CALLBACK fgo_pre_startup(void) goto fail; } - /* hr = ftdi_hook_init(&fgo_hook_cfg.ftdi); if (FAILED(hr)) { goto fail; } - */ hr = led1509306_hook_init(&fgo_hook_cfg.led1509306); diff --git a/fgohook/ftdi.c b/fgohook/ftdi.c index 50b7d11..bda7507 100644 --- a/fgohook/ftdi.c +++ b/fgohook/ftdi.c @@ -8,15 +8,22 @@ 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. If these fail, the "CABINET LED" check on startup will always return "NG". + + Credits: + + OLEG */ #include - +#include +#include #include +#include #include "fgohook/ftdi.h" #include "hook/iohook.h" +#include "hook/table.h" #include "hooklib/setupapi.h" @@ -24,10 +31,97 @@ 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; assert(cfg != NULL); @@ -36,6 +130,18 @@ HRESULT ftdi_hook_init(const struct ftdi_config *cfg) 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)); hr = iohook_open_nul_fd(&ftdi_fd); @@ -50,6 +156,68 @@ HRESULT ftdi_hook_init(const struct ftdi_config *cfg) return hr; } + sprintf(port_name, "COM%d", cfg->port_no); + dprintf("FTDI: Hook enabled.\n"); 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); +} diff --git a/fgohook/ftdi.h b/fgohook/ftdi.h index c40fb3b..e1cd9d6 100644 --- a/fgohook/ftdi.h +++ b/fgohook/ftdi.h @@ -8,6 +8,7 @@ struct ftdi_config { bool enable; + uint32_t port_no; }; DEFINE_GUID( diff --git a/hooklib/setupapi.c b/hooklib/setupapi.c index edd416a..6f4fbb5 100644 --- a/hooklib/setupapi.c +++ b/hooklib/setupapi.c @@ -16,6 +16,7 @@ struct setupapi_class { const GUID *guid; const wchar_t *path; + char *a_path; HDEVINFO cur_handle; }; @@ -29,6 +30,12 @@ static HDEVINFO WINAPI my_SetupDiGetClassDevsW( HWND hwndParent, DWORD Flags); +static HDEVINFO WINAPI my_SetupDiGetClassDevsA( + const GUID *ClassGuid, + char *Enumerator, + HWND hwndParent, + DWORD Flags); + static BOOL WINAPI my_SetupDiEnumDeviceInterfaces( HDEVINFO DeviceInfoSet, SP_DEVINFO_DATA *DeviceInfoData, @@ -44,6 +51,14 @@ static BOOL WINAPI my_SetupDiGetDeviceInterfaceDetailW( DWORD *RequiredSize, 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); /* Links */ @@ -54,6 +69,12 @@ static HDEVINFO (WINAPI *next_SetupDiGetClassDevsW)( HWND hwndParent, DWORD Flags); +static HDEVINFO (WINAPI *next_SetupDiGetClassDevsA)( + const GUID *ClassGuid, + char *Enumerator, + HWND hwndParent, + DWORD Flags); + static BOOL (WINAPI *next_SetupDiEnumDeviceInterfaces)( HDEVINFO DeviceInfoSet, SP_DEVINFO_DATA *DeviceInfoData, @@ -69,6 +90,14 @@ static BOOL (WINAPI *next_SetupDiGetDeviceInterfaceDetailW)( DWORD *RequiredSize, 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); /* Hook tbl */ @@ -78,6 +107,10 @@ static const struct hook_symbol setupapi_syms[] = { .name = "SetupDiGetClassDevsW", .patch = my_SetupDiGetClassDevsW, .link = (void *) &next_SetupDiGetClassDevsW, + }, { + .name = "SetupDiGetClassDevsA", + .patch = my_SetupDiGetClassDevsA, + .link = (void *) &next_SetupDiGetClassDevsA, }, { .name = "SetupDiEnumDeviceInterfaces", .patch = my_SetupDiEnumDeviceInterfaces, @@ -86,6 +119,10 @@ static const struct hook_symbol setupapi_syms[] = { .name = "SetupDiGetDeviceInterfaceDetailW", .patch = my_SetupDiGetDeviceInterfaceDetailW, .link = (void *) &next_SetupDiGetDeviceInterfaceDetailW, + }, { + .name = "SetupDiGetDeviceInterfaceDetailA", + .patch = my_SetupDiGetDeviceInterfaceDetailA, + .link = (void *) &next_SetupDiGetDeviceInterfaceDetailA, }, { .name = "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 *new_array; + size_t a_path_len; HRESULT hr; 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_->guid = iface_class; 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; end: @@ -189,6 +232,40 @@ static HDEVINFO WINAPI my_SetupDiGetClassDevsW( 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( HDEVINFO DeviceInfoSet, SP_DEVINFO_DATA *DeviceInfoData, @@ -322,6 +399,76 @@ pass: 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) { size_t i;