From 75f171663cd15d3086b3ea069c91adc3627b3f25 Mon Sep 17 00:00:00 2001 From: Hay1tsme Date: Tue, 4 Feb 2025 04:09:19 -0500 Subject: [PATCH] add winusb hook and usbio board skeletons --- board/guid.h | 7 ++ board/j9100628a.c | 2 + board/j9100647a.c | 54 +++++++++++ board/j9100647a.h | 22 +++++ board/meson.build | 3 + hooklib/meson.build | 3 + hooklib/setupapi.c | 146 +++++++++++++++++++++++++++++ hooklib/winusb.c | 223 ++++++++++++++++++++++++++++++++++++++++++++ hooklib/winusb.h | 26 ++++++ idmac/fastio.c | 18 +++- idmac/fastio.h | 1 + idmac/idmac.c | 11 ++- ll3io/ll3io.c | 2 +- meson.build | 5 +- ri/meson.build | 14 +++ ri/ri.c | 168 +++++++++++++++++++++++++++++++++ ri/ri.h | 6 ++ sivahook/fastio.c | 47 +++++++--- sivahook/fastio.h | 32 +++---- sivaio/config.c | 10 +- sivaio/config.h | 4 +- sivaio/meson.build | 4 +- sivaio/sivaio.c | 64 +++---------- 23 files changed, 775 insertions(+), 97 deletions(-) create mode 100644 board/j9100647a.c create mode 100644 board/j9100647a.h create mode 100644 hooklib/winusb.c create mode 100644 hooklib/winusb.h create mode 100644 ri/meson.build create mode 100644 ri/ri.c create mode 100644 ri/ri.h diff --git a/board/guid.h b/board/guid.h index 707e85a..6d353d8 100644 --- a/board/guid.h +++ b/board/guid.h @@ -8,3 +8,10 @@ DEFINE_GUID( 0xF16F, 0x11CF, 0x88, 0xCB, 0x00, 0x11, 0x11, 0x00, 0x00, 0x30); + +DEFINE_GUID( + usbio_guid, + 0x46C3136FL, + 0x0FD5, + 0x4973, + 0xBC, 0x5A, 0xF4, 0xA9, 0xF3, 0x52, 0x81, 0x39); diff --git a/board/j9100628a.c b/board/j9100628a.c index 317420f..9385be6 100644 --- a/board/j9100628a.c +++ b/board/j9100628a.c @@ -15,6 +15,8 @@ #include "util/dprintf.h" #include "util/dump.h" +// JVS card reader + static const uint8_t j9100628a_ident[] = "taito;JVS-Reader;Ver1.00;JPN,Multipurpose"; static uint8_t j9100628a_features[] = { diff --git a/board/j9100647a.c b/board/j9100647a.c new file mode 100644 index 0000000..e238d50 --- /dev/null +++ b/board/j9100647a.c @@ -0,0 +1,54 @@ +#include + +#include +#include + +#include +#include +#include +#include + +#include "board/guid.h" +#include "board/j9100647a.h" + +#include "hook/iobuf.h" +#include "hook/iohook.h" + +#include "hooklib/setupapi.h" + +#include "util/dprintf.h" + +// USB IO + +static HRESULT usbio_handle_irp(struct irp *irp); + +static const wchar_t usbio_path[] = L"$usbio"; + +static HANDLE usbio_fd; +static void *usbio_ops_ctx; + +HRESULT usbio_hook_init() +{ + HRESULT hr; + + hr = iohook_open_nul_fd(&usbio_fd); + + if (FAILED(hr)) { + return hr; + } + + iohook_push_handler(usbio_handle_irp); + + hr = setupapi_add_phantom_dev(&usbio_guid, usbio_path); + + if (FAILED(hr)) { + return hr; + } + + return S_OK; +} + +static HRESULT usbio_handle_irp(struct irp *irp) +{ + return S_OK; +} diff --git a/board/j9100647a.h b/board/j9100647a.h new file mode 100644 index 0000000..9f79e6b --- /dev/null +++ b/board/j9100647a.h @@ -0,0 +1,22 @@ +#pragma once +#include +#include + +#pragma pack(push,1) + +// needs to handle digital and analog reads and writes, coin stuff, and +// having an ad-on device (usually a card reader) and maybe an SD card?? + +// Mayhaps move this to a seperate thing in the event a second USB IO +// providor is needed? +struct usbio_dev { + // TODO: populate with handler functions for various commands that + // come in via winusb + // It might also just do a mass bulk update, in which case we need + // a struct that encompases all the digital and analog I/O pins and + // their states. +}; + +#pragma pack(pop) + +HRESULT usbio_hook_init(); diff --git a/board/meson.build b/board/meson.build index 2cb30e6..12132a9 100644 --- a/board/meson.build +++ b/board/meson.build @@ -7,6 +7,7 @@ board_lib = static_library( ], link_with : [ iccard_lib, + hooklib_lib, ], sources : [ 'config.c', @@ -17,6 +18,8 @@ board_lib = static_library( 'io3.h', 'j9100628a.c', 'j9100628a.h', + 'j9100647a.c', + 'j9100647a.h', 'io4.c', 'io4.h', 'sg-cmd.c', diff --git a/hooklib/meson.build b/hooklib/meson.build index 6a6f536..401c38f 100644 --- a/hooklib/meson.build +++ b/hooklib/meson.build @@ -4,6 +4,7 @@ hooklib_lib = static_library( implicit_include_directories : false, dependencies : [ capnhook.get_variable('hook_dep'), + winusb_lib, ], sources : [ 'cursor.c', @@ -28,5 +29,7 @@ hooklib_lib = static_library( 'setupapi.h', 'spike.c', 'spike.h', + 'winusb.c', + 'winusb.h', ], ) diff --git a/hooklib/setupapi.c b/hooklib/setupapi.c index edd416a..6d106eb 100644 --- a/hooklib/setupapi.c +++ b/hooklib/setupapi.c @@ -23,6 +23,12 @@ static void setupapi_hook_init(void); /* API hooks */ +static HDEVINFO WINAPI my_SetupDiGetClassDevsA( + const GUID *ClassGuid, + char *Enumerator, + HWND hwndParent, + DWORD Flags); + static HDEVINFO WINAPI my_SetupDiGetClassDevsW( const GUID *ClassGuid, wchar_t *Enumerator, @@ -44,10 +50,24 @@ 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 */ +static HDEVINFO (WINAPI *next_SetupDiGetClassDevsA)( + const GUID *ClassGuid, + char *Enumerator, + HWND hwndParent, + DWORD Flags); + static HDEVINFO (WINAPI *next_SetupDiGetClassDevsW)( const GUID *ClassGuid, wchar_t *Enumerator, @@ -69,12 +89,24 @@ 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 */ static const struct hook_symbol setupapi_syms[] = { { + .name = "SetupDiGetClassDevsA", + .patch = my_SetupDiGetClassDevsA, + .link = (void *) &next_SetupDiGetClassDevsA, + }, { .name = "SetupDiGetClassDevsW", .patch = my_SetupDiGetClassDevsW, .link = (void *) &next_SetupDiGetClassDevsW, @@ -86,6 +118,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, @@ -155,6 +191,40 @@ void setupapi_hook_insert_hooks(HMODULE target) _countof(setupapi_syms)); } +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 HDEVINFO WINAPI my_SetupDiGetClassDevsW( const GUID *ClassGuid, wchar_t *Enumerator, @@ -322,6 +392,82 @@ 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 wchar_t *wstr; + char path_ch[MAX_PATH]; + size_t nbytes_wstr; + 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) { + match = true; + } + } + + LeaveCriticalSection(&setupapi_lock); + + if (!match) { + goto pass; + } + + wstr = (const wchar_t *) DeviceInterfaceData->Reserved; + nbytes_wstr = (wcslen(wstr) + 1) * sizeof(wchar_t); + + wcstombs_s(&nbytes_str, path_ch, MAX_PATH, (wchar_t *) DeviceInterfaceData->Reserved, MAX_PATH); + nbytes_total = offsetof(SP_DEVICE_INTERFACE_DETAIL_DATA_A, 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, path_ch, 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; diff --git a/hooklib/winusb.c b/hooklib/winusb.c new file mode 100644 index 0000000..4590e5f --- /dev/null +++ b/hooklib/winusb.c @@ -0,0 +1,223 @@ +#include +#include +#include +#include +#include + +#include "hook/table.h" + +#include "hooklib/winusb.h" + +#include "util/dprintf.h" + +static bool winusb_initted; +static CRITICAL_SECTION winusb_lock; +static struct winusb_dev *winusb_classes; +static size_t winusb_nclasses; + +static void winusb_hook_init(); + +BOOL my_WinUsb_QueryPipe( + WINUSB_INTERFACE_HANDLE InterfaceHandle, + UCHAR AlternateInterfaceNumber, + UCHAR PipeIndex, + PWINUSB_PIPE_INFORMATION PipeInformation +); + +BOOL my_WinUsb_QueryInterfaceSettings( + WINUSB_INTERFACE_HANDLE InterfaceHandle, + UCHAR AlternateInterfaceNumber, + PUSB_INTERFACE_DESCRIPTOR UsbAltInterfaceDescriptor +); + +BOOL my_WinUsb_GetDescriptor( + WINUSB_INTERFACE_HANDLE InterfaceHandle, + UCHAR DescriptorType, + UCHAR Index, + USHORT LanguageID, + PUCHAR Buffer, + ULONG BufferLength, + PULONG LengthTransferred +); + +BOOL my_WinUsb_WritePipe( + WINUSB_INTERFACE_HANDLE InterfaceHandle, + UCHAR PipeID, + PUCHAR Buffer, + ULONG BufferLength, + PULONG LengthTransferred, + LPOVERLAPPED Overlapped +); + +BOOL my_WinUsb_QueryDeviceInformation( + WINUSB_INTERFACE_HANDLE InterfaceHandle, + ULONG InformationType, + PULONG BufferLength, + PVOID Buffer +); + +BOOL my_WinUsb_ReadPipe( + WINUSB_INTERFACE_HANDLE InterfaceHandle, + UCHAR PipeID, + PUCHAR Buffer, + ULONG BufferLength, + PULONG LengthTransferred, + LPOVERLAPPED Overlapped +); + +BOOL my_WinUsb_Initialize( + HANDLE DeviceHandle, + PWINUSB_INTERFACE_HANDLE InterfaceHandle +); + +BOOL my_WinUsb_Free( + WINUSB_INTERFACE_HANDLE InterfaceHandle +); + +BOOL (*next_WinUsb_QueryPipe)( + WINUSB_INTERFACE_HANDLE InterfaceHandle, + UCHAR AlternateInterfaceNumber, + UCHAR PipeIndex, + PWINUSB_PIPE_INFORMATION PipeInformation +); + +BOOL (*next_WinUsb_QueryInterfaceSettings)( + WINUSB_INTERFACE_HANDLE InterfaceHandle, + UCHAR AlternateInterfaceNumber, + PUSB_INTERFACE_DESCRIPTOR UsbAltInterfaceDescriptor +); + +BOOL (*next_WinUsb_GetDescriptor)( + WINUSB_INTERFACE_HANDLE InterfaceHandle, + UCHAR DescriptorType, + UCHAR Index, + USHORT LanguageID, + PUCHAR Buffer, + ULONG BufferLength, + PULONG LengthTransferred +); + +BOOL (*next_WinUsb_WritePipe)( + WINUSB_INTERFACE_HANDLE InterfaceHandle, + UCHAR PipeID, + PUCHAR Buffer, + ULONG BufferLength, + PULONG LengthTransferred, + LPOVERLAPPED Overlapped +); + +BOOL (*next_WinUsb_QueryDeviceInformation)( + WINUSB_INTERFACE_HANDLE InterfaceHandle, + ULONG InformationType, + PULONG BufferLength, + PVOID Buffer +); + +BOOL (*next_WinUsb_ReadPipe)( + WINUSB_INTERFACE_HANDLE InterfaceHandle, + UCHAR PipeID, + PUCHAR Buffer, + ULONG BufferLength, + PULONG LengthTransferred, + LPOVERLAPPED Overlapped +); + +BOOL (*next_WinUsb_Initialize)( + HANDLE DeviceHandle, + PWINUSB_INTERFACE_HANDLE InterfaceHandle +); + +BOOL (*next_WinUsb_Free)( + WINUSB_INTERFACE_HANDLE InterfaceHandle +); + +static const struct hook_symbol winusb_syms[] = { + { + .name = "WinUsb_QueryPipe", + .patch = my_WinUsb_QueryPipe, + .link = (void *) &next_WinUsb_QueryPipe, + }, { + .name = "WinUsb_QueryInterfaceSettings", + .patch = my_WinUsb_QueryInterfaceSettings, + .link = (void *) &next_WinUsb_QueryInterfaceSettings, + }, { + .name = "WinUsb_GetDescriptor", + .patch = my_WinUsb_GetDescriptor, + .link = (void *) &next_WinUsb_GetDescriptor, + }, { + .name = "WinUsb_WritePipe", + .patch = my_WinUsb_WritePipe, + .link = (void *) &next_WinUsb_WritePipe, + }, { + .name = "WinUsb_QueryDeviceInformation", + .patch = my_WinUsb_QueryDeviceInformation, + .link = (void *) &next_WinUsb_QueryDeviceInformation, + }, { + .name = "WinUsb_ReadPipe", + .patch = my_WinUsb_ReadPipe, + .link = (void *) &next_WinUsb_ReadPipe, + }, { + .name = "WinUsb_Initialize", + .patch = my_WinUsb_Initialize, + .link = (void *) &next_WinUsb_Initialize, + }, { + .name = "WinUsb_Free", + .patch = my_WinUsb_Free, + .link = (void *) &next_WinUsb_Free, + } +}; + +HRESULT winusb_add_phantom_dev(const struct winusb_dev *dev) +{ + struct winusb_dev *class_; + struct winusb_dev *new_array; + HRESULT hr; + + assert(dev != NULL); + + winusb_hook_init(); + + EnterCriticalSection(&winusb_lock); + + new_array = realloc( + winusb_classes, + (winusb_nclasses + 1) * sizeof(struct winusb_dev)); + + if (new_array == NULL) { + hr = E_OUTOFMEMORY; + + goto end; + } + + winusb_classes = new_array; + + // TODO: Copy the dev class to the new slot in the array + class_ = &winusb_classes[winusb_nclasses++]; + hr = S_OK; + +end: + LeaveCriticalSection(&winusb_lock); + + return hr; +} + +static void winusb_hook_init() +{ + if (winusb_initted) { + return; + } + + winusb_hook_insert_hooks(NULL); + + InitializeCriticalSection(&winusb_lock); + winusb_initted = true; +} + +void winusb_hook_insert_hooks(HMODULE target) +{ + hook_table_apply( + target, + "winusb.dll", + winusb_syms, + _countof(winusb_syms)); +} diff --git a/hooklib/winusb.h b/hooklib/winusb.h new file mode 100644 index 0000000..619af13 --- /dev/null +++ b/hooklib/winusb.h @@ -0,0 +1,26 @@ +#pragma once +#include +#include +#include + +#pragma pack(push,1) + +// winusb - hooks for winusb ident, read and write passed to device +// usio - providor for winusb, passes along read/write +// ll3io - gives usio the data to write + +struct winusb_dev { + HANDLE fd; + GUID class_guid; + const wchar_t *path; + //uint8_t read_pipe_id; // duno if this ever needs to change? + //uint8_t write_pipe_id; + struct _USB_DEVICE_DESCRIPTOR descriptor; + void (*read_pipe)(void *ctx, uint8_t pipe_id, uint8_t *bfr, uint32_t bfr_len); + void (*write_pipe)(void *ctx, uint8_t pipe_id, uint8_t *bfr, uint32_t bfr_len); +}; + +#pragma pack(pop) + +HRESULT winusb_add_phantom_dev(const struct winusb_dev *dev); +void winusb_hook_insert_hooks(HMODULE target); diff --git a/idmac/fastio.c b/idmac/fastio.c index 78d62af..3c03bd9 100644 --- a/idmac/fastio.c +++ b/idmac/fastio.c @@ -37,6 +37,7 @@ HRESULT fastio_hook_init(fastio_provider_t main, fastio_provider_t sub) void fastio_match_board_number(uint8_t board_no, struct fastio_node root, struct fastio_node *board) { assert(&root != NULL); + // FIXME board = &root; while (board->next != NULL && board->next->board_no != board_no) { @@ -51,13 +52,26 @@ void fastio_match_board_number(uint8_t board_no, struct fastio_node root, struct } void fastio_digital_read(void* ctx, uint8_t board_no, uint32_t *out) +{ + //struct fastio_node *req_board = NULL; + //fastio_match_board_number(board_no, fio_main, req_board); + + // If we fail to find, or the board we found doesn't have the handler we need, + // quietly return with out unmodified + //if (req_board != NULL && req_board->digital_in != NULL) { + if (fio_main.digital_in != NULL) { + fio_main.digital_in(ctx, out); + } +} + +void fastio_coins_in(void* ctx, uint8_t board_no, uint8_t slot_no, uint32_t *out) { struct fastio_node *req_board = NULL; fastio_match_board_number(board_no, fio_main, req_board); // If we fail to find, or the board we found doesn't have the handler we need, // quietly return with out unmodified - if (req_board != NULL && req_board->digital_in != NULL) { - fio_main.digital_in(ctx, out); + if (req_board != NULL && req_board->coins_in != NULL) { + fio_main.coins_in(ctx, slot_no, out); } } diff --git a/idmac/fastio.h b/idmac/fastio.h index 1dbe578..8a70c19 100644 --- a/idmac/fastio.h +++ b/idmac/fastio.h @@ -22,3 +22,4 @@ typedef HRESULT (*fastio_provider_t)(struct fastio_node *root); HRESULT fastio_hook_init(fastio_provider_t main, fastio_provider_t sub); void fastio_digital_read(void* ctx, uint8_t board_no, uint32_t *out); +void fastio_coins_in(void* ctx, uint8_t board_no, uint8_t slot_no, uint32_t *out); diff --git a/idmac/idmac.c b/idmac/idmac.c index 3329351..91eb495 100644 --- a/idmac/idmac.c +++ b/idmac/idmac.c @@ -316,9 +316,6 @@ static int hook_iDmacDrvRegisterRead(HANDLE a1, DWORD register_id, DWORD* regist case 0x4004: *register_val = -2; break; // Status case 0x4120: // JVS Buttons - /*if (GetAsyncKeyState(VK_DELETE) & 0x8000) { - *register_val = 0x40; // Test - }*/ fastio_digital_read(NULL, 0, (uint32_t *)register_val); break; @@ -326,8 +323,12 @@ static int hook_iDmacDrvRegisterRead(HANDLE a1, DWORD register_id, DWORD* regist case 0x4128: break; // Analog 2 case 0x412C: break; // Analog 3 - case 0x4140: break; // Coin slot 1 - case 0x4144: break; // Coin slot 2 + 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 case 0x41A0: break; case 0x41A4: break; diff --git a/ll3io/ll3io.c b/ll3io/ll3io.c index 906c800..e567903 100644 --- a/ll3io/ll3io.c +++ b/ll3io/ll3io.c @@ -24,7 +24,7 @@ uint16_t ll3_io_get_api_version(void) HRESULT ll3_io_init(void) { dprintf("ll3 IO: Init\n"); - ll3_io_config_load(&cfg, L".\\bananatools.ini"); + ll3_io_config_load(&cfg, L".\\taitools.ini"); return S_OK; } diff --git a/meson.build b/meson.build index 1b8d8b0..870240d 100644 --- a/meson.build +++ b/meson.build @@ -41,13 +41,16 @@ dxguid_lib = cc.find_library('dxguid') xinput_lib = cc.find_library('xinput') crypt_lib = cc.find_library('crypt32') winhttp_lib = cc.find_library('winhttp') +hid_lib = cc.find_library('hid') +winusb_lib = cc.find_library('winusb') inc = include_directories('.') capnhook = subproject('capnhook') +subdir('ri') subdir('iccard') -subdir('board') subdir('hooklib') +subdir('board') subdir('jvs') subdir('platform') subdir('util') diff --git a/ri/meson.build b/ri/meson.build new file mode 100644 index 0000000..8e7d91e --- /dev/null +++ b/ri/meson.build @@ -0,0 +1,14 @@ +ri_lib = static_library( + 'ri', + include_directories : inc, + implicit_include_directories : false, + dependencies : [ + capnhook.get_variable('hook_dep'), + capnhook.get_variable('hooklib_dep'), + hid_lib, + ], + sources : [ + 'ri.c', + 'ri.h', + ], +) diff --git a/ri/ri.c b/ri/ri.c new file mode 100644 index 0000000..be164da --- /dev/null +++ b/ri/ri.c @@ -0,0 +1,168 @@ +#include + +#include +#include +#include +#include +#include + +#include "hook/iohook.h" +#include "util/dprintf.h" + +#include "ri/ri.h" + +static HWND ri_hwnd; +static WNDCLASSEX ri_wndclass; +static HANDLE selected_ri_dev = (HANDLE)-1; +static uintptr_t ri_thread; + +LRESULT CALLBACK ri_win_proc(HWND hWnd, UINT msg, WPARAM wparam, LPARAM lParam); +static unsigned int __stdcall ri_thread_proc(void *ctx); + +HRESULT ri_init(uint8_t dev_num) +{ + wchar_t ri_dev_name[MAX_PATH] = L"\0"; + wchar_t hid_prod_name[MAX_PATH] = L"\0"; + UINT num_ri_devs = 0; + UINT len_ri_dev_name = 0; + DWORD err = 0; + PRAWINPUTDEVICELIST ri_devs = NULL; + + if (GetRawInputDeviceList(NULL, &num_ri_devs, sizeof(RAWINPUTDEVICELIST)) != 0) { + err = GetLastError(); + dprintf("RawInput: GetRawInputDeviceList failed to get number of devices %08lX\n", err); + return E_FAIL; + } + + ri_devs = malloc(sizeof(RAWINPUTDEVICELIST) * num_ri_devs); + GetRawInputDeviceList(ri_devs, &num_ri_devs, sizeof(RAWINPUTDEVICELIST)); + + if (num_ri_devs <= 0) { + err = GetLastError(); + dprintf("RawInput: GetRawInputDeviceList failed to get devices info %08lX\n", err); + free(ri_devs); + return E_FAIL; + } + + dprintf("RawInput: Raw Input device list (%d devices):\n", num_ri_devs); + for (int i = 0; i < num_ri_devs; i++) { + len_ri_dev_name = 0; + if (GetRawInputDeviceInfoW(ri_devs[i].hDevice, RIDI_DEVICENAME, NULL, &len_ri_dev_name) != 0) { + dprintf("RawInput: GetRawInputDeviceInfoW #%d failed to get name size\n", i); + break; + } + + if (len_ri_dev_name <= 0) { + dprintf("RawInput: GetRawInputDeviceInfoW #%d len_ri_dev_name <= 0\n", i); + break; + } + + if (len_ri_dev_name >= MAX_PATH) { + dprintf("\tDev #%d - (name too long, %d characters)\n", i, len_ri_dev_name); + continue; + } + + if (GetRawInputDeviceInfoW(ri_devs[i].hDevice, RIDI_DEVICENAME, ri_dev_name, &len_ri_dev_name) <= 0) { + dprintf("RawInput: GetRawInputDeviceInfoW #%d failed to get name\n", i); + break; + } + + HANDLE hiddev = CreateFileW(ri_dev_name, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + + if (hiddev == NULL) { + dprintf("RawInput: CreateFileW failed on dev #%d for device %ls\n", i, ri_dev_name); + continue; + } + + if (!HidD_GetProductString(hiddev, hid_prod_name, MAX_PATH)) { + //dprintf("RawInput: HidD_GetProductString failed on dev #%d for device %ls\n", i, ri_dev_name); + continue; + } + + dprintf("\tDev #%d - %ls\n", i, hid_prod_name); + } + + selected_ri_dev = ri_devs[dev_num].hDevice; + + free(ri_devs); + + ri_wndclass.cbSize = sizeof(WNDCLASSEX); + ri_wndclass.hInstance = GetModuleHandle(NULL); + ri_wndclass.lpfnWndProc = ri_win_proc; + ri_wndclass.lpszClassName = "Taitools Input"; + + RegisterClassEx(&ri_wndclass); + + ri_thread = _beginthreadex( + NULL, + 0, + ri_thread_proc, + NULL, + 0, + NULL); + return S_OK; +} + +void ri_exit() +{ + if (ri_hwnd) { + PostMessage(ri_hwnd, WM_CLOSE, 0, 0); + } +} + +static unsigned int __stdcall ri_thread_proc(void *ctx) +{ + dprintf("RawInput: ri_thread_proc begin\n"); + SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL); + + ri_hwnd = CreateWindowExA(0, ri_wndclass.lpszClassName, "Taitools Input", 0, 0, 0, 0, 0, NULL, NULL, ri_wndclass.hInstance, NULL); + + RAWINPUTDEVICE Rid[4]; + Rid[0].usUsagePage = 0x01; // HID_USAGE_PAGE_GENERIC + Rid[0].usUsage = 0x02; // HID_USAGE_GENERIC_MOUSE + Rid[0].dwFlags = RIDEV_NOLEGACY; // adds mouse and also ignores legacy mouse messages + Rid[0].hwndTarget = ri_hwnd; + + Rid[1].usUsagePage = 0x01; // HID_USAGE_PAGE_GENERIC + Rid[1].usUsage = 0x06; // HID_USAGE_GENERIC_KEYBOARD + Rid[1].dwFlags = RIDEV_NOLEGACY; // adds keyboard and also ignores legacy keyboard messages + Rid[1].hwndTarget = ri_hwnd; + + Rid[2].usUsagePage = 0x01; // HID_USAGE_PAGE_GENERIC + Rid[2].usUsage = 0x05; // HID_USAGE_GENERIC_GAMEPAD + Rid[2].dwFlags = 0; // adds game pad + Rid[2].hwndTarget = ri_hwnd; + + Rid[3].usUsagePage = 0x01; // HID_USAGE_PAGE_GENERIC + Rid[3].usUsage = 0x04; // HID_USAGE_GENERIC_JOYSTICK + Rid[3].dwFlags = 0; // adds joystick + Rid[3].hwndTarget = ri_hwnd; + + if (!RegisterRawInputDevices(Rid, 4, sizeof(Rid[0]))) { + dprintf("RawInput: Failed to register RI devices\n"); + return E_FAIL; + } + + MSG msg; + while (GetMessage(&msg, ri_hwnd, 0, 0) > 0) { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + + DestroyWindow(ri_hwnd); + ri_hwnd = NULL; + UnregisterClass(ri_wndclass.lpszClassName, ri_wndclass.hInstance); + dprintf("RawInput: ri_thread_proc end\n"); + return S_OK; +} + +LRESULT CALLBACK ri_win_proc(HWND hWnd, UINT msg, WPARAM wparam, LPARAM lParam) +{ + switch (msg) { + case WM_INPUT: + //dprintf("RawInput: Got input\n"); + break; + } + + return DefWindowProc(hWnd, msg, wparam, lParam); +} \ No newline at end of file diff --git a/ri/ri.h b/ri/ri.h new file mode 100644 index 0000000..6afd6b7 --- /dev/null +++ b/ri/ri.h @@ -0,0 +1,6 @@ +#pragma once +#include +#include + +HRESULT ri_init(uint8_t dev_num); +void ri_exit(); diff --git a/sivahook/fastio.c b/sivahook/fastio.c index 157f51a..7160279 100644 --- a/sivahook/fastio.c +++ b/sivahook/fastio.c @@ -10,11 +10,11 @@ #include "util/dprintf.h" +static uint16_t coins; +static uint16_t services; + static void siva_fastio_digital_read(void *ctx, uint32_t *out); -static void siva_fastio_coin_read( - void *ctx, - uint8_t slot_no, - uint32_t *out); +static void siva_fastio_coin_read(void *ctx, uint8_t slot_no, uint32_t *out); HRESULT siva_fastio_init(struct fastio_node *out) { @@ -22,6 +22,7 @@ HRESULT siva_fastio_init(struct fastio_node *out) assert(out != NULL); + out->next = NULL; out->digital_in = siva_fastio_digital_read; out->coins_in = siva_fastio_coin_read; @@ -34,13 +35,37 @@ HRESULT siva_fastio_init(struct fastio_node *out) static void siva_fastio_digital_read(void *ctx, uint32_t *out) { - + uint8_t btn = 0; + uint8_t stick = 0; + *out = 0; + + assert(siva_dll.get_btns != NULL); + + siva_dll.get_btns(&btn, &stick); + + if (btn & BTN_TEST) { + *out |= SIVA_SWITCH_SYS_TEST; + } + + if (btn & BTN_SERVICE) { + *out |= SIVA_SWITCH_SYS_SERVICE; + } } -static void siva_fastio_coin_read( - void *ctx, - uint8_t slot_no, - uint32_t *out) +static void siva_fastio_coin_read(void *ctx, uint8_t slot_no, uint32_t *out) { - -} \ No newline at end of file + uint16_t coin = 0; + uint16_t service = 0; + + assert(siva_dll.get_btns != NULL); + + if (slot_no != 1) { + *out = 0; + return; + } + + siva_dll.read_coin_counter(&coin, &service); + + *out += coin; + *out += service; +} diff --git a/sivahook/fastio.h b/sivahook/fastio.h index 03257ef..e4f3238 100644 --- a/sivahook/fastio.h +++ b/sivahook/fastio.h @@ -4,22 +4,22 @@ #include "jvs/jvs-bus.h" #include "idmac/fastio.h" -enum SIVA_SWITCH { - RIGHT_BUTTON = 0x000080, - RIGHT_UP = 0x010000, - RIGHT_DOWN = 0x040000, - RIGHT_LEFT = 0x100000, - RIGHT_RIGHT = 0x400000, - LEFT_BUTTON = 0x000020, - LEFT_UP = 0x000100, - LEFT_DOWN = 0x000400, - LEFT_LEFT = 0x001000, - LEFT_RIGHT = 0x004000, - SYS_SERVICE = 0x000004, - SYS_TEST = 0x000040, - SYS_SELECT = 0x000008, - SYS_ENTER = 0x000010, - SYS_COIN = 0x000001, +enum { + SIVA_SWITCH_RIGHT_BUTTON = 0x000080, + SIVA_SWITCH_RIGHT_UP = 0x010000, + SIVA_SWITCH_RIGHT_DOWN = 0x040000, + SIVA_SWITCH_RIGHT_LEFT = 0x100000, + SIVA_SWITCH_RIGHT_RIGHT = 0x400000, + SIVA_SWITCH_LEFT_BUTTON = 0x000020, + SIVA_SWITCH_LEFT_UP = 0x000100, + SIVA_SWITCH_LEFT_DOWN = 0x000400, + SIVA_SWITCH_LEFT_LEFT = 0x001000, + SIVA_SWITCH_LEFT_RIGHT = 0x004000, + SIVA_SWITCH_SYS_SERVICE = 0x000004, + SIVA_SWITCH_SYS_TEST = 0x000040, + SIVA_SWITCH_SYS_SELECT = 0x000008, + SIVA_SWITCH_SYS_ENTER = 0x000010, + SIVA_SWITCH_SYS_COIN = 0x000001, }; HRESULT siva_fastio_init(struct fastio_node *out); diff --git a/sivaio/config.c b/sivaio/config.c index e19f954..89a94ea 100644 --- a/sivaio/config.c +++ b/sivaio/config.c @@ -8,12 +8,12 @@ void siva_io_config_load(struct siva_input_config *cfg, const wchar_t *filename) { - cfg->test = GetPrivateProfileIntW(L"jvs", L"test", VK_HOME, filename); - cfg->service = GetPrivateProfileIntW(L"jvs", L"service", VK_DELETE, filename); - cfg->coin = GetPrivateProfileIntW(L"jvs", L"coin", VK_INSERT, filename); + cfg->test = GetPrivateProfileIntW(L"jvs", L"test", VK_HOME, filename); + cfg->service = GetPrivateProfileIntW(L"jvs", L"service", VK_DELETE, filename); + cfg->coin = GetPrivateProfileIntW(L"jvs", L"coin", VK_INSERT, filename); - cfg->is_xinput = GetPrivateProfileIntW(L"deck", L"controller_type", 0, filename); - cfg->xinput_player = GetPrivateProfileIntW(L"deck", L"controller_num", 0, filename); + cfg->is_ri = GetPrivateProfileIntW(L"deck", L"input_type", 0, filename); // 0 for KB, 1 for RI + cfg->device_num = GetPrivateProfileIntW(L"deck", L"device_num", 1, filename); cfg->btn_l = GetPrivateProfileIntW(L"deck", L"left_button", 'C', filename); cfg->btn_r = GetPrivateProfileIntW(L"deck", L"right_button", 'N', filename); diff --git a/sivaio/config.h b/sivaio/config.h index 3f82c82..ccc3731 100644 --- a/sivaio/config.h +++ b/sivaio/config.h @@ -5,8 +5,8 @@ #pragma pack(push, 1) struct siva_input_config { - uint8_t is_xinput; - uint8_t xinput_player; + uint8_t is_ri; + uint8_t device_num; uint8_t test; uint8_t service; diff --git a/sivaio/meson.build b/sivaio/meson.build index 68b312e..59ed057 100644 --- a/sivaio/meson.build +++ b/sivaio/meson.build @@ -3,8 +3,8 @@ sivaio_lib = static_library( name_prefix : '', include_directories : inc, implicit_include_directories : false, - dependencies : [ - xinput_lib, + link_with : [ + ri_lib, ], sources : [ 'sivaio.c', diff --git a/sivaio/sivaio.c b/sivaio/sivaio.c index ba0bb39..0cba932 100644 --- a/sivaio/sivaio.c +++ b/sivaio/sivaio.c @@ -1,5 +1,4 @@ #include -#include #include #include @@ -8,6 +7,7 @@ #include "sivaio/sivaio.h" #include "sivaio/config.h" +#include "ri/ri.h" #include "util/dprintf.h" @@ -16,7 +16,6 @@ static bool siva_io_service = false; static uint16_t siva_coin_ct = 0; static uint16_t siva_service_ct = 0; static struct siva_input_config cfg; -static HANDLE selected_ri_dev = (HANDLE)-1; uint16_t siva_io_get_api_version(void) { @@ -24,64 +23,24 @@ uint16_t siva_io_get_api_version(void) } HRESULT siva_io_init(void) -{ - wchar_t ri_dev_name[MAX_PATH] = L"\0"; - UINT num_ri_devs = 0; - UINT len_ri_dev_name = 0; - DWORD err = 0; - PRAWINPUTDEVICELIST ri_devs = NULL; - +{ dprintf("Siva IO: Init\n"); - siva_io_config_load(&cfg, L".\\bananatools.ini"); + siva_io_config_load(&cfg, L".\\taitools.ini"); - if (GetRawInputDeviceList(NULL, &num_ri_devs, sizeof(RAWINPUTDEVICELIST)) != 0) { - err = GetLastError(); - dprintf("Siva IO: GetRawInputDeviceList failed to get number of devices %08lX\n", err); - return E_FAIL; + if (cfg.is_ri) { + return ri_init(cfg.device_num); } - - ri_devs = malloc(sizeof(RAWINPUTDEVICELIST) * num_ri_devs); - GetRawInputDeviceList(ri_devs, &num_ri_devs, sizeof(RAWINPUTDEVICELIST)); - - if (num_ri_devs <= 0) { - err = GetLastError(); - dprintf("Siva IO: GetRawInputDeviceList failed to get devices info %08lX\n", err); - free(ri_devs); - return E_FAIL; - } - - dprintf("Siva IO: Raw Input device list (%d devices):\n", num_ri_devs); - for (int i = 0; i < num_ri_devs; i++) { - len_ri_dev_name = 0; - if (GetRawInputDeviceInfoW(ri_devs[i].hDevice, RIDI_DEVICENAME, NULL, &len_ri_dev_name) != 0) { - dprintf("Siva IO: GetRawInputDeviceInfoW #%d failed to get name size\n", i); - break; - } - - if (len_ri_dev_name <= 0) { - dprintf("Siva IO: GetRawInputDeviceInfoW #%d len_ri_dev_name <= 0\n", i); - break; - } - - if (len_ri_dev_name >= MAX_PATH) { - dprintf("\tDev #%d - (name too long, %d characters)\n", i, len_ri_dev_name); - continue; - } - - if (GetRawInputDeviceInfoW(ri_devs[i].hDevice, RIDI_DEVICENAME, ri_dev_name, &len_ri_dev_name) <= 0) { - dprintf("Siva IO: GetRawInputDeviceInfoW #%d failed to get name\n", i); - break; - } - - dprintf("\tDev #%d - %ls\n", i, ri_dev_name); - } - - free(ri_devs); return S_OK; } void siva_io_get_btns(uint8_t *btn, uint8_t *stick) { + + if (GetAsyncKeyState(VK_MENU) && GetAsyncKeyState(VK_F4)) { + ri_exit(); + return; + } + if (GetAsyncKeyState(cfg.test) & 0x8000) { *btn |= BTN_TEST; } @@ -89,6 +48,7 @@ void siva_io_get_btns(uint8_t *btn, uint8_t *stick) if (GetAsyncKeyState(cfg.service) & 0x8000) { *btn |= BTN_SERVICE; } + } void siva_io_read_coin_counter(uint16_t *coins, uint16_t *services)