Lots of stuff

This commit is contained in:
Bottersnike 2023-07-07 12:58:55 +01:00
parent 50737e6011
commit 3423861c3c
Signed by: Bottersnike
SSH Key Fingerprint: SHA256:3g0ghwd4dNX1k1RX8qazbiT+3RIYn/daeBevHZVCiU0
142 changed files with 18602 additions and 1784 deletions

View File

@ -1,4 +1,7 @@
BUILD_DIR := build
BUILD_DIR_32 := $(BUILD_DIR)\build32
BUILD_DIR_64 := $(BUILD_DIR)\build64
COMMIT := $(shell git rev-parse --short HEAD)
DIST_DIR := dist
BUILD_DRIVE := M:
@ -8,19 +11,33 @@ MICE := "$(BUILD_DIR)/src\mice.exe"
# VCVARS := "C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Community\\VC\\Auxiliary\\Build\\vcvars32.bat"
# For windows XP:
VCVARS := "C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Community\\VC\\Auxiliary\\Build\\vcvars32.bat" -vcvars_ver=14.16
VCVARS_32 := "C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Community\\VC\\Auxiliary\\Build\\vcvars32.bat" -vcvars_ver=14.16
VCVARS_64 := "C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Community\\VC\\Auxiliary\\Build\\vcvars64.bat" -vcvars_ver=14.16
.ONESHELL:
.PHONY: all
all: mice dist
# all: mice mice64 dist
.PHONY: mice
mice:
-@subst $(BUILD_DRIVE) .
@cd /D $(BUILD_DRIVE) \
& $(VCVARS) \
& meson.py setup --cross cross-32.ini $(BUILD_DRIVE)\$(BUILD_DIR) \
& meson.py compile -C $(BUILD_DRIVE)\$(BUILD_DIR)
& $(VCVARS_32) \
& meson.py setup --cross cross-32.ini $(BUILD_DRIVE)\$(BUILD_DIR_32) \
& meson.py configure -Dmice_version=$(COMMIT) $(BUILD_DRIVE)\$(BUILD_DIR_32) \
& meson.py compile -C $(BUILD_DRIVE)\$(BUILD_DIR_32)
@subst $(BUILD_DRIVE) /D
.PHONY: mice64
mice64:
-@subst $(BUILD_DRIVE) .
@cd /D $(BUILD_DRIVE) \
& $(VCVARS_64) \
& meson.py setup --cross cross-64.ini $(BUILD_DRIVE)\$(BUILD_DIR_64) \
& meson.py configure -Dmice_version=$(COMMIT) $(BUILD_DRIVE)\$(BUILD_DIR_64) -Dwin64=true \
& meson.py compile -C $(BUILD_DRIVE)\$(BUILD_DIR_64)
@subst $(BUILD_DRIVE) /D
.PHONY: clean
@ -39,21 +56,26 @@ dist:
@-mkdir $(DIST_DIR)\Execute\Z > NUL 2>&1
@-mkdir $(DIST_DIR)\Execute\S > NUL 2>&1
@copy /Y "$(BUILD_DIR)/src/micetools/micekeychip\micekeychip.exe" "$(DIST_DIR)/micekeychip.exe"
@copy /Y "$(BUILD_DIR)/src/micetools/micemaster\micemaster.exe" "$(DIST_DIR)/micemaster.exe"
@copy /Y "$(BUILD_DIR)/src/micetools/lib/libpcp\libpcp.lib" "$(DIST_DIR)/libpcp.lib"
@copy /Y "$(BUILD_DIR_32)/src/micetools/micekeychip\micekeychip.exe" "$(DIST_DIR)/micekeychip.exe"
@copy /Y "$(BUILD_DIR_32)/src/micetools/micemaster\micemaster.exe" "$(DIST_DIR)/micemaster.exe"
@copy /Y "$(BUILD_DIR_32)/src/micetools/lib/libpcp\libpcp.lib" "$(DIST_DIR)/libpcp.lib"
@copy /Y "$(BUILD_DIR)/src/micetools/launcher\mice.exe" "$(DIST_DIR)/mice.exe"
# @copy /Y "$(BUILD_DIR)/src/micetools/launcher\mice.pdb" "$(DIST_DIR)/mice.pdb"
@copy /Y "$(BUILD_DIR)/src/micetools/dll\mice.pdb" "$(DIST_DIR)/mice.pdb"
@copy /Y "$(BUILD_DIR)/src/micetools/dll\mice.dll" "$(DIST_DIR)/mice.dll"
@copy /Y "$(BUILD_DIR_32)/src/micetools/launcher\mice.exe" "$(DIST_DIR)/mice.exe"
# @copy /Y "$(BUILD_DIR_32)/src/micetools/launcher\mice.pdb" "$(DIST_DIR)/mice.pdb"
@copy /Y "$(BUILD_DIR_32)/src/micetools/dll\mice.pdb" "$(DIST_DIR)/mice.pdb"
@copy /Y "$(BUILD_DIR_32)/src/micetools/dll\mice.dll" "$(DIST_DIR)/mice.dll"
@copy /Y "$(BUILD_DIR)/src/micetools/miceboot\miceprestartup.exe" "$(DIST_DIR)/Execute/miceprestartup.exe"
@copy /Y "$(BUILD_DIR)/src/micetools/miceboot\micestartup.exe" "$(DIST_DIR)/Execute/micestartup.exe"
@copy /Y "$(BUILD_DIR)/src/micetools/miceboot\mxmaster.exe" "$(DIST_DIR)/Execute/S/mxmaster.exe"
# @copy /Y "$(BUILD_DIR_64)/src/micetools/launcher\mice64.exe" "$(DIST_DIR)/mice64.exe"
# @copy /Y "$(BUILD_DIR_64)/src/micetools/launcher\mice64.pdb" "$(DIST_DIR)/mice64.pdb"
# @copy /Y "$(BUILD_DIR_64)/src/micetools/dll\mice64.pdb" "$(DIST_DIR)/mice64.pdb"
# @copy /Y "$(BUILD_DIR_64)/src/micetools/dll\mice64.dll" "$(DIST_DIR)/mice64.dll"
@copy /Y "$(BUILD_DIR)/src/micetools/util\*.exe" "$(DIST_DIR)/util/"
@copy /Y "$(BUILD_DIR)/src/micetools/util\*.pdb" "$(DIST_DIR)/util/"
@copy /Y "$(BUILD_DIR_32)/src/micetools/miceboot\miceprestartup.exe" "$(DIST_DIR)/Execute/miceprestartup.exe"
@copy /Y "$(BUILD_DIR_32)/src/micetools/miceboot\micestartup.exe" "$(DIST_DIR)/Execute/micestartup.exe"
@copy /Y "$(BUILD_DIR_32)/src/micetools/miceboot\mxmaster.exe" "$(DIST_DIR)/Execute/S/mxmaster.exe"
@copy /Y "$(BUILD_DIR_32)/src/micetools/util\*.exe" "$(DIST_DIR)/util/"
@copy /Y "$(BUILD_DIR_32)/src/micetools/util\*.pdb" "$(DIST_DIR)/util/"
@xcopy /E /H /C /R /Q /Y src\system "$(DIST_DIR)\system/*"
@xcopy /E /H /C /R /Q /Y src\patches "$(DIST_DIR)\patches/*"

View File

@ -9,4 +9,3 @@ system = 'windows'
cpu_family = 'x86'
cpu = 'i686'
endian = 'little'

11
cross-64.ini Normal file
View File

@ -0,0 +1,11 @@
[binaries]
c = 'cl'
cpp = 'cl'
strip = 'cl'
ar = ['lib', '/LTCG']
[host_machine]
system = 'windows'
cpu_family = 'x86_64'
cpu = 'x86_64'
endian = 'little'

View File

@ -5,17 +5,38 @@ project('micetools', 'c', default_options: [
'warning_level=3',
])
winxp = true
subsystem = 'console,5.01'
add_global_arguments('-DMICE_VERSION=' + '"' + get_option('mice_version') + '"', language : 'c')
if get_option('win64')
add_project_arguments(
'/D_AMD64_',
language: 'c',
)
winxp = false
subsystem = 'console'
else
add_project_arguments(
'/D_X86_',
language: 'c',
)
winxp = true
subsystem = 'console,5.01'
endif
if (host_machine.cpu_family() == 'x86')
add_project_arguments('-DMICE_WIN32', language: 'c')
endif
openssl_inc = include_directories('openssl-1.0.1/include')
openssl_lib = meson.get_compiler('c').find_library('libeay32', dirs: [
join_paths(meson.source_root(), 'openssl-1.0.1/lib')
], required: true)
if get_option('win64')
openssl_lib = meson.get_compiler('c').find_library('libeay64', dirs: [
join_paths(meson.source_root(), 'openssl-1.0.1/lib')
], required: true)
else
openssl_lib = meson.get_compiler('c').find_library('libeay32', dirs: [
join_paths(meson.source_root(), 'openssl-1.0.1/lib')
], required: true)
endif
assert(openssl_lib.found(), 'Please download openssl!')
freeglut_lib = meson.get_compiler('c').find_library('freeglut', dirs: [
@ -27,9 +48,13 @@ add_project_link_arguments(
'/DYNAMICBASE',
'/OPT:REF',
'/LTCG',
'/IGNORE:4099', # no PDBs
language: 'c'
)
add_project_link_arguments(
'/IGNORE:4099', # no PDBs
language: 'cpp'
)
add_project_arguments(
'/DWIN32_LEAN_AND_MEAN', # Strip out headers we don't really need
'/D_WIN32_WINNT=_WIN32_WINNT_WINXP', # hahahahaha I hate it
@ -54,6 +79,9 @@ add_project_arguments(
'/we4057', # ... differs in levels of indirection (slightly) from ...
'/we4024', # ... different types for formal and actual paramter ...
'/we4013', # ... undefined; assuming extern returning int
'/we4431', # missing type specifier - int assumed.
'/W4',
language: 'c',
)

View File

@ -1 +1,10 @@
option('vsenv', type: 'boolean', value: false)
option(
'win64',
type: 'boolean',
value: false,
description: 'Set this flag when targeting Win64 rather than Win32 (default)'
)
option(
'mice_version',
type: 'string',
)

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -1,4 +1,5 @@
inih = subproject('inih_dep')
detours = subproject('detours')
cimgui = subproject('cimgui_dep', default_options: [
'win32=enabled',
'dx9=enabled',

View File

@ -20,8 +20,11 @@ typedef struct {
} ERROR_LOG_BODY;
typedef struct {
// 0 = Common, 1 = Individual
uint8_t ChuteType;
// 0 = Common, 1 = Individual
uint8_t ServiceType;
// 0 = Normal, 1 = Freeplay
uint8_t Operation;
uint8_t CoinRate[2];
uint8_t BonusAdder;

View File

@ -4,6 +4,7 @@
com_device_t* GetComDevice(HANDLE hFile) {
open_hook_t* pHData = GetDataForHandle(hFile, HDATA_FILE);
if (pHData == NULL || pHData->hook == NULL || pHData->hook->com_hook == NULL) return NULL;
return pHData->hook->com_hook->com_device;
}
@ -13,18 +14,23 @@ BOOL DevGetCommTimeouts(HANDLE hFile, LPCOMMTIMEOUTS lpCommTimeouts) { return TR
BOOL DevSetCommTimeouts(HANDLE hFile, LPCOMMTIMEOUTS lpCommTimeouts) { return TRUE; }
BOOL DevSetupComm(HANDLE hFile, DWORD dwInQueue, DWORD dwOutQueue) { return TRUE; }
BOOL DevPurgeComm(HANDLE hFile, DWORD dwFlags) {
if (dwFlags & PURGE_RXCLEAR) ringbuf_purge(&(GetComDevice(hFile)->out));
com_device_t* dev = GetComDevice(hFile);
if (dev == NULL) return FALSE;
if (dwFlags & PURGE_RXCLEAR) ringbuf_purge(&(dev->out));
return TRUE;
}
BOOL DevGetCommModemStatus(HANDLE hFile, LPDWORD lpModemStatus) {
if (!lpModemStatus) return FALSE;
com_device_t* dev = GetComDevice(hFile);
if (!dev) return false;
if (dev == NULL) return FALSE;
*lpModemStatus = dev->modemStatus;
return TRUE;
}
BOOL DevWaitCommEvent(HANDLE hFile, LPDWORD lpEvtMask, LPOVERLAPPED lpOverlapped) {
WaitForSingleObject(GetComDevice(hFile)->dataOutReady, INFINITE);
com_device_t* dev = GetComDevice(hFile);
if (dev == NULL) return FALSE;
WaitForSingleObject(dev->dataOutReady, INFINITE);
if (lpOverlapped != NULL) SetEvent(lpOverlapped->hEvent);
return TRUE;
}
@ -39,8 +45,12 @@ BOOL DevClearCommError(HANDLE hFile, LPDWORD lpErrors, LPCOMSTAT lpStat) {
lpStat->fEof = FALSE;
lpStat->fTxim = FALSE;
lpStat->fReserved = 0;
lpStat->cbInQue = ringbuf_available(&(GetComDevice(hFile)->out));
lpStat->cbOutQue = ringbuf_available(&(GetComDevice(hFile)->in));
com_device_t* dev = GetComDevice(hFile);
if (dev == NULL) return FALSE;
lpStat->cbInQue = ringbuf_available(&dev->out);
lpStat->cbOutQue = ringbuf_available(&dev->in);
}
return TRUE;
}
@ -49,22 +59,28 @@ BOOL DevWriteFile(file_context_t* ctx, LPCVOID lpBuffer, DWORD nNumberOfBytesToW
LPDWORD lpNumberOfBytesWritten, LPOVERLAPPED lpOverlapped) {
if (nNumberOfBytesToWrite > 0xffff) return FALSE;
com_device_t* dev = GetComDevice(ctx->m_Handle);
if (dev == NULL) return FALSE;
// Ignore overflow
ringbuf_write(&(dev->in), lpBuffer, nNumberOfBytesToWrite & 0xffff);
SetEvent(dev->dataInReady);
ringbuf_write(&dev->in, lpBuffer, nNumberOfBytesToWrite & 0xffff);
if (!SetEvent(dev->dataInReady))
log_error(plfComm, "Failed to signal data in: %d", GetLastError());
if (lpNumberOfBytesWritten) *lpNumberOfBytesWritten = nNumberOfBytesToWrite;
return TRUE;
}
BOOL DevReadFile(file_context_t* ctx, LPVOID lpBuffer, DWORD nNumberOfBytesToRead,
LPDWORD lpNumberOfBytesRead, LPOVERLAPPED lpOverlapped) {
if (nNumberOfBytesToRead > 0xffff) return FALSE;
com_device_t* comdev = GetComDevice(ctx->m_Handle);
com_device_t* dev = GetComDevice(ctx->m_Handle);
if (dev == NULL) return FALSE;
// Make sure we have at least one byte to return
// while (!ringbuf_available(&(comdev->out))) {
// WaitForSingleObject(comdev->event, INFINITE);
// while (!ringbuf_available(&(dev->out))) {
// WaitForSingleObject(dev->event, INFINITE);
// }
short read = ringbuf_read(&(comdev->out), lpBuffer, nNumberOfBytesToRead & 0xffff);
short read = ringbuf_read(&dev->out, lpBuffer, nNumberOfBytesToRead & 0xffff);
if (lpNumberOfBytesRead) *lpNumberOfBytesRead = read;
if (lpOverlapped) {
@ -75,10 +91,7 @@ BOOL DevReadFile(file_context_t* ctx, LPVOID lpBuffer, DWORD nNumberOfBytesToRea
}
short comdev_read_blocking(com_device_t* com, unsigned char* buffer, short bytes) {
while (comdev_available(com) < bytes) {
WaitForSingleObject(com->dataInReady, INFINITE);
SwitchToThread();
}
while (comdev_available(com) < bytes) WaitForSingleObject(com->dataInReady, INFINITE);
return ringbuf_read(&com->in, buffer, bytes);
}
short comdev_read(com_device_t* com, LPVOID buffer, short bytes) {
@ -94,6 +107,7 @@ BYTE comdev_peek(com_device_t* com) { return com->in.buffer[com->in.read]; }
// Read data from a com device, unescaping as we go
void comio_read(com_device_t* com, LPVOID data, BYTE len) {
LPBYTE lpbData = (LPBYTE)data;
BYTE one_byte;
for (; len; len--) {
comdev_read_blocking(com, &one_byte, 1);
@ -101,14 +115,15 @@ void comio_read(com_device_t* com, LPVOID data, BYTE len) {
comdev_read_blocking(com, &one_byte, 1);
one_byte++;
}
*(((LPBYTE)data)++) = one_byte;
*(lpbData++) = one_byte;
}
}
// Write data to a com device, escaping as we go
void comio_write(com_device_t* com, LPCVOID data, BYTE len) {
LPBYTE lpbData = (LPBYTE)data;
BYTE one_byte;
for (; len; len--) {
one_byte = *(((LPBYTE)data)++);
one_byte = *(lpbData++);
if (one_byte == COMIO_MARK || one_byte == COMIO_SYNC) {
BYTE mark = COMIO_MARK;
comdev_write(com, &mark, 1);
@ -120,11 +135,7 @@ void comio_write(com_device_t* com, LPCVOID data, BYTE len) {
unsigned char comio_next_req(com_device_t* com, comio_recv_head_t* head, LPVOID data) {
BYTE one_byte;
do {
if (comdev_available(com) < (sizeof *head + 1)) {
SwitchToThread();
continue;
}
comdev_read(com, &one_byte, 1);
comdev_read_blocking(com, &one_byte, 1);
if (one_byte != COMIO_SYNC) {
log_error(plfComm, "Garbage on JVS: %02x", one_byte);
continue;
@ -165,25 +176,31 @@ void comio_reply(com_device_t* com, comio_recv_head_t* req, BYTE status, BYTE le
comio_write(com, &one_byte, 1);
}
BOOL attach_com_device(BYTE port, FnComDeviceThread* thread) {
BOOL attach_com_device(BYTE port, PVIRTUAL_SERIAL_DEVICE lpDevice) {
if (port < 1 || port > NUM_COM_PORTS) {
log_error(plfComm, "Requested COM%hhu but that is out of range!", port);
return FALSE;
}
com_device_t* com = com_devices[port - 1];
if (com->thread != INVALID_HANDLE_VALUE) {
if (port == RESERVED_JVS_COM_PORT) return FALSE;
if (com->thread != NULL) {
if (port == RESERVED_JVS_COM_PORT) {
log_warning(plfComm, "Refusing to attach to reserved port COM%hhu", port);
return FALSE;
}
// No need to change what's assigned!
if (com->thread_worker == thread) return TRUE;
if (com->lpDevice == lpDevice) return TRUE;
log_warning(plfComm, "COM%hhu is already attached!", port);
TerminateThread(com->thread, (DWORD)-1);
}
com->thread = CreateThread(NULL, 0, thread, com, 0, NULL);
com->thread_worker = thread;
com->thread = CreateThread(NULL, 0, lpDevice->m_Entrypoint, com, 0, NULL);
if (com->thread == NULL) {
log_error(plfComm, "Attach to COM%hhu failed: %d", port, GetLastError());
return FALSE;
}
com->lpDevice = lpDevice;
return TRUE;
}
@ -196,15 +213,15 @@ void detach_com_device(BYTE port) {
if (!com->thread) return;
TerminateThread(com->thread, (DWORD)-1);
com->thread = INVALID_HANDLE_VALUE;
com->thread = NULL;
}
void detach_all_com_devices(void) {
for (int i = 0; i < NUM_COM_PORTS; i++) {
if (i == RESERVED_JVS_COM_PORT - 1) continue;
if (com_devices[i]->thread != INVALID_HANDLE_VALUE) {
if (com_devices[i]->thread != NULL) {
TerminateThread(com_devices[i]->thread, (DWORD)-1);
com_devices[i]->thread = INVALID_HANDLE_VALUE;
com_devices[i]->thread = NULL;
}
}
}
@ -219,6 +236,8 @@ com_device_t* new_com_device(BYTE port) {
file->altFilename = com->wDosName;
com_device->com = com;
com_device->file = file;
com_device->dataInReady = CreateEventA(NULL, FALSE, FALSE, NULL);
com_device->dataOutReady = CreateEventW(NULL, TRUE, FALSE, NULL);
com->GetCommState = DevGetCommState;
com->SetCommState = DevSetCommState;
@ -235,8 +254,7 @@ com_device_t* new_com_device(BYTE port) {
ringbuf_purge(&com_device->in);
ringbuf_purge(&com_device->out);
com_device->dataOutReady = CreateEventW(NULL, TRUE, FALSE, com_device->com->wName);
com_device->thread = INVALID_HANDLE_VALUE;
com_device->thread = NULL;
hook_file(file);
@ -244,7 +262,7 @@ com_device_t* new_com_device(BYTE port) {
}
void init_com_devices(void) {
for (BYTE i = 0; i < NUM_COM_PORTS; i++) {
for (BYTE i = 1; i < NUM_COM_PORTS; i++) {
com_devices[i] = new_com_device(i + 1);
}
}

View File

@ -8,6 +8,11 @@
typedef struct com_device com_device_t;
typedef DWORD(WINAPI FnComDeviceThread)(com_device_t* com);
typedef struct VIRTUAL_SERIAL_DEVICE {
LPCSTR m_Name;
FnComDeviceThread* m_Entrypoint;
} VIRTUAL_SERIAL_DEVICE, *PVIRTUAL_SERIAL_DEVICE;
struct com_device {
com_hook_t* com;
file_hook_t* file;
@ -18,7 +23,7 @@ struct com_device {
HANDLE dataInReady;
HANDLE dataOutReady;
HANDLE thread;
FnComDeviceThread* thread_worker;
PVIRTUAL_SERIAL_DEVICE lpDevice;
};
com_device_t* com_devices[NUM_COM_PORTS];
@ -60,7 +65,7 @@ unsigned char comio_next_req(com_device_t* com, comio_recv_head_t* head, LPVOID
void comio_reply(com_device_t* com, comio_recv_head_t* req, BYTE status, BYTE len, LPCVOID data);
com_device_t* new_com_device(BYTE port);
BOOL attach_com_device(BYTE port, FnComDeviceThread* thread);
BOOL attach_com_device(BYTE port, PVIRTUAL_SERIAL_DEVICE thread);
void detach_com_device(BYTE port);
void detach_all_com_devices(void);
void init_com_devices(void);

View File

@ -23,8 +23,15 @@
#include "../lib/mice/mice.h"
#include "./util/_util.h"
#include "micefs.h"
void mice_got_game_id(char game_id[4]);
#define size2int(x) ((int)((x) & 0x7fffffff))
#define size2uint(x) ((unsigned int)((x) & 0xffffffff))
void _MiceGotGameId(char game_id[4]);
BOOL MiceGuessGameId(char* lpGameId);
extern WCHAR exeName[MAX_PATH + 1];
extern DWORD imageOffset;
extern size_t imageOffset;
extern BOOL g_bIsInDllMain;

View File

@ -6,46 +6,52 @@
#include "smb_pca9535.h"
typedef struct _device_list {
const char* m_Name;
FnComDeviceThread* m_Thread;
VIRTUAL_SERIAL_DEVICE m_Device;
struct _device_list* m_Next;
} device_list_t;
device_list_t device_list = { .m_Next = NULL };
#define _start_device_n(n) \
if (strcmp(MiceConfig.devices.com##n, name) == 0) attach_com_device(n, thread)
inline void start_device(const char* name, FnComDeviceThread* thread) {
_start_device_n(1);
_start_device_n(2);
_start_device_n(3);
_start_device_n(5);
_start_device_n(6);
_start_device_n(7);
_start_device_n(8);
static DWORD WINAPI dummy_comdev_thread(com_device_t* dev) {
BYTE buffer[1];
while (1) {
comdev_read_blocking(dev, buffer, 1);
log_warning(plfComm, "Idle data on port %ls: %02x", dev->com->wName, buffer[0]);
}
}
#define _stop_if_unregistered(n) \
if (MiceConfig.devices.com##n[0] == '\0') detach_com_device(n)
static VIRTUAL_SERIAL_DEVICE dummySerialDevice = {
.m_Name = "Port idler",
.m_Entrypoint = dummy_comdev_thread,
};
inline void stop_old_devices() {
_stop_if_unregistered(1);
_stop_if_unregistered(2);
_stop_if_unregistered(3);
_stop_if_unregistered(5);
_stop_if_unregistered(6);
_stop_if_unregistered(7);
_stop_if_unregistered(8);
inline void start_virtual_device(BYTE bPort, LPCSTR szName) {
if (szName[0] != '\0') {
device_list_t* device = &device_list;
while (device->m_Next) {
device = device->m_Next;
if (strcmp(szName, device->m_Device.m_Name) == 0) {
attach_com_device(bPort, &device->m_Device);
return;
}
}
log_error(plfComm, "Device %s requested by unknown! (COM%hhu)", szName, bPort);
}
if (MiceConfig.devices.add_idlers)
attach_com_device(bPort, &dummySerialDevice);
else
detach_com_device(bPort);
}
void start_devices() {
stop_old_devices();
device_list_t* device = &device_list;
while (device->m_Next) {
device = device->m_Next;
start_device(device->m_Name, device->m_Thread);
}
// start_virtual_device(1, MiceConfig.devices.com1);
start_virtual_device(2, MiceConfig.devices.com2);
start_virtual_device(3, MiceConfig.devices.com3);
start_virtual_device(5, MiceConfig.devices.com5);
start_virtual_device(6, MiceConfig.devices.com6);
start_virtual_device(7, MiceConfig.devices.com7);
start_virtual_device(8, MiceConfig.devices.com8);
}
void register_device(const char* name, FnComDeviceThread* thread) {
@ -54,8 +60,8 @@ void register_device(const char* name, FnComDeviceThread* thread) {
device_list_t* us = tail->m_Next = malloc(sizeof(device_list_t));
us->m_Name = name;
us->m_Thread = thread;
us->m_Device.m_Name = name;
us->m_Device.m_Entrypoint = thread;
us->m_Next = NULL;
}
@ -64,8 +70,8 @@ void install_devices() {
install_touch_bd();
install_aime_bd();
install_servo_15069();
start_devices();
install_gacchu_guts_card();
install_gacchu_guts_screen();
smbus_install(/* 0x20 */ PCA9535_ADDRESS, &smbus_PCA9535_write, &smbus_PCA9535_read);

View File

@ -7,6 +7,8 @@ void install_led_bd();
void install_touch_bd();
void install_aime_bd();
void install_servo_15069();
void install_gacchu_guts_card();
void install_gacchu_guts_screen();
smbus_callback_t smbus_N2_write;
smbus_callback_t smbus_N2_read;

View File

@ -8,6 +8,8 @@ devices_files = files(
'ser_maitouch.c',
'ser_tn32msec.c',
'ser_servo_838-15069.c',
'ser_gacchu_guts_card.c',
'ser_gacchu_guts_screen.c',
# SMBus devices
'smb_pca9535.c',
'smb_ds2460.c',

View File

@ -0,0 +1,31 @@
/**
* Commands in:
*
* - Length prefix (ie 2)
* - Command (ie "C2" or "Z8")
* - 0x03
*
*/
#include <stdio.h>
#include "_devices.h"
static DWORD WINAPI ser_gacchu_guts_card(com_device_t* com) {
puts("GG CARD");
BYTE nBytes;
BYTE buffer[256];
BYTE tail;
while (1) {
comdev_read_blocking(com, &nBytes, 1);
comdev_read_blocking(com, buffer, nBytes);
comdev_read_blocking(com, &tail, 1);
printf("Got Gacchu command: %.*s\n", nBytes, buffer);
BYTE response[1];
response[0] = '\0';
// comdev_write(com, response, 1);
}
}
void install_gacchu_guts_card() { register_device("gacchu_guts_card", ser_gacchu_guts_card); }

View File

@ -0,0 +1,187 @@
#include <stdio.h>
#include "_devices.h"
/*
Packet format:
String packets:
[0]: commandNum > 16 ? 0x81 : 0x01
[...]: string. does not contain null.
[n]: commandNum > 16 ? 0x8d : 0x0d
Binary packets:
[0]: 0x55
[1]:
[2]:
[3]:
[4]:
[5]:
[6]:
[7]: Sum of ([1] through [6]) + 0xAA
Responses:
Type(0) packets:
[0]: 0x80 | (if 0x40 set, arg2 = 0x80, else arg2 = 0)
[1]: arg0 & 0x7f
[2]: (arg0 >> 7) & 0x7f
[3]: arg1 & 0x7f
[4]: (arg1 >> 7) & 0x7f
Type(2) packets:
[0]: 0x40 | (if 0x02 set, arg2 = 0, else arg2 = 0x80)
[1]: arg0 & 0x3f
[2]: (arg0 >> 6) & 0x3f
[3]: arg1 & 0x3f
[4]: (arg1 >> 6) & 0x3f
[5]: ???
Binary packets:
// String packets (this seems.. like an impossible contradiction!?):
// [0]: 0x01
// [1]: 0x0d
// [0]: 0x55
// [1]: 0x54
// [...?] -> Buffer length reset to 2. Do these matter?
// [9] 0x55
// [10] 0x54
// --- OR ---
[0]: 0x55
[1]: 0x54
[2]: if low two bits set (& 3), [7] contains arg2, else arg2=0
[3]: arg0 & 0xff
[4]: arg0 >> 8
[5]: arg1 & 0xff
[6]: arg1 >> 8
[7]: arg2
[8]:
[9]: Sum of ([1] through [8]) + 0xAA
--- OR ---
Whatever (005c1edb) is doing
From the looks of it, 0x41 is some sort of continuation byte,
every 10 bytes.
*/
/*
FQF[02x: arg0] = 11 (set frequency?)
FQF00 = 12 (get frequency?)
.5A[02x: touch panel effect][02x: ??] = 16 (set config?)
*/
/*
First command received:
= Screen command 8
[]Z[]
01
5A
0D
Second command sent:
= Screen command 16
= ".5A0001"
But the last four digits are replaced with "%02X%02X"
[].5AFF00[]
01
2E 35 41 46 46 30 30
0D
*/
static inline void response_ok(com_device_t* lpDev, char* szResponse) {
int nBytes = szResponse ? strlen(szResponse) : 0;
if (nBytes > 8) nBytes = 8;
BYTE buffer[10];
buffer[0] = 0x01;
if (nBytes) memcpy(&buffer[1], szResponse, nBytes);
buffer[nBytes + 1] = 0x0d;
comdev_write(lpDev, buffer, (nBytes + 2) & 0xffff);
}
static inline void response_two_short(com_device_t* lpDev, SHORT arg0, SHORT arg1) {
BYTE buffer[5];
buffer[0] = 0x80;
buffer[1] = arg0 & 0x7f;
buffer[2] = (arg0 >> 7) & 0x7f;
buffer[3] = arg1 & 0x7f;
buffer[4] = (arg1 >> 7) & 0x7f;
comdev_write(lpDev, buffer, 5);
}
static BYTE command_do[4] = {
0xd0,
0xce,
0xb8,
0xb1,
};
static DWORD WINAPI ser_gacchu_guts_screen(com_device_t* dev) {
BYTE bHead;
BYTE buffer[256];
puts("Gacchu screen start");
while (1) {
comdev_read_blocking(dev, &bHead, 1);
if (bHead == 0x55) {
log_error(plfGacchuGuts, "Screen binary!");
comdev_read_blocking(dev, buffer, 7);
continue;
}
if (bHead != 0x01 && bHead != 0x81) {
log_error(plfGacchuGuts, "Screen babble: %02x", bHead);
continue;
}
WORD index = 0;
BYTE tail = bHead == 0x01 ? 0x0D : 0x8D;
do {
comdev_read_blocking(dev, &buffer[index++], 1);
} while (index < _countof(buffer) && buffer[index - 1] != tail);
// comdev_read_blocking(dev, buffer, nBytes);
// comdev_read_blocking(dev, &tail, 1);
// Done and working (hopefully!)
if (index == 2 && memcmp(buffer, "Z", 1) == 0) {
response_ok(dev, "0");
}
// Not working :(
else if (index == 6 && memcmp(buffer, "FQF", 3) == 0) {
BYTE value = 0;
_snscanf_s((const char*)&buffer[3], 2, "%02hhX", &value);
if (value == 0) {
log_game(plfGacchuGuts, "Got FQF00 command. What now...?");
response_ok(dev, " ");
} else {
log_game(plfGacchuGuts, "Got FQF[%02x] command. What now...?", value);
response_ok(dev, "0"); // Meant to do " " vs "0" I think?
}
}
else if (index == 8 && memcmp(buffer, ".5A", 3) == 0) {
log_game(plfGacchuGuts, "Got .5A command. What now...?");
/*
uVar9 = (arg0 * 1024) / (0x4000 - 1)
*/
// At a guess, this is getting the display resolution.
response_two_short(dev, 1024, 768);
}
else if (index == 5 && memcmp(buffer, command_do, 4) == 0) {
log_game(plfGacchuGuts, "Got D0 command. What now...?");
response_ok(dev, "0"); // Probably wrong
} else {
log_error(plfGacchuGuts, "%ls: Got Gacchu screen: %02x(%d):[%02x]%.*s\n",
dev->com->wName, bHead, index, buffer[0], index - 1, buffer);
log_error(plfGacchuGuts, "%ls: Got Gacchu bytes: %02x %02x %02x %02x %02x\n",
dev->com->wName, buffer[0], buffer[1], buffer[2], buffer[3], buffer[4]);
}
}
}
void install_gacchu_guts_screen() { register_device("gacchu_guts_screen", ser_gacchu_guts_screen); }

View File

@ -81,12 +81,8 @@ static DWORD WINAPI led_bd_thread(com_device_t* dev) {
while (1) {
rs232c_recv_head_t head;
if (comdev_available(dev) < sizeof head) {
// Sleep(100);
continue;
}
comdev_read(dev, (unsigned char*)&head, sizeof head);
comdev_read(dev, extra, head.length);
comdev_read_blocking(dev, (unsigned char*)&head, sizeof head);
comdev_read_blocking(dev, extra, head.length);
// log_info(plfMaiLED, "Bound %02x->%02x", head.src, head.dst);

View File

@ -1,11 +1,7 @@
#include "../hooks/gui.h"
#include "_devices.h"
static BYTE read_one(com_device_t* dev) {
while (!comdev_available(dev)) Sleep(50);
BYTE data;
comdev_read(dev, &data, 1);
return data;
}
static BYTE read_one(com_device_t* dev) {}
const BYTE TOUCH_ID_LUT[] = "ABCD\0EFGH\0IJKL\0MNOPQRSTU\0VWXY\0";
static BYTE get_touch_id(BYTE id) {
@ -15,26 +11,130 @@ static BYTE get_touch_id(BYTE id) {
return 0xff;
}
BOOL touch_is_enabled = false;
// High byte: index, Low byte: bitflag
#define BUTTON_A1 0x0101
#define BUTTON_B1 0x0102
#define BUTTON_A2 0x0104
#define BUTTON_B2 0x0108
#define BUTTON_A3 0x0201
#define BUTTON_B3 0x0202
#define BUTTON_A4 0x0204
#define BUTTON_B4 0x0208
#define BUTTON_A5 0x0301
#define BUTTON_B5 0x0302
#define BUTTON_A6 0x0304
#define BUTTON_B6 0x0308
#define BUTTON_A7 0x0401
#define BUTTON_B7 0x0402
#define BUTTON_A8 0x0404
#define BUTTON_B8 0x0408
#define BUTTON_C 0x0410
WORD getSensorInRegion(float mX, float mY, float rX, float rY, float rW, float rH) {
// Out of region
if (mX < rX || mY < rY || mX > rX + rW || mY > rY + rH) return 0;
// i is now a position in a region from (-1,-1) to (1,1)
float iX = ((mX - rX) / (rW / 2)) - 1;
float iY = ((mY - rY) / (rH / 2)) - 1;
float r2 = iX * iX + iY * iY;
// Bound to a unit circle
if (r2 > 1) return 0;
// Centre button
if (r2 < (121.0f / 540.0f) * (121.0f / 540.0f)) return BUTTON_C;
WORD button = 0;
// Four quadrants
if (iX > 0 && iY < 0) button = -iY > iX ? BUTTON_A1 : BUTTON_A2;
if (iX > 0 && iY > 0) button = iX > iY ? BUTTON_A3 : BUTTON_A4;
if (iX < 0 && iY > 0) button = iY > -iX ? BUTTON_A5 : BUTTON_A6;
if (iX < 0 && iY < 0) button = -iX > -iY ? BUTTON_A7 : BUTTON_A8;
// Inner ring of buttons
if (r2 < (298.0f / 540.0f) * (298.0f / 540.0f))
button = (button & 0xff00) | ((button & 0xff) << 1);
return button;
}
static BYTE g_ActiveResponse[14];
static void populateActiveResponse() {
// Placeholders
g_ActiveResponse[1] = '@';
g_ActiveResponse[2] = '@';
g_ActiveResponse[3] = '@';
g_ActiveResponse[4] = '@';
//
g_ActiveResponse[7] = '@';
g_ActiveResponse[8] = '@';
g_ActiveResponse[9] = '@';
g_ActiveResponse[10] = '@';
if (!GetAsyncKeyState(VK_LBUTTON)) return;
POINT pCursor;
GetCursorPos(&pCursor);
if (!mainWindow) return;
if (!ScreenToClient(mainWindow, &pCursor)) return;
RECT winRect;
if (!GetWindowRect(mainWindow, &winRect)) return;
DWORD dwStyle = GetWindowLongW(mainWindow, GWL_STYLE);
UnadjustWindowRect(&winRect, dwStyle, FALSE);
int w = winRect.right - winRect.left;
int h = winRect.bottom - winRect.top;
float x = (float)pCursor.x / (float)(w);
float y = (float)pCursor.y / (float)(h);
// If the window is square, assume `1P_ONLY` is set
WORD button;
if (w == h) {
button = getSensorInRegion(x, y, 0.0f, 0.0f, 1.0f, 1.0f);
if (button) g_ActiveResponse[button >> 8] |= button & 0xff;
} else {
// 1P
button = getSensorInRegion(x, y, 0.0f, 0.4375f, 0.5f, 0.5625f);
if (button) g_ActiveResponse[button >> 8] |= button & 0xff;
// 2P
button = getSensorInRegion(x, y, 0.5f, 0.4375f, 0.5f, 0.5625f);
if (button) g_ActiveResponse[(button >> 8) + 6] |= button & 0xff;
}
}
BOOL touch_is_enabled = TRUE; // Default on is important!
BYTE thresh = 0x00; // Lazy caching of single value
DWORD WINAPI touch_bd_thread(com_device_t* dev) {
log_info(plfMaiTouch, "%ls woke up", dev->com->wName);
// Constant values
g_ActiveResponse[0] = '(';
g_ActiveResponse[5] = '@';
g_ActiveResponse[6] = '@';
g_ActiveResponse[11] = '@';
g_ActiveResponse[12] = '@';
g_ActiveResponse[13] = ')';
while (1) {
if (touch_is_enabled && !comdev_available(dev)) {
// Active mode!
comdev_write(dev, (unsigned char*)"(@@@@@@@@@@@@)", 14);
Sleep(100);
populateActiveResponse();
comdev_write(dev, g_ActiveResponse, 14);
Sleep(5); // 200Hz should be plenty
continue;
}
while (read_one(dev) != '{') continue;
while (comdev_available(dev) < 5) {
log_info(plfMaiTouch, "<. .>");
Sleep(50);
}
BYTE startWait;
do {
comdev_read_blocking(dev, &startWait, 1);
} while (startWait != '{');
BYTE command[5];
comdev_read(dev, command, 5);
comdev_read_blocking(dev, command, 5);
BYTE response[6];
memcpy(response, "( )", 6);

View File

@ -4,6 +4,53 @@
#define SERVO_OK 0
#define SERVO_NG 8
/*
From AndyGeezer:
SUD = Sega Universal Drive
-- sample init code --
ff00007f <-- reset sud
81307f4e <-- set init values/reset sud
fc00205c <-- init sud
fd00007d
fd00007d <-- poll until not returning 0x44
fd00007d
fa001f65 <-- change echo status to return
83600467 <-- set global power
86010205 <-- set friction
move the wheel left/right to centre here..
8800040c <-- set go to target point power
f0000070 <-- set target point
84010005 <-- direction off
80000000 <-- motor off
8b2000ff <-- centering power
862f00ff <-- friction power
800001FF <-- motor on
fd00007d <-- poll
80<param><param2><crc> = power
examples:
80 00 01 = Constantly on
80 01 01 = Run once
80 00 00 = Motor off
*/
static DWORD WINAPI ser_servo_15069_thread(com_device_t* dev) {
log_game(plfServo15069, "%ls woke up", dev->com->wName);

View File

@ -43,7 +43,14 @@ static LPCSTR GetCardIdentifier(DWORD player) {
player == 0 ? MiceConfig.aime.player1_cardfile : MiceConfig.aime.player2_cardfile;
LPSTR cardIdentifier = player == 0 ? cardIdentifier1P : cardIdentifier2P;
if (_PathFileExistsA(cardFile)) {
const size_t cSize = strlen(cardFile) + 1;
wchar_t* wc = malloc(cSize);
if (!wc) return NULL;
MultiByteToWideChar(0, 0, cardFile, -1, wc, cSize + 1);
BOOL exists = FileExistsW(wc);
free(wc);
if (exists) {
log_info(plfAime, "Reading P%d card from %s", player + 1, cardFile);
HANDLE hFile =
@ -127,6 +134,13 @@ static CardType TN32GetCardInfo(LPCSTR lpIdentifier, PACCESS_CODE lpAccessCode,
&lpFelicaId->m_ID[6], &lpFelicaId->m_ID[7], &nChars) == 8 &&
nChars == 23)
return CardType_FeliCa;
} else if (len == 23) {
if (sscanf_s(lpIdentifier, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx%n",
&lpFelicaId->m_ID[0], &lpFelicaId->m_ID[1], &lpFelicaId->m_ID[2],
&lpFelicaId->m_ID[3], &lpFelicaId->m_ID[4], &lpFelicaId->m_ID[5],
&lpFelicaId->m_ID[6], &lpFelicaId->m_ID[7], &nChars) == 8 &&
nChars == 23)
return CardType_FeliCa;
}
return CardType_Unknown;
}
@ -160,8 +174,6 @@ static void MifarePopulate(PNFC_CARD lpCard, PACCESS_CODE lpAccessCode) {
DWORD nSerial = AccessCodeToSerial(lpAccessCode);
lpCard->m_Mifare.m_Uid = nSerial;
printf("Serial: %d\n", nSerial);
// Block 0: Manufacture data (only used by BNG)
// Block 1: Game ID information (kCARD_DETECT_KEY_B_READ_1)
@ -536,8 +548,6 @@ DWORD WINAPI aime_bd_thread(com_device_t* dev) {
break;
}
}
Sleep(50);
}
}

View File

@ -2,7 +2,7 @@
#include "../../maiBackupStructs.h"
#include "_devices.h"
#define EEPROM_PATH L"dev/eeprom.bin"
#define EEPROM_PATH MiceIpcRelativePath("eeprom.bin")
#include "../../sysconf.h"
@ -52,17 +52,21 @@ void set_eeprom_static_config() {
}
void build_eeprom() { // return;
log_info(plfEeprom, "Building default EEPROM file");
log_misc(plfEeprom, "Building default EEPROM file");
memset(EEPROM_DATA, 0xff, EEPROM_SIZE);
set_eeprom_static_config();
BOOL freeplay = TRUE;
AM_SYSDATAwH_CREDIT Credit = {
.m_Config = {
.ChuteType = 0,
.ServiceType = 1,
.CreditRate = 1,
.Operation = freeplay ? 1 : 0,
.CoinRate = { 1, 1 },
.BonusAdder = 0,
.CreditRate = 1,
.Cost = { 1, 1, 1, 1, 1, 1, 1, 1 },
},
};
@ -86,29 +90,17 @@ void build_eeprom() { // return;
fix_crc(DevConfig);
memcpy(&EEPROM_DATA[AM_SYSDATAwH_ALPB_DEV_CONFIG_REG], &DevConfig, sizeof DevConfig);
memcpy(&EEPROM_DATA[AM_SYSDATAwH_ALPB_DEV_CONFIG_DUP], &DevConfig, sizeof DevConfig);
// eeprom_dump();
}
AM_SYSDATAwH_HISTORY AmHistory = {
// By making the game ID "____" we ensure games overwrite this, letting us see what they write.
// This is currently the best way I have found to retrieve the game ID
.m_GameId = { '_', '_', '_', '_' },
};
/** Clobber EEPROM with our user settings */
/* Clobber EEPROM with our user settings */
void eeprom_fixup() {
set_eeprom_static_config();
set_eeprom_network_config();
// AmHistory.m_Region = MiceConfig.sysconf.region & (1 | 2 | 4 | 8);
// fix_crc(AmHistory);
// memcpy(&EEPROM_DATA[AM_SYSDATAwH_HISTORY_REG], &AmHistory, sizeof AmHistory);
// memcpy(&EEPROM_DATA[AM_SYSDATAwH_HISTORY_DUP], &AmHistory, sizeof AmHistory);
}
void ensure_valid_eeprom() {
if (!EEPROM_DATA) {
BOOL isNew = !FileExists(EEPROM_PATH);
BOOL isNew = !FileExistsA(EEPROM_PATH);
EEPROM_DATA =
open_mapped_file(EEPROM_PATH, EEPROM_SIZE, &EEPROM_FILE, &EEPROM_FILE_MAPPING);
@ -140,14 +132,14 @@ void eeprom_write(WORD addr, BYTE* data, BYTE length) {
if (addr == AM_SYSDATAwH_HISTORY_REG && length == sizeof(AM_SYSDATAwH_HISTORY)) {
PAM_SYSDATAwH_HISTORY pHistory = (PAM_SYSDATAwH_HISTORY)data;
mice_got_game_id(pHistory->m_GameId);
_MiceGotGameId(pHistory->m_GameId);
} else if (addr >= 0x1000 && length > 8) {
char game_id[4];
game_id[0] = data[7];
game_id[1] = data[6];
game_id[2] = data[5];
game_id[3] = data[4];
mice_got_game_id(game_id);
_MiceGotGameId(game_id);
}
memcpy(EEPROM_DATA + addr, data, length);

View File

@ -2,6 +2,31 @@
DWORD NvidiaDebugLevel = 0;
/* ============= AMD ============= */
__declspec(dllexport) int amvGetAvailableDriverEx_Amd(LPVOID pGpuHandle, DWORD dwGpuHandleSize) {
return 0;
}
__declspec(dllexport) int amvGetAvailableDriver_Amd() {
return amvGetAvailableDriverEx_Amd(NULL, 4);
}
__declspec(dllexport) int amvSetCustomDisplaySettingEx_Amd(LPVOID pGpuHandle,
DWORD dwGpuHandleSize,
LPWORD NV_SetCustomDisplaySetting) {
return 0;
}
__declspec(dllexport) int amvSetCustomDisplaySetting_Amd(LPVOID pGpuHandle) {
return amvSetCustomDisplaySettingEx_Amd(NULL, 4, pGpuHandle);
}
__declspec(dllexport) int amvSetDisplayModeEx_Amd(LPVOID pGpuHandle, DWORD dwGpuHandleSize,
BYTE displayMode) {
return 0;
}
__declspec(dllexport) int amvSetDisplayMode_Amd(BYTE displayMode) {
return amvSetDisplayModeEx_Amd(NULL, 4, displayMode);
}
/* ============= Nvidia ============= */
__declspec(dllexport) int amvFinalize_Nvidia() { return 0; }
__declspec(dllexport) int amvGetAvailableDriverEx_Nvidia(LPVOID pGpuHandle, DWORD dwGpuHandleSize) {
return 0;

View File

@ -0,0 +1,7 @@
#include <Windows.h>
// TODO: ATIDL_GetGamma
// TODO: ATIDL_SetGamma
__declspec(dllexport) int ATIDL_GetGamma(int a, void* p) { return 0; }
__declspec(dllexport) int ATIDL_SetGamma(int a, void* p) { return 0; }

View File

@ -1,3 +1,4 @@
#include <detours.h>
#include <signal.h>
#include "../lib/util/pid.h"
@ -8,54 +9,12 @@
WCHAR exeName[MAX_PATH + 1];
char exeNameC[MAX_PATH + 1];
DWORD imageOffset;
#define WIN32_EXE_BASE 0x00400000
DWORD GetImageBase(void) {
WCHAR sModulePath[MAX_PATH];
GetModuleFileNameW(NULL, sModulePath, MAX_PATH);
HANDLE hObject =
_CreateFileW(sModulePath, FILE_READ_DATA, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
if (hObject == INVALID_HANDLE_VALUE) {
log_error(plfBoot, "Failed to open %ls %03x", sModulePath, GetLastError());
return 0;
}
IMAGE_DOS_HEADER dosHeader = { 0 };
DWORD nRead;
_SetFilePointer(hObject, 0, NULL, FILE_BEGIN);
_ReadFile(hObject, &dosHeader, sizeof dosHeader, &nRead, NULL);
if (nRead != sizeof dosHeader) {
log_error(plfBoot, "Failed to read DOS header %03x", GetLastError());
return 0;
}
if (dosHeader.e_magic != IMAGE_DOS_SIGNATURE) {
log_error(plfBoot, "Invalid DOS magic number: %04x", dosHeader.e_magic);
return 0;
}
IMAGE_NT_HEADERS32 ntHeaders32 = { 0 };
_SetFilePointer(hObject, dosHeader.e_lfanew, NULL, FILE_BEGIN);
_ReadFile(hObject, &ntHeaders32, sizeof ntHeaders32, &nRead, NULL);
if (nRead != sizeof ntHeaders32) {
log_error(plfBoot, "Failed to read NT header %03x", GetLastError());
return 0;
}
if (ntHeaders32.Signature != IMAGE_NT_SIGNATURE) {
log_error(plfBoot, "Invalid NT signature: %08x", ntHeaders32.Signature);
return 0;
}
_CloseHandle(hObject);
return ntHeaders32.OptionalHeader.ImageBase;
}
size_t imageOffset;
void apply_patches(HMODULE hModule) {
void* baseAddress = (void*)hModule;
DWORD imageBase = GetImageBase();
DWORD imageBase = MiceGetImageBase();
if (imageBase == 0) {
log_error(plfBoot, "Failed to locate image base. Patches will not be applied.");
return;
@ -69,22 +28,22 @@ void apply_patches(HMODULE hModule) {
patch_t* patch = patch_list->next;
if (patch == NULL) {
log_warning(plfBoot, "No patches to apply. Did you forgot an amiDebug patch file?");
log_info(plfBoot, "No patches to apply. Skipping.");
return;
}
while (patch) {
DWORD oldProt;
VirtualProtect((void*)((DWORD)patch->address + imageOffset), patch->count,
PAGE_EXECUTE_READWRITE, &oldProt);
VirtualProtect((void*)(patch->address + imageOffset), patch->count, PAGE_EXECUTE_READWRITE,
&oldProt);
if (memcmp(patch->match, (void*)((DWORD)patch->address + imageOffset), patch->count) != 0) {
if (memcmp(patch->match, (void*)(patch->address + imageOffset), patch->count) != 0) {
log_error(plfBoot, "Patch %s failed! from-value missmatch", patch->name);
VirtualProtect((void*)((DWORD)patch->address + imageOffset), patch->count, oldProt,
&oldProt);
VirtualProtect((void*)(patch->address + imageOffset), patch->count, oldProt, &oldProt);
patch = patch->next;
continue;
}
memcpy((void*)((DWORD)patch->address + imageOffset), patch->replace, patch->count);
memcpy((void*)(patch->address + imageOffset), patch->replace, patch->count);
log_misc(plfBoot, "Patched %d bytes at %08x (%s)", patch->count, patch->address,
patch->name);
@ -111,39 +70,48 @@ void init_injection(HMODULE hModule) {
log_info(plfBoot, "Handover complete. Now executing within %ls", exeName);
// Start Mice FS
BOOL success = TRUE;
success &= MiceFSInit();
if (success) success &= MiceFSAddRingedgeLayers(FALSE);
if (!success) {
if (!MiceFSInit()) {
log_error(plfFile, "Failed to initialise Mice FS stack: %d", GetLastError());
exit(1);
}
if (MiceConfig.mice.original && MiceConfig.mice.original[0] == '\0') {
CHAR szCurrentDir[MAX_PATH + 1];
GetCurrentDirectoryA(sizeof szCurrentDir, szCurrentDir);
MiceFSAddLayer(RING_MOUNT_ORIGINAL, szCurrentDir);
MiceFSAddLayer(RING_MOUNT_GAME, szCurrentDir);
BOOL success = TRUE;
success &= MiceFSAddDevLayers();
CHAR szWorkPath[MAX_PATH + 1];
if (!MiceConfig.mice.original || MiceConfig.mice.original[0] == '\0') {
_GetCurrentDirectoryA(sizeof szWorkPath, szWorkPath);
success &= MiceFSAddLayer(RING_MOUNT_ORIGINAL, szWorkPath);
success &= MiceFSAddLayer(RING_MOUNT_GAME, szWorkPath);
} else {
MiceFSAddLayer(RING_MOUNT_ORIGINAL, MiceConfig.mice.original);
MiceFSAddLayer(RING_MOUNT_GAME, MiceConfig.mice.original);
success &= MiceFSAddLayer(RING_MOUNT_ORIGINAL, MiceConfig.mice.original);
success &= MiceFSAddLayer(RING_MOUNT_GAME, MiceConfig.mice.original);
}
if (MiceConfig.mice.patch && MiceConfig.mice.patch[0] != '\0') {
MiceFSAddLayer(RING_MOUNT_PATCH, MiceConfig.mice.patch);
MiceFSAddLayer(RING_MOUNT_GAME, MiceConfig.mice.patch);
success &= MiceFSAddLayer(RING_MOUNT_PATCH, MiceConfig.mice.patch);
success &= MiceFSAddLayer(RING_MOUNT_GAME, MiceConfig.mice.patch);
}
if (MiceConfig.mice.extend && MiceConfig.mice.extend[0] != '\0') {
MiceFSAddLayer(RING_MOUNT_EXTEND_VOL, MiceConfig.mice.extend);
MiceFSAddLayer(RING_MOUNT_GAME, MiceConfig.mice.extend);
success &= MiceFSAddLayer(RING_MOUNT_EXTEND_VOL, MiceConfig.mice.extend);
success &= MiceFSAddLayer(RING_MOUNT_GAME, MiceConfig.mice.extend);
}
if (MiceConfig.mice.extend2 && MiceConfig.mice.extend2[0] != '\0') {
MiceFSAddLayer(RING_MOUNT_EXTEND2_VOL, MiceConfig.mice.extend2);
MiceFSAddLayer(RING_MOUNT_GAME, MiceConfig.mice.extend2);
}
if (success) success &= MiceFSAddDevLayers();
success &= MiceFSAddRingedgeLayers(FALSE);
MiceFSSetCwd(RING_MOUNT_GAME "\\");
if (!success) {
log_error(plfFile, "Failed to add Mice FS layers: %d", GetLastError());
exit(1);
}
szWorkPath[0] = '\0';
strcat_s(szWorkPath, sizeof szWorkPath, RING_MOUNT_GAME "\\");
if (_miceIpcData && _miceIpcData->m_LauncherIsReady)
strcat_s(szWorkPath, sizeof szWorkPath, _miceIpcData->m_PathPrefix);
MiceFSSetCwd(szWorkPath);
// Setup default COM devices
init_com_devices();
@ -158,7 +126,10 @@ void init_injection(HMODULE hModule) {
// MX SuperIO: Communicate with the HW monitor chip
if (MiceConfig.drivers.mxsuperio) setup_mxsuperio();
// MX JVS: Interacting with JVS-based devices
if (MiceConfig.drivers.mxjvs) setup_mxjvs();
if (MiceConfig.drivers.mxjvs) {
setup_mxjvs();
load_keybind_config();
}
// MX HW Reset: Forcibly reboot the machine
if (MiceConfig.drivers.mxhwreset) setup_mxhwreset();
// MX SMBus: Communicate over the LPC bus. This contains the EEPROM, and PCA9535
@ -177,23 +148,9 @@ void init_injection(HMODULE hModule) {
// Must be the last thing called!
prebind_hooks();
// TODO: Figure out why we're needing to call this manually (medium priority)
if (wcscmp(exeName, L"ALLNetProc.exe") == 0) {
log_warning(plfBoot, "Making explicit call to OPENSSL_add_all_algorithms_noconf");
DWORD imageBase = GetImageBase();
imageOffset = (DWORD)hModule - imageBase;
// OPENSSL_add_all_algorithms_noconf (old exe)
// ((void (*)(void))(0x00459770 + imageOffset))();
// OPENSSL_add_all_algorithms_noconf (pink exe)
// ((void (*)(void))(0x00463480 + imageOffset))();
// TODO: Find finale offset
}
setup_hooks();
start_devices();
}
void tea_hook_test(char* fmt, ...) {
@ -203,24 +160,63 @@ void tea_hook_test(char* fmt, ...) {
va_end(argp);
}
BOOL g_bIsInDllMain = TRUE;
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) {
if (ul_reason_for_call != DLL_PROCESS_ATTACH) return TRUE;
g_bIsInDllMain = TRUE;
GetModuleFileNameW(NULL, exeName, MAX_PATH);
wcscpy_s(exeName, MAX_PATH + 1, PathFindFileNameW(exeName));
if (!MiceIpcSetup(FALSE)) {
fprintf(stderr, "Failed to initialise IPC from within micelib. Bailing hard!");
TerminateProcess(GetCurrentProcess(), 0);
return FALSE;
}
HMODULE exeModule = GetModuleHandleA(NULL);
init_injection(exeModule);
if (wcscmp(exeName, L"InitialD8_GLW_RE_SBZZ_dumped_.exe") == 0) {
CreateHook32((void*)(0x00407850), &tea_hook_test);
// *((DWORD*)(0x00407850)) = (DWORD)(&logcb);
_MiceGotGameId(_miceIpcData->m_GameId);
// InitialD 8
if (false) {
DWORD dword = 0;
MiceHookPatchAtImage(exeModule, (PVOID)0x0126867c, &dword, 4);
BYTE movEax1[] = { 0xb8, 0x01, 0x00, 0x00, 0x00 };
// Bypass cgGcIsProfileSupported
MiceHookNopAtImage(exeModule, (PVOID)0xb4c9ac, 6);
MiceHookPatchAtImage(exeModule, (PVOID)0xb4c9ac, movEax1, sizeof movEax1);
MiceHookNopAtImage(exeModule, (PVOID)0xb4ca9f, 6);
MiceHookPatchAtImage(exeModule, (PVOID)0xb4ca9f, movEax1, sizeof movEax1);
// change glProgramEnvParameters4fvNV to EXT version that works with any GPUs
static const char* arb = "glProgramEnvParameters4fvEXT";
MiceHookPatchAtImage(exeModule, (PVOID)0xB70E26, &arb, 4);
// force volatile texture (driver bug(?) check) presence
MiceHookNopAtImage(exeModule, (PVOID)(0xB6BC20 + 0x5667), 2);
DWORD profile;
BOOL amd = TRUE;
if (amd)
profile = 6151; // CG_PROFILE_FP40
else
profile = 7000; // CG_PROFILE_ARBFP1
// Vertex shader is compiled with profile 6150
// Pixel shader is compiled with profile 7000
// Change shader profile for glareGenerator
MiceHookPatchAtImage(exeModule, (PVOID)0x7D06A8, &profile, 4);
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
void* original = (void*)0x00407850;
DetourAttach(&original, tea_hook_test);
DetourTransactionCommit();
}
// if (wcscmp(exeName, L"RingGame.exe") == 0) {
// log_warning(plfBoot, "Bodge hook goo!");
// CreateHook32((void*)(0x005f2580), &tea_hook_test);
// }
g_bIsInDllMain = FALSE;
return TRUE;
}

View File

@ -1,5 +1,5 @@
#include "../lib/am/amOemstring.h"
#include "../lib/dmi/dmi.h"
#include "../lib/mice/dmi.h"
#include "mx.h"
#define DMI_HEADER_START 0x000f0000

View File

@ -4,35 +4,42 @@
#define JVS_NODE_BROADCAST 0xff
#define JVS_VERSION_CMD 0x13 // A real board reports 1.1, but we support 1.3
#define JVS_VERSION_JVS 0x20
#define JVS_VERSION_JVS 0x30 // My board is 0x20, but SBWU needs 0x30
#define JVS_VERSION_COMM 0x10
#define JVS_STATUS_OK 0x01
#define JVS_STATUS_UKCOM 0x02
#define JVS_STATUS_SUM 0x03
#define JVS_STATUS_OVERFLOW 0x04
#define JVS_STATUS_UNKNOWN 0xff // Not a spec-compliant status, but there's none for this!
typedef enum JVS_STATUS {
JVS_STATUS_OK = 0x01,
JVS_STATUS_UKCOM = 0x02,
JVS_STATUS_SUM = 0x03,
JVS_STATUS_OVERFLOW = 0x04,
JVS_STATUS_UNKNOWN = 0xfe, // Not a spec-compliant status, but there's none for this!
JVS_STATUS_SILENCE = 0xff, // Pseudo-status to indicate that the response is not to be sent
} JVS_STATUS;
#define JVS_REPORT_OK 0x01
#define JVS_REPORT_PARAM_NODATA 0x02
#define JVS_REPORT_PARAM_INVALID 0x03
#define JVS_REPORT_BUSY 0x04
typedef enum JVS_REPORT {
JVS_REPORT_OK = 0x01,
JVS_REPORT_PARAM_NODATA = 0x02,
JVS_REPORT_PARAM_INVALID = 0x03,
JVS_REPORT_BUSY = 0x04,
} JVS_REPORT;
#define JVS_FEATURE_PAD 0x00
#define JVS_FEATURE_EOF 0x00
#define JVS_FEATURE_PLAYERS 0x01
#define JVS_FEATURE_COINS 0x02
#define JVS_FEATURE_ANALOG 0x03
#define JVS_FEATURE_ROTARY 0x04
#define JVS_FEATURE_KEYCODE 0x05
#define JVS_FEATURE_SCREEN_POS 0x06
#define JVS_FEATURE_MISC_SWITCH 0x07
#define JVS_FEATURE_CARDS 0x10
#define JVS_FEATURE_MEDAL_HOPPER 0x11
#define JVS_FEATURE_GPIO 0x12
#define JVS_FEATURE_ANALOG_OUT 0x13
#define JVS_FEATURE_CHAR_OUT 0x14
#define JVS_FEATURE_BACKUP 0x15
typedef enum JVS_FEATURE {
JVS_FEATURE_PAD = 0x00,
JVS_FEATURE_EOF = 0x00,
JVS_FEATURE_PLAYERS = 0x01,
JVS_FEATURE_COINS = 0x02,
JVS_FEATURE_ANALOG = 0x03,
JVS_FEATURE_ROTARY = 0x04,
JVS_FEATURE_KEYCODE = 0x05,
JVS_FEATURE_SCREEN_POS = 0x06,
JVS_FEATURE_MISC_SWITCH = 0x07,
JVS_FEATURE_CARDS = 0x10,
JVS_FEATURE_MEDAL_HOPPER = 0x11,
JVS_FEATURE_GPIO = 0x12,
JVS_FEATURE_ANALOG_OUT = 0x13,
JVS_FEATURE_CHAR_OUT = 0x14,
JVS_FEATURE_BACKUP = 0x15,
} JVS_FEATURE;
#define JVS_CHARTYPE_UNKNOWN 0x00
#define JVS_CHARTYPE_NUMBER 0x01

View File

@ -0,0 +1,74 @@
#include <Windows.h>
#include "../../input.h"
#include "../jvs.h"
#define JVS_IO_MAX 31
#define MICE_JVS_MAX 256
// Every single byte could be masked
#define MICE_JVS_MASKED (MICE_JVS_MAX * 2)
#define new(type, instance) _##type##_vftable.ctor(&instance)
typedef struct MICE_JVS MICE_JVS, *PMICE_JVS;
typedef struct MICE_JVS_vftable MICE_JVS_vftable;
struct MICE_JVS_vftable {
void (*ctor)(PMICE_JVS this);
JVS_STATUS (*transact)(PMICE_JVS this, BYTE command);
void (*readAllButtons)(PMICE_JVS this);
};
extern MICE_JVS_vftable _MiceJvsBase_vftable;
extern MICE_JVS_vftable _MiceJvs837_14572_vftable;
extern MICE_JVS_vftable _MiceJvs837_14895_vftable;
struct MICE_JVS {
MICE_JVS_vftable* vftable;
LPBYTE m_lpInData;
DWORD m_nInIdx;
LPBYTE m_lpOutData;
DWORD m_nOutIdx;
BYTE m_Address;
LPCSTR m_BoardId;
BYTE m_CommandVersion;
BYTE m_JvsRevision;
BYTE m_VersionComm;
BOOL m_SenseOut;
BYTE m_Players;
BYTE m_ButtonsPerPlayer;
BYTE m_Coins;
BYTE m_NumButtons;
LPBOOL m_ButtonStates;
PMICE_BUTTON_BINDING m_Bindings;
DWORD m_CoinCounts[2];
};
#pragma pack(push, 1)
typedef struct JVS_PACKET {
BYTE m_Sync;
BYTE m_Dst;
BYTE m_nBytes;
BYTE m_Data[MICE_JVS_MAX - 3];
} JVS_PACKET, *PJVS_PACKET;
#pragma pack(pop)
static inline BYTE MiceJvsRead(PMICE_JVS this) {
if (this->m_lpInData == NULL) return 0xff;
if (this->m_nInIdx < MICE_JVS_MAX) return this->m_lpInData[this->m_nInIdx++];
return 0xff;
}
#include <stdio.h>
static inline void MiceJvsWrite(PMICE_JVS this, BYTE data) {
if (this->m_lpOutData == NULL) return;
if (this->m_nOutIdx < MICE_JVS_MAX) this->m_lpOutData[this->m_nOutIdx++] = data;
}
extern MICE_JVS _MiceJvsBoards[JVS_IO_MAX];

View File

@ -0,0 +1,148 @@
#include <Windows.h>
#include "../../common.h"
#include "jvs.h"
#define PLAYER_COUNT 2
#define COIN_COUNTERS 2
#define SWITCH_BYTES 2
#define PLAYER_SWITCH_COUNT 13 // Must be less than 8*SWITCH_BYTES !!
BOOL coin_solenoid = false;
static const char JVS_837_14572_ID[] = "SEGA ENTERPRISES,LTD.;I/O BD JVS;837-13551 ;Ver1.00;98/10";
static void Ctor(PMICE_JVS this) {
_MiceJvsBase_vftable.ctor(this);
this->vftable = &_MiceJvs837_14572_vftable;
this->vftable->readAllButtons = _MiceJvsBase_vftable.readAllButtons;
this->m_BoardId = JVS_837_14572_ID;
this->m_CommandVersion = 0x13;
this->m_JvsRevision = 0x20;
this->m_VersionComm = 0x10;
// Coin + Test + 13 switches per player
this->m_ButtonsPerPlayer = PLAYER_SWITCH_COUNT;
this->m_Coins = COIN_COUNTERS;
this->m_Players = PLAYER_COUNT;
this->m_NumButtons = this->m_Coins + 1 + (this->m_ButtonsPerPlayer * this->m_Players);
this->m_ButtonStates = malloc(this->m_NumButtons * sizeof *this->m_ButtonStates);
ZeroMemory(this->m_ButtonStates, this->m_NumButtons * sizeof *this->m_ButtonStates);
this->m_Bindings = malloc(this->m_NumButtons * sizeof *this->m_Bindings);
ZeroMemory(this->m_Bindings, this->m_NumButtons * sizeof *this->m_Bindings);
ZeroMemory(this->m_CoinCounts, sizeof this->m_CoinCounts);
}
static JVS_STATUS Transact(PMICE_JVS this, BYTE command) {
switch (command) {
case JVS_CMD_READ_SW:
BYTE players = MiceJvsRead(this);
BYTE switch_bytes = MiceJvsRead(this);
if (players > this->m_Players || switch_bytes != SWITCH_BYTES) {
MiceJvsWrite(this, JVS_REPORT_PARAM_INVALID);
return JVS_STATUS_OK;
}
MiceJvsWrite(this, JVS_REPORT_OK);
this->vftable->readAllButtons(this);
// Test button
MiceJvsWrite(this, this->m_ButtonStates[this->m_Coins] ? 0x80 : 0x00);
for (int player = 0; player < players; player++) {
unsigned short buttons = 0x0000;
for (int j = 0; j < this->m_ButtonsPerPlayer; j++) {
buttons <<= 1;
if (this->m_ButtonStates[this->m_Coins + 1 +
(this->m_ButtonsPerPlayer * player) + j]) {
buttons |= 1;
}
}
buttons <<= (16 - this->m_ButtonsPerPlayer);
for (int i = switch_bytes - 1; i >= 0; i--)
MiceJvsWrite(this, (buttons >> (i * 8)) & 0xff);
}
return JVS_STATUS_OK;
case JVS_CMD_READ_COIN:
MiceJvsWrite(this, JVS_REPORT_OK);
unsigned char coin_count;
coin_count = MiceJvsRead(this);
MiceInputPollDevices();
for (int i = 0; i < this->m_Coins; i++)
if (MiceInputGetButtonState(&this->m_Bindings[i])) this->m_CoinCounts[i]++;
for (unsigned char slot = 0; slot < this->m_Coins; slot++) {
MiceJvsWrite(this, (this->m_CoinCounts[slot] >> 8) & 0xff);
MiceJvsWrite(this, this->m_CoinCounts[slot] & 0xff);
}
return JVS_STATUS_OK;
case JVS_CMD_READ_ANALOGS:
MiceJvsWrite(this, JVS_REPORT_OK);
// TODO: Actually emulate these (super low priority)
unsigned char analog_count;
analog_count = MiceJvsRead(this);
for (int i = analog_count; i > 0; i--) {
MiceJvsWrite(this, 0xde);
MiceJvsWrite(this, 0xad);
}
return JVS_STATUS_OK;
case JVS_CMD_WRITE_GPIO1:
MiceJvsWrite(this, JVS_REPORT_OK);
unsigned char gpio_bytes;
gpio_bytes = MiceJvsRead(this);
for (int i = 0; i < gpio_bytes; i++) {
unsigned char gpio_value;
gpio_value = MiceJvsRead(this);
if (i == 0) {
if (!!(gpio_value & 0x80) != coin_solenoid) {
coin_solenoid = !!(gpio_value & 0x80);
log_info(plfMxJvs, "Coin solenoid: %s",
coin_solenoid ? "Locked" : "Unlocked");
}
}
// log_warning(plfMxJvs, "Unhandled GPIO write: *(%d) = %02x", i, gpio_value);
}
return JVS_STATUS_OK;
case JVS_CMD_WRITE_GPIO2:
case JVS_CMD_WRITE_GPIO3:
MiceJvsWrite(this, JVS_REPORT_OK);
unsigned char gpioByteIndex;
unsigned char gpioByteData;
gpioByteIndex = MiceJvsRead(this);
gpioByteData = MiceJvsRead(this);
log_warning(plfMxJvs, "GPIO%d Unhandled: [%02x]=%02x",
(command - JVS_CMD_WRITE_GPIO2) + 2, gpioByteIndex, gpioByteData);
return JVS_STATUS_OK;
case JVS_CMD_COIN_DECREASE:
MiceJvsWrite(this, JVS_REPORT_OK);
unsigned char slot;
slot = MiceJvsRead(this);
unsigned char cAmount[2];
cAmount[0] = MiceJvsRead(this);
cAmount[1] = MiceJvsRead(this);
unsigned short sAmount = cAmount[0] << 8 | cAmount[1];
// board->coin_counts[slot] -= sAmount;
return JVS_STATUS_OK;
default:
return _MiceJvsBase_vftable.transact(this, command);
}
}
MICE_JVS_vftable _MiceJvs837_14572_vftable = {
.ctor = Ctor,
.transact = Transact,
};

View File

@ -0,0 +1,169 @@
#include <Windows.h>
#include "../../common.h"
#include "jvs.h"
#define PLAYER_COUNT 1
#define COIN_COUNTERS 2
#define SWITCH_BYTES 2
BOOL coin_solenoid = false;
static const char JVS_837_14895_ID[] = ";;837-14895;;;FE MODE;";
static void Ctor(PMICE_JVS this) {
_MiceJvsBase_vftable.ctor(this);
this->vftable = &_MiceJvs837_14895_vftable;
this->vftable->readAllButtons = _MiceJvsBase_vftable.readAllButtons;
this->m_BoardId = JVS_837_14895_ID;
this->m_CommandVersion = 0x13;
this->m_JvsRevision = 0x30;
this->m_VersionComm = 0x10;
// Eeh whatever I'll do this eventually
this->m_Players = 0;
this->m_ButtonsPerPlayer = 0;
this->m_Coins = 0;
this->m_NumButtons = 0;
}
// TODO: Urgent: Restore buttons
static JVS_STATUS Transact(PMICE_JVS this, BYTE command) {
switch (command) {
case JVS_CMD_GET_FEATURES:
MiceJvsWrite(this, JVS_REPORT_OK);
MiceJvsWrite(this, JVS_FEATURE_PLAYERS);
MiceJvsWrite(this, PLAYER_COUNT);
MiceJvsWrite(this, 22); // bits per player
MiceJvsWrite(this, JVS_FEATURE_PAD);
// We need at least 15 general outputs
MiceJvsWrite(this, JVS_FEATURE_GPIO);
MiceJvsWrite(this, 16);
MiceJvsWrite(this, JVS_FEATURE_PAD);
MiceJvsWrite(this, JVS_FEATURE_PAD);
// Toss in two coin counters for good luck
MiceJvsWrite(this, JVS_FEATURE_COINS);
MiceJvsWrite(this, COIN_COUNTERS);
MiceJvsWrite(this, JVS_FEATURE_PAD);
MiceJvsWrite(this, JVS_FEATURE_PAD);
MiceJvsWrite(this, JVS_FEATURE_EOF);
return JVS_STATUS_OK;
case JVS_CMD_READ_SW:
unsigned char players;
unsigned char switch_bytes;
players = MiceJvsRead(this);
switch_bytes = MiceJvsRead(this);
if (players > PLAYER_COUNT || switch_bytes != 3) {
MiceJvsWrite(this, JVS_REPORT_PARAM_INVALID);
return JVS_STATUS_OK;
}
// update_jvs_buttons(board);
// MiceJvsWrite(this, JVS_REPORT_OK);
// MiceJvsWrite(this, board->last_sysbuttons);
// for (int player = 0; player < players; player++) {
// for (int i = switch_bytes - 1; i >= 0; i--) {
// MiceJvsWrite(this, (board->last_buttons[player] >> (i * 8)) & 0xff);
// }
// }
MiceJvsWrite(this, JVS_REPORT_OK);
MiceJvsWrite(this, 0);
for (int player = 0; player < players; player++) {
for (int i = switch_bytes - 1; i >= 0; i--) {
MiceJvsWrite(this, (0x00 >> (i * 8)) & 0xff);
}
}
return JVS_STATUS_OK;
case JVS_CMD_READ_COIN:
MiceJvsWrite(this, JVS_REPORT_OK);
unsigned char coin_count;
coin_count = MiceJvsRead(this);
// int coin1 = jvsKeybindings[board->num].buttons[0];
// int coin2 = jvsKeybindings[board->num].buttons[1];
// if (coin1 && GetAsyncKeyState(coin1) & 1) board->coin_counts[0]++;
// if (coin2 && GetAsyncKeyState(coin2) & 1) board->coin_counts[1]++;
// for (unsigned char slot = 0; slot < coin_count; slot++) {
// MiceJvsWrite(this, board->coin_counts[slot] >> 8);
// MiceJvsWrite(this, board->coin_counts[slot] & 0xff);
// }
for (unsigned char slot = 0; slot < coin_count; slot++) {
MiceJvsWrite(this, 0);
MiceJvsWrite(this, 0);
}
return JVS_STATUS_OK;
case JVS_CMD_READ_ANALOGS:
MiceJvsWrite(this, JVS_REPORT_OK);
// TODO: Actually emulate these (super low priority)
unsigned char analog_count;
analog_count = MiceJvsRead(this);
for (int i = analog_count; i > 0; i--) {
MiceJvsWrite(this, 0xde);
MiceJvsWrite(this, 0xad);
}
return JVS_STATUS_OK;
case JVS_CMD_WRITE_GPIO1:
MiceJvsWrite(this, JVS_REPORT_OK);
unsigned char gpio_bytes;
gpio_bytes = MiceJvsRead(this);
for (int i = 0; i < gpio_bytes; i++) {
unsigned char gpio_value;
gpio_value = MiceJvsRead(this);
if (i == 0) {
if (!!(gpio_value & 0x80) != coin_solenoid) {
coin_solenoid = !!(gpio_value & 0x80);
log_info(plfMxJvs, "Coin solenoid: %s",
coin_solenoid ? "Locked" : "Unlocked");
}
}
// log_warning(plfMxJvs, "Unhandled GPIO write: *(%d) = %02x", i, gpio_value);
}
return JVS_STATUS_OK;
case JVS_CMD_WRITE_GPIO2:
case JVS_CMD_WRITE_GPIO3:
MiceJvsWrite(this, JVS_REPORT_OK);
unsigned char gpioByteIndex;
unsigned char gpioByteData;
gpioByteIndex = MiceJvsRead(this);
gpioByteData = MiceJvsRead(this);
log_warning(plfMxJvs, "GPIO%d Unhandled: [%02x]=%02x",
(command - JVS_CMD_WRITE_GPIO2) + 2, gpioByteIndex, gpioByteData);
return JVS_STATUS_OK;
case JVS_CMD_COIN_DECREASE:
MiceJvsWrite(this, JVS_REPORT_OK);
unsigned char slot;
slot = MiceJvsRead(this);
unsigned char cAmount[2];
cAmount[0] = MiceJvsRead(this);
cAmount[1] = MiceJvsRead(this);
unsigned short sAmount = cAmount[0] << 8 | cAmount[1];
// board->coin_counts[slot] -= sAmount;
return JVS_STATUS_OK;
default:
return _MiceJvsBase_vftable.transact(this, command);
}
}
MICE_JVS_vftable _MiceJvs837_14895_vftable = {
.ctor = Ctor,
.transact = Transact,
};

View File

@ -0,0 +1,115 @@
#include <Windows.h>
#include "../../common.h"
#include "jvs.h"
static void Ctor(PMICE_JVS this) {
this->vftable = &_MiceJvsBase_vftable;
this->m_nInIdx = 0;
this->m_lpInData = NULL;
this->m_nOutIdx = 0;
this->m_lpOutData = NULL;
this->m_BoardId = NULL;
this->m_Address = 0xff;
// Sane, but impractical, defaults. Boards should set better values.
this->m_CommandVersion = 0x10;
this->m_JvsRevision = 0x20;
this->m_VersionComm = 0x10;
}
static JVS_STATUS Transact(PMICE_JVS this, BYTE command) {
switch (command) {
case JVS_CMD_RESET:
if (MiceJvsRead(this) != JVS_CMD_RESET_ASSERT) return JVS_STATUS_UKCOM;
this->m_Address = 0xff;
this->m_SenseOut = TRUE;
return JVS_STATUS_SILENCE;
case JVS_CMD_CHANGE_COMMS:
return JVS_STATUS_SILENCE;
case JVS_CMD_ASSIGN_ADDR:
MiceJvsWrite(this, JVS_REPORT_OK);
this->m_SenseOut = FALSE;
// we don't bother remembering the address because at the moment we only simulate
// a single board in the JVS chain.
MiceJvsRead(this);
return JVS_STATUS_OK;
case JVS_CMD_READ_ID:
MiceJvsWrite(this, JVS_REPORT_OK);
if (this->m_BoardId == NULL)
MiceJvsWrite(this, 0x00);
else
for (size_t i = 0; i < strlen(this->m_BoardId); i++)
MiceJvsWrite(this, this->m_BoardId[i]);
return JVS_STATUS_OK;
case JVS_CMD_GET_CMD_VERSION:
MiceJvsWrite(this, JVS_REPORT_OK);
MiceJvsWrite(this, this->m_CommandVersion);
return JVS_STATUS_OK;
case JVS_CMD_GET_JVS_VERSION:
MiceJvsWrite(this, JVS_REPORT_OK);
MiceJvsWrite(this, this->m_JvsRevision);
return JVS_STATUS_OK;
case JVS_CMD_GET_COMM_VERSION:
MiceJvsWrite(this, JVS_REPORT_OK);
MiceJvsWrite(this, this->m_VersionComm);
return JVS_STATUS_OK;
case JVS_CMD_GET_FEATURES:
MiceJvsWrite(this, JVS_REPORT_OK);
MiceJvsWrite(this, JVS_FEATURE_PLAYERS);
MiceJvsWrite(this, this->m_Players);
MiceJvsWrite(this, this->m_ButtonsPerPlayer);
MiceJvsWrite(this, JVS_FEATURE_PAD);
MiceJvsWrite(this, JVS_FEATURE_COINS);
MiceJvsWrite(this, this->m_Coins);
MiceJvsWrite(this, JVS_FEATURE_PAD);
MiceJvsWrite(this, JVS_FEATURE_PAD);
// TODO: Make this based on `this`
MiceJvsWrite(this, JVS_FEATURE_ANALOG);
MiceJvsWrite(this, 8); // 8 ADC channels
MiceJvsWrite(this, JVS_FEATURE_PAD); // ?? (was "10" prior)
MiceJvsWrite(this, JVS_FEATURE_PAD);
// TODO: Make this based on `this`
MiceJvsWrite(this, JVS_FEATURE_GPIO);
MiceJvsWrite(this, 6); // 6 ports
MiceJvsWrite(this, JVS_FEATURE_PAD);
MiceJvsWrite(this, JVS_FEATURE_PAD);
MiceJvsWrite(this, JVS_FEATURE_EOF);
return JVS_STATUS_OK;
case JVS_CMD_RECEIVE_MAIN_ID:
unsigned char tempRead = 0xff;
while (tempRead != 0) tempRead = MiceJvsRead(this);
// TODO: Do we need to report here?
return JVS_STATUS_OK;
default:
log_error(plfMxJvs, "Unknown command: 0x%02x", command);
return JVS_STATUS_UKCOM;
}
}
static void ReadAllButtons(PMICE_JVS this) {
MiceInputPollDevices();
for (DWORD i = 0; i < this->m_NumButtons; i++) {
this->m_ButtonStates[i] = MiceInputGetButtonState(&(this->m_Bindings[i]));
}
}
MICE_JVS_vftable _MiceJvsBase_vftable = {
.ctor = Ctor,
.transact = Transact,
.readAllButtons = ReadAllButtons,
};

View File

@ -7,4 +7,8 @@ drivers_files = files(
'mxsram.c',
'mxsuperio.c',
'htsysmnt.c',
'jvs_boards/jvs_base.c',
'jvs_boards/jvs_837_14572.c',
'jvs_boards/jvs_837_14895.c',
)

View File

@ -2,290 +2,22 @@
#include "../comdevice.h"
#include "../common.h"
#include "../input.h"
#include "../key_config.h"
#include "jvs.h"
#include "jvs_boards/jvs.h"
#include "mx.h"
BOOL JVS_SENSE = false;
BOOL coin_solenoid = false;
BOOL test_btn = false;
#define JVS_SENSE (MiceConfig.keys.board_count == 0 ? FALSE : _MiceJvsBoards[0].m_SenseOut)
#define PLAYER_COUNT 2
#define COIN_COUNTERS 2
#define SWITCH_BYTES 2
// const char JVS_837_14572_ID[] = "SEGA ENTERPRISES,LTD.;I/O BD JVS;837-14572 ;Ver1.00;98/10";
const char JVS_837_14572_ID[] = "SEGA ENTERPRISES,LTD.;I/O BD JVS;837-13551 ;Ver1.00;98/10";
typedef struct _jvs_board {
int num;
unsigned short coin_counts[COIN_COUNTERS];
unsigned char (*handler)(struct _jvs_board* board, unsigned char* inData, short inCount,
unsigned char* outData, unsigned char* outCount);
const char* id;
unsigned char last_sysbuttons;
unsigned short last_buttons[PLAYER_COUNT];
} jvs_board_t;
#define JVS_FLAG_NONE 0
#define JVS_FLAG_NC 1
#define JVS_FLAG_INVERT 2
jvs_board_t jvs_boards[JVS_IO_MAX] = { 0 };
short jvs_unpad(unsigned char* paddedData, short length, unsigned char* unpaddedData) {
short index = 0;
bool escape = false;
for (short i = 0; i < length; i++) {
if (escape) {
unpaddedData[index++] = paddedData[i] + 1;
escape = false;
} else if (paddedData[i] == JVS_MARK)
escape = true;
else
unpaddedData[index++] = paddedData[i];
JVS_STATUS MiceJvsWrapper(PMICE_JVS this, DWORD nMaxRead) {
JVS_STATUS status = JVS_STATUS_OK;
// -1, because we don't want to treat the checksum as a command!
while (this->m_nInIdx < nMaxRead - 1) {
JVS_STATUS subStatus = this->vftable->transact(this, MiceJvsRead(this));
if (subStatus > status) status = subStatus;
}
return index;
}
short jvs_pad(unsigned char* unpaddedData, short length, unsigned char* paddedData,
short paddedMax) {
short index = 0;
for (short i = 0; i < length; i++) {
if (i > paddedMax) return -1;
if (i != 0 && (unpaddedData[i] == JVS_MARK || unpaddedData[i] == JVS_SYNC)) {
paddedData[index++] = JVS_MARK;
paddedData[index++] = unpaddedData[i] - 1;
} else {
paddedData[index++] = unpaddedData[i];
}
}
return index;
}
void update_jvs_buttons(jvs_board_t* board) {
unsigned char sysButtons = 0x00;
if (GetAsyncKeyState(jvsKeybindings[board->num].test) < 0) sysButtons |= 0x80;
board->last_sysbuttons = sysButtons;
for (int player = 0; player < PLAYER_COUNT; player++) {
unsigned short buttons = 0x0000;
for (int i = 0; i < SWITCH_BYTES * 8; i++) {
buttons <<= 1;
if (i < 14) {
int scancode = jvsKeybindings[board->num].buttons[(i + 1) * 2 + player];
bool invert = jvsKeybindings[board->num].invert[(i + 1) * 2 + player];
if (scancode == 0) continue;
if (invert)
buttons |= (GetAsyncKeyState(scancode) >= 0); // << i;
else
buttons |= (GetAsyncKeyState(scancode) < 0); // << i;
}
// 0x80 == push 3
// buttons |= 1;
// buttons |= 0x80;
}
board->last_buttons[player] = buttons;
}
}
unsigned char jvs_exchange(jvs_board_t* board, unsigned char* inData, short inCount,
unsigned char* response, unsigned char* outCount) {
short jvsIndex = 0;
unsigned char respIndex = 0;
#define jvs_read(x) \
if (jvsIndex >= inCount) { \
return JVS_STATUS_OVERFLOW; \
} else { \
(x) = inData[jvsIndex++]; \
}
#define jvs_write(x) response[respIndex++] = (x);
static bool flipflop = false;
while (jvsIndex < inCount) {
unsigned char cmd;
jvs_read(cmd);
// log_info(plfMxJvs, "CMD: %02x", cmd);
switch (cmd) {
case JVS_CMD_RESET:
unsigned char reset_assert;
jvs_read(reset_assert);
if (reset_assert != JVS_CMD_RESET_ASSERT) return JVS_STATUS_UKCOM;
JVS_SENSE = true;
// Special case
*outCount = 0;
return JVS_STATUS_OK;
case JVS_CMD_CHANGE_COMMS:
// Special case
*outCount = 0;
return JVS_STATUS_OK;
case JVS_CMD_ASSIGN_ADDR:
jvs_write(JVS_REPORT_OK);
JVS_SENSE = false;
// we don't bother remembering the address because at the moment we only simulate
// a single board in the JVS chain.
unsigned char _;
jvs_read(_);
break;
case JVS_CMD_READ_ID:
jvs_write(JVS_REPORT_OK);
for (size_t i = 0; i < strlen(board->id); i++) jvs_write(board->id[i]);
break;
case JVS_CMD_GET_CMD_VERSION:
jvs_write(JVS_REPORT_OK);
jvs_write(JVS_VERSION_CMD);
break;
case JVS_CMD_GET_JVS_VERSION:
jvs_write(JVS_REPORT_OK);
jvs_write(JVS_VERSION_JVS);
break;
case JVS_CMD_GET_COMM_VERSION:
jvs_write(JVS_REPORT_OK);
jvs_write(JVS_VERSION_COMM);
break;
case JVS_CMD_GET_FEATURES:
jvs_write(JVS_REPORT_OK);
jvs_write(JVS_FEATURE_PLAYERS);
jvs_write(PLAYER_COUNT);
jvs_write(13); // bits per player
jvs_write(JVS_FEATURE_PAD);
jvs_write(JVS_FEATURE_COINS);
jvs_write(COIN_COUNTERS);
jvs_write(JVS_FEATURE_PAD);
jvs_write(JVS_FEATURE_PAD);
jvs_write(JVS_FEATURE_ANALOG);
jvs_write(8); // 8 ADC channels
jvs_write(JVS_FEATURE_PAD); // ?? (was "10" prior)
jvs_write(JVS_FEATURE_PAD);
jvs_write(JVS_FEATURE_GPIO);
jvs_write(6); // 6 ports
jvs_write(JVS_FEATURE_PAD);
jvs_write(JVS_FEATURE_PAD);
jvs_write(JVS_FEATURE_EOF);
break;
case JVS_CMD_RECEIVE_MAIN_ID:
unsigned char tempRead = 0xff;
while (tempRead != 0) jvs_read(tempRead);
// TODO: Do we need to report here?
break;
case JVS_CMD_READ_SW:
unsigned char players;
unsigned char switch_bytes;
jvs_read(players);
jvs_read(switch_bytes);
if (players > PLAYER_COUNT || switch_bytes != 2) {
jvs_write(JVS_REPORT_PARAM_INVALID);
break;
}
update_jvs_buttons(board);
jvs_write(JVS_REPORT_OK);
jvs_write(board->last_sysbuttons);
for (int player = 0; player < players; player++) {
for (int i = switch_bytes - 1; i >= 0; i--) {
jvs_write((board->last_buttons[player] >> (i * 8)) & 0xff);
}
}
break;
case JVS_CMD_READ_COIN:
jvs_write(JVS_REPORT_OK);
unsigned char coin_count;
jvs_read(coin_count);
int coin1 = jvsKeybindings[board->num].buttons[0];
int coin2 = jvsKeybindings[board->num].buttons[1];
if (coin1 && GetAsyncKeyState(coin1) & 1) board->coin_counts[0]++;
if (coin2 && GetAsyncKeyState(coin2) & 1) board->coin_counts[1]++;
for (unsigned char slot = 0; slot < coin_count; slot++) {
jvs_write(board->coin_counts[slot] >> 8);
jvs_write(board->coin_counts[slot] & 0xff);
}
break;
case JVS_CMD_READ_ANALOGS:
jvs_write(JVS_REPORT_OK);
// TODO: Actually emulate these (super low priority)
unsigned char analog_count;
jvs_read(analog_count);
for (int i = analog_count; i > 0; i--) {
jvs_write(0xde);
jvs_write(0xad);
}
break;
case JVS_CMD_WRITE_GPIO1:
jvs_write(JVS_REPORT_OK);
unsigned char gpio_bytes;
jvs_read(gpio_bytes);
for (int i = 0; i < gpio_bytes; i++) {
unsigned char gpio_value;
jvs_read(gpio_value);
if (i == 0) {
if (!!(gpio_value & 0x80) != coin_solenoid) {
coin_solenoid = !!(gpio_value & 0x80);
log_info(plfMxJvs, "Coin solenoid: %s",
coin_solenoid ? "Locked" : "Unlocked");
}
}
// log_warning(plfMxJvs, "Unhandled GPIO write: *(%d) = %02x", i, gpio_value);
}
break;
case JVS_CMD_WRITE_GPIO2:
case JVS_CMD_WRITE_GPIO3:
jvs_write(JVS_REPORT_OK);
unsigned char gpioByteIndex;
unsigned char gpioByteData;
jvs_read(gpioByteIndex);
jvs_read(gpioByteData);
log_warning(plfMxJvs, "GPIO%d Unhandled: [%02x]=%02x",
(cmd - JVS_CMD_WRITE_GPIO2) + 2, gpioByteIndex, gpioByteData);
break;
case JVS_CMD_COIN_DECREASE:
jvs_write(JVS_REPORT_OK);
unsigned char slot;
jvs_read(slot);
unsigned char cAmount[2];
jvs_read(cAmount[0]);
jvs_read(cAmount[1]);
unsigned short sAmount = cAmount[0] << 8 | cAmount[1];
board->coin_counts[slot] -= sAmount;
break;
default:
log_error(plfMxJvs, "Unknown command: 0x%02x", cmd);
return JVS_STATUS_UKCOM;
}
}
#undef jvs_read
#undef jvs_write
*outCount = respIndex;
return JVS_STATUS_OK;
return status;
}
void jvs_send_status(unsigned char status, unsigned char* outData, LPDWORD outCount) {
@ -306,78 +38,116 @@ void jvs_send_status(unsigned char status, unsigned char* outData, LPDWORD outCo
}
}
void mxjvs_handle(unsigned char* paddedIn, short inCount, unsigned char* outData, short maxOut,
LPDWORD outCount) {
*outCount = 0;
unsigned char* inData = malloc(inCount);
inCount = jvs_unpad(paddedIn, inCount, inData);
BYTE jvsInUnmasked[MICE_JVS_MAX];
BYTE jvsOutUnmasked[MICE_JVS_MAX];
BYTE jvsOutMasked[MICE_JVS_MASKED];
void mxjvs_handle(unsigned char* lpMaskedIn, short nMaskedCount, unsigned char* outData,
short maxOut, LPDWORD outCount) {
SHORT nIn = 0;
BOOL wasMark = FALSE;
for (int i = 0; i < nMaskedCount; i++) {
if (lpMaskedIn[i] == JVS_MARK) {
wasMark = TRUE;
continue;
}
if (wasMark)
jvsInUnmasked[nIn++] = lpMaskedIn[i] + 1;
else
jvsInUnmasked[nIn++] = lpMaskedIn[i];
}
PJVS_PACKET lpPacket = (PJVS_PACKET)jvsInUnmasked;
// JVS frame is 4 bytes in total
if (inCount < 4) {
log_error(plfMxJvs, "inCount impossibly small: %d", inCount);
if (nIn < 4) {
log_error(plfMxJvs, "inCount impossibly small: %d", nIn);
jvs_send_status(JVS_STATUS_UNKNOWN, outData, outCount);
free(inData);
return;
}
// This isn't a JVS packet
if (inData[0] != JVS_SYNC) {
log_error(plfMxJvs, "SYNC missing. Saw 0x%02x", inData[0]);
// This isn't a JVS packet. We should scan for SYNC, but I don't think we'll ever need to
if (lpPacket->m_Sync != JVS_SYNC) {
log_error(plfMxJvs, "SYNC missing. Saw 0x%02x", lpPacket->m_Sync);
jvs_send_status(JVS_STATUS_UNKNOWN, outData, outCount);
free(inData);
return;
}
// Validate the checksum before proceeding
unsigned char sum = 0;
bool escape = false;
for (int i = 1; i < inCount - 1; i++) sum += inData[i];
if (sum != inData[inCount - 1]) {
for (int i = 1; i < nIn - 1; i++) sum += jvsInUnmasked[i];
if (sum != jvsInUnmasked[nIn - 1]) {
log_error(plfMxJvs, "Checksum failed. Computed 0x%02x, expected 0x%02x", sum,
inData[inCount - 1]);
jvsInUnmasked[nIn - 1]);
jvs_send_status(JVS_STATUS_SUM, outData, outCount);
return;
}
unsigned char destination = inData[1];
// Not broadcast, not master-bound, and within bounds
if (destination != 0xff && (destination == 0 || destination > MiceConfig.keys.board_count))
return;
DWORD nBoardCount = MiceConfig.keys.board_count;
if (nBoardCount > _countof(_MiceJvsBoards)) nBoardCount = _countof(_MiceJvsBoards);
unsigned char* response = malloc(maxOut);
unsigned char packetSize = 0;
unsigned char status = JVS_STATUS_UNKNOWN;
if (destination == 0xff) {
for (int i = 0; i < MiceConfig.keys.board_count; i++) {
jvs_board_t* board = &jvs_boards[i];
status = board->handler(board, inData + 3, inData[2] - 1, response + 4, &packetSize);
if (packetSize != 0) break;
// Not broadcast, not master-bound, and within bounds
if (lpPacket->m_Dst != 0xff && (lpPacket->m_Dst == 0 || lpPacket->m_Dst > nBoardCount)) {
log_warning(plfMxJvs, "JVS bound for %02x ignored", lpPacket->m_Dst);
*outCount = 0;
return;
}
JVS_STATUS status = JVS_STATUS_UNKNOWN;
DWORD nBytesWrote = 0;
if (lpPacket->m_Dst == 0xff) {
for (DWORD i = 0; i < nBoardCount; i++) {
PMICE_JVS lpMiceJvs = &_MiceJvsBoards[i];
lpMiceJvs->m_lpInData = jvsInUnmasked;
lpMiceJvs->m_lpOutData = jvsOutUnmasked;
lpMiceJvs->m_nInIdx = 3;
lpMiceJvs->m_nOutIdx = 4;
status = MiceJvsWrapper(lpMiceJvs, nIn);
if (lpMiceJvs->m_nOutIdx > 4) {
nBytesWrote = lpMiceJvs->m_nOutIdx - 4;
break;
}
}
} else {
jvs_board_t* board = &jvs_boards[MiceConfig.keys.board_count - destination];
status = board->handler(board, inData + 3, inData[2] - 1, response + 4, &packetSize);
PMICE_JVS lpMiceJvs = &_MiceJvsBoards[nBoardCount - lpPacket->m_Dst];
lpMiceJvs->m_lpInData = jvsInUnmasked;
lpMiceJvs->m_lpOutData = jvsOutUnmasked;
lpMiceJvs->m_nInIdx = 3;
lpMiceJvs->m_nOutIdx = 4;
status = MiceJvsWrapper(lpMiceJvs, nIn);
nBytesWrote = lpMiceJvs->m_nOutIdx - 4;
}
if (status == JVS_STATUS_SILENCE) {
*outCount = 0;
return;
}
free(inData);
if (status == JVS_STATUS_OK) {
if (packetSize == 0) return;
response[0] = JVS_SYNC;
response[1] = JVS_NODE_MASTER;
response[2] = packetSize + 2;
response[3] = status;
((PJVS_PACKET)&jvsOutUnmasked)->m_Dst = JVS_NODE_MASTER;
((PJVS_PACKET)&jvsOutUnmasked)->m_nBytes = (nBytesWrote + 2) & 0xff;
jvsOutUnmasked[3] = status;
sum = 0;
for (int i = 1; i < packetSize + 4; i++) sum += response[i];
response[packetSize + 4] = sum;
for (DWORD i = 1; i < nBytesWrote + 4; i++) sum += jvsOutUnmasked[i];
jvsOutUnmasked[nBytesWrote + 4] = sum;
short paddedLength = jvs_pad(response, packetSize + 5, outData, maxOut);
*outCount = (paddedLength == -1) ? 0 : paddedLength;
DWORD nPadded = 1;
jvsOutMasked[0] = JVS_SYNC;
for (DWORD i = 1; i <= nBytesWrote + 4; i++) {
if (i == JVS_MARK || i == JVS_SYNC) {
jvsOutMasked[nPadded++] = JVS_MARK;
jvsOutMasked[nPadded++] = jvsOutUnmasked[i] - 1;
} else
jvsOutMasked[nPadded++] = jvsOutUnmasked[i];
}
free(response);
*outCount = nPadded;
memcpy_s(outData, maxOut, jvsOutMasked, nPadded);
} else {
log_error(plfMxJvs, "JVS board %d returned status %d", destination, status);
free(response);
log_error(plfMxJvs, "JVS board %d returned status %d", lpPacket->m_Dst, status);
jvs_send_status(status, outData, outCount);
}
}
@ -410,7 +180,7 @@ BOOL mxjvs_GetCommState(void* com, LPDCB lpDCB) { return TRUE; }
BOOL mxjvs_SetCommTimeouts(void* com, LPCOMMTIMEOUTS lpDCB) { return TRUE; }
BOOL mxjvs_GetCommModemStatus(void* com, LPDWORD lpModelStat) {
*lpModelStat = !JVS_SENSE ? MS_DSR_ON : 0;
*lpModelStat = JVS_SENSE ? 0 : MS_DSR_ON;
return TRUE;
}
@ -423,10 +193,12 @@ BOOL mxjvs_SetCommState(void* com, LPDCB lpDCB) {
}
void init_jvs_boards() {
for (int i = 0; i < _countof(jvs_boards); i++) {
jvs_boards[i].num = i;
jvs_boards[i].id = JVS_837_14572_ID;
jvs_boards[i].handler = &jvs_exchange;
// new (MiceJvs837_14895, _MiceJvsBoards[0]);
new (MiceJvs837_14572, _MiceJvsBoards[0]);
// Init all the others
for (int i = 1; i < _countof(_MiceJvsBoards); i++) {
new (MiceJvs837_14572, _MiceJvsBoards[i]);
}
}
@ -455,11 +227,16 @@ DWORD __stdcall mxjvs_comdev_thread(com_device_t* com) {
short packetSize = (bufferPtr - inBuffer) & 0xFFFF;
mxjvs_handle(inBuffer, packetSize, outBuffer, _countof(outBuffer), &bytesReturned);
com->modemStatus = !JVS_SENSE ? MS_DSR_ON : 0;
com->modemStatus = JVS_SENSE ? 0 : MS_DSR_ON;
comdev_write(com, outBuffer, bytesReturned & 0xFFFF);
}
}
VIRTUAL_SERIAL_DEVICE jvsSerialDevice = {
.m_Name = "JVS",
.m_Entrypoint = mxjvs_comdev_thread,
};
void setup_mxjvs() {
init_jvs_boards();
@ -479,6 +256,5 @@ void setup_mxjvs() {
mxjvs->com_hook = jvscom;
// TODO: Looks like some things might use JVS on COM4. We should setup a comdevice for this!
attach_com_device(4, mxjvs_comdev_thread);
attach_com_device(4, &jvsSerialDevice);
}

View File

@ -167,19 +167,19 @@ void init_nv_storage() {
void dump_nv_storage() {
FILE* fp;
if (fopen_s(&fp, "dev/kc/nvram.bin", "wb")) {
if (fopen_s(&fp, MiceIpcRelativePath("keychip\\nvram.bin"), "wb")) {
log_error(plfMxParallel, "Failed to open nvram.bin");
return;
}
fwrite(nvram, 1, sizeof nvram, fp);
fclose(fp);
if (fopen_s(&fp, "dev/kc/eeprom.bin", "wb")) {
if (fopen_s(&fp, MiceIpcRelativePath("keychip\\eeprom.bin"), "wb")) {
log_error(plfMxParallel, "Failed to open eeprom.bin");
return;
}
fwrite(eeprom, 1, sizeof eeprom, fp);
fclose(fp);
if (fopen_s(&fp, "dev/kc/flash.bin", "wb")) {
if (fopen_s(&fp, MiceIpcRelativePath("keychip\\flash.bin"), "wb")) {
log_error(plfMxParallel, "Failed to open flash.bin");
return;
}

View File

@ -1,5 +1,5 @@
#include "../hooks/setupapi_.h"
#include "../lib/dmi/dmi.h"
#include "../../lib/mice/dmi.h"
#include "mx.h"
#include "smbus.h"

View File

@ -2,8 +2,8 @@
#include "../../maiBackupStructs.h"
#include "mx.h"
#define SRAM_PATH L"dev/sram.bin"
#define SRAM_SIZE 1024 * 2084
// The size of RingEdge[2], which is larger than RingWide needs
#define SRAM_SIZE_MAX 1024 * 2084
LPBYTE SRAM_DATA = NULL;
HANDLE SRAM_FILE = INVALID_HANDLE_VALUE;
HANDLE SRAM_FILE_MAPPING = INVALID_HANDLE_VALUE;
@ -20,9 +20,9 @@ HANDLE SRAM_FILE_MAPPING = INVALID_HANDLE_VALUE;
} while (0)
void build_sram() {
log_info(plfMxSram, "Building default SRAM file");
log_warning(plfMxSram, "Building default SRAM file");
memset(SRAM_DATA, 0xff, SRAM_SIZE);
memset(SRAM_DATA, 0xff, SRAM_SIZE_MAX);
// TODO: Do we want to re-enable this with actual values
#if false
@ -52,12 +52,12 @@ void build_sram() {
void ensure_valid_sram() {
if (!SRAM_DATA) {
BOOL isNew = !FileExists(SRAM_PATH);
BOOL isNew = !FileExistsA(SRAM_PATH);
SRAM_DATA = open_mapped_file(SRAM_PATH, SRAM_SIZE, &SRAM_FILE, &SRAM_FILE_MAPPING);
SRAM_DATA = open_mapped_file(SRAM_PATH, SRAM_SIZE_MAX, &SRAM_FILE, &SRAM_FILE_MAPPING);
if (SRAM_DATA == NULL) {
log_error(plfMxSram, "SRAM will be memory-backed and not syncronised!");
SRAM_DATA = malloc(SRAM_SIZE);
SRAM_DATA = malloc(SRAM_SIZE_MAX);
}
if (isNew) build_sram();
@ -68,7 +68,7 @@ BOOL WINAPI mxsram_DeviceIoControl(file_context_t* ctx, DWORD dwIoControlCode, L
DWORD nInBufferSize, LPVOID lpOutBuffer, DWORD nOutBufferSize,
LPDWORD lpBytesReturned, LPOVERLAPPED lpOverlapped) {
DWORD SRAM_VERSION = 0x01000001;
DWORD SRAM_SECTOR_SIZE = 4; // Max is 0x800
DWORD SRAM_SECTOR_SIZE = MiceConfig.sysconf.platform == MICE_PLATFORM_RINGEDGE2 ? 4 : 512;
switch (dwIoControlCode) {
case IOCTL_MXSRAM_PING: // Get version
@ -88,6 +88,8 @@ BOOL WINAPI mxsram_DeviceIoControl(file_context_t* ctx, DWORD dwIoControlCode, L
PDISK_GEOMETRY out = (PDISK_GEOMETRY)lpOutBuffer;
memset(out, 0, sizeof *out);
// I'm unsure how these values change specifically for RW, RE1, RE2
// I'm also unsure (ie highly doubtful) it truly matters.
out->Cylinders.QuadPart = 256;
out->MediaType = FixedMedia;
out->TracksPerCylinder = 2;
@ -119,8 +121,8 @@ BOOL mxsram_WriteFile(file_context_t* ctx, LPCVOID lpBuffer, DWORD nNumberOfByte
LPDWORD lpNumberOfBytesWritten, LPOVERLAPPED lpOverlapped) {
log_misc(plfMxSram, "sram write 0x%04x bytes at 0x%04x", nNumberOfBytesToWrite,
ctx->m_Pointer.LowPart);
if (ctx->m_Pointer.LowPart + nNumberOfBytesToWrite >= SRAM_SIZE) {
nNumberOfBytesToWrite = SRAM_SIZE - ctx->m_Pointer.LowPart;
if (ctx->m_Pointer.LowPart + nNumberOfBytesToWrite >= SRAM_SIZE_MAX) {
nNumberOfBytesToWrite = SRAM_SIZE_MAX - ctx->m_Pointer.LowPart;
}
ensure_valid_sram();
memcpy(SRAM_DATA + ctx->m_Pointer.LowPart, lpBuffer, nNumberOfBytesToWrite);
@ -132,8 +134,8 @@ BOOL mxsram_ReadFile(file_context_t* ctx, LPVOID lpBuffer, DWORD nNumberOfBytesT
LPDWORD lpNumberOfBytesRead, LPOVERLAPPED lpOverlapped) {
log_misc(plfMxSram, "sram read 0x%04x bytes at 0x%04x", nNumberOfBytesToRead,
ctx->m_Pointer.LowPart);
if (ctx->m_Pointer.LowPart + nNumberOfBytesToRead >= SRAM_SIZE) {
nNumberOfBytesToRead = SRAM_SIZE - ctx->m_Pointer.LowPart;
if (ctx->m_Pointer.LowPart + nNumberOfBytesToRead >= SRAM_SIZE_MAX) {
nNumberOfBytesToRead = SRAM_SIZE_MAX - ctx->m_Pointer.LowPart;
}
ensure_valid_sram();
memcpy((LPVOID)lpBuffer, SRAM_DATA + ctx->m_Pointer.LowPart, nNumberOfBytesToRead);

View File

@ -1,14 +1,166 @@
#include "common.h"
#include "devices/_devices.h"
#include "drivers/jvs_boards/jvs.h"
#include "input.h"
#include "key_config.h"
#define IS_GAME(match) (strncmp(game_id, #match, 4) == 0)
void mice_got_game_id(char game_id[4]) {
static char last_game_id[4] = { '_', '_', '_', '_' };
MICE_BUTTON_BINDING maimaiDefaultBindings[31] = {
// Coins
{ .m_Type = MICE_BB_TYPE_GET_ASYNC_KEY, .m_Invert = FALSE, .m_AsyncKey.m_Key = '1' },
{ .m_Type = MICE_BB_TYPE_GET_ASYNC_KEY, .m_Invert = FALSE, .m_AsyncKey.m_Key = '2' },
// Test
{ .m_Type = MICE_BB_TYPE_UNBOUND },
// 1P
{ .m_Type = MICE_BB_TYPE_UNBOUND },
{ .m_Type = MICE_BB_TYPE_UNBOUND },
{ .m_Type = MICE_BB_TYPE_UNBOUND },
{ .m_Type = MICE_BB_TYPE_UNBOUND },
{ .m_Type = MICE_BB_TYPE_GET_ASYNC_KEY, .m_Invert = TRUE, .m_AsyncKey.m_Key = 'E' },
{ .m_Type = MICE_BB_TYPE_GET_ASYNC_KEY, .m_Invert = TRUE, .m_AsyncKey.m_Key = 'W' },
{ .m_Type = MICE_BB_TYPE_UNBOUND },
{ .m_Type = MICE_BB_TYPE_GET_ASYNC_KEY, .m_Invert = TRUE, .m_AsyncKey.m_Key = 'D' },
{ .m_Type = MICE_BB_TYPE_GET_ASYNC_KEY, .m_Invert = TRUE, .m_AsyncKey.m_Key = 'C' },
{ .m_Type = MICE_BB_TYPE_GET_ASYNC_KEY, .m_Invert = TRUE, .m_AsyncKey.m_Key = 'X' },
{ .m_Type = MICE_BB_TYPE_GET_ASYNC_KEY, .m_Invert = TRUE, .m_AsyncKey.m_Key = 'Z' },
{ .m_Type = MICE_BB_TYPE_GET_ASYNC_KEY, .m_Invert = TRUE, .m_AsyncKey.m_Key = 'A' },
{ .m_Type = MICE_BB_TYPE_GET_ASYNC_KEY, .m_Invert = TRUE, .m_AsyncKey.m_Key = 'Q' },
{ .m_Type = MICE_BB_TYPE_UNBOUND },
// 2P
{ .m_Type = MICE_BB_TYPE_UNBOUND },
{ .m_Type = MICE_BB_TYPE_UNBOUND },
{ .m_Type = MICE_BB_TYPE_UNBOUND },
{ .m_Type = MICE_BB_TYPE_UNBOUND },
{ .m_Type = MICE_BB_TYPE_GET_ASYNC_KEY, .m_Invert = TRUE, .m_AsyncKey.m_Key = VK_NUMPAD9 },
{ .m_Type = MICE_BB_TYPE_GET_ASYNC_KEY, .m_Invert = TRUE, .m_AsyncKey.m_Key = VK_NUMPAD8 },
{ .m_Type = MICE_BB_TYPE_UNBOUND },
{ .m_Type = MICE_BB_TYPE_GET_ASYNC_KEY, .m_Invert = TRUE, .m_AsyncKey.m_Key = VK_NUMPAD6 },
{ .m_Type = MICE_BB_TYPE_GET_ASYNC_KEY, .m_Invert = TRUE, .m_AsyncKey.m_Key = VK_NUMPAD3 },
{ .m_Type = MICE_BB_TYPE_GET_ASYNC_KEY, .m_Invert = TRUE, .m_AsyncKey.m_Key = VK_NUMPAD2 },
{ .m_Type = MICE_BB_TYPE_GET_ASYNC_KEY, .m_Invert = TRUE, .m_AsyncKey.m_Key = VK_NUMPAD1 },
{ .m_Type = MICE_BB_TYPE_GET_ASYNC_KEY, .m_Invert = TRUE, .m_AsyncKey.m_Key = VK_NUMPAD4 },
{ .m_Type = MICE_BB_TYPE_GET_ASYNC_KEY, .m_Invert = TRUE, .m_AsyncKey.m_Key = VK_NUMPAD7 },
{ .m_Type = MICE_BB_TYPE_UNBOUND },
};
MICE_BUTTON_BINDING apmDefaultBindings[31] = {
// Coins
{ .m_Type = MICE_BB_TYPE_GET_ASYNC_KEY, .m_Invert = FALSE, .m_AsyncKey.m_Key = VK_F1 },
{ .m_Type = MICE_BB_TYPE_GET_ASYNC_KEY, .m_Invert = FALSE, .m_AsyncKey.m_Key = VK_F2 },
// Test
{ .m_Type = MICE_BB_TYPE_UNBOUND },
// 1P
{ .m_Type = MICE_BB_TYPE_GET_ASYNC_KEY, .m_Invert = FALSE, .m_AsyncKey.m_Key = VK_RETURN },
{ .m_Type = MICE_BB_TYPE_GET_ASYNC_KEY, .m_Invert = FALSE, .m_AsyncKey.m_Key = '*' },
{ .m_Type = MICE_BB_TYPE_GET_ASYNC_KEY, .m_Invert = FALSE, .m_AsyncKey.m_Key = VK_UP },
{ .m_Type = MICE_BB_TYPE_GET_ASYNC_KEY, .m_Invert = FALSE, .m_AsyncKey.m_Key = VK_DOWN },
{ .m_Type = MICE_BB_TYPE_GET_ASYNC_KEY, .m_Invert = FALSE, .m_AsyncKey.m_Key = VK_LEFT },
{ .m_Type = MICE_BB_TYPE_GET_ASYNC_KEY, .m_Invert = FALSE, .m_AsyncKey.m_Key = VK_RIGHT },
{ .m_Type = MICE_BB_TYPE_GET_ASYNC_KEY,
.m_Invert = FALSE,
.m_AsyncKey.m_Key = '1' }, // 1P Light
{ .m_Type = MICE_BB_TYPE_GET_ASYNC_KEY,
.m_Invert = FALSE,
.m_AsyncKey.m_Key = '2' }, // 1P Middle
{ .m_Type = MICE_BB_TYPE_GET_ASYNC_KEY,
.m_Invert = FALSE,
.m_AsyncKey.m_Key = '3' }, // 1P Heavy
{ .m_Type = MICE_BB_TYPE_GET_ASYNC_KEY, .m_Invert = FALSE, .m_AsyncKey.m_Key = '4' }, // 1P Exs
{ .m_Type = MICE_BB_TYPE_GET_ASYNC_KEY, .m_Invert = FALSE, .m_AsyncKey.m_Key = '5' },
{ .m_Type = MICE_BB_TYPE_GET_ASYNC_KEY, .m_Invert = FALSE, .m_AsyncKey.m_Key = '6' },
{ .m_Type = MICE_BB_TYPE_GET_ASYNC_KEY,
.m_Invert = FALSE,
.m_AsyncKey.m_Key = MICE_BB_TYPE_UNBOUND },
{ .m_Type = MICE_BB_TYPE_GET_ASYNC_KEY,
.m_Invert = FALSE,
.m_AsyncKey.m_Key = MICE_BB_TYPE_UNBOUND },
if (memcmp(game_id, last_game_id, 4) == 0) return;
memcpy(last_game_id, game_id, 4);
{ .m_Type = MICE_BB_TYPE_GET_ASYNC_KEY, .m_Invert = FALSE, .m_AsyncKey.m_Key = VK_BACK },
{ .m_Type = MICE_BB_TYPE_GET_ASYNC_KEY, .m_Invert = FALSE, .m_AsyncKey.m_Key = '-' },
{ .m_Type = MICE_BB_TYPE_GET_ASYNC_KEY, .m_Invert = FALSE, .m_AsyncKey.m_Key = VK_NUMPAD8 },
{ .m_Type = MICE_BB_TYPE_GET_ASYNC_KEY, .m_Invert = FALSE, .m_AsyncKey.m_Key = VK_NUMPAD2 },
{ .m_Type = MICE_BB_TYPE_GET_ASYNC_KEY, .m_Invert = FALSE, .m_AsyncKey.m_Key = VK_NUMPAD4 },
{ .m_Type = MICE_BB_TYPE_GET_ASYNC_KEY, .m_Invert = FALSE, .m_AsyncKey.m_Key = VK_NUMPAD6 },
{ .m_Type = MICE_BB_TYPE_GET_ASYNC_KEY, .m_Invert = FALSE, .m_AsyncKey.m_Key = 'Q' },
{ .m_Type = MICE_BB_TYPE_GET_ASYNC_KEY, .m_Invert = FALSE, .m_AsyncKey.m_Key = 'W' },
{ .m_Type = MICE_BB_TYPE_GET_ASYNC_KEY, .m_Invert = FALSE, .m_AsyncKey.m_Key = 'E' },
{ .m_Type = MICE_BB_TYPE_GET_ASYNC_KEY, .m_Invert = FALSE, .m_AsyncKey.m_Key = 'R' },
{ .m_Type = MICE_BB_TYPE_GET_ASYNC_KEY, .m_Invert = FALSE, .m_AsyncKey.m_Key = 'T' },
{ .m_Type = MICE_BB_TYPE_GET_ASYNC_KEY, .m_Invert = FALSE, .m_AsyncKey.m_Key = 'Y' },
{ .m_Type = MICE_BB_TYPE_GET_ASYNC_KEY,
.m_Invert = FALSE,
.m_AsyncKey.m_Key = MICE_BB_TYPE_UNBOUND },
{ .m_Type = MICE_BB_TYPE_GET_ASYNC_KEY,
.m_Invert = FALSE,
.m_AsyncKey.m_Key = MICE_BB_TYPE_UNBOUND },
};
void _MiceSetupMaimai() {
MiceConfig.devices.com1 = "";
MiceConfig.devices.com2 = "aime_tn32msec";
MiceConfig.devices.com3 = "maitouch";
MiceConfig.devices.com5 = "";
MiceConfig.devices.com6 = "mailed";
MiceConfig.devices.com7 = "";
MiceConfig.devices.com8 = "mailed";
// Maimai is going to keep checking COM5 and COM7; we don't care.
MiceConfig.devices.add_idlers = false;
MiceConfig.sysconf.dipsw = 0b01111000;
MiceConfig.window.nosize = true;
if (MiceConfig.keys.board_count == 0) MiceConfig.keys.board_count = 1;
free(_MiceJvsBoards[0].m_Bindings);
_MiceJvsBoards[0].m_Bindings = malloc(sizeof maimaiDefaultBindings);
memcpy(_MiceJvsBoards[0].m_Bindings, maimaiDefaultBindings, sizeof maimaiDefaultBindings);
_MiceJvsBoards[0].m_NumButtons = _countof(maimaiDefaultBindings);
_MiceJvsBoards[0].m_Coins = 2;
_MiceJvsBoards[0].m_Players = 2;
_MiceJvsBoards[0].m_ButtonsPerPlayer = 14;
free(_MiceJvsBoards[0].m_ButtonStates);
_MiceJvsBoards[0].m_ButtonStates =
malloc(_countof(maimaiDefaultBindings) * sizeof *_MiceJvsBoards[0].m_ButtonStates);
// Maimai is going to check if these exist. They do, now.
make_dirs(MiceIpcRelativePath("dev\\w\\maimai"));
make_dirs(MiceIpcRelativePath("dev\\v\\maimai"));
make_dirs(MiceIpcRelativePath("dev\\y\\maimai_deliver\\maimai"));
}
void _MiceSetupApm() {
MiceConfig.devices.com1 = "";
MiceConfig.devices.com2 = "";
MiceConfig.devices.com3 = "";
MiceConfig.devices.com5 = "";
MiceConfig.devices.com6 = "";
MiceConfig.devices.com7 = "";
MiceConfig.devices.com8 = "";
MiceConfig.sysconf.dipsw = 0b01000000; // 720p
if (MiceConfig.keys.board_count == 0) MiceConfig.keys.board_count = 1;
free(_MiceJvsBoards[0].m_Bindings);
_MiceJvsBoards[0].m_Bindings = malloc(sizeof apmDefaultBindings);
memcpy(_MiceJvsBoards[0].m_Bindings, apmDefaultBindings, sizeof apmDefaultBindings);
_MiceJvsBoards[0].m_NumButtons = _countof(apmDefaultBindings);
_MiceJvsBoards[0].m_Coins = 2;
_MiceJvsBoards[0].m_Players = 2;
_MiceJvsBoards[0].m_ButtonsPerPlayer = 14;
free(_MiceJvsBoards[0].m_ButtonStates);
_MiceJvsBoards[0].m_ButtonStates =
malloc(_countof(apmDefaultBindings) * sizeof *_MiceJvsBoards[0].m_ButtonStates);
}
void _MiceGotGameId(char game_id[4]) {
static bool gotGameId = false;
if (gotGameId) return;
if (game_id[0] != 'S') return;
if (game_id[1] < 'A' || game_id[1] > 'Z') return;
if (game_id[2] < 'A' || game_id[2] > 'Z') return;
if (game_id[3] < 'A' || game_id[3] > 'Z') return;
gotGameId = true;
if (!MiceConfig.devices.do_auto) return;
@ -18,79 +170,47 @@ void mice_got_game_id(char game_id[4]) {
IS_GAME(SDDZ /* maimai MiLK [PLUS] */) || IS_GAME(SDEY /* maimai FiNALE */) ||
IS_GAME(SBYC /* maimai china */)) {
log_info(plfBoot, "Detect game MaiMai");
MiceConfig.devices.com1 = "";
MiceConfig.devices.com2 = "aime_tn32msec";
MiceConfig.devices.com3 = "maitouch";
MiceConfig.devices.com5 = "";
MiceConfig.devices.com6 = "mailed";
MiceConfig.devices.com7 = "";
MiceConfig.devices.com8 = "mailed";
if (MiceConfig.keys.board_count == 0) MiceConfig.keys.board_count = 1;
if (!jvsKeybindings[0].notdefault) {
// Zero and invert all buttons
memset(&jvsKeybindings[0].buttons[3 * 2], 0, 12 * 2);
memset(&jvsKeybindings[0].invert[3 * 2], 1, 12 * 2);
// Setup default keybinds
jvsKeybindings[0].buttons[6 * 2] = 'A'; // 1P1
jvsKeybindings[0].buttons[5 * 2] = 'Q'; // 1P2
jvsKeybindings[0].buttons[8 * 2] = 'W'; // 1P3
jvsKeybindings[0].buttons[9 * 2] = 'E'; // 1P4
jvsKeybindings[0].buttons[10 * 2] = 'D'; // 1P5
jvsKeybindings[0].buttons[11 * 2] = 'C'; // 1P6
jvsKeybindings[0].buttons[12 * 2] = 'X'; // 1P7
jvsKeybindings[0].buttons[13 * 2] = 'Z'; // 1P8
jvsKeybindings[0].buttons[6 * 2 + 1] = VK_NUMPAD4; // 2P1
jvsKeybindings[0].buttons[5 * 2 + 1] = VK_NUMPAD7; // 2P2
jvsKeybindings[0].buttons[8 * 2 + 1] = VK_NUMPAD8; // 2P3
jvsKeybindings[0].buttons[9 * 2 + 1] = VK_NUMPAD9; // 2P4
jvsKeybindings[0].buttons[10 * 2 + 1] = VK_NUMPAD6; // 2P5
jvsKeybindings[0].buttons[11 * 2 + 1] = VK_NUMPAD3; // 2P6
jvsKeybindings[0].buttons[12 * 2 + 1] = VK_NUMPAD2; // 2P7
jvsKeybindings[0].buttons[13 * 2 + 1] = VK_NUMPAD1; // 2P8
}
} else if (IS_GAME(SBYG /* APM2 */)) {
_MiceSetupMaimai();
} else if (IS_GAME(SBYG /* APM2 */) || IS_GAME(SDCM /* UNIB */)) {
log_info(plfBoot, "Detect game APM2");
MiceConfig.devices.com1 = "";
MiceConfig.devices.com2 = "";
MiceConfig.devices.com3 = "";
MiceConfig.devices.com5 = "";
MiceConfig.devices.com6 = "";
MiceConfig.devices.com7 = "";
MiceConfig.devices.com8 = "";
_MiceSetupApm();
if (MiceConfig.keys.board_count == 0) MiceConfig.keys.board_count = 1;
// MiceConfig.devices.com1 = "";
// MiceConfig.devices.com2 = "";
// MiceConfig.devices.com3 = "";
// MiceConfig.devices.com5 = "";
// MiceConfig.devices.com6 = "";
// MiceConfig.devices.com7 = "";
// MiceConfig.devices.com8 = "";
if (!jvsKeybindings[0].notdefault) {
puts("!!");
// if (MiceConfig.keys.board_count == 0) MiceConfig.keys.board_count = 1;
// Zero all buttons
memset(&jvsKeybindings[0].buttons[3 * 2], 0, 12 * 2);
memset(&jvsKeybindings[0].invert[3 * 2], 0, 12 * 2);
// if (!jvsKeybindings[0].notdefault) {
// puts("!!");
jvsKeybindings[0].buttons[0 * 2] = VK_BACK;
jvsKeybindings[0].buttons[1 * 2] = VK_RETURN;
// // Zero all buttons
// memset(&jvsKeybindings[0].buttons[3 * 2], 0, 12 * 2);
// memset(&jvsKeybindings[0].invert[3 * 2], 0, 12 * 2);
jvsKeybindings[0].buttons[3 * 2] = VK_UP;
jvsKeybindings[0].buttons[4 * 2] = VK_DOWN;
jvsKeybindings[0].buttons[5 * 2] = VK_LEFT;
jvsKeybindings[0].buttons[6 * 2] = VK_RIGHT;
// jvsKeybindings[0].buttons[0 * 2] = VK_BACK;
// jvsKeybindings[0].buttons[1 * 2] = VK_RETURN;
jvsKeybindings[0].buttons[7 * 2] = 'Q';
jvsKeybindings[0].buttons[8 * 2] = 'W';
jvsKeybindings[0].buttons[9 * 2] = 'E';
jvsKeybindings[0].buttons[10 * 2] = 'A';
jvsKeybindings[0].buttons[11 * 2] = 'S';
jvsKeybindings[0].buttons[12 * 2] = 'D';
// jvsKeybindings[0].buttons[3 * 2] = VK_UP;
// jvsKeybindings[0].buttons[4 * 2] = VK_DOWN;
// jvsKeybindings[0].buttons[5 * 2] = VK_LEFT;
// jvsKeybindings[0].buttons[6 * 2] = VK_RIGHT;
// 2P is unbound by default, as a (nice) keymap with both
// will probably also involve changing 1P too.
}
// jvsKeybindings[0].buttons[7 * 2] = 'Q';
// jvsKeybindings[0].buttons[8 * 2] = 'W';
// jvsKeybindings[0].buttons[9 * 2] = 'E';
// jvsKeybindings[0].buttons[10 * 2] = 'A';
// jvsKeybindings[0].buttons[11 * 2] = 'S';
// jvsKeybindings[0].buttons[12 * 2] = 'D';
// // 2P is unbound by default, as a (nice) keymap with both
// // will probably also involve changing 1P too.
// }
} else if (IS_GAME(SBVH /* Sega & Sonic All-Stars Racing Arcade */)) {
log_info(plfBoot, "Detect game Sega & Sonic All-Stars Racing Arcade");
@ -101,6 +221,15 @@ void mice_got_game_id(char game_id[4]) {
MiceConfig.devices.com6 = "";
MiceConfig.devices.com7 = "";
MiceConfig.devices.com8 = "";
} else if (IS_GAME(SBWU)) {
log_info(plfBoot, "Detect game Gacchu Guts");
MiceConfig.devices.com1 = "gacchu_guts_card";
MiceConfig.devices.com2 = "gacchu_guts_screen";
MiceConfig.devices.com3 = "gacchu_guts_screen";
MiceConfig.devices.com5 = "";
MiceConfig.devices.com6 = "";
MiceConfig.devices.com7 = "";
MiceConfig.devices.com8 = "";
} else {
if (game_id[0] != '\0') {
log_warning(plfBoot, "Unknown game ID: %.4s", game_id);
@ -109,6 +238,8 @@ void mice_got_game_id(char game_id[4]) {
return;
}
save_current_config();
MiceConfig.devices.do_auto = false;
save_current_config(true);
start_devices();
}

View File

@ -3,6 +3,7 @@
#define CIMGUI_DEFINE_ENUMS_AND_STRUCTS
#endif
#include "../devices/smb_at24c64an.h"
#include "../drivers/jvs_boards/jvs.h"
#include "../key_config.h"
#include "cimgui.h"
#include "imgui/backends/GL/freeglut.h"
@ -15,15 +16,20 @@ const ImVec4 DISABLED_COL = { .7f, .7f, .7f, 1.0f };
const ImVec4 WARN_COL = { 1.0f, 1.0f, .1f, 1.0f };
const ImVec4 DANGER_COL = { 1.0f, .1f, .1f, 1.0f };
struct {
typedef struct JVS_BUTTON_NAME {
const char* name;
int index;
int pinNum;
} JVS_BUTTON_NAMES[JVS_BUTTON_PAIR_COUNT] = {
} JVS_BUTTON_NAME, *PJVS_BUTTON_NAME;
JVS_BUTTON_NAME JVS_BUTTON_NAMES[JVS_BUTTON_PAIR_COUNT] = {
{ "Coin", 45 }, { "Start", 17 }, { "Service", 41 }, { "UP", 23 }, { "DOWN", 25 },
{ "LEFT", 21 }, { "RIGHT", 19 }, { "Push 1", 27 }, { "Push 2", 29 }, { "Push 3", 31 },
{ "Push 4", 33 }, { "Push 5", 35 }, { "Push 6", 37 }, { "Push 7", 39 }, { "Push 8", 47 },
};
JVS_BUTTON_NAME JVS_BUTTON_NAMES_MAIMAI[14] = {
{ "Coin" }, { "Button 1" }, { "Button 2" }, { "Button 3" }, { "Button 4" },
{ "Button 5" }, { "Button 6" }, { "Button 7" }, { "Button 8" },
};
const char* RESOLUTION_NAMES[] = {
"Unspecified", "640x480", "1024x600", "1024x768",
@ -176,11 +182,10 @@ void hud_eeprom(ImGuiKey open_key) {
if (igIsKeyPressed_Bool(open_key, false)) showEeprom = !showEeprom;
// TODO: Less hacky :)
extern BYTE EEPROM_DATA[0x2000];
extern LPBYTE EEPROM_DATA;
editor.Open = showEeprom;
if (showEeprom)
MemoryEditor_DrawWindow(&editor, "EEPROM Editor", EEPROM_DATA, sizeof EEPROM_DATA, 0x000);
if (showEeprom) MemoryEditor_DrawWindow(&editor, "EEPROM Editor", EEPROM_DATA, 0x2000, 0x000);
}
void hud_sram(ImGuiKey open_key) {
static MemoryEditor editor;
@ -239,7 +244,7 @@ bool AddSettingBool(const char* name, const char* help, bool* value) {
igNextColumn();
igPopID();
if (changed) save_current_config();
if (changed) save_current_config(false);
return changed;
}
@ -257,7 +262,7 @@ bool AddSettingString(const char* name, const char* help, char** value) {
int newLen = strlen(buffer) + 1;
*value = realloc(*value, newLen);
memcpy(*value, buffer, newLen);
save_current_config();
save_current_config(false);
}
igNextColumn();
@ -283,7 +288,7 @@ bool AddSettingIPv4(const char* name, const char* help, unsigned int* value) {
if (sscanf(buffer, "%hhu.%hhu.%hhu.%hhu%n", &a, &b, &c, &d, &n) == 4 &&
n == strlen(buffer)) {
*value = (a << 24) | (b << 16) | (c << 8) | d;
save_current_config();
save_current_config(false);
} else {
changed = false;
}
@ -349,6 +354,8 @@ bool igDipsw(const char* label, bool* value) {
return pressed;
}
#define SERIAL_HELP \
"This value was automatically generated for you and uniquely identifies your computer"
void tab_settings_system() {
igColumns(2, "SettingsSystem", true);
igTextUnformatted("Name", NULL);
@ -374,7 +381,7 @@ void tab_settings_system() {
if (igRadioButton_Bool("##JPN", MiceConfig.sysconf.region == 1)) {
MiceConfig.sysconf.region = 1;
staticChanged = true;
save_current_config();
save_current_config(false);
}
igSameLine(0.0, -1.0);
igSeparatorEx(ImGuiSeparatorFlags_Vertical);
@ -384,7 +391,7 @@ void tab_settings_system() {
if (igRadioButton_Bool("##USA", MiceConfig.sysconf.region == 2)) {
MiceConfig.sysconf.region = 2;
staticChanged = true;
save_current_config();
save_current_config(false);
}
igSameLine(0.0, -1.0);
igSeparatorEx(ImGuiSeparatorFlags_Vertical);
@ -394,7 +401,7 @@ void tab_settings_system() {
if (igRadioButton_Bool("##EXP", MiceConfig.sysconf.region == 4)) {
MiceConfig.sysconf.region = 4;
staticChanged = true;
save_current_config();
save_current_config(false);
}
igSameLine(0.0, -1.0);
igSeparatorEx(ImGuiSeparatorFlags_Vertical);
@ -404,16 +411,29 @@ void tab_settings_system() {
if (igRadioButton_Bool("##", MiceConfig.sysconf.region == 8)) {
MiceConfig.sysconf.region = 8;
staticChanged = true;
save_current_config();
save_current_config(false);
}
igNextColumn();
igPopID();
}
staticChanged |= AddSettingBool("Rental", NULL, &MiceConfig.sysconf.rental);
staticChanged |=
AddSettingString("Serial", "Main board serial number", &MiceConfig.sysconf.serial);
if (staticChanged) build_eeprom();
// The 'M' prefix isn't technically foolproof, but it's good enough for a simple help message
staticChanged |= AddSettingString(
"PCB serial number",
(MiceConfig.sysconf.serial && MiceConfig.sysconf.serial[0] == 'M' ? SERIAL_HELP : NULL),
&MiceConfig.sysconf.serial);
if (staticChanged) {
build_eeprom();
save_current_config(false);
}
if (AddSettingString(
"Keychip serial number",
(MiceConfig.sysconf.keyid && MiceConfig.sysconf.keyid[0] == 'M' ? SERIAL_HELP : NULL),
&MiceConfig.sysconf.keyid)) {
save_current_config(false);
}
igSeparator();
@ -428,7 +448,7 @@ void tab_settings_system() {
vec0)) {
MiceConfig.sysconf.dipsw =
((MiceConfig.sysconf.dipsw & 0b1'000'1111) | (i << 4)) & 0xff;
save_current_config();
save_current_config(false);
}
if (is_selected) igSetItemDefaultFocus();
}
@ -445,7 +465,7 @@ void tab_settings_system() {
vec0)) {
MiceConfig.sysconf.dipsw =
((MiceConfig.sysconf.dipsw & 0b1111'0'111) | (i << 3)) & 0xff;
save_current_config();
save_current_config(false);
}
if (is_selected) igSetItemDefaultFocus();
}
@ -461,7 +481,7 @@ void tab_settings_system() {
if (i != 0) igSameLine(0.0, 2);
if (igDipsw("", &val)) {
MiceConfig.sysconf.dipsw = (MiceConfig.sysconf.dipsw & ~(1 << i)) | (val << i);
save_current_config();
save_current_config(false);
}
igPopID();
}
@ -503,7 +523,7 @@ void tab_settings_window() {
igEndDisabled();
igEndDisabled();
if (changed) save_current_config();
if (changed) save_current_config(false);
igEndColumns();
}
@ -518,6 +538,11 @@ void tab_settings_network() {
igSeparator();
bool networkChanged = false;
networkChanged |=
AddSettingIPv4("Real Upstream DNS",
"When not set to 0.0.0.0, used in place of any system configured servers.",
&MiceConfig.network.upstream_dns_server);
igSeparator();
networkChanged |= AddSettingIPv4("IP Address", NULL, &MiceConfig.network.ip_address);
networkChanged |= AddSettingIPv4("Subnet Mask", NULL, &MiceConfig.network.subnet_mask);
networkChanged |= AddSettingIPv4("Gateway", NULL, &MiceConfig.network.gateway);
@ -538,7 +563,7 @@ void tab_settings_network() {
changed |= AddSettingIPv4("bbrouter.loc", NULL, &MiceConfig.network.bbrouter_loc);
changed |= AddSettingIPv4("mobirouter.loc", NULL, &MiceConfig.network.mobirouter_loc);
changed |= AddSettingIPv4("dslrouter.loc", NULL, &MiceConfig.network.dslrouter_loc);
if (changed) save_current_config();
if (changed) save_current_config(false);
igSeparator();
{
@ -557,7 +582,7 @@ void tab_settings_network() {
NULL, NULL)) {
_snscanf_s(buffer, _countof(buffer), "%02x", &scan);
MiceConfig.network.mac = (MiceConfig.network.mac & 0x00FFFF) | ((scan & 0xff) << 16);
save_current_config();
save_current_config(false);
}
igSameLine(0.0, 0);
igTextUnformatted(":", NULL);
@ -568,7 +593,7 @@ void tab_settings_network() {
NULL, NULL)) {
_snscanf_s(buffer, _countof(buffer), "%02x", &scan);
MiceConfig.network.mac = (MiceConfig.network.mac & 0xFF00FF) | ((scan & 0xff) << 8);
save_current_config();
save_current_config(false);
}
igSameLine(0.0, 0);
igTextUnformatted(":", NULL);
@ -579,7 +604,7 @@ void tab_settings_network() {
NULL, NULL)) {
_snscanf_s(buffer, _countof(buffer), "%02x", &scan);
MiceConfig.network.mac = (MiceConfig.network.mac & 0xFFFF00) | (scan & 0xff);
save_current_config();
save_current_config(false);
}
igPopStyleVar(1);
@ -641,7 +666,7 @@ void tab_settings_adavanced() {
igEndColumns();
if (changed) save_current_config();
if (changed) save_current_config(false);
}
void tab_main_settings() {
@ -691,90 +716,102 @@ bool igKeyBindPopup(const char* name, int* boundKey) {
}
return false;
}
bool igKeyBindPopup_New(const char* name, PMICE_BUTTON_BINDING binding) {
if (igBeginPopupModal(name, NULL, ImGuiWindowFlags_AlwaysAutoResize)) {
igText("Press any button");
if (igButton("Cancel", vec0)) {
igCloseCurrentPopup();
igEndPopup();
return true;
}
void AddSettingButton(int board, int id) {
if (MiceInputGetNewBinding(binding)) {
igCloseCurrentPopup();
igEndPopup();
return true;
}
igEndPopup();
}
return false;
}
void AddSettingButton(PMICE_JVS board, int player, int button) {
char keyName[32];
static int currentlyBinding;
char pinInfo[32];
snprintf(pinInfo, _countof(pinInfo), "CN3, Pins %d/%d", JVS_BUTTON_NAMES[id].pinNum,
JVS_BUTTON_NAMES[id].pinNum + 1);
AddSetting(JVS_BUTTON_NAMES[id].name, pinInfo);
if (jvsKeybindings[board].buttons[id * 2] == 0) {
igTextColored(DISABLED_COL, "None");
} else {
GetKeyNameTextA(MapVirtualKey(jvsKeybindings[board].buttons[id * 2], MAPVK_VK_TO_VSC) << 16,
keyName, _countof(keyName));
igTextUnformatted(keyName, NULL);
int index = player * board->m_ButtonsPerPlayer + button + board->m_Coins + 1;
PMICE_BUTTON_BINDING bind = &(board->m_Bindings[index]);
switch (bind->m_Type) {
case MICE_BB_TYPE_UNBOUND:
igTextColored(DISABLED_COL, "None");
break;
case MICE_BB_TYPE_DI_JOY:
switch (bind->m_DIJoy.m_ButtonMajor) {
case MICE_BUTTON_MAJOR_AXIS:
igTextColored(DISABLED_COL, "Axis");
break;
case MICE_BUTTON_MAJOR_DPAD:
igText("D-Pad %s", bind->m_DIJoy.m_ButtonMinor == MICE_DPAD_UP ? "Up"
: bind->m_DIJoy.m_ButtonMinor == MICE_DPAD_DOWN ? "Down"
: bind->m_DIJoy.m_ButtonMinor == MICE_DPAD_LEFT ? "Left"
: bind->m_DIJoy.m_ButtonMinor == MICE_DPAD_RIGHT ? "Right"
: "??");
break;
case MICE_BUTTON_MAJOR_BUTTON:
igText("Button %d", bind->m_DIJoy.m_ButtonMinor + 1);
break;
}
break;
case MICE_BB_TYPE_GET_ASYNC_KEY:
GetKeyNameTextA(MapVirtualKey(bind->m_AsyncKey.m_Key, MAPVK_VK_TO_VSC) << 16, keyName,
_countof(keyName));
igTextUnformatted(keyName, NULL);
break;
}
igNextColumn();
char name[16];
char name2[16];
char clear[16];
char clear2[16];
char invertName[16];
char invertName2[16];
snprintf(name, _countof(name), "Bind##Bind%d", id);
snprintf(name2, _countof(name2), "Bind##Bind2p%d", id);
snprintf(clear, _countof(clear), "Clear##Bind%d", id);
snprintf(clear2, _countof(clear2), "Clear##Bind2p%d", id);
snprintf(invertName, _countof(invertName), "##Invert%d", id);
snprintf(invertName2, _countof(invertName2), "##Invert2p%d", id);
snprintf(name, _countof(name), "Bind##Bind%d", index);
snprintf(clear, _countof(clear), "Clear##Bind%d", index);
snprintf(invertName, _countof(invertName), "##Invert%d", index);
if (igButton(name, vec0)) {
currentlyBinding = 1;
MiceInputGetNewBinding(NULL);
igOpenPopup_Str(name, ImGuiPopupFlags_None);
}
if (jvsKeybindings[board].buttons[id * 2]) {
if (bind->m_Type != MICE_BB_TYPE_UNBOUND) {
igSameLine(0, -1);
if (igButton(clear, vec0)) {
jvsKeybindings[board].buttons[id * 2] = 0;
save_current_config();
bind->m_Type = MICE_BB_TYPE_UNBOUND;
save_current_config(false);
}
}
igNextColumn();
igBeginDisabled(!jvsKeybindings[board].buttons[id * 2]);
if (igCheckbox(invertName, &jvsKeybindings[board].invert[id * 2])) save_current_config();
igBeginDisabled(bind->m_Type == MICE_BB_TYPE_UNBOUND);
if (igCheckbox(invertName, (bool*)&bind->m_Invert)) save_current_config(false);
igEndDisabled();
igNextColumn();
if (jvsKeybindings[board].buttons[id * 2 + 1] == 0) {
igTextColored(DISABLED_COL, "None");
} else {
GetKeyNameTextA(MapVirtualKey(jvsKeybindings[board].buttons[id * 2 + 1], MAPVK_VK_TO_VSC)
<< 16,
keyName, _countof(keyName));
igTextUnformatted(keyName, NULL);
}
if (igKeyBindPopup_New(name, bind)) save_current_config(false);
}
igNextColumn();
if (igButton(name2, vec0)) {
currentlyBinding = 2;
igOpenPopup_Str(name, ImGuiPopupFlags_None);
}
if (jvsKeybindings[board].buttons[id * 2 + 1]) {
igSameLine(0, -1);
if (igButton(clear2, vec0)) {
jvsKeybindings[board].buttons[id * 2 + 1] = 0;
save_current_config();
void AddButtonsForBoard(PMICE_JVS board) {
for (DWORD button = 0; button < board->m_ButtonsPerPlayer; button++) {
char pinInfo[32];
snprintf(pinInfo, _countof(pinInfo), "CN3, Pins %d/%d", JVS_BUTTON_NAMES[button].pinNum,
JVS_BUTTON_NAMES[button].pinNum + 1);
AddSetting(JVS_BUTTON_NAMES[button].name, pinInfo);
for (DWORD player = 0; player < board->m_Players; player++) {
AddSettingButton(board, player, button);
}
}
igNextColumn();
igBeginDisabled(!jvsKeybindings[board].buttons[id * 2 + 1]);
if (igCheckbox(invertName2, &jvsKeybindings[board].invert[id * 2 + 1])) save_current_config();
igEndDisabled();
igNextColumn();
int boundKey;
if (igKeyBindPopup(name, &boundKey)) {
if (boundKey != -1) {
jvsKeybindings[board].buttons[id * 2 + (currentlyBinding - 1)] = boundKey;
jvsKeybindings[board].notdefault = 1;
save_current_config();
}
currentlyBinding = 0;
}
}
void tab_jvs_board(int num) {
@ -804,7 +841,7 @@ void tab_jvs_board(int num) {
igSeparator();
for (int i = 0; i < _countof(JVS_BUTTON_NAMES); i++) AddSettingButton(num, i);
AddButtonsForBoard(&_MiceJvsBoards[0]);
igSeparator();
AddSetting("Test", NULL);
@ -822,14 +859,14 @@ void tab_jvs_board(int num) {
igSameLine(0, -1);
if (igButton("Clear##ClearJvsTest", vec0)) {
jvsKeybindings[num].test = 0;
save_current_config();
save_current_config(false);
}
}
int boundKey;
if (igKeyBindPopup("BindJvsTest", &boundKey))
if (boundKey != -1) {
jvsKeybindings[num].test = boundKey;
save_current_config();
save_current_config(false);
}
igEndColumns();
@ -865,14 +902,14 @@ void tab_system_buttons() {
igSameLine(0, -1);
if (igButton("Clear##ClearTest", vec0)) {
MiceConfig.keys.test = 0;
save_current_config();
save_current_config(false);
}
}
igNextColumn();
if (igKeyBindPopup("BindSysTest", &boundKey))
if (boundKey != -1) {
MiceConfig.keys.test = boundKey;
save_current_config();
save_current_config(false);
}
igTextUnformatted("System Service", NULL);
@ -891,14 +928,14 @@ void tab_system_buttons() {
igSameLine(0, -1);
if (igButton("Clear##ClearService", vec0)) {
MiceConfig.keys.service = 0;
save_current_config();
save_current_config(false);
}
}
igNextColumn();
if (igKeyBindPopup("BindSysService", &boundKey))
if (boundKey != -1) {
MiceConfig.keys.service = boundKey;
save_current_config();
save_current_config(false);
}
}
@ -907,7 +944,7 @@ void tab_main_keybinds() {
ImGuiInputTextFlags_None)) {
if (MiceConfig.keys.board_count < 0) MiceConfig.keys.board_count = 0;
if (MiceConfig.keys.board_count > JVS_IO_MAX) MiceConfig.keys.board_count = JVS_IO_MAX;
save_current_config();
save_current_config(false);
}
if (igBeginTabBar("JVSBoards", 0)) {
@ -929,7 +966,8 @@ void tab_main_keybinds() {
void tab_main_aime_cards() {
igText(
"Specify the cards to be inserted when using the TN32MSEC AiMe reader module.\nCards can be "
"Specify the cards to be inserted when using the TN32MSEC AiMe reader module.\nCards can "
"be "
"specified as either an NFC ID or an access code.\nIf a card file is present, it will be "
"used preferentially.");
@ -944,7 +982,7 @@ void tab_main_aime_cards() {
igEndColumns();
if (changed) save_current_config();
if (changed) save_current_config(false);
}
void hud_control(ImGuiKey open_key) {

View File

@ -1,47 +1,132 @@
#include "drive.h"
physical_disk_t SSD = {
.m_SerialNumber = 0x00144DB0,
/* ================ BOOT SSD ================ */
// 60GB SSD used by maimai and Project Diva
physical_disk_t SSD_60GB = {
.m_SerialNumber = 0x4d696365,
.m_BusType = BusTypeAta,
.m_BootPartition = 1,
.m_HasSegaboot = TRUE,
.m_BlockSize = BLOCK_SIZE_HDD,
// Number of physical sectors. 59.9885 GiB
.m_TotalSize = 125805015, // = (sum of parts) + (n * 63)
.m_DiskType = DiskType_HardDisk,
.m_IsFormatted = true,
.m_Partitions = {
// 1.5GB boot partition
{ .m_Size = 0x300B85, .m_Filesystem = MBR_FS_NTFS },
// 1.5GB recovery partition
{ .m_Size = 0x300BC4, .m_Filesystem = MBR_FS_NTFS },
},
.m_Extended = {
// 512MB OS update
{ 0x102d83, MBR_FS_FAT16, SPD_OS, .m_ReadFunc = &ReadFunc_OSLogFiles, .m_WriteFunc = &WriteFunc_OS },
// 2GB patch0
{ 0x403947, MBR_FS_FAT16, SPD_Patch0, .m_ReadFunc = &ReadFunc_Patch0, .m_WriteFunc = &WriteFunc_Patch0 },
// 2GB patch1
{ 0x403947, MBR_FS_FAT16, SPD_Patch1, .m_ReadFunc = NULL },
// 40GB appdata
{ 0x48ed459, MBR_FS_NTFS, SPD_AppData, .m_ReadFunc = NULL },
// 16GB original0
{ 0x20014aa, MBR_FS_FAT16, SPD_Original0, .m_ReadFunc = &ReadFunc_Original0, .m_WriteFunc = &WriteFunc_Original0 },
{ 0 },
},
};
// 30GB SSD used by all other RingEdge and RingEdge2 games
physical_disk_t SSD_30GB = {
.m_SerialNumber = 0x4d696365,
.m_BusType = BusTypeAta,
.m_BootPartition = 1,
.m_HasSegaboot = TRUE,
.m_BlockSize = BLOCK_SIZE_HDD,
// Number of physical sectors. 29.9902 GiB
// TODO: Recapture these images! My numbers miss-match with Nibs', and neither decrypt
// My size: 62894080 (lack 395: Failed reading the last chunk of sectors and gave up)
// Nibs's size: 62894471 (lack 4 : Ignored locked sectors)
// The following number is theorhetical
.m_TotalSize = 62894475, // = (sum of parts) + (n * 63)
.m_DiskType = DiskType_HardDisk,
.m_IsFormatted = true,
.m_Partitions = {
// 1GB boot partition
{ .m_Size = 0x201c84, .m_Filesystem = MBR_FS_NTFS },
// 1GB recovery partition
{ .m_Size = 0x201cc3, .m_Filesystem = MBR_FS_NTFS },
},
.m_Extended = {
// 512MB OS update
{ 0x102d83, MBR_FS_FAT16, SPD_OS, .m_ReadFunc = &ReadFunc_OSLogFiles, .m_WriteFunc = &WriteFunc_OS },
// 2GB patch0
{ 0x403947, MBR_FS_FAT16, SPD_Patch0, .m_ReadFunc = &ReadFunc_Patch0, .m_WriteFunc = &WriteFunc_Patch0 },
// 2GB patch1
{ 0x403947, MBR_FS_FAT16, SPD_Patch1, .m_ReadFunc = NULL },
// 15.5GB appdata
{ 0x1eead23, MBR_FS_NTFS, SPD_AppData, .m_ReadFunc = NULL },
// 8GB original0
{ 0x1002996, MBR_FS_FAT16, SPD_Original0, .m_ReadFunc = &ReadFunc_Original0, .m_WriteFunc = &WriteFunc_Original0 },
{ 0 },
},
};
// 7.5GB SSD used by RingWide games (we're calling that 8GB for naming convenience)
physical_disk_t SSD_8GB = {
.m_SerialNumber = 0x4d696365,
.m_BusType = BusTypeAta,
.m_BootPartition = 1,
.m_HasSegaboot = TRUE,
.m_BlockSize = BLOCK_SIZE_HDD,
// Number of physical sectors. (Allocated) + (Disk slack)
.m_TotalSize = 15711570 + 17070,
.m_DiskType = DiskType_HardDisk,
.m_IsFormatted = true,
.m_Partitions = {
// 1GB boot partition
{ .m_Size = 0x201c84, .m_Filesystem = MBR_FS_NTFS },
// 1GB recovery partition
{ .m_Size = 0x201cc3, .m_Filesystem = MBR_FS_NTFS },
},
.m_Extended = {
// 512MB OS update
{ 0x102d83, MBR_FS_FAT16, SPD_OS, .m_ReadFunc = &ReadFunc_OSLogFiles, .m_WriteFunc = &WriteFunc_OS },
// 1GB patch0
{ 0x1f6041, MBR_FS_FAT16, SPD_Patch0, .m_ReadFunc = &ReadFunc_Patch0, .m_WriteFunc = &WriteFunc_Patch0 },
// 1GB patch1
{ 0x1f6041, MBR_FS_FAT16, SPD_Patch1, .m_ReadFunc = NULL },
// 337MB appdata
{ 0xa8a2c, MBR_FS_NTFS, SPD_AppData, .m_ReadFunc = NULL },
// 2.7GB original0
{ 0x560a60, MBR_FS_FAT16, SPD_Original0, .m_ReadFunc = &ReadFunc_Original0, .m_WriteFunc = &WriteFunc_Original0 },
{ 0 },
},
};
/* ================ EXTRA HDD ================ */
// TODO: Get real sizes for this
physical_disk_t APM_HDD = {
.m_BusType = BusTypeUsb,
.m_HasSegaboot = false,
.m_BlockSize = BLOCK_SIZE_HDD,
.m_TotalSize = 64 * 1024 * 1024 * (1024 / BLOCK_SIZE_HDD),
.m_DiskType = DiskType_HardDisk,
.m_IsFormatted = true,
.m_Partitions = {
// 1.5GB boot partitions
// ~64GB big block
{
.m_Size = 0x300B85,
.m_Filesystem = MBR_FS_NTFS,
},
// 1.5GB recovery partitions
{
.m_Size = 0x300BC4,
.m_Size = 0x801eb80,
.m_Filesystem = MBR_FS_NTFS,
.m_Volume = {
.m_Name = "APM",
.m_MountPoint = 'I', // the APM loader mounts this for us
}
},
},
.m_Extended = {
{ 0x102d83, MBR_FS_FAT16, SPD_OS, .m_ReadFunc = &ReadFunc_OSLogFiles, .m_WriteFunc = &WriteFunc_OS }, // 512MB OS update
{ 0x403947, MBR_FS_FAT16, SPD_Patch0, .m_ReadFunc = &ReadFunc_Patch0, .m_WriteFunc = &WriteFunc_Patch0 }, // 2GB patch0
{ 0x403947, MBR_FS_FAT16, SPD_Patch1, .m_ReadFunc = NULL }, // 2GB patch1
{ 0x48ed459, MBR_FS_NTFS, SPD_AppData, .m_ReadFunc = NULL }, // 40GB something
{
// 16GB partition for the game
// The real value here should be "0x20014aa,"
0x20014aa, // 16GB, FiNALE
// Instead, we're going to just allocate ~8GB, the exact size of SDCQ
// 0xeafc00, // ~8GB. Lol. Lmao.
MBR_FS_FAT16,
SPD_Original0,
.m_ReadFunc = &ReadFunc_Original0,
.m_WriteFunc = &WriteFunc_Original0,
},
{ 0 },
},
.m_Extended = {{ 0 }},
};
/* ================ ASSORTED USBS ================ */
physical_disk_t UPDATE_USB = {
.m_BusType = BusTypeUsb,
.m_VID = "13FE",
@ -124,6 +209,8 @@ physical_disk_t MAI_USB_DONGLE = {
},
.m_Extended = {{ 0 }},
};
/* ================ DVD DRIVES ================ */
physical_disk_t ALPHA_DVD = {
.m_BusType = BusTypeScsi,
.m_DeviceType = DeviceTypeCdRom,
@ -142,35 +229,20 @@ physical_disk_t ALPHA_DVD = {
} },
};
physical_disk_t APM_HDD = {
.m_BusType = BusTypeUsb,
.m_HasSegaboot = false,
.m_BlockSize = BLOCK_SIZE_HDD,
.m_TotalSize = 64 * 1024 * 1024 * (1024 / BLOCK_SIZE_HDD),
.m_DiskType = DiskType_HardDisk,
.m_IsFormatted = true,
.m_Partitions = {
// ~64GB big block
{
.m_Size = 0x801eb80,
.m_Filesystem = MBR_FS_NTFS,
.m_Volume = {
.m_Name = "APM",
.m_MountPoint = 'I', // the APM loader mounts this for us
}
},
},
.m_Extended = {{ 0 }},
};
physical_disk_t* PHYSICAL_DISKS[] = {
&SSD,
// &UPDATE_USB,
// &DOWNLOAD_USB,
// &APM_HDD,
// &MAI_USB_DONGLE,
// &LOG_USB,
// &ALPHA_DVD,
virtual_disk_t AVAILABLE_DISKS[] = {
// IMPORTANT: Only one of these can be selected!
{ &SSD_60GB, "60GB Boot SSD", TRUE },
{ &SSD_30GB, "30GB Boot SSD", FALSE },
{ &SSD_8GB, "7.5GB Boot SSD", FALSE },
// Extra HDD
{ &APM_HDD, "APM Secondary HDD", FALSE },
// USBs
{ &UPDATE_USB, "Game update USB (SEGA_INS)", FALSE },
{ &DOWNLOAD_USB, "Game download USB (SEGA_DL)", FALSE },
{ &LOG_USB, "Debug log USB", FALSE },
{ &MAI_USB_DONGLE, "maimai bootstrap USB", FALSE },
// DVDs
{ &ALPHA_DVD, "Alpha DVD", FALSE },
{ NULL, NULL, FALSE },
};

View File

@ -7,9 +7,10 @@ typedef struct _physical_disk physical_disk_t;
typedef struct _disk_partition disk_partition_t;
typedef struct _disk_volume disk_volume_t;
typedef struct _disk_raw disk_raw_t;
typedef struct _virtual_disk virtual_disk_t;
#define MAX_DISKS 32
extern physical_disk_t* PHYSICAL_DISKS[MAX_DISKS];
extern virtual_disk_t AVAILABLE_DISKS[MAX_DISKS];
typedef BOOL(mice_partition_read_function_t)(DWORD nOffset, LPVOID lpBuffer,
DWORD nNumberOfBytesToRead,
@ -80,3 +81,10 @@ struct _physical_disk {
disk_partition_t m_Partitions[4];
disk_partition_t m_Extended[];
};
struct _virtual_disk {
physical_disk_t* m_Disk;
LPCSTR m_Name;
BOOL m_Installed;
BOOL m_Attached;
};

View File

@ -7,6 +7,8 @@
#include "../../util/_util.h"
#include "../files.h"
static DWORD _AttachedPhysicalDisks = 0;
/*
First 512 bytes of SPD_Original0:
LOADER::LoadBootIDHeader
@ -46,10 +48,17 @@ BYTE Original0BootIDHeader[512] = {
0x2F, 0x99, 0xC8, 0x54, 0xD2, 0xDB, 0x52, 0x49, 0xD6, 0xB6, 0x07, 0x1A, 0xBA, 0x9A, 0x85, 0xBB,
};
physical_disk_t* _GetDisk0() {
for (int i = 0; i < MAX_DISKS; i++) {
if (AVAILABLE_DISKS[i].m_Installed) return AVAILABLE_DISKS[i].m_Disk;
}
return NULL;
}
BOOL ReadFunc_Original0(DWORD nOffset, LPVOID lpBuffer, DWORD nNumberOfBytesToRead,
LPDWORD lpNumberOfBytesRead) {
*lpNumberOfBytesRead = 0;
if (!_PathFileExistsA(ORIGINAL0_PATH)) {
if (!FileExistsA(ORIGINAL0_PATH)) {
log_error(plfDrive, "Failed to open %s (does not exist)", ORIGINAL0_PATH);
return FALSE;
}
@ -60,8 +69,11 @@ BOOL ReadFunc_Original0(DWORD nOffset, LPVOID lpBuffer, DWORD nNumberOfBytesToRe
log_error(plfDrive, "Failed to open %s", ORIGINAL0_PATH);
return FALSE;
}
physical_disk_t* lpSsd = _GetDisk0();
if (lpSsd == NULL) return FALSE;
LARGE_INTEGER seekTo;
seekTo.QuadPart = (LONGLONG)nOffset * (LONGLONG)SSD.m_BlockSize;
seekTo.QuadPart = (LONGLONG)nOffset * (LONGLONG)lpSsd->m_BlockSize;
_SetFilePointerEx(hFile, seekTo, NULL, FILE_BEGIN);
BOOL ret = _ReadFile(hFile, lpBuffer, nNumberOfBytesToRead, lpNumberOfBytesRead, NULL);
if (!ret) log_error(plfDrive, "Failed to read to %s: %03x", ORIGINAL0_PATH, GetLastError());
@ -78,8 +90,11 @@ BOOL WriteFunc_Original0(DWORD nOffset, LPCVOID lpBuffer, DWORD nNumberOfBytesTo
log_error(plfDrive, "Failed to open %s", ORIGINAL0_PATH);
return FALSE;
}
physical_disk_t* lpSsd = _GetDisk0();
if (lpSsd == NULL) return FALSE;
LARGE_INTEGER seekTo;
seekTo.QuadPart = (LONGLONG)nOffset * (LONGLONG)SSD.m_BlockSize;
seekTo.QuadPart = (LONGLONG)nOffset * (LONGLONG)lpSsd->m_BlockSize;
_SetFilePointerEx(hFile, seekTo, NULL, FILE_BEGIN);
BOOL ret = _WriteFile(hFile, lpBuffer, nNumberOfBytesToWrite, lpNumberOfBytesWritten, NULL);
if (!ret) log_error(plfDrive, "Failed to write to %s: %03x", ORIGINAL0_PATH, GetLastError());
@ -90,7 +105,7 @@ BOOL WriteFunc_Original0(DWORD nOffset, LPCVOID lpBuffer, DWORD nNumberOfBytesTo
BOOL ReadFunc_Patch0(DWORD nOffset, LPVOID lpBuffer, DWORD nNumberOfBytesToRead,
LPDWORD lpNumberOfBytesRead) {
*lpNumberOfBytesRead = 0;
if (!_PathFileExistsA(PATCH0_PATH)) {
if (!FileExistsA(PATCH0_PATH)) {
log_error(plfDrive, "Failed to open %s (does not exist)", PATCH0_PATH);
return FALSE;
}
@ -101,8 +116,11 @@ BOOL ReadFunc_Patch0(DWORD nOffset, LPVOID lpBuffer, DWORD nNumberOfBytesToRead,
log_error(plfDrive, "Failed to open %s", PATCH0_PATH);
return FALSE;
}
physical_disk_t* lpSsd = _GetDisk0();
if (lpSsd == NULL) return FALSE;
LARGE_INTEGER seekTo;
seekTo.QuadPart = (LONGLONG)nOffset * (LONGLONG)SSD.m_BlockSize;
seekTo.QuadPart = (LONGLONG)nOffset * (LONGLONG)lpSsd->m_BlockSize;
_SetFilePointerEx(hFile, seekTo, NULL, FILE_BEGIN);
BOOL ret = _ReadFile(hFile, lpBuffer, nNumberOfBytesToRead, lpNumberOfBytesRead, NULL);
if (!ret) log_error(plfDrive, "Failed to read to %s: %03x", PATCH0_PATH, GetLastError());
@ -119,8 +137,11 @@ BOOL WriteFunc_Patch0(DWORD nOffset, LPCVOID lpBuffer, DWORD nNumberOfBytesToWri
log_error(plfDrive, "Failed to open %s", PATCH0_PATH);
return FALSE;
}
physical_disk_t* lpSsd = _GetDisk0();
if (lpSsd == NULL) return FALSE;
LARGE_INTEGER seekTo;
seekTo.QuadPart = (LONGLONG)nOffset * (LONGLONG)SSD.m_BlockSize;
seekTo.QuadPart = (LONGLONG)nOffset * (LONGLONG)lpSsd->m_BlockSize;
_SetFilePointerEx(hFile, seekTo, NULL, FILE_BEGIN);
BOOL ret = _WriteFile(hFile, lpBuffer, nNumberOfBytesToWrite, lpNumberOfBytesWritten, NULL);
if (!ret) log_error(plfDrive, "Failed to write to %s: %03x", PATCH0_PATH, GetLastError());
@ -217,6 +238,7 @@ BOOL WINAPI x_drive_DeviceIoControl(file_context_t* ctx, DWORD dwIoControlCode,
}
}
extern physical_disk_t ALPHA_DVD; // Bit hacky, but good enough for now
BOOL WINAPI q_drive_DeviceIoControl(file_context_t* ctx, DWORD dwIoControlCode, LPVOID lpInBuffer,
DWORD nInBufferSize, LPVOID lpOutBuffer, DWORD nOutBufferSize,
LPDWORD lpBytesReturned, LPOVERLAPPED lpOverlapped) {
@ -379,14 +401,17 @@ disk_volume_t* getVolumeByPath(LPCSTR lpRootPathName, DWORD match) {
return FALSE;
}
for (size_t disk = 0; disk < MAX_DISKS && PHYSICAL_DISKS[disk] != NULL; disk++) {
for (size_t disk = 0; disk < MAX_DISKS && AVAILABLE_DISKS[disk].m_Disk != NULL; disk++) {
if (!AVAILABLE_DISKS[disk].m_Installed) continue;
for (size_t part = 0; part < 4; part++) {
disk_volume_t* volume = &(PHYSICAL_DISKS[disk]->m_Partitions[part].m_Volume);
disk_volume_t* volume = &(AVAILABLE_DISKS[disk].m_Disk->m_Partitions[part].m_Volume);
if (matchVolume(volume, lpRootPathName, match)) return volume;
}
for (size_t part = 0; PHYSICAL_DISKS[disk]->m_Extended[part].m_PartitionNumber; part++) {
disk_volume_t* volume = &(PHYSICAL_DISKS[disk]->m_Extended[part].m_Volume);
for (size_t part = 0; AVAILABLE_DISKS[disk].m_Disk->m_Extended[part].m_PartitionNumber;
part++) {
disk_volume_t* volume = &(AVAILABLE_DISKS[disk].m_Disk->m_Extended[part].m_Volume);
if (matchVolume(volume, lpRootPathName, match)) return volume;
}
}
@ -646,10 +671,41 @@ void init_pd(physical_disk_t* pd) {
hook_file(hook);
}
BOOL attach_disk(virtual_disk_t* lpDisk) {
if (lpDisk->m_Disk->m_DriveNumber != (DWORD)-1) return FALSE;
if (lpDisk->m_Attached) return TRUE;
lpDisk->m_Attached = TRUE;
lpDisk->m_Disk->m_DriveNumber = _AttachedPhysicalDisks++;
lpDisk->m_Disk->m_DeviceName[0] = '\0';
lpDisk->m_Disk->m_DosDeviceName[0] = '\0';
init_pd(lpDisk->m_Disk);
return TRUE;
}
BOOL detach_disk(virtual_disk_t* lpDisk) {
if (lpDisk->m_Disk->m_DriveNumber == (DWORD)-1) return FALSE;
if (!lpDisk->m_Attached) return TRUE;
wchar_t hookPath[21];
swprintf_s(hookPath, _countof(hookPath), L"\\\\.\\%ls", lpDisk->m_Disk->m_DosDeviceName);
file_hook_t* hook = unhook_file(hookPath);
if (hook == NULL) return FALSE;
lpDisk->m_Disk->m_DriveNumber = (DWORD)-1;
lpDisk->m_Attached = FALSE;
free((void*)hook->filename);
free(hook);
return TRUE;
}
void init_all_pd() {
for (int i = 0; i < MAX_DISKS && PHYSICAL_DISKS[i] != NULL; i++) {
PHYSICAL_DISKS[i]->m_DriveNumber = i;
init_pd(PHYSICAL_DISKS[i]);
for (int i = 0; i < MAX_DISKS && AVAILABLE_DISKS[i].m_Disk != NULL; i++) {
AVAILABLE_DISKS[i].m_Disk->m_DriveNumber = (DWORD)-1;
AVAILABLE_DISKS[i].m_Attached = FALSE;
}
for (int i = 0; i < MAX_DISKS && AVAILABLE_DISKS[i].m_Disk != NULL; i++) {
if (AVAILABLE_DISKS[i].m_Installed) attach_disk(&AVAILABLE_DISKS[i]);
}
}
@ -704,11 +760,6 @@ void hook_drives() {
q_drive->DeviceIoControl = &q_drive_DeviceIoControl;
q_drive->ReadFile = &q_drive_ReadFile;
hook_file(q_drive);
// TODO: ewwwwwwwwwwwwwwwwww
file_hook_t* q_drive_lower = new_file_hook(L"\\\\.\\q:");
q_drive_lower->DeviceIoControl = &q_drive_DeviceIoControl;
q_drive_lower->ReadFile = &q_drive_ReadFile;
hook_file(q_drive_lower);
hook("Kernel32.dll", "FindFirstVolumeW", &FakeFindFirstVolumeW, NULL);
hook("Kernel32.dll", "FindNextVolumeW", &FakeFindNextVolumeW, NULL);
@ -734,14 +785,15 @@ void hook_drives() {
hook("Winmm.dll", "mciSendStringA", &Fake_mciSendStringA, NULL);
make_dirs(DISK_PATH);
make_dirs(DISK_PATH));
SegaBootRecordDefault.crc =
amiCrc32RCalc(sizeof SegaBootRecordDefault - 4, &SegaBootRecordDefault.version, 0);
HANDLE hFile;
DWORD numberOfBytesRead;
if (_PathFileExistsA(SBR0_PATH)) {
if (FileExistsA(SBR0_PATH)) {
hFile =
_CreateFileA(SBR0_PATH, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
if (hFile == INVALID_HANDLE_VALUE) {
@ -755,7 +807,7 @@ void hook_drives() {
// memcpy(&SegaBootRecord0, &SegaBootRecordDefault, sizeof SegaBootRecord0);
}
if (_PathFileExistsA(SBR1_PATH)) {
if (FileExistsA(SBR1_PATH)) {
hFile =
_CreateFileA(SBR1_PATH, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
if (hFile == INVALID_HANDLE_VALUE) {

View File

@ -15,17 +15,12 @@
#include "disks.h"
#include "irb.h"
#define DISK_PATH "dev/disk/"
#define SPD_PATH (DISK_PATH "spd.bin")
#define SBR0_PATH (DISK_PATH "sbr0.bin")
#define SBR1_PATH (DISK_PATH "sbr1.bin")
#define ORIGINAL0_PATH (DISK_PATH "original0.bin")
#define PATCH0_PATH (DISK_PATH "patch0.bin")
extern physical_disk_t SSD;
extern physical_disk_t UPDATE_USB;
extern physical_disk_t LOG_USB;
extern physical_disk_t ALPHA_DVD;
#define DISK_PATH MiceIpcRelativePath("disk\\"
#define SPD_PATH DISK_PATH "spd.bin")
#define SBR0_PATH DISK_PATH "sbr0.bin")
#define SBR1_PATH DISK_PATH "sbr1.bin")
#define ORIGINAL0_PATH DISK_PATH "original0.bin")
#define PATCH0_PATH DISK_PATH "patch0.bin")
extern sbr_t SegaBootRecordDefault;
extern sbr_t SegaBootRecord0;
@ -35,6 +30,9 @@ extern sbr_t SegaBootRecord1;
void init_volume(disk_volume_t* vol);
void init_pd(physical_disk_t* pd);
void init_all_pd();
BOOL attach_disk(virtual_disk_t* lpDisk);
BOOL detach_disk(virtual_disk_t* lpDisk);
physical_disk_t* _GetDisk0();
mice_partition_read_function_t ReadFunc_Original0;
mice_partition_write_function_t WriteFunc_Original0;

View File

@ -9,12 +9,17 @@ disk_volume_t* incrementFindIndex(HANDLE hFindVolume) {
if (find_index == NULL) return NULL;
while (1) {
if (find_index->disk >= MAX_DISKS || PHYSICAL_DISKS[find_index->disk] == NULL) {
if (find_index->disk >= MAX_DISKS || AVAILABLE_DISKS[find_index->disk].m_Disk == NULL) {
return NULL;
}
if (!AVAILABLE_DISKS[find_index->disk].m_Installed) {
find_index->disk++;
find_index->partition = 0;
continue;
}
if (find_index->partition > 3) {
if (PHYSICAL_DISKS[find_index->disk]
if (AVAILABLE_DISKS[find_index->disk].m_Disk
->m_Extended[find_index->partition - 4]
.m_PartitionNumber == 0) {
find_index->disk++;
@ -22,18 +27,18 @@ disk_volume_t* incrementFindIndex(HANDLE hFindVolume) {
continue;
}
return &(PHYSICAL_DISKS[find_index->disk]
return &(AVAILABLE_DISKS[find_index->disk].m_Disk
->m_Extended[(find_index->partition++) - 4]
.m_Volume);
}
if (PHYSICAL_DISKS[find_index->disk]
if (AVAILABLE_DISKS[find_index->disk].m_Disk
->m_Partitions[find_index->partition]
.m_PartitionNumber == 0) {
find_index->partition = 4;
continue;
}
return &(PHYSICAL_DISKS[find_index->disk]->m_Partitions[find_index->partition++].m_Volume);
return &(AVAILABLE_DISKS[find_index->disk].m_Disk->m_Partitions[find_index->partition++].m_Volume);
}
}
@ -333,7 +338,7 @@ BOOL WINAPI FakeGetDiskFreeSpaceExA(LPCSTR lpDirectoryName,
// return FALSE;
// }
// We're going to be remapping the drive to ./dev/, so the free bytes are whatever the current
// We're going to be remapping the drive to ./mice/dev/, so the free bytes are whatever the current
// real drive has free. No point claiming we have more than we do!
return TrueGetDiskFreeSpaceExA(NULL, lpFreeBytesAvailableToCaller, lpTotalNumberOfBytes,
lpTotalNumberOfFreeBytes);

View File

@ -72,8 +72,11 @@ BOOL WINAPI pd_DeviceIoControl(file_context_t* ctx, DWORD dwIoControlCode, LPVOI
log_error(plfDrive, "Unimeplemented ATA %02X command: %02x", command, data);
return FALSE;
case IOCTL_DISK_GET_LENGTH_INFO:
physical_disk_t* lpSsd = _GetDisk0();
if (lpSsd == NULL) return FALSE;
PGET_LENGTH_INFORMATION pLi = (PGET_LENGTH_INFORMATION)lpOutBuffer;
pLi->Length.QuadPart = SSD.m_TotalSize * (long long)SSD.m_BlockSize;
pLi->Length.QuadPart = lpSsd->m_TotalSize * (long long)lpSsd->m_BlockSize;
*lpBytesReturned = sizeof *pLi;
return TRUE;
}
@ -81,6 +84,8 @@ BOOL WINAPI pd_DeviceIoControl(file_context_t* ctx, DWORD dwIoControlCode, LPVOI
return FALSE;
}
// TODO: File-backed
BYTE SEGABOOT_DATA_CACHE[512 * 60] = { 0xff };
BOOL pd_ReadFile(file_context_t* ctx, LPVOID lpBuffer, DWORD nNumberOfBytesToRead,
LPDWORD lpNumberOfBytesRead, LPOVERLAPPED lpOverlapped) {
physical_disk_t* pd = (physical_disk_t*)ctx->m_HookData;
@ -126,7 +131,7 @@ BOOL pd_ReadFile(file_context_t* ctx, LPVOID lpBuffer, DWORD nNumberOfBytesToRea
}
if (ptrLBA <= MBR_LBA_GAP) {
// Read within the 63 extra tracks
log_error(plfDrive, "Read failed");
log_error(plfDrive, "Read failed (%08x)", ptrLBA);
return FALSE;
}
@ -139,7 +144,8 @@ BOOL pd_ReadFile(file_context_t* ctx, LPVOID lpBuffer, DWORD nNumberOfBytesToRea
DWORD readOffset = ptrLBA - pd->m_Partitions[i].m_PhysicalLBA;
if (pd->m_Partitions[i].m_ReadFunc == NULL) {
log_error(plfDrive, "Attempted read in %d/%d at block offset %08x; No read function",
log_error(plfDrive,
"Attempted read in %d/%d at block offset %08x; No read function",
pd->m_DriveNumber, pd->m_Partitions[i].m_PartitionNumber, readOffset);
return FALSE;
}
@ -230,12 +236,21 @@ BOOL pd_ReadFile(file_context_t* ctx, LPVOID lpBuffer, DWORD nNumberOfBytesToRea
*lpNumberOfBytesRead = sizeof SegaBootRecord1;
return TRUE;
}
if (ptrLBA >= headerLBA && ptrLBA < headerLBA + EXT_HEADER_GAP) {
DWORD nDataOffset = (ptrLBA - headerLBA - 4) * pd->m_BlockSize;
if (nNumberOfBytesToRead > sizeof SEGABOOT_DATA_CACHE - nDataOffset) {
nNumberOfBytesToRead = sizeof SEGABOOT_DATA_CACHE - nDataOffset;
}
memcpy(lpBuffer, SEGABOOT_DATA_CACHE, nNumberOfBytesToRead);
*lpNumberOfBytesRead = nNumberOfBytesToRead;
return TRUE;
}
}
if (ptrLBA >= pd->m_Extended[i].m_PhysicalLBA - EXT_HEADER_GAP &&
ptrLBA < pd->m_Extended[i].m_PhysicalLBA) {
if (ptrLBA >= headerLBA && ptrLBA < headerLBA + EXT_HEADER_GAP) {
// Read within the 63 extra tracks
log_error(plfDrive, "Read failed");
log_error(plfDrive, "Read failed (%08x)", ptrLBA);
return FALSE;
}
@ -244,7 +259,8 @@ BOOL pd_ReadFile(file_context_t* ctx, LPVOID lpBuffer, DWORD nNumberOfBytesToRea
DWORD readOffset = ptrLBA - pd->m_Extended[i].m_PhysicalLBA;
if (pd->m_Extended[i].m_ReadFunc == NULL) {
log_error(plfDrive, "Attempted read in %d/%d at block offset %08x; No read function",
log_error(plfDrive,
"Attempted read in %d/%d at block offset %08x; No read function",
pd->m_DriveNumber, pd->m_Extended[i].m_PartitionNumber, readOffset);
return FALSE;
}
@ -262,7 +278,7 @@ BOOL pd_ReadFile(file_context_t* ctx, LPVOID lpBuffer, DWORD nNumberOfBytesToRea
}
}
log_error(plfDrive, "Read failed");
log_error(plfDrive, "Read failed (%08x)", ptrLBA);
return FALSE;
}

View File

@ -3,13 +3,15 @@
#include "../util/_util.h"
static const bool ALLOW_FILE_PASSTHROUGH = true;
// TODO: This should be part of MiceFS I think
file_hook_t* MiceFSLocateHookW(_In_ LPCWSTR lpFileName);
file_hook_t* MiceFSLocateHookW(LPCWSTR lpFileName) {
file_hook_t* file_hook = file_hook_list;
while (file_hook != NULL) {
if (wcscmp(lpFileName, file_hook->filename) == 0 ||
(file_hook->altFilename != NULL && wcscmp(lpFileName, file_hook->altFilename) == 0)) {
if (_wcsicmp(lpFileName, file_hook->filename) == 0 ||
(file_hook->altFilename != NULL && _wcsicmp(lpFileName, file_hook->altFilename) == 0)) {
return file_hook;
}
file_hook = file_hook->next;
@ -19,6 +21,7 @@ file_hook_t* MiceFSLocateHookW(LPCWSTR lpFileName) {
HANDLE open_hook(file_hook_t* file_hook) {
open_hook_t* opened = (open_hook_t*)malloc(sizeof(open_hook_t));
if (opened == NULL) return INVALID_HANDLE_VALUE;
ZeroMemory(opened, sizeof *opened);
opened->hook = file_hook;
@ -51,7 +54,25 @@ void hook_file(file_hook_t* hook) {
file_hook_t* hl = file_hook_list;
while (hl->next != NULL) hl = hl->next;
hl->next = hook;
};
}
file_hook_t* unhook_file(LPCWSTR lpFilename) {
file_hook_t* hl = file_hook_list;
if (hl == NULL) return NULL;
file_hook_t* previous = NULL;
do {
if (_wcsicmp(hl->filename, lpFilename) == 0 || _wcsicmp(hl->altFilename, lpFilename) == 0) {
if (previous == NULL)
file_hook_list = hl->next;
else
previous->next = hl->next;
return hl;
}
previous = hl;
hl = hl->next;
} while (hl != NULL);
return NULL;
}
struct buffer_file {
LPBYTE buffer;
@ -116,23 +137,35 @@ HANDLE WINAPI FakeCreateFileW(LPCWSTR lpFileName, DWORD dwDesiredAccess, DWORD d
LPSECURITY_ATTRIBUTES lpSecurityAttributes,
DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes,
HANDLE hTemplateFile) {
size_t len = wcslen(lpFileName);
if (wcscmp(&lpFileName[len - 4], L".dbg") == 0 || wcscmp(&lpFileName[len - 4], L".pdb") == 0) {
return TrueCreateFileW(lpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes,
dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);
}
file_hook_t* found_fh = MiceFSLocateHookW(lpFileName);
if (found_fh != NULL) {
HANDLE handle = open_hook(found_fh);
log_info(plfHooks, "CreateFileW(%ls) -> 0x%p", lpFileName, handle);
return handle;
}
if (!ALLOW_FILE_PASSTHROUGH) {
SetLastError(ERROR_FILE_NOT_FOUND);
return INVALID_HANDLE_VALUE;
}
HANDLE handle;
MiceFSRedirectPathW(lpFileName, &lpFileName);
handle = TrueCreateFileW(lpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes,
dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);
if (handle == INVALID_HANDLE_VALUE)
log_warning(plfHooks, "CreateFileW(%ls) failed", lpFileName);
else
log_misc(plfHooks, "CreateFileW(%ls) -> 0x%p", lpFileName, handle);
if (handle == INVALID_HANDLE_VALUE) {
if (!(_wcsicmp(lpFileName, L"C:\\windows\\system32\\atipblag.dat") == 0 ||
wcsncmp(lpFileName, L"\\\\?\\hid#", 8) == 0))
log_warning(plfHooks, "CreateFileW(%ls) failed", lpFileName);
} else {
log_info(plfHooks, "CreateFileW(%ls) -> 0x%p", lpFileName, handle);
}
return handle;
}
HANDLE WINAPI FakeCreateFileA(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode,
@ -148,35 +181,31 @@ HANDLE WINAPI FakeCreateFileA(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dw
log_info(plfHooks, "CreateFileA(%s) -> 0x%p", lpFileName, handle);
return handle;
}
if (!ALLOW_FILE_PASSTHROUGH) {
SetLastError(ERROR_FILE_NOT_FOUND);
return INVALID_HANDLE_VALUE;
}
MiceFSRedirectPathA(lpFileName, &lpFileName);
HANDLE handle = TrueCreateFileA(lpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes,
dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);
if (handle == INVALID_HANDLE_VALUE)
log_warning(plfHooks, "CreateFileA(%s) failed", lpFileName);
else
if (handle == INVALID_HANDLE_VALUE) {
if (_stricmp(lpFileName, "C:\\windows\\system32\\atipblag.dat") != 0)
log_warning(plfHooks, "CreateFileA(%s) failed", lpFileName);
} else
log_misc(plfHooks, "CreateFileA(%s) -> 0x%p", lpFileName, handle);
return handle;
}
BOOL WINAPI FakePathFileExistsA(LPCSTR pszPath) {
MiceFSRedirectPathA(pszPath, &pszPath);
BOOL ret = TruePathFileExistsA(pszPath);
log_misc(plfHooks, "PathFileExistsA(%s) = %d", pszPath, ret);
return ret;
}
BOOL WINAPI FakePathFileExistsW(LPCWSTR pszPath) {
MiceFSRedirectPathW(pszPath, &pszPath);
BOOL ret = TruePathFileExistsW(pszPath);
log_misc(plfHooks, "PathFileExistsW(%ls) = %d", pszPath, ret);
return ret;
}
BOOL WINAPI FakeDeleteFileA(LPCSTR pszPath) {
if (!ALLOW_FILE_PASSTHROUGH) return FALSE;
MiceFSRedirectPathA(pszPath, &pszPath);
return TrueDeleteFileA(pszPath);
}
BOOL WINAPI FakeDeleteFileW(LPCWSTR pszPath) {
if (!ALLOW_FILE_PASSTHROUGH) return FALSE;
MiceFSRedirectPathW(pszPath, &pszPath);
return TrueDeleteFileW(pszPath);
}
@ -186,9 +215,6 @@ BOOL WINAPI FakeDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID lp
LPDWORD lpBytesReturned, LPOVERLAPPED lpOverlapped) {
open_hook_t* pHData = GetDataForHandle(hDevice, HDATA_FILE);
if (pHData == NULL) {
// log_trace(plfHooks, "DeviceIoControl(0x%p, 0x%08x, 0x%p, 0x%x, -, 0x%x, 0, 0)", hDevice,
// dwIoControlCode, lpInBuffer, nInBufferSize, nOutBufferSize);
return TrueDeviceIoControl(hDevice, dwIoControlCode, lpInBuffer, nInBufferSize, lpOutBuffer,
nOutBufferSize, lpBytesReturned, lpOverlapped);
}
@ -326,7 +352,6 @@ BOOL WINAPI FakeCloseHandle(HANDLE hObject) {
return TrueCloseHandle(hObject);
}
void FileTimeToTimet(__time64_t* t, LPFILETIME pft) {
ULARGE_INTEGER time_value;
time_value.HighPart = pft->dwHighDateTime;
@ -405,8 +430,7 @@ void hook_io() {
hook("Kernel32.dll", "ReadFile", FakeReadFile, (void**)&TrueReadFile);
hook("Kernel32.dll", "GetFileSizeEx", FakeGetFileSizeEx, (void**)&TrueGetFileSizeEx);
hook("Shlwapi.dll", "PathFileExistsA", FakePathFileExistsA, (void**)&TruePathFileExistsA);
hook("Shlwapi.dll", "PathFileExistsW", FakePathFileExistsW, (void**)&TruePathFileExistsW);
// PathIsDirectory, PathFileExists, etc just call GetFileAttributes under the hood
hook("Kernel32.dll", "DeleteFileA", FakeDeleteFileA, (void**)&TrueDeleteFileA);
hook("Kernel32.dll", "DeleteFileW", FakeDeleteFileW, (void**)&TrueDeleteFileW);
hook("Kernel32.dll", "GetCurrentDirectoryA", FakeGetCurrentDirectoryA,
@ -420,10 +444,8 @@ void hook_io() {
(void**)&TrueGetFileAttributesA);
hook("Kernel32.dll", "GetFileAttributesW", FakeGetFileAttributesW,
(void**)&TrueGetFileAttributesW);
hook("Kernel32.dll", "CreateDirectoryA", FakeCreateDirectoryA,
(void**)&TrueCreateDirectoryA);
hook("Kernel32.dll", "CreateDirectoryW", FakeCreateDirectoryW,
(void**)&TrueCreateDirectoryW);
hook("Kernel32.dll", "CreateDirectoryA", FakeCreateDirectoryA, (void**)&TrueCreateDirectoryA);
hook("Kernel32.dll", "CreateDirectoryW", FakeCreateDirectoryW, (void**)&TrueCreateDirectoryW);
hook("MSVCR90.DLL", "_stat64i32", Fake_stat64i32, (void**)&True_stat64i32);
}

View File

@ -47,8 +47,6 @@ _MICE_FILES BOOL(WINAPI* TrueReadFile)(HANDLE hFile, LPVOID lpBuffer, DWORD nNum
LPDWORD lpNumberOfBytesRead, LPOVERLAPPED lpOverlapped);
_MICE_FILES BOOL(WINAPI* TrueGetFileSizeEx)(HANDLE hFile, PLARGE_INTEGER lpFileSize);
_MICE_FILES BOOL(WINAPI* TrueCloseHandle)(HANDLE hObject);
_MICE_FILES BOOL(WINAPI* TruePathFileExistsA)(LPCSTR pszPath);
_MICE_FILES BOOL(WINAPI* TruePathFileExistsW)(LPCWSTR pszPath);
_MICE_FILES BOOL(WINAPI* TrueDeleteFileA)(LPCSTR lpFileName);
_MICE_FILES BOOL(WINAPI* TrueDeleteFileW)(LPCWSTR lpFileName);
_MICE_FILES HANDLE(WINAPI* TrueFindFirstFileA)(LPCSTR lpFileName, LPWIN32_FIND_DATA lpFindFileData);
@ -93,7 +91,8 @@ static int(WINAPIV* True_stat64i32)(const char* path, _stat64i32_t* buffer);
#define _CreateFileA (TrueCreateFileA ? TrueCreateFileA : CreateFileA)
#define _SetFilePointer (TrueSetFilePointer ? TrueSetFilePointer : SetFilePointer)
#define _SetFilePointerEx (TrueSetFilePointerEx ? TrueSetFilePointerEx : SetFilePointerEx)
#define _PathFileExistsA (TruePathFileExistsA ? TruePathFileExistsA : PathFileExistsA)
#define _GetFileAttributesW (TrueGetFileAttributesW ? TrueGetFileAttributesW : GetFileAttributesW)
// GetFileAttributesA internally calls (hooked)GetFileAttributesW
#define _GetCurrentDirectoryA \
(TrueGetCurrentDirectoryA ? TrueGetCurrentDirectoryA : GetCurrentDirectoryA)
#define _GetCurrentDirectoryW \
@ -137,3 +136,4 @@ file_hook_t* new_file_hook(LPCWSTR filename);
void hook_file(file_hook_t* hook);
void hook_io();
void hook_file_with_buffer(LPCWSTR filename, LPBYTE buffer, DWORD nBytes, DWORD access);
file_hook_t* unhook_file(LPCWSTR lpFilename);

View File

@ -1,8 +1,12 @@
#include "gui.h"
#include <detours.h>
#include "../input.h"
extern LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
HWND mainWindow;
HWND mainWindow = NULL;
static unsigned int hookType;
@ -22,41 +26,61 @@ HWND GetProcessWindow() {
return window;
}
BOOL UnFrameWindow(HWND hwnd) {
static const LONG frameFlags = WS_BORDER | WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU;
LONG UnFrameWindow(HWND hwnd) {
SetLastError(ERROR_SUCCESS);
LONG style = GetWindowLongW(hwnd, GWL_STYLE);
if (GetLastError() != ERROR_SUCCESS) return FALSE;
if (GetLastError() != ERROR_SUCCESS) return style;
RECT rect;
if (!GetClientRect(hwnd, &rect)) return FALSE;
if (!GetClientRect(hwnd, &rect)) return style;
style &= ~(WS_BORDER | WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU);
if (!AdjustWindowRect(&rect, style, FALSE)) return FALSE;
// Nothing to style
if ((style & frameFlags) == 0) return style;
SetWindowLongW(hwnd, GWL_STYLE, style);
LONG newStyle = style & ~(frameFlags);
if (!AdjustWindowRect(&rect, newStyle, FALSE)) return style;
SetWindowLongW(hwnd, GWL_STYLE, newStyle);
if (!SetWindowPos(hwnd, HWND_TOP, rect.left, rect.top, rect.right - rect.left,
rect.bottom - rect.top, SWP_FRAMECHANGED | SWP_NOMOVE))
return FALSE;
return TRUE;
return style;
return newStyle;
}
BOOL FrameWindow(HWND hwnd) {
LONG FrameWindow(HWND hwnd) {
SetLastError(ERROR_SUCCESS);
LONG style = GetWindowLongW(hwnd, GWL_STYLE);
if (GetLastError() != ERROR_SUCCESS) return FALSE;
if (GetLastError() != ERROR_SUCCESS) return style;
// Nothing to do
if ((style & frameFlags) == frameFlags) return style;
RECT rect;
if (!GetClientRect(hwnd, &rect)) return FALSE;
if (!GetClientRect(hwnd, &rect)) return style;
style |= WS_BORDER | WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU;
if (!AdjustWindowRect(&rect, style, FALSE)) return FALSE;
LONG newStyle = style | frameFlags;
if (!AdjustWindowRect(&rect, newStyle, FALSE)) return style;
SetWindowLongW(hwnd, GWL_STYLE, style);
SetWindowLongW(hwnd, GWL_STYLE, newStyle);
if (!SetWindowPos(hwnd, HWND_TOP, rect.left, rect.top, rect.right - rect.left,
rect.bottom - rect.top, SWP_FRAMECHANGED | SWP_NOMOVE))
return FALSE;
return TRUE;
return style;
return newStyle;
}
BOOL UnadjustWindowRect(LPRECT prc, DWORD dwStyle, BOOL fMenu) {
RECT rc;
SetRectEmpty(&rc);
BOOL fRc = AdjustWindowRect(&rc, dwStyle, fMenu);
if (fRc) {
prc->left -= rc.left;
prc->top -= rc.top;
prc->right -= rc.right;
prc->bottom -= rc.bottom;
}
return fRc;
}
BOOL GetD3D9Device(void** pTable, size_t Size) {
@ -155,12 +179,19 @@ void post_win_create(HWND hWnd) {
if (hookType == UI_HOOK_DX9) {
void* d3d9Device[119];
if (GetD3D9Device(d3d9Device, sizeof(d3d9Device))) {
*((PVOID*)&TrueEndScene) = CreateHook32((PVOID)d3d9Device[42], (PVOID)hkEndScene);
TrueEndScene = d3d9Device[42];
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
DetourAttach((PVOID*)&TrueEndScene, hkEndScene);
DetourTransactionCommit();
}
if (hWnd && !SetWindowSubclass(hWnd, WndProc, (int)&WndProc, (DWORD_PTR)NULL)) {
if (hWnd && !SetWindowSubclass(hWnd, WndProc, (UINT_PTR)&WndProc, (DWORD_PTR)NULL)) {
log_error(plfGUI, "failed to SetWindowSubclass(%d)", GetLastError());
}
} else {
MiceInputInit(hWnd);
}
}
@ -175,6 +206,8 @@ BOOL CALLBACK MonitorEnumProc(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMoni
}
void SetupWindowPosition(LPRECT lpRect, DWORD dwStyle) {
UnadjustWindowRect(lpRect, dwStyle, FALSE);
int x = lpRect->left;
int y = lpRect->top;
int w = lpRect->right - x;
@ -191,6 +224,17 @@ void SetupWindowPosition(LPRECT lpRect, DWORD dwStyle) {
if (MiceConfig.window.centre) {
x = ((monitorRect.right - monitorRect.left) - w) / 2;
y = ((monitorRect.bottom - monitorRect.top) - h) / 2;
// if ((dwStyle & frameFlags) == frameFlags) {
// RECT adjustedRect;
// memcpy(&adjustedRect, lpRect, sizeof *lpRect);
// UnadjustWindowRect(&adjustedRect, dwStyle, FALSE);
// // We're going to only adjust y, on the assumption x is unchanged, and even if it is
// // it'll be symmetic. y has the titlebar to worry about.
// int outerH = adjustedRect.bottom - adjustedRect.top;
// y += (outerH - h) / 2;
// }
} else {
x = MiceConfig.window.x;
y = MiceConfig.window.y;
@ -284,12 +328,16 @@ HRESULT STDMETHODCALLTYPE FakeCreateDevice(IDirect3D9* this, UINT Adapter, D3DDE
Adapter = MiceConfig.window.adaptor;
RECT winRect;
GetWindowRect(hFocusWindow, &winRect);
DWORD dwStyle = GetWindowLongW(hFocusWindow, GWL_STYLE);
SetupWindowPosition(&winRect, dwStyle);
if (!GetWindowRect(hFocusWindow, &winRect)) {
log_error(plfGUI, "GetWindowRect failed: %d", GetLastError());
} else {
DWORD dwStyle = GetWindowLongW(hFocusWindow, GWL_STYLE);
SetupWindowPosition(&winRect, dwStyle);
SetWindowPos(hFocusWindow, HWND_TOP, winRect.left, winRect.top, winRect.right - winRect.left,
winRect.bottom - winRect.top, 0);
// I have no idea why, but this is causing crashes???
SetWindowPos(hFocusWindow, HWND_TOP, winRect.left, winRect.top,
winRect.right - winRect.left, winRect.bottom - winRect.top, 0);
}
HRESULT res = TrueCreateDevice(this, Adapter, DeviceType, hFocusWindow, BehaviorFlags,
pPresentationParameters, ppReturnedDeviceInterface);
@ -313,6 +361,9 @@ HRESULT STDMETHODCALLTYPE FakeCreateDevice(IDirect3D9* this, UINT Adapter, D3DDE
}
}
log_info(plfD3D9, "Device created: %d", res);
MiceInputInit(hFocusWindow);
return res;
}
@ -337,12 +388,12 @@ IDirect3D9* WINAPI FakeDirect3DCreate9(UINT SDKVersion) {
hookType = UI_HOOK_DX9;
TrueCreateDevice = pD3D->lpVtbl->CreateDevice;
DWORD patch = (DWORD)&FakeCreateDevice;
patch_at(&pD3D->lpVtbl->CreateDevice, (char*)&patch, 4);
size_t patch = (size_t)&FakeCreateDevice;
MiceHookPatchAt(&pD3D->lpVtbl->CreateDevice, (char*)&patch, sizeof patch);
TrueEnumAdapterModes = pD3D->lpVtbl->EnumAdapterModes;
patch = (DWORD)&FakeEnumAdapterModes;
patch_at(&pD3D->lpVtbl->EnumAdapterModes, (char*)&patch, 4);
patch = (size_t)&FakeEnumAdapterModes;
MiceHookPatchAt(&pD3D->lpVtbl->EnumAdapterModes, (char*)&patch, sizeof patch);
return pD3D;
};
@ -423,7 +474,7 @@ void hook_gui() {
hook("User32.dll", "ChangeDisplaySettingsExA", FakeChangeDisplaySettingsExA, NULL);
hook("User32.dll", "SetCursor", FakeSetCursor, (void**)&TrueSetCursor);
if (PathFileExistsA("FREEGLUT.DLL")) {
if (PathFileExistsA("FREEGLUT.DLL") && FALSE) {
// Hooked as a way to identify use of GLUT
hook("FREEGLUT.DLL", "glutInitDisplayMode", Fake_glutInitDisplayMode,
(void**)&True_glutInitDisplayMode);

View File

@ -43,5 +43,6 @@ void register_gui_hook(FnEndScene* end_scene);
void hook_gui();
void setup_hud_gui();
BOOL UnadjustWindowRect(LPRECT prc, DWORD dwStyle, BOOL fMenu);
extern HWND mainWindow;
extern DWORD changeCursorState;

View File

@ -89,7 +89,7 @@ BOOL WINAPI FakeReportEventA(HANDLE hEventLog, WORD wType, WORD wCategory, DWORD
case EVENTLOG_INFORMATION_TYPE:
default:
for (int i = 0; i < wNumStrings; i++)
log_info(plfEvtlog, trim_string((char*)lpStrings[i]));
log_game(plfEvtlog, trim_string((char*)lpStrings[i]));
break;
}
return TRUE;
@ -97,16 +97,17 @@ BOOL WINAPI FakeReportEventA(HANDLE hEventLog, WORD wType, WORD wCategory, DWORD
BOOL WINAPI FakeDeregisterEventSource(HANDLE hEventLog) { return TRUE; }
// static VOID(WINAPI* TrueOutputDebugStringA)(LPCSTR lpOutputString);
// VOID WINAPI FakeOutputDebugStringA(LPCSTR lpOutputString) { log_info("debug", "%s",
// lpOutputString); }
VOID WINAPI FakeOutputDebugStringA(LPCSTR lpOutputString) {
log_game(plfDebugLog, "%s", lpOutputString);
}
void hook_logging() {
// hook("MSVCR90.DLL", "printf", Fakeprintf, (void**)&Trueprintf);
// hook("MSVCR90.DLL", "fprintf", Fakefprintf, (void**)&Truefprintf);
// hook("MSVCR90.DLL", "fprintf_s", Fakefprintf_s, (void**)&Truefprintf_s);
hook("MSVCR90.DLL", "fprintf", Fakefprintf, (void**)&Truefprintf);
// hook("MSVCR90.DLL", "fprintf_s"\z, Fakefprintf_s, (void**)&Truefprintf_s);
// hook("MSVCR90.DLL", "vfprintf_s", Fakevfprintf_s, (void**)&Truevfprintf_s);
hook("Kernel32.dll", "OutputDebugStringA", FakeOutputDebugStringA, NULL);
hook("Advapi32.dll", "RegisterEventSourceA", FakeRegisterEventSourceA,
(void**)&TrueRegisterEventSourceA);
hook("Advapi32.dll", "ReportEventA", FakeReportEventA, (void**)&TrueReportEventA);

View File

@ -1,11 +1,73 @@
#include "network.h"
#pragma comment(lib, "ws2_32.lib")
#pragma comment(lib, "Dnsapi.lib")
#define IP(a, b, c, d) (((a) << 24) | ((b) << 16) | ((c) << 8) | (d))
#define NAOMINET IP(14, 128, 27, 15)
#define IB_NAOMINET IP(14, 128, 27, 9)
#define AIME_NAOMINET IP(112, 137, 187, 91)
int WINAPI Fake_connect(SOCKET s, const SOCKADDR* name, int namelen) {
ULONG addr = _byteswap_ulong(((SOCKADDR_IN*)name)->sin_addr.S_un.S_addr);
USHORT port = _byteswap_ushort(((SOCKADDR_IN*)name)->sin_port);
// Poorly exclude nxauth and mxgcatcher.
// TODO: better
if (port != 40190 && port != 40110 && port != 40102 && port != 40103) {
if (addr == NAOMINET || addr == IB_NAOMINET || addr == AIME_NAOMINET) {
log_error(
plfNetwork,
"DANGER!! Game is attempting to connect to SEGA services! Check your configuration!");
return -1;
}
if (addr == IP(127, 0, 0, 1)) {
switch (port) {
case 40100:
case 40101:
log_info(plfNetwork, "connect(master)");
break;
case 40102:
case 40103:
log_info(plfNetwork, "connect(installer)");
break;
case 40104:
case 40105:
log_info(plfNetwork, "connect(network)");
break;
case 40106:
case 40107:
log_info(plfNetwork, "connect(keychip)");
break;
case 40108:
case 40112:
log_info(plfNetwork, "connect(gdeliver)");
break;
case 40110:
case 40113:
log_info(plfNetwork, "connect(gcatcher)");
break;
case 40114:
case 40115:
log_info(plfNetwork, "connect(storage)");
break;
case 40190:
case 40191:
case 40192:
case 40193:
// nxAuth
break;
case 40194:
case 40195:
log_info(plfNetwork, "connect(nxmount)");
break;
case 40196:
case 40197:
log_info(plfNetwork, "connect(nxrelay)");
break;
default:
log_info(plfNetwork, "connect(localhost:%hu)", port);
break;
}
} else {
log_info(plfNetwork, "connect(%hhu.%hhu.%hhu.%hhu:%hu)", (addr >> 24) & 0xff,
(addr >> 16) & 0xff, (addr >> 8) & 0xff, addr & 0xff, port);
}
@ -94,11 +156,40 @@ dns INTERCEPT_DNS[] = {
DNS_RECORDA dummy_record;
static BOOL _DoDnsLookup(PCSTR pszName, DWORD* lpResolved) {
DNS_STATUS status;
PDNS_RECORDA pDnsRecord = NULL;
if (MiceConfig.network.upstream_dns_server) {
IP4_ARRAY upstreamDns;
upstreamDns.AddrCount = 1;
upstreamDns.AddrArray[0] = _byteswap_ulong(MiceConfig.network.upstream_dns_server);
status = TrueDnsQuery_A(pszName, DNS_TYPE_A, DNS_QUERY_BYPASS_CACHE, &upstreamDns,
&pDnsRecord, NULL);
} else {
status = TrueDnsQuery_A(pszName, DNS_TYPE_A, DNS_QUERY_STANDARD, NULL, &pDnsRecord, NULL);
}
if (status != 0) {
log_error(plfNetwork, "DNS(%s):FAILED", pszName);
return FALSE;
}
if (pDnsRecord == NULL || pDnsRecord->wType != DNS_TYPE_A) {
log_error(plfNetwork, "DNS(%s):NXRECORD", pszName);
return FALSE;
}
if (lpResolved) *lpResolved = _byteswap_ulong(pDnsRecord->Data.A.IpAddress);
DnsRecordListFree(pDnsRecord, DnsFreeRecordListDeep);
return TRUE;
}
DNS_STATUS WINAPI FakeDnsQuery_A(PCSTR pszName, WORD wType, DWORD Options, PVOID pExtra,
PDNS_RECORDA* ppQueryResults, PVOID* pReserved) {
if (ppQueryResults) {
for (size_t i = 0; i < sizeof INTERCEPT_DNS / sizeof INTERCEPT_DNS[0]; i++) {
if (strcmp(pszName, INTERCEPT_DNS[i].name) == 0) {
if (INTERCEPT_DNS[i].address && *INTERCEPT_DNS[i].address &&
strcmp(pszName, INTERCEPT_DNS[i].name) == 0) {
printf("%08x\n", MiceConfig.network.naominet_jp);
log_info(plfNetwork, "DNS Replacing %s with %08x", pszName,
@ -115,21 +206,42 @@ DNS_STATUS WINAPI FakeDnsQuery_A(PCSTR pszName, WORD wType, DWORD Options, PVOID
}
}
log_info(plfNetwork, "DNS passthrough for %s", pszName);
if (MiceConfig.network.upstream_dns_server) {
IP4_ARRAY upstreamDns;
upstreamDns.AddrCount = 1;
upstreamDns.AddrArray[0] = _byteswap_ulong(MiceConfig.network.upstream_dns_server);
return TrueDnsQuery_A(pszName, wType, DNS_QUERY_BYPASS_CACHE, &upstreamDns, ppQueryResults,
pReserved);
}
return TrueDnsQuery_A(pszName, wType, Options, pExtra, ppQueryResults, pReserved);
};
}
INT WSAAPI FakeWSAStringToAddressA(LPSTR AddressString, INT AddressFamily,
LPWSAPROTOCOL_INFOA lpProtocolInfo, LPSOCKADDR lpAddress,
LPINT lpAddressLength) {
log_misc(plfNetwork, "WSA DNS lookup for %s", AddressString);
for (size_t i = 0; i < sizeof INTERCEPT_DNS / sizeof INTERCEPT_DNS[0]; i++) {
if (strcmp(AddressString, INTERCEPT_DNS[i].name) == 0) {
log_info(plfNetwork, "WSA DNS Replacing %s with %08x", AddressString,
*INTERCEPT_DNS[i].address);
if (AddressFamily == AF_INET) {
for (size_t i = 0; i < sizeof INTERCEPT_DNS / sizeof INTERCEPT_DNS[0]; i++) {
if (INTERCEPT_DNS[i].address && *INTERCEPT_DNS[i].address &&
strcmp(AddressString, INTERCEPT_DNS[i].name) == 0) {
log_info(plfNetwork, "WSA DNS Replacing %s with %08x", AddressString,
*INTERCEPT_DNS[i].address);
lpAddress->sa_family = AF_INET;
PULONG addr = &(((SOCKADDR_IN*)lpAddress)->sin_addr.S_un.S_addr);
*addr = _byteswap_ulong(*INTERCEPT_DNS[i].address);
return ERROR_SUCCESS;
}
}
DWORD nResolved;
if (_DoDnsLookup(AddressString, &nResolved)) {
log_info(plfNetwork, "WSA DNS Replacing %s with %08x", AddressString, nResolved);
lpAddress->sa_family = AF_INET;
PULONG addr = &(((SOCKADDR_IN*)lpAddress)->sin_addr.S_un.S_addr);
*addr = _byteswap_ulong(*INTERCEPT_DNS[i].address);
*addr = _byteswap_ulong(nResolved);
return ERROR_SUCCESS;
}
}
@ -140,11 +252,13 @@ INT WSAAPI FakeWSAStringToAddressA(LPSTR AddressString, INT AddressFamily,
INT WINAPI Fake_getaddrinfo(PCSTR pNodeName, PCSTR pServiceName, const ADDRINFOA* pHints,
PADDRINFOA* ppResult) {
char szNewAddress[16];
if (!pNodeName) return True_getaddrinfo(pNodeName, pServiceName, pHints, ppResult);
for (size_t i = 0; i < sizeof INTERCEPT_DNS / sizeof INTERCEPT_DNS[0]; i++) {
if (strcmp(pNodeName, INTERCEPT_DNS[i].name) == 0) {
char szNewAddress[16];
if (INTERCEPT_DNS[i].address && *INTERCEPT_DNS[i].address &&
strcmp(pNodeName, INTERCEPT_DNS[i].name) == 0) {
sprintf_s(szNewAddress, sizeof szNewAddress, "%d.%d.%d.%d",
(*INTERCEPT_DNS[i].address >> 24) & 0xff,
(*INTERCEPT_DNS[i].address >> 16) & 0xff,
@ -159,8 +273,19 @@ INT WINAPI Fake_getaddrinfo(PCSTR pNodeName, PCSTR pServiceName, const ADDRINFOA
// Exclude a few known services
if (strcmp(pNodeName, "0.0.0.0") != 0 && strcmp(pNodeName, "127.0.0.0") != 0 &&
strcmp(pNodeName, "240.0.0.0") != 0)
strcmp(pNodeName, "240.0.0.0") != 0) {
// Try doing a lookup using our upstream DNS service
DWORD nResolved;
if (_DoDnsLookup(pNodeName, &nResolved)) {
sprintf_s(szNewAddress, sizeof szNewAddress, "%d.%d.%d.%d", (nResolved >> 24) & 0xff,
(nResolved >> 16) & 0xff, (nResolved >> 8) & 0xff, nResolved & 0xff);
szNewAddress[sizeof szNewAddress - 1] = '\0';
return True_getaddrinfo(szNewAddress, pServiceName, pHints, ppResult);
}
log_info(plfNetwork, "GAI DNS passthrough for %s:%s", pNodeName, pServiceName);
}
return True_getaddrinfo(pNodeName, pServiceName, pHints, ppResult);
}
@ -235,7 +360,7 @@ void hook_network() {
hook("Ws2_32.dll", "socket", Fake_socket, (void**)&True_socket);
hook("Ws2_32.dll", "bind", Fake_bind, (void**)&True_bind);
hook("Ws2_32.dll", "getaddrinfo", Fake_getaddrinfo, (void**)&True_getaddrinfo);
// hook("Ws2_32.dll", "sendto", Fake_sendto, (void**)&True_sendto);
hook("Ws2_32.dll", "sendto", Fake_sendto, (void**)&True_sendto);
hook("Ws2_32.dll", "WSAStringToAddressA", FakeWSAStringToAddressA,
(void**)&TrueWSAStringToAddressA);
hook("Iphlpapi.dll", "GetIfTable", FakeGetIfTable, (void**)&TrueGetIfTable);

View File

@ -1,5 +1,7 @@
#include "processes.h"
#include "../lib/mice/ipc.h"
BOOL WINAPI FakeCreateProcessA(LPCSTR lpApplicationName, LPSTR lpCommandLine,
LPSECURITY_ATTRIBUTES lpProcessAttributes,
LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles,
@ -14,6 +16,9 @@ BOOL WINAPI FakeCreateProcessA(LPCSTR lpApplicationName, LPSTR lpCommandLine,
lpEnvironment, lpCurrentDirectory, lpStartupInfo,
lpProcessInformation);
}
// Bind everything to our one single console
dwCreationFlags &= ~CREATE_NEW_CONSOLE;
dwCreationFlags |= CREATE_NO_WINDOW;
if (lpCommandLine &&
(strcmp(lpCommandLine, "s:\\mxkeychip.exe") == 0 ||
@ -41,8 +46,15 @@ BOOL WINAPI FakeCreateProcessA(LPCSTR lpApplicationName, LPSTR lpCommandLine,
MiceFSRedirectPathA(lpApplicationName, &lpApplicationName);
log_info(plfProcesses, "CreateProcessA %s %s", lpApplicationName, lpCommandLine);
return start_and_inject(INVALID_HANDLE_VALUE, lpApplicationName, lpCommandLine, MICELIB, FALSE,
0, NULL, 0, lpProcessInformation);
if (!_miceIpcData->m_LauncherIsReady || _miceIpcData->m_MiceDll[0] == '\0') {
log_error(plfProcesses, "MiceLIB not provided via IPC!");
return FALSE;
}
log_info(plfProcesses, "Spawning \"%s\" %s", lpApplicationName, lpCommandLine);
return start_and_inject(INVALID_HANDLE_VALUE, lpApplicationName, lpCommandLine,
_miceIpcData->m_MiceDll, FALSE, 0, NULL, dwCreationFlags,
lpProcessInformation);
}
BOOL WINAPI FakeCreateProcessW(LPCWSTR lpApplicationName, LPWSTR lpCommandLine,
LPSECURITY_ATTRIBUTES lpProcessAttributes,
@ -50,23 +62,26 @@ BOOL WINAPI FakeCreateProcessW(LPCWSTR lpApplicationName, LPWSTR lpCommandLine,
DWORD dwCreationFlags, LPVOID lpEnvironment,
LPCWSTR lpCurrentDirectory, LPSTARTUPINFOW lpStartupInfo,
LPPROCESS_INFORMATION lpProcessInformation) {
log_info(plfProcesses, "CreateProcessW %ls %ls", lpApplicationName, lpCommandLine);
// if (lpCommandLine && (wcscmp(lpCommandLine, L"chkdsk.exe") == 0 ||
// wcscmp(lpCommandLine, L"ALLNetProc_Win.exe") == 0 ||
// wcscmp(lpCommandLine, L"ALLNetProc_Ring.exe") == 0 ||
// wcscmp(lpCommandLine, L"ALLNetProc.exe") == 0)) {
if (lpCommandLine && (wcscmp(lpCommandLine, L"chkdsk.exe") == 0)) {
if (lpCommandLine && (_wcsnicmp(lpCommandLine, L"chkdsk.exe", 10) == 0)) {
if (lpProcessInformation) {
lpProcessInformation->hProcess = CreateEventA(NULL, FALSE, TRUE, NULL);
lpProcessInformation->hThread = CreateEventA(NULL, FALSE, TRUE, NULL);
}
return TRUE;
}
// Bind everything to our one single console
dwCreationFlags &= ~CREATE_NEW_CONSOLE;
dwCreationFlags |= CREATE_NO_WINDOW;
int nMultiChars = WideCharToMultiByte(CP_ACP, 0, lpCommandLine, -1, NULL, 0, NULL, NULL);
LPSTR commandLine = malloc(nMultiChars);
LPSTR commandLine = malloc(nMultiChars + 1);
commandLine[0] = '\0';
WideCharToMultiByte(CP_ACP, 0, lpCommandLine, -1, commandLine, nMultiChars, NULL, NULL);
commandLine[nMultiChars] = '\0';
CHAR szApplicationName[MAX_PATH + 1];
LPCSTR lpApplicationNameA;
@ -88,8 +103,16 @@ BOOL WINAPI FakeCreateProcessW(LPCWSTR lpApplicationName, LPWSTR lpCommandLine,
}
MiceFSRedirectPathA(lpApplicationNameA, &lpApplicationNameA);
return start_and_inject(INVALID_HANDLE_VALUE, lpApplicationNameA, commandLine, MICELIB, FALSE,
0, NULL, 0, lpProcessInformation);
if (!_miceIpcData->m_LauncherIsReady || _miceIpcData->m_MiceDll[0] == '\0') {
log_error(plfProcesses, "MiceLIB not provided via IPC!");
return FALSE;
}
log_info(plfProcesses, "Spawning \"%s\" %s", lpApplicationNameA, commandLine);
return start_and_inject(INVALID_HANDLE_VALUE, lpApplicationNameA, commandLine,
_miceIpcData->m_MiceDll, FALSE, 0, NULL, dwCreationFlags,
lpProcessInformation);
}
BOOL WINAPI FakeGetExitCodeProcess(HANDLE hProcess, LPDWORD lpExitCode) {

View File

@ -71,13 +71,13 @@ BOOL WINAPI FakeSetupDiGetDeviceInterfaceDetailA(HDEVINFO DeviceInfoSet, PSP_DEV
log_misc(plfSetupAPI, "Intercepted SetupDiGetDeviceInterfaceDetailA");
const WCHAR* res = (WCHAR*)DeviceInterfaceData->Reserved;
int new_len = (wcslen(res) + 1) * (sizeof *res);
size_t new_len = (wcslen(res) + 1) * (sizeof *res);
char* new_res = (char*)malloc(new_len);
size_t convertedChars = 0;
wcstombs_s(&convertedChars, new_res, new_len, res, _TRUNCATE);
size_t len = offsetof(SP_DEVICE_INTERFACE_DETAIL_DATA_W, DevicePath) + convertedChars;
if (RequiredSize) *RequiredSize = len;
if (RequiredSize) *RequiredSize = len & 0xffffffff;
if (!DeviceInterfaceDetailData && DeviceInterfaceDetailDataSize < len) {
SetLastError(ERROR_INSUFFICIENT_BUFFER);
return FALSE;

View File

@ -66,7 +66,9 @@ LONG WINAPI FakeRtlGetVersion(PRTL_OSVERSIONINFOW lpVersionInformation) {
// TODO: We should probably handle libamv_amd.dll at some point too
HMODULE WINAPI FakeLoadLibraryA(LPCSTR lpLibFileName) {
if (strcmp(lpLibFileName, "libamv_nvidia.dll") == 0) {
if (_stricmp(lpLibFileName, "libamv_nvidia.dll") == 0 ||
_stricmp(lpLibFileName, "libamv_amd.dll") == 0 ||
_stricmp(lpLibFileName, "atipdlxx.dll") == 0) {
return TrueLoadLibraryA(MICELIB);
}
return TrueLoadLibraryA(lpLibFileName);
@ -74,7 +76,9 @@ HMODULE WINAPI FakeLoadLibraryA(LPCSTR lpLibFileName) {
#define WIDEN2(x) L##x
#define WIDEN(x) WIDEN2(x)
HMODULE WINAPI FakeLoadLibraryW(LPCWSTR lpLibFileName) {
if (wcscmp(lpLibFileName, L"libamv_nvidia.dll") == 0) {
if (_wcsicmp(lpLibFileName, L"libamv_nvidia.dll") == 0 ||
_wcsicmp(lpLibFileName, L"libamv_amd.dll") == 0 ||
_wcsicmp(lpLibFileName, L"atipdlxx.dll") == 0) {
return TrueLoadLibraryW(WIDEN(MICELIB));
}
return TrueLoadLibraryW(lpLibFileName);

230
src/micetools/dll/input.c Normal file
View File

@ -0,0 +1,230 @@
#include "input.h"
#pragma comment(lib, "dinput8.lib")
#pragma comment(lib, "dxguid.lib")
#include <GuidDef.h>
#include <Objbase.h>
#include <stdio.h>
#include "../lib/mice/log.h"
static PMICE_DI_DEVICE _MiceDIDevices = NULL;
static LPDIRECTINPUT8A _MiceDI = NULL;
void MiceInputPollDevices(void) {
PMICE_DI_DEVICE lpDevice = _MiceDIDevices;
while (lpDevice != NULL) {
lpDevice->m_lpInput->lpVtbl->Poll(lpDevice->m_lpInput);
switch (lpDevice->m_dwType) {
case DI8DEVTYPE_JOYSTICK:
case DI8DEVTYPE_GAMEPAD:
lpDevice->m_lpInput->lpVtbl->GetDeviceState(lpDevice->m_lpInput,
sizeof lpDevice->m_State.m_Joystate,
&lpDevice->m_State.m_Joystate);
break;
}
lpDevice = lpDevice->m_Next;
}
}
void MiceInputFreeDevices(void) {
PMICE_DI_DEVICE lpDevice = _MiceDIDevices;
while (lpDevice != NULL) {
lpDevice->m_lpInput->lpVtbl->Unacquire(lpDevice->m_lpInput);
lpDevice->m_lpInput->lpVtbl->Release(lpDevice->m_lpInput);
PMICE_DI_DEVICE next = lpDevice->m_Next;
free(lpDevice);
lpDevice = next;
}
_MiceDIDevices = NULL;
}
BOOL MiceInputGetNewBinding(PMICE_BUTTON_BINDING lpBinding) {
MiceInputPollDevices();
PMICE_DI_DEVICE lpDevice = _MiceDIDevices;
while (lpDevice != NULL) {
PMICE_DI_STATE state = &lpDevice->m_State;
PMICE_DI_STATE lastState = &lpDevice->m_LastState;
if (lpBinding != NULL) {
switch (lpDevice->m_dwType) {
case DI8DEVTYPE_JOYSTICK:
case DI8DEVTYPE_GAMEPAD:
for (int button = 0; button < 32; button++) {
if (state->m_Joystate.rgbButtons[button] &&
!lastState->m_Joystate.rgbButtons[button]) {
lpBinding->m_Type = MICE_BB_TYPE_DI_JOY;
lpBinding->m_DIJoy.m_lpDeviceGuid = lpDevice->m_GUID;
lpBinding->m_DIJoy.m_ButtonMajor = MICE_BUTTON_MAJOR_BUTTON;
lpBinding->m_DIJoy.m_ButtonMinor = button;
return TRUE;
}
}
if (state->m_Joystate.rgdwPOV[0] != lastState->m_Joystate.rgdwPOV[0]) {
BOOL bound = FALSE;
int to = -1;
if (state->m_Joystate.rgdwPOV[0] == 0) {
to = MICE_DPAD_UP;
bound = TRUE;
} else if (state->m_Joystate.rgdwPOV[0] == 18000) {
to = MICE_DPAD_DOWN;
bound = TRUE;
} else if (state->m_Joystate.rgdwPOV[0] == 27000) {
to = MICE_DPAD_LEFT;
bound = TRUE;
} else if (state->m_Joystate.rgdwPOV[0] == 9000) {
to = MICE_DPAD_RIGHT;
bound = TRUE;
}
if (bound) {
lpBinding->m_Type = MICE_BB_TYPE_DI_JOY;
lpBinding->m_DIJoy.m_lpDeviceGuid = lpDevice->m_GUID;
lpBinding->m_DIJoy.m_ButtonMajor = MICE_BUTTON_MAJOR_DPAD;
lpBinding->m_DIJoy.m_ButtonMinor = to;
return TRUE;
}
}
// TODO: Axes
break;
}
}
memcpy(lastState, state, sizeof *lastState);
lpDevice = lpDevice->m_Next;
}
// Skip the mouse buttons
for (int i = 8; i < 0xff; i++) {
if (GetAsyncKeyState(i) < 0) {
lpBinding->m_AsyncKey.m_Key = (CHAR)i;
lpBinding->m_Type = MICE_BB_TYPE_GET_ASYNC_KEY;
return TRUE;
}
}
return FALSE;
}
static BOOL CALLBACK _DInputEnum(LPDIDEVICEINSTANCEA lpddi, LPVOID data) {
PMICE_DI_DEVICE lpTail = _MiceDIDevices;
PMICE_DI_DEVICE lpNew;
if (lpTail == NULL) {
lpNew = _MiceDIDevices = malloc(sizeof *lpNew);
} else {
while (lpTail->m_Next != NULL) lpTail = lpTail->m_Next;
lpNew = lpTail->m_Next = malloc(sizeof *lpNew);
}
ZeroMemory(lpNew, sizeof *lpNew);
lpNew->m_GUID = lpddi->guidInstance;
lpNew->m_dwType = lpddi->dwDevType & 0xff;
memcpy_s(lpNew->m_szName, sizeof lpNew->m_szName, lpddi->tszProductName,
sizeof lpddi->tszProductName);
lpNew->m_szName[sizeof lpNew->m_szName - 1] = '\0';
printf("Found device: %s\n", lpNew->m_szName);
return DIENUM_CONTINUE;
}
int MiceInputGrabDevices(HWND hWnd) {
if (_MiceDI == NULL) return -2;
// The first argument here is throwing warnings
#pragma warning(disable : 4090 4028)
_MiceDI->lpVtbl->EnumDevices(_MiceDI, DI8DEVTYPE_JOYSTICK, _DInputEnum, NULL,
DIEDFL_ATTACHEDONLY);
_MiceDI->lpVtbl->EnumDevices(_MiceDI, DI8DEVTYPE_GAMEPAD, _DInputEnum, NULL,
DIEDFL_ATTACHEDONLY);
#pragma warning(default : 4090 4028)
PMICE_DI_DEVICE lpDevice = _MiceDIDevices;
while (lpDevice != NULL) {
_MiceDI->lpVtbl->CreateDevice(_MiceDI, &lpDevice->m_GUID, &lpDevice->m_lpInput, NULL);
switch (lpDevice->m_dwType) {
case DI8DEVTYPE_GAMEPAD:
case DI8DEVTYPE_JOYSTICK:
lpDevice->m_lpInput->lpVtbl->SetCooperativeLevel(
lpDevice->m_lpInput, hWnd, DISCL_BACKGROUND | DISCL_NONEXCLUSIVE);
lpDevice->m_lpInput->lpVtbl->SetDataFormat(lpDevice->m_lpInput, &c_dfDIJoystick);
lpDevice->m_lpInput->lpVtbl->Acquire(lpDevice->m_lpInput);
break;
}
lpDevice = lpDevice->m_Next;
}
return 0;
}
static BOOL _MiceInputHasInit = FALSE;
int MiceInputInit(HWND hWnd) {
if (_MiceInputHasInit) return 0;
_MiceInputHasInit = TRUE;
if (_MiceDI == NULL)
if (!(SUCCEEDED(DirectInput8Create(GetModuleHandle(NULL), DIRECTINPUT_VERSION,
&IID_IDirectInput8, (void **)&_MiceDI, NULL)))) {
log_error(plfMisc, "DirectInput8Create failed: %d", GetLastError());
_MiceDI = NULL;
return -1;
}
return MiceInputGrabDevices(hWnd);
}
void MiceInputDestroy(void) {
MiceInputFreeDevices();
_MiceDI->lpVtbl->Release(_MiceDI);
_MiceDI = NULL;
_MiceInputHasInit = FALSE;
}
BOOL MiceInputGetButtonState(PMICE_BUTTON_BINDING lpBinding) {
BOOL pressed = FALSE;
switch (lpBinding->m_Type) {
case MICE_BB_TYPE_GET_ASYNC_KEY: {
pressed = (GetAsyncKeyState(lpBinding->m_AsyncKey.m_Key) < 0);
break;
}
case MICE_BB_TYPE_DI_JOY: {
PMICE_DI_DEVICE lpDevice = _MiceDIDevices;
while (lpDevice != NULL) {
if (IsEqualGUID(&lpDevice->m_GUID, &lpBinding->m_DIJoy.m_lpDeviceGuid)) break;
lpDevice = lpDevice->m_Next;
}
if (lpDevice == NULL) break;
switch (lpBinding->m_DIJoy.m_ButtonMajor) {
case MICE_BUTTON_MAJOR_AXIS:
break;
case MICE_BUTTON_MAJOR_DPAD: {
DWORD pov = lpDevice->m_State.m_Joystate.rgdwPOV[0];
switch (lpBinding->m_DIJoy.m_ButtonMinor) {
case MICE_DPAD_UP:
pressed = pov == 0 || pov == 4500 || pov == 31500;
break;
case MICE_DPAD_DOWN:
pressed = pov == 18000 || pov == 22500 || pov == 13500;
break;
case MICE_DPAD_LEFT:
pressed = pov == 27000 || pov == 31500 || pov == 22500;
break;
case MICE_DPAD_RIGHT:
pressed = pov == 9000 || pov == 4500 || pov == 13500;
break;
}
break;
}
case MICE_BUTTON_MAJOR_BUTTON: {
DWORD button = lpBinding->m_DIJoy.m_ButtonMinor;
if (button <= 32) pressed = lpDevice->m_State.m_Joystate.rgbButtons[button] > 0;
break;
}
}
}
}
if (lpBinding->m_Invert) pressed = !pressed;
return pressed;
}

61
src/micetools/dll/input.h Normal file
View File

@ -0,0 +1,61 @@
#pragma once
#include <Windows.h>
#define CINTERFACE
#define INITGUID
#define DIRECTINPUT_VERSION 0x0800
#include <dinput.h>
typedef enum MICE_BUTTON_BINDING_TYPE {
MICE_BB_TYPE_UNBOUND,
MICE_BB_TYPE_GET_ASYNC_KEY,
MICE_BB_TYPE_DI_JOY,
} MICE_BUTTON_BINDING_TYPE;
typedef enum MICE_BUTTON_MAJOR {
MICE_BUTTON_MAJOR_AXIS,
MICE_BUTTON_MAJOR_DPAD,
MICE_BUTTON_MAJOR_BUTTON,
} MICE_BUTTON_MAJOR;
#define MICE_DPAD_UP 0 // POV == 0
#define MICE_DPAD_DOWN 1 // POV = 18000
#define MICE_DPAD_LEFT 2 // POV == 27000
#define MICE_DPAD_RIGHT 3 // POV == 9000
typedef struct MICE_BUTTON_BINDING {
MICE_BUTTON_BINDING_TYPE m_Type;
BOOL m_Invert;
union {
struct {
CHAR m_Key;
} m_AsyncKey;
struct {
GUID m_lpDeviceGuid;
MICE_BUTTON_MAJOR m_ButtonMajor;
DWORD m_ButtonMinor;
} m_DIJoy;
};
} MICE_BUTTON_BINDING, *PMICE_BUTTON_BINDING;
typedef union MICE_DI_STATE {
DIJOYSTATE m_Joystate;
} MICE_DI_STATE, *PMICE_DI_STATE;
typedef struct MICE_DI_DEVICE {
LPDIRECTINPUTDEVICE8A m_lpInput;
GUID m_GUID;
CHAR m_szName[MAX_PATH];
DWORD m_dwType;
MICE_DI_STATE m_State;
MICE_DI_STATE m_LastState;
struct MICE_DI_DEVICE* m_Next;
} MICE_DI_DEVICE, *PMICE_DI_DEVICE;
int MiceInputInit(HWND hWnd);
void MiceInputDestroy(void);
int MiceInputGrabDevices(HWND hWnd);
void MiceInputPollDevices(void);
void MiceInputFreeDevices(void);
BOOL MiceInputGetButtonState(PMICE_BUTTON_BINDING lpBinding);
BOOL MiceInputGetNewBinding(PMICE_BUTTON_BINDING lpBinding);

View File

@ -4,11 +4,12 @@ subdir('hooks')
subdir('gui')
shared_library(
'mice',
get_option('win64') ? 'mice64' : 'mice',
name_prefix: '',
vs_module_defs: 'mice.def',
vs_module_defs: get_option('win64') ? 'mice64.def' : 'mice.def',
sources: [
'amvStub/amv.c',
'dllStub/amv.c',
'dllStub/ati.c',
'util/misc.c',
'util/hook.c',
@ -21,11 +22,12 @@ shared_library(
'comdevice.c',
'games.c',
'input.c',
'micefs.c',
'dllmain.c',
],
link_with: [
dmi_lib,
mice_lib,
amiTimer,
amiMd5,
@ -37,6 +39,7 @@ shared_library(
],
dependencies: [
cimgui.get_variable('cimgui_dep'),
detours.get_variable('detours_dep'),
# freeglut_lib, # forces the use of freeglut.dll!
]
)

View File

@ -0,0 +1 @@
LIBRARY mice64

View File

@ -6,9 +6,7 @@
#include <stdlib.h>
#include <string.h>
// TODO: This is awful
extern BOOL(WINAPI* TruePathFileExistsA)(LPCSTR pszPath);
#define _PathFileExistsA (TruePathFileExistsA ? TruePathFileExistsA : PathFileExistsA)
#include "hooks/files.h"
static char miceFSCwd[MAX_PATH + 1];
@ -51,7 +49,7 @@ static volatile LONG miceFsLockCount = 0;
BOOL MiceFSInit(VOID) {
// By not using MiceFSSetCwd we can save a buffer allocation
GetCurrentDirectoryA(sizeof miceFSCwd, miceFSCwd);
_GetCurrentDirectoryA(sizeof miceFSCwd, miceFSCwd);
return TRUE;
}
@ -114,58 +112,113 @@ BOOL MiceFSAddDevLayers(VOID) {
CHAR szMountPoint[4];
CHAR szTargetPath[MAX_PATH + 1];
ZeroMemory(szTargetPath, sizeof szTargetPath);
strcpy_s(szTargetPath, sizeof szTargetPath, ".\\dev\\x\\");
strcpy_s(szTargetPath, sizeof szTargetPath, MiceIpcRelativePath("dev\\x\\"));
DWORD index = strlen(szTargetPath) - 2;
CHAR szCurrentDir[MAX_PATH + 1];
_GetCurrentDirectoryA(sizeof szCurrentDir, szCurrentDir);
// See below TODO
if (szCurrentDir[0] == RING_MOUNT_APPDATA[0]) {
log_error(plfBoot,
"Booting on the %s drive is currently unsupported. There's a potential for it to "
"do nasty things to your computer at the moment.",
RING_MOUNT_APPDATA);
exit(0);
}
BOOL success = TRUE;
for (int i = 0; i < 26; i++) {
if (i == 2) continue; // TODO: DON'T SKIP C
// TODO: DON'T SKIP C
/**
* Note: This is currently skipped because things such as DLLs, COM
* registrations, etc. are all stored on C.
* I have, however, run into an issue with a game (I forget which)
* where _not_ hooking C caused issues.
* This will likely require fine-grained whitelists.
*/
if (i == 2) continue;
// TODO: Cleaner way to not skip the current drive?
// Currently skipped because of games that compile shaders at runtime (eg SDCM), however
// this could cause issues if a game is running on a drive letter that we really need to
// hook. _Are_ there any drive letters that would prove fatal? Appdata, probably. To
// protect users from themselves, we're currently rejecting the use of Y: as a boot drive
// entirely. This is ugly, and I hate it very much, but I have bigger fish to fry for now.
if (i == szCurrentDir[0] - 'A' || i == szCurrentDir[0] - 'a') continue;
szMountPoint[0] = 'A' + (char)i;
szMountPoint[1] = ':';
szMountPoint[2] = '\\';
szMountPoint[3] = '\0';
szTargetPath[6] = 'a' + (char)i;
szTargetPath[index] = 'a' + (char)i;
success &= MiceFSAddLayer(szMountPoint, szTargetPath);
}
return success;
}
BOOL MiceFSAddRingedgeLayers(BOOL bIsOsupdate) {
/**
* Note: Layers are searched in reverse order. Most lookups will be served by:
* 1. original
* 2. pathch
* 3. extend
* so those are added last!
*/
BOOL success = TRUE;
// Windows file systems
success &= MiceFSAddLayer(RING_MOUNT_OS, "mount/os");
// success &= MiceFSAddLayer(RING_MOUNT_EXTEND, "mount/extend");
success &= MiceFSAddLayer(RING_MOUNT_RECOVERY, "mount/os_recovery");
// TrueCrypt Volumes
success &= MiceFSAddLayer(RING_MOUNT_SYSTEM, "mount/system");
success &= MiceFSAddLayer(RING_MOUNT_ORIGINAL, "mount/original");
success &= MiceFSAddLayer(RING_MOUNT_PATCH, "mount/patch");
if (bIsOsupdate) {
success &= MiceFSAddLayer(RING_MOUNT_OS_UPDATE, "mount/os_update");
success &= MiceFSAddLayer(RING_MOUNT_OS_DEFAULT_DRVIERS, "mount/os_default_drivers");
} else {
// success &= MiceFSAddLayer(RING_MOUNT_EXTEND_VOL, "mount/extend/extend");
// success &= MiceFSAddLayer(RING_MOUNT_EXTEND2_VOL, "mount/extend/extend2");
}
// geminifs
success &= MiceFSAddLayer(RING_MOUNT_GAME, "mount/original");
success &= MiceFSAddLayer(RING_MOUNT_GAME, "mount/patch");
// External media
success &= MiceFSAddLayer(RING_MOUNT_APM, "mount/apm");
success &= MiceFSAddLayer(RING_MOUNT_AM_LOG, "mount/am_log");
success &= MiceFSAddLayer(RING_MOUNT_DVD, "mount/dvd");
success &= MiceFSAddLayer(RING_MOUNT_DEV, "mount/dev");
// TODO: Configurable!
MiceFSAddLayer("R:", "H:\\Arcades\\USBs\\FiNALE_DL\\usb");
MiceFSAddLayer("S:", "C:\\Users\\Nathan\\Desktop\\ac_research\\sega\\S-Drive");
MiceFSAddLayer("C:\\System\\Execute", "C:\\Users\\Nathan\\Desktop\\ac_research\\sega\\S-Drive");
// Windows file systems
// TODO: See note about the C: drive above
// success &= MiceFSAddLayer(RING_MOUNT_OS, MiceIpcRelativePath("mount\\os"));
// success &= MiceFSAddLayer(RING_MOUNT_APPDATA, MiceIpcRelativePath("mount\\extend"));
success &= MiceFSAddLayer(RING_MOUNT_RECOVERY, MiceIpcRelativePath("mount\\os_recovery"));
// External media
success &= MiceFSAddLayer(RING_MOUNT_APM, MiceIpcRelativePath("mount\\apm"));
success &= MiceFSAddLayer(RING_MOUNT_AM_LOG, MiceIpcRelativePath("mount\\am_log"));
success &= MiceFSAddLayer(RING_MOUNT_DVD, MiceIpcRelativePath("mount\\dvd"));
success &= MiceFSAddLayer(RING_MOUNT_DEV, MiceIpcRelativePath("mount\\dev"));
success &= MiceFSAddLayer("C:\\Documents and Settings\\AppUser",
MiceIpcRelativePath("mount\\appuser"));
success &= MiceFSAddLayer("C:\\Documents and Settings\\SystemUser",
MiceIpcRelativePath("mount\\systemuser"));
success &=
MiceFSAddLayer("C:\\DOCUME~1\\SYSTEM~1\\LOCALS~1\\Temp\\", MiceIpcRelativePath("temp"));
// TrueCrypt Volumes
success &= MiceFSAddLayer(RING_MOUNT_SYSTEM, MiceIpcRelativePath("mount\\system"));
if (bIsOsupdate) {
success &= MiceFSAddLayer(RING_MOUNT_OS_UPDATE, MiceIpcRelativePath("mount\\os_update"));
success &= MiceFSAddLayer(RING_MOUNT_OS_DEFAULT_DRVIERS,
MiceIpcRelativePath("mount\\os_default_drivers"));
} else {
// success &= MiceFSAddLayer(RING_MOUNT_EXTEND_VOL,
// MiceIpcRelativePath("mount\\extend/extend")); success &=
// MiceFSAddLayer(RING_MOUNT_EXTEND2_VOL, MiceIpcRelativePath("mount\\extend/extend2"));
}
success &= MiceFSAddLayer(RING_MOUNT_PATCH, MiceIpcRelativePath("mount\\patch"));
success &= MiceFSAddLayer(RING_MOUNT_ORIGINAL, MiceIpcRelativePath("mount\\original"));
// geminifs
success &= MiceFSAddLayer(RING_MOUNT_GAME, MiceIpcRelativePath("mount\\patch"));
success &= MiceFSAddLayer(RING_MOUNT_GAME, MiceIpcRelativePath("mount\\original"));
// Make directories that we're going to need
make_dirs(MiceIpcRelativePath("mount\\appuser\\temp"));
make_dirs(MiceIpcRelativePath("temp"));
// Directories games read and write
make_dirs(MiceIpcRelativePath("dev\\w"));
make_dirs(MiceIpcRelativePath("dev\\v"));
make_dirs(MiceIpcRelativePath("dev\\y"));
make_dirs(MiceIpcRelativePath("dev\\x"));
return success;
}
@ -288,14 +341,17 @@ BOOL MiceFSRedirectPathA(LPCSTR lpFilename, LPCSTR* pszRedirected) {
PMICE_FS_LAYER layer = miceFsRoot.m_Next;
CHAR szTail[MAX_PATH + 1];
wchar_t szwPath[MAX_PATH + 1];
BOOL bFound = FALSE;
while (layer) {
if (MiceFSMatchPathA(szExpanded, layer->m_lpMountPoint, szTail, sizeof szTail)) {
_redirected_path[0] = '\0';
PathCombineA(_redirected_path, layer->m_lpTargetPath, szTail);
*pszRedirected = _redirected_path;
if (pszRedirected) *pszRedirected = _redirected_path;
if (_PathFileExistsA(_redirected_path)) {
MultiByteToWideChar(0, 0, _redirected_path, -1, szwPath, _countof(szwPath));
if (FileExistsW(szwPath)) {
MiceReleaseLockShared(miceFsLockCount);
return TRUE;
}
@ -320,6 +376,56 @@ BOOL MiceFSRedirectPathW(LPCWSTR lpFileName, LPCWSTR* pszRedirected) {
if (!bRedirected) return FALSE;
MultiByteToWideChar(CP_ACP, 0, szRedirected, -1, _redirected_path_w, sizeof _redirected_path_w);
*pszRedirected = _redirected_path_w;
if (pszRedirected) *pszRedirected = _redirected_path_w;
return bRedirected;
}
void MiceFSDebugPrintLayers(void) {
MiceTakeLockShared(miceFsLockCount);
PMICE_FS_LAYER lpLayer = &miceFsRoot;
while (lpLayer = lpLayer->m_Next) {
printf("%s -> %s\n", lpLayer->m_lpMountPoint, lpLayer->m_lpTargetPath);
}
MiceReleaseLockShared(miceFsLockCount);
}
BOOL MiceFSDebugTraceRedirectPathA(LPCSTR lpFilename, LPCSTR* pszRedirected) {
printf("Tracing redirect of %s:\n", lpFilename);
CHAR szExpanded[MAX_PATH + 1];
if (!MiceFSGetFullPathNameA(lpFilename, sizeof szExpanded, szExpanded, NULL)) {
printf(":: Redirect ended early with no action taken.");
return FALSE;
}
MiceTakeLockShared(miceFsLockCount);
PMICE_FS_LAYER layer = miceFsRoot.m_Next;
CHAR szTail[MAX_PATH + 1];
wchar_t szwPath[MAX_PATH + 1];
BOOL bFound = FALSE;
while (layer) {
if (MiceFSMatchPathA(szExpanded, layer->m_lpMountPoint, szTail, sizeof szTail)) {
_redirected_path[0] = '\0';
PathCombineA(_redirected_path, layer->m_lpTargetPath, szTail);
if (pszRedirected) *pszRedirected = _redirected_path;
MultiByteToWideChar(0, 0, _redirected_path, -1, szwPath, _countof(szwPath));
printf("-> %s\n", _redirected_path);
if (FileExistsW(szwPath)) {
MiceReleaseLockShared(miceFsLockCount);
printf(":: Redirect ended with valid redirection found.");
return TRUE;
}
bFound = TRUE;
}
layer = layer->m_Next;
}
MiceReleaseLockShared(miceFsLockCount);
printf(":: Redirect ended with no redirection found.");
return FALSE;
}

View File

@ -3,7 +3,7 @@
#include <Windows.h>
#define RING_MOUNT_OS "C:"
#define RING_MOUNT_EXTEND "Y:"
#define RING_MOUNT_APPDATA "Y:"
#define RING_MOUNT_RECOVERY "Z:"
#define RING_MOUNT_SYSTEM "S:"
#define RING_MOUNT_ORIGINAL "O:"
@ -71,7 +71,7 @@ VOID MiceFSSetCwd(LPCSTR lpNewCwd);
BOOL MiceFSAddLayer(_In_z_ LPCSTR lpMountPoint, _In_z_ LPCSTR lpTargetPath);
/**
* @brief Add layers for all drive letters backed by ".\dev\[letter]"
* @brief Add layers for all drive letters backed by ".\mice\dev\[letter]"
* If used, this should be the first set of layers added, to act as a fallback
*
* @return BOOL Success. As this function adds 26 layers, and failiure could occur at any time,
@ -148,8 +148,17 @@ BOOL MiceFSMatchPathA(_In_z_ LPCSTR lpPath, _In_z_ LPCSTR lpPrefix,
* @param pszRedirected Redirected real filename
* @return BOOL If redirection occured
*/
BOOL MiceFSRedirectPathA(_In_z_ LPCSTR lpFileName, _Out_ LPCSTR* pszRedirected);
BOOL MiceFSRedirectPathA(_In_z_ LPCSTR lpFileName, _Out_opt_ LPCSTR* pszRedirected);
/**
* @brief Wide variant of MiceFSRedirectPathA
*/
BOOL MiceFSRedirectPathW(_In_z_ LPCWSTR lpFileName, _Out_ LPCWSTR* pszRedirected);
BOOL MiceFSRedirectPathW(_In_z_ LPCWSTR lpFileName, _Out_opt_ LPCWSTR* pszRedirected);
/**
* @brief Output a list of all filesystem layers to stdout
*/
void MiceFSDebugPrintLayers(void);
/**
* @brief Perform MiceFSRedirectPathA, with trace logging to stdout
*/
BOOL MiceFSDebugTraceRedirectPathA(_In_z_ LPCSTR lpFileName, _Out_opt_ LPCSTR* pszRedirected);

View File

@ -6,7 +6,8 @@
#define HDATA_FIND_VOLUME 1
#define HDATA_ANY 0xFFFFFFFF
BOOL FileExists(wchar_t* szPath);
BOOL FileExistsW(const wchar_t* szPath);
BOOL FileExistsA(const char* szPath);
PVOID GetDataForHandle(HANDLE hObject, DWORD type);
void SetDataForHandle(HANDLE hObject, DWORD type, PVOID pData, BOOL isHeap);
BOOL RemoveDataForHandle(HANDLE hObject, DWORD type);
@ -24,7 +25,7 @@ char GetGamedataDrive(void);
BOOL IsGamedataLocalPath(LPCSTR path);
void make_dirs(const char* path);
void* open_mapped_file(LPCWSTR path, DWORD size, HANDLE* file, HANDLE* file_mapping);
void* open_mapped_file(LPCSTR path, DWORD size, HANDLE* file, HANDLE* file_mapping);
#define char_lower(value) (('A' <= (value) && (value) <= 'Z') ? ((value) - 'A' + 'a') : (value))
#define char_upper(value) (('a' <= (value) && (value) <= 'z') ? ((value) - 'a' + 'A') : (value))

View File

@ -1,5 +1,6 @@
#include "hook.h"
#include <detours.h>
#include <memory.h>
#include <stdbool.h>
#include <stdlib.h>
@ -28,132 +29,176 @@ void hook(LPCSTR dll, LPCSTR name, void* patch, void** store) {
append_hook(hook);
}
void patch_at(PVOID addr, const char* patch, DWORD length) {
DWORD MiceGetImageBase(void) {
static DWORD imageBase = 0;
if (imageBase != 0) return imageBase;
WCHAR sModulePath[MAX_PATH];
GetModuleFileNameW(NULL, sModulePath, MAX_PATH);
HANDLE hObject =
CreateFileW(sModulePath, FILE_READ_DATA, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
if (hObject == INVALID_HANDLE_VALUE) {
log_error(plfBoot, "Failed to open %ls %03x", sModulePath, GetLastError());
return 0;
}
IMAGE_DOS_HEADER dosHeader = { 0 };
DWORD nRead;
SetFilePointer(hObject, 0, NULL, FILE_BEGIN);
ReadFile(hObject, &dosHeader, sizeof dosHeader, &nRead, NULL);
if (nRead != sizeof dosHeader) {
log_error(plfBoot, "Failed to read DOS header %03x", GetLastError());
return 0;
}
if (dosHeader.e_magic != IMAGE_DOS_SIGNATURE) {
log_error(plfBoot, "Invalid DOS magic number: %04x", dosHeader.e_magic);
return 0;
}
IMAGE_NT_HEADERS32 ntHeaders32 = { 0 };
SetFilePointer(hObject, dosHeader.e_lfanew, NULL, FILE_BEGIN);
ReadFile(hObject, &ntHeaders32, sizeof ntHeaders32, &nRead, NULL);
if (nRead != sizeof ntHeaders32) {
log_error(plfBoot, "Failed to read NT header %03x", GetLastError());
return 0;
}
if (ntHeaders32.Signature != IMAGE_NT_SIGNATURE) {
log_error(plfBoot, "Invalid NT signature: %08x", ntHeaders32.Signature);
return 0;
}
CloseHandle(hObject);
return (imageBase = ntHeaders32.OptionalHeader.ImageBase);
}
void MiceHookPatchAt(PVOID addr, const void* patch, DWORD length) {
DWORD oldProt;
VirtualProtect(addr, length, PAGE_EXECUTE_READWRITE, &oldProt);
memcpy(addr, patch, length);
VirtualProtect(addr, length, oldProt, &oldProt);
}
void clear_at(PVOID addr, BYTE clearVal, DWORD length) {
void MiceHookClearAt(PVOID addr, BYTE clearVal, DWORD length) {
DWORD oldProt;
VirtualProtect(addr, length, PAGE_EXECUTE_READWRITE, &oldProt);
memset(addr, clearVal, length);
VirtualProtect(addr, length, oldProt, &oldProt);
}
BOOL Detour(PVOID src, PVOID dst, const intptr_t len) {
if (len < 5) return FALSE;
// BOOL Detour(PVOID src, PVOID dst, const intptr_t len) {
// if (len < 5) return FALSE;
DWORD oldProt;
VirtualProtect(src, len, PAGE_EXECUTE_READWRITE, &oldProt);
// DWORD oldProt;
// VirtualProtect(src, len, PAGE_EXECUTE_READWRITE, &oldProt);
*(PCHAR)src = '\xE9';
*(PINT)((int)src + 1) = (int)dst - (int)src - 5;
// *(PCHAR)src = '\xE9';
// *(PINT)((size_t)src + 1) = size2int((size_t)dst - (size_t)src - 5);
VirtualProtect(src, len, oldProt, &oldProt);
return TRUE;
}
// VirtualProtect(src, len, oldProt, &oldProt);
// return TRUE;
// }
void* Win32HotpatchHook(PVOID src, PVOID dst) {
LPBYTE bSrc = (LPBYTE)src;
// void* Win32HotpatchHook(PVOID src, PVOID dst) {
// LPBYTE bSrc = (LPBYTE)src;
DWORD oldProt;
VirtualProtect(bSrc - 5, 7, PAGE_EXECUTE_READWRITE, &oldProt);
// DWORD oldProt;
// VirtualProtect(bSrc - 5, 7, PAGE_EXECUTE_READWRITE, &oldProt);
// relative JMP to dst
bSrc[-5] = 0xE9;
DWORD relJump = (DWORD)dst - (DWORD)src;
bSrc[-1] = (relJump >> 24) & 0xff;
bSrc[-2] = (relJump >> 16) & 0xff;
bSrc[-3] = (relJump >> 8) & 0xff;
bSrc[-4] = relJump & 0xff;
// JMP $-5
bSrc[0] = 0xEB;
bSrc[1] = 0xF9;
// // relative JMP to dst
// bSrc[-5] = 0xE9;
// size_t relJump = (size_t)dst - (size_t)src;
// bSrc[-1] = (relJump >> 24) & 0xff;
// bSrc[-2] = (relJump >> 16) & 0xff;
// bSrc[-3] = (relJump >> 8) & 0xff;
// bSrc[-4] = relJump & 0xff;
// // JMP $-5
// bSrc[0] = 0xEB;
// bSrc[1] = 0xF9;
VirtualProtect(bSrc - 5, 7, oldProt, &oldProt);
// VirtualProtect(bSrc - 5, 7, oldProt, &oldProt);
// We don't need a gateway; we can just jump right in
return bSrc + 2;
}
// // We don't need a gateway; we can just jump right in
// return bSrc + 2;
// }
#define CMP2(x, a, b) (x[0] == 0x##a && x[1] == 0x##b)
#define CMP3(x, a, b, c) (CMP2(x, a, b) && x[2] == 0x##c)
#define CMP4(x, a, b, c, d) (CMP3(x, a, b, c) && x[3] == 0x##d)
#define CMP5(x, a, b, c, d, e) (CMP4(x, a, b, c, d) && x[4] == 0x##e)
void* CreateHook32(PVOID src, PVOID dst) {
LPBYTE bSrc = (LPBYTE)src;
// #define CMP2(x, a, b) (x[0] == 0x##a && x[1] == 0x##b)
// #define CMP3(x, a, b, c) (CMP2(x, a, b) && x[2] == 0x##c)
// #define CMP4(x, a, b, c, d) (CMP3(x, a, b, c) && x[3] == 0x##d)
// #define CMP5(x, a, b, c, d, e) (CMP4(x, a, b, c, d) && x[4] == 0x##e)
// void* CreateHook32(PVOID src, PVOID dst) {
// LPBYTE bSrc = (LPBYTE)src;
// If this DLL is hotpatchable, sieze the opportunity
if (bSrc[0] == 0x8b && bSrc[1] == 0xff && bSrc[-1] == 0xCC && bSrc[-2] == 0xCC &&
bSrc[-3] == 0xCC && bSrc[-4] == 0xCC && bSrc[-5] == 0xCC) {
return Win32HotpatchHook(src, dst);
}
// // If this DLL is hotpatchable, sieze the opportunity
// if (bSrc[0] == 0x8b && bSrc[1] == 0xff && bSrc[-1] == 0xCC && bSrc[-2] == 0xCC &&
// bSrc[-3] == 0xCC && bSrc[-4] == 0xCC && bSrc[-5] == 0xCC) {
// return Win32HotpatchHook(src, dst);
// }
intptr_t len = 5;
// intptr_t len = 5;
// This is a very crude way to identify common instruction patterns
// to select or patch length.
if (CMP2(bSrc, ff, 25)) {
// jmp DWORD PTR ds:0x........
len = 6;
} else if (bSrc[0] == 0x6a && bSrc[2] == 0x68) {
// push 0x... (byte)
// push 0x... (dword)
len = 7;
} else if (bSrc[0] == 0x6a && bSrc[2] == 0xb8) {
// push 0x... (byte)
// mov eax,0x... (dword)
len = 7;
} else if (bSrc[0] == 0x68) {
// push 0x... (dword)
len = 5;
} else if (CMP5(bSrc, 55, 8B, EC, 83, E4)) {
// pusb ebp
// mov ebp,esp
// and esp,ffffff**
len = 6;
} else if (CMP5(bSrc, 55, 8B, EC, 8B, 45)) {
// pusb ebp
// mov ebp,esp
// mov eax,DWORD PTR [...]
len = 6;
} else if (CMP5(bSrc, 55, 8B, EC, 80, 3D)) {
// pusb ebp
// mov ebp,esp
// cmd BYTE PTR ds:0x...,0x...
len = 10;
} else if (CMP5(bSrc, B8, 00, 10, 00, 00)) {
// mov eax,0x1000
len = 5;
} else {
log_error(plfHooks, "Unable to identify gateway length! Function peek:");
for (int i = 0; i < 16; i++) {
printf("%02x ", ((LPBYTE)src)[i]);
}
puts("");
log_error(plfHooks, "Unsafely defaulting to 5!");
len = 5;
}
// // This is a very crude way to identify common instruction patterns
// // to select or patch length.
// if (CMP2(bSrc, ff, 25)) {
// // jmp DWORD PTR ds:0x........
// len = 6;
// } else if (bSrc[0] == 0x6a && bSrc[2] == 0x68) {
// // push 0x... (byte)
// // push 0x... (dword)
// len = 7;
// } else if (bSrc[0] == 0x6a && bSrc[2] == 0xb8) {
// // push 0x... (byte)
// // mov eax,0x... (dword)
// len = 7;
// } else if (bSrc[0] == 0x68) {
// // push 0x... (dword)
// len = 5;
// } else if (CMP5(bSrc, 55, 8B, EC, 83, E4)) {
// // pusb ebp
// // mov ebp,esp
// // and esp,ffffff**
// len = 6;
// } else if (CMP5(bSrc, 55, 8B, EC, 8B, 45)) {
// // pusb ebp
// // mov ebp,esp
// // mov eax,DWORD PTR [...]
// len = 6;
// } else if (CMP5(bSrc, 55, 8B, EC, 80, 3D)) {
// // pusb ebp
// // mov ebp,esp
// // cmd BYTE PTR ds:0x...,0x...
// len = 10;
// } else if (CMP5(bSrc, B8, 00, 10, 00, 00)) {
// // mov eax,0x1000
// len = 5;
// } else {
// char hex_str[16 * 3 + 1];
// hex_str[0] = 0;
// for (int i = 0; i < 16; i++) {
// snprintf(&hex_str[i * 3], 4, "%02x ", ((LPBYTE)src)[i]);
// }
// hex_str[sizeof hex_str - 1] = 0;
// log_error(plfHooks, "Unable to identify gateway length! Function peek: %s", hex_str);
// log_error(plfHooks, "Unsafely defaulting to 5!");
// len = 5;
// }
PVOID gateway = VirtualAlloc(0, len + 5, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
if (!gateway) return NULL;
// PVOID gateway = VirtualAlloc(0, len + 5, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
// if (!gateway) return NULL;
memcpy(gateway, src, len);
// memcpy(gateway, src, len);
*(PCHAR)((int)gateway + len) = '\xE9';
*(PINT)((int)gateway + len + 1) = (int)src - (int)gateway - 5;
// *(PCHAR)((size_t)gateway + len) = '\xE9';
// *(PINT)((size_t)gateway + len + 1) = size2int((size_t)src - (size_t)gateway - 5);
Detour(src, dst, len);
// Detour(src, dst, len);
return gateway;
}
// return gateway;
// }
extern FARPROC (*TrueGetProcAddress)(HMODULE hModule, LPCSTR lpProcName);
// extern FARPROC (*TrueGetProcAddress)(HMODULE hModule, LPCSTR lpProcName);
void setup_hooks() {
log_info(plfHooks, "attaching");
LONG detourError;
if (hook_list == NULL) {
log_warning(plfHooks, "No hooks to register!");
return;
@ -176,13 +221,27 @@ void setup_hooks() {
if (original == NULL) {
log_warning(plfHooks, "failed to get original %s (%03x)", hook->name, GetLastError());
} else {
void* gateway = CreateHook32(original, hook->patch);
if (hook->store != NULL) *hook->store = gateway;
// void* gateway = CreateHook(original, hook->patch);
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
detourError = DetourAttach(&original, hook->patch);
if (detourError != NO_ERROR) {
log_error(plfHooks, "DetourAttach failed: %d", detourError);
DetourTransactionAbort();
continue;
}
detourError = DetourTransactionCommit();
if (detourError != NO_ERROR) {
log_error(plfHooks, "DetourTransactionCommit failed: %d", detourError);
continue;
}
if (hook->store != NULL) *hook->store = original;
log_misc(plfHooks, "hooked %s", hook->name);
}
hook = hook->next;
} while (hook != NULL);
log_info(plfHooks, "attach complete");
}

View File

@ -10,11 +10,21 @@ typedef struct function_hook {
struct function_hook* next;
} function_hook_t;
static BOOL Detour(PVOID src, PVOID dst, const intptr_t len);
#define NOP 0x90
void patch_at(PVOID addr, const char* patch, DWORD length);
void clear_at(PVOID addr, BYTE clearVal, DWORD length);
void* CreateHook32(PVOID src, PVOID dst);
DWORD MiceGetImageBase(void);
void MiceHookPatchAt(PVOID addr, const void* patch, DWORD length);
#define MiceHookPatchAtImage(hModule, addr, patch, length) \
MiceHookPatchAt((PVOID)((DWORD)(addr) + ((DWORD)(hModule)-MiceGetImageBase())), (patch), \
(length))
void MiceHookClearAt(PVOID addr, BYTE clearVal, DWORD length);
#define MiceHookClearAtImage(hModule, addr, clearVal, length) \
MiceHookClearAt((PVOID)((DWORD)(addr) + ((DWORD)(hModule)-MiceGetImageBase())), (clearVal), \
(length))
#define MiceHookNopAt(addr, length) MiceHookClearAt((addr), NOP, (length))
#define MiceHookNopAtImage(hModule, addr, length) \
MiceHookClearAtImage((hModule), (addr), NOP, (length))
static void append_hook(function_hook_t* hook);
void hook(LPCSTR dll, LPCSTR name, void* patch, void** store);

View File

@ -31,8 +31,14 @@ void PrintStack(void) {
free(symbol);
}
BOOL FileExists(wchar_t* szPath) {
DWORD dwAttrib = GetFileAttributesW(szPath);
BOOL FileExistsW(const wchar_t* szPath) {
DWORD dwAttrib = _GetFileAttributesW(szPath);
return (dwAttrib != INVALID_FILE_ATTRIBUTES && !(dwAttrib & FILE_ATTRIBUTE_DIRECTORY));
}
BOOL FileExistsA(const char* szPath) {
wchar_t szPathW[MAX_PATH + 1];
MultiByteToWideChar(0, 0, szPath, -1, szPathW, _countof(szPathW));
DWORD dwAttrib = _GetFileAttributesW(szPathW);
return (dwAttrib != INVALID_FILE_ATTRIBUTES && !(dwAttrib & FILE_ATTRIBUTE_DIRECTORY));
}
@ -156,17 +162,17 @@ void make_dirs(const char* path) {
free(temp);
}
void* open_mapped_file(LPCWSTR lpFilename, DWORD size, HANDLE* file, HANDLE* file_mapping) {
char szFileName[MAX_PATH] = { 0 };
WideCharToMultiByte(CP_ACP, 0, lpFilename, wcslen(lpFilename), szFileName, sizeof szFileName,
NULL, NULL);
make_dirs(szFileName);
void* open_mapped_file(LPCSTR lpFilename, DWORD size, HANDLE* file, HANDLE* file_mapping) {
// char szFileName[MAX_PATH] = { 0 };
// WideCharToMultiByte(CP_ACP, 0, lpFilename, wcslen(lpFilename), szFileName,
// size2int(sizeof szFileName), NULL, NULL);
make_dirs(lpFilename);
*file = _CreateFileW(lpFilename, GENERIC_READ | GENERIC_WRITE,
*file = _CreateFileA(lpFilename, GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_ALWAYS,
FILE_ATTRIBUTE_NORMAL, NULL);
if (*file == INVALID_HANDLE_VALUE) {
log_error(plfMisc, "Failed to CreateFileW(%ls): %d", lpFilename, GetLastError());
log_error(plfMisc, "Failed to CreateFileW(%s): %d", lpFilename, GetLastError());
return NULL;
}

View File

@ -3,6 +3,8 @@
#include <stdlib.h>
#include <string.h>
#include "../hooks/files.h"
BOOL PathEqual(LPCSTR path1, LPCSTR path2) {
char buffer1[MAX_PATH];
char buffer2[MAX_PATH];
@ -24,10 +26,10 @@ BOOL PathPrefix(LPCSTR path, LPCSTR prefix) {
static char WORKING_DIR[MAX_PATH + 1] = { 0 };
char GetGamedataDrive(void) {
if (WORKING_DIR[0] == 0x00) GetCurrentDirectoryA(sizeof WORKING_DIR, WORKING_DIR);
if (WORKING_DIR[0] == 0x00) _GetCurrentDirectoryA(sizeof WORKING_DIR, WORKING_DIR);
return WORKING_DIR[0];
}
BOOL IsGamedataLocalPath(LPCSTR path) {
if (WORKING_DIR[0] == 0x00) GetCurrentDirectoryA(sizeof WORKING_DIR, WORKING_DIR);
if (WORKING_DIR[0] == 0x00) _GetCurrentDirectoryA(sizeof WORKING_DIR, WORKING_DIR);
return PathPrefix(path, WORKING_DIR);
}

View File

@ -3,8 +3,14 @@
#include "../lib/mice/mice.h"
const char* KNOWN_GAMES[] = {
// Ideally, we're running from the X: root
"maimai\\maimai_dump_.exe",
"maimai\\maimai_dump.exe",
"maimai\\Game.exe",
// Preferentially use a decrypted dump if present
"maimai_dump_.exe",
"maimai_dump.exe",
"Game.exe",
// Specific games
"DOA5A.exe",
@ -16,50 +22,12 @@ const char* KNOWN_GAMES[] = {
"maimai.exe",
};
bool locate_file(char* path, size_t len, const char* exe) {
WIN32_FIND_DATA fdFile;
HANDLE hFind = NULL;
char work_path[2048];
snprintf(work_path, sizeof work_path, ".\\*.*");
if ((hFind = FindFirstFile(work_path, &fdFile)) == INVALID_HANDLE_VALUE) return false;
do {
if (!strcmp(fdFile.cFileName, ".") || !strcmp(fdFile.cFileName, "..")) continue;
if (fdFile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) continue;
if (!strcmp(fdFile.cFileName, exe)) {
snprintf(path, len, ".\\%s", fdFile.cFileName);
FindClose(hFind);
return true;
}
} while (FindNextFile(hFind, &fdFile));
FindClose(hFind);
return false;
}
bool locate_game(char* path, size_t len) {
// This is slightly wasteful, but is needed to ensure priority!
for (size_t i = 0; i < ((sizeof KNOWN_GAMES) / (sizeof KNOWN_GAMES[0])); i++) {
if (locate_file(path, len, KNOWN_GAMES[i])) {
for (size_t i = 0; i < _countof(KNOWN_GAMES); i++) {
if (PathFileExistsA(KNOWN_GAMES[i])) {
snprintf(path, len, ".\\%s", KNOWN_GAMES[i]);
return true;
}
}
return false;
}
bool locate_library(char* path, size_t len) {
if (locate_file(path, len, MiceConfig.launcher.mice_dll)) return true;
// Don't call DllMain! We don't want to hook ourself!
HANDLE mice = LoadLibraryExA(MiceConfig.launcher.mice_dll, NULL, DONT_RESOLVE_DLL_REFERENCES);
if (mice != NULL) {
GetModuleFileNameA(mice, path, len);
return true;
}
return false;
}

View File

@ -4,6 +4,4 @@
#include <stdio.h>
#include <tchar.h>
bool locate_exe(char* path, size_t len, const char* exe);
bool locate_game(char* path, size_t len);
bool locate_library(char* path, size_t len);

View File

@ -1,6 +1,7 @@
#include <Windows.h>
#include <stdio.h>
#include "../lib/mice/ipc.h"
#include "../lib/mice/mice.h"
#include "../lib/util/pid.h"
#include "locate.h"
@ -10,7 +11,10 @@ bool debug_wait = false;
int boot_delay = 0;
char exe_name[MAX_PATH + 1] = "";
size_t nCommandLine = 256;
BYTE _MiceLauncherNext = 2;
HANDLE _MiceLauncherNextEvent = INVALID_HANDLE_VALUE;
size_t nCommandLine = 0;
char* commandLine = NULL;
static void print_help(char* exe) {
@ -71,19 +75,22 @@ static bool parse_cmdline(int argc, char* argv[]) {
return false;
}
} else {
size_t newLength = nCommandLine + 1 + strlen(argv[i]) + 1;
if (newLength > nCommandLine) {
nCommandLine = newLength;
nCommandLine += 1 + strlen(argv[i]) + 1;
if (commandLine == NULL) {
commandLine = malloc(nCommandLine);
commandLine[0] = '\0';
} else {
commandLine = realloc(commandLine, nCommandLine);
}
strcat_s(commandLine, nCommandLine, " ");
strcat_s(commandLine, nCommandLine, argv[i]);
commandLine[nCommandLine - 1] = '\0';
}
}
return true;
}
static DWORD WINAPI MiceMailslotWatcher(HANDLE* pSlot) {
static DWORD WINAPI MiceIpcMessageWatcher(PVOID _) {
// Enable colour support in conhost
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
DWORD dwMode = 0;
@ -101,132 +108,253 @@ static DWORD WINAPI MiceMailslotWatcher(HANDLE* pSlot) {
}
}
OVERLAPPED ov;
HANDLE hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
ov.Offset = ov.OffsetHigh = 0;
ov.hEvent = hEvent;
char readBuffer[4096];
DWORD nRead, nBytes;
while (1) {
nRead = nBytes = 0;
ReadFile(*pSlot, readBuffer, sizeof readBuffer, &nRead, &ov);
GetOverlappedResult(*pSlot, &ov, &nBytes, TRUE);
DWORD nWrote;
WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), readBuffer, nBytes, &nWrote, NULL);
MICE_IPC_MESSAGE message;
MiceIpcPopMessage(&message, TRUE);
if (hLogFile != INVALID_HANDLE_VALUE) {
// The only VT100 sequences being used are colours, so this lazy approach works
BOOL inVt100 = FALSE;
for (unsigned int i = 0; i < nBytes; i++) {
if (readBuffer[i] == '\033') {
inVt100 = TRUE;
continue;
switch (message.m_Type) {
case MICE_IPC_TYPE_LOG:
// printf("%s", message.m_Message);
DWORD nWrote;
WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), message.m_Message, message.m_Size,
&nWrote, NULL);
if (hLogFile != INVALID_HANDLE_VALUE) {
// The only VT100 sequences being used are colours, so this lazy approach works
BOOL inVt100 = FALSE;
for (unsigned int i = 0; i < message.m_Size; i++) {
if (message.m_Message[i] == '\033') {
inVt100 = TRUE;
continue;
}
if (inVt100 && message.m_Message[i] == 'm') {
inVt100 = FALSE;
continue;
}
if (!inVt100)
WriteFile(hLogFile, &(message.m_Message[i]), 1, &nWrote, NULL);
}
// FlushFileBuffers(hLogFile);
}
if (inVt100 && readBuffer[i] == 'm') {
inVt100 = FALSE;
continue;
}
if (!inVt100) WriteFile(hLogFile, &(readBuffer[i]), 1, &nWrote, NULL);
}
// FlushFileBuffers(hLogFile);
// FlushFileBuffers(GetStdHandle(STD_OUTPUT_HANDLE));
break;
}
}
}
static BOOL setup_mailslot(void) {
DWORD pid = GetCurrentProcessId();
char slotName[MAX_PATH + 1];
sprintf_s(slotName, MAX_PATH, "\\\\.\\mailslot\\micelog%d", pid);
HANDLE* pSlot = malloc(sizeof(HANDLE));
if (pSlot == NULL) {
fprintf(stderr, "malloc(pSlot) failed\n");
return FALSE;
}
*pSlot = CreateMailslotA(slotName, 0, MAILSLOT_WAIT_FOREVER, NULL);
if (*pSlot == INVALID_HANDLE_VALUE) {
fprintf(stderr, "Creation of mailslot failed %d\n", GetLastError());
return FALSE;
}
CreateThread(NULL, 0, MiceMailslotWatcher, pSlot, 0, NULL);
return TRUE;
}
/**
* Because logging is via a mailslot, we need to give it a chance to flush messages before
* terminating. While we could engineer something overly fancy, the only situation this ever occurs
* is in the main() function just below.
* Because logging is via IPC, we need to give it a chance to flush messages before
* terminating. While we could engineer something overly fancy, the only situation
* this ever occurs is in the main() function just below.
*
* I'll let the code speak for itself.
*/
static int terminate(int err) {
Sleep(100);
static int terminate(int err, char* szMessage) {
printf("Mice termination occuring... %d\n", err);
log_info(plfBoot, "Terminating");
Sleep(1000);
extern unsigned char g_szFault[255 + 1];
extern BYTE g_nFault;
if (g_nFault) {
MessageBeep(MB_ICONERROR);
MessageBoxA(NULL, (LPCSTR)g_szFault, "System Fault",
MB_OK | MB_SETFOREGROUND | MB_SYSTEMMODAL);
} else if (szMessage) {
MessageBeep(MB_ICONERROR);
MessageBoxA(NULL, szMessage, "Boot Failed", MB_OK | MB_SETFOREGROUND | MB_SYSTEMMODAL);
}
return err;
}
HANDLE hJob = INVALID_HANDLE_VALUE;
BOOL WINAPI MiceHandlerRoutine(DWORD CtrlType) {
if (hJob != INVALID_HANDLE_VALUE) CloseHandle(hJob);
ExitProcess(terminate(0));
ExitProcess(terminate(0, NULL));
}
#include "../lib/mice/spad.h"
static BOOL StartGame(LPPROCESS_INFORMATION lpPi, LPCSTR args) {
// Clear out the next flag. If the game closes without setting this, we don't want to restart
// the game.
_MiceLauncherNext = 0;
hJob = CreateJobObject(NULL, NULL);
JOBOBJECT_EXTENDED_LIMIT_INFORMATION info;
info.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
SetInformationJobObject(hJob, JobObjectExtendedLimitInformation, &info, sizeof info);
size_t nFullCommandLine = strlen(exe_name) + 1;
if (args != NULL && strlen(args) > 0) nFullCommandLine += 1 + strlen(args);
if (nCommandLine > 0) nFullCommandLine += 1 + nCommandLine;
char* fullCommandLine = malloc(nFullCommandLine);
if (args != NULL && nCommandLine > 0) {
sprintf_s(fullCommandLine, nFullCommandLine, "%s %s %s", exe_name, args, commandLine);
} else if (args == NULL && nCommandLine > 0) {
sprintf_s(fullCommandLine, nFullCommandLine, "%s %s", exe_name, commandLine);
} else if (args != NULL) {
sprintf_s(fullCommandLine, nFullCommandLine, "%s %s", exe_name, args);
} else {
sprintf_s(fullCommandLine, nFullCommandLine, "%s", exe_name);
}
char* extra_injections = MiceConfig.launcher.inject;
if (!start_and_inject(hJob, exe_name, fullCommandLine, _miceIpcData->m_MiceDll, debug_wait,
boot_delay, extra_injections, 0, lpPi)) {
free(fullCommandLine);
return FALSE;
}
free(fullCommandLine);
return TRUE;
}
static BOOL _GameIdSearcher(char* lpBasePath, char* lpGameId) {
WIN32_FIND_DATAA findFileData;
CHAR szSearchPath[MAX_PATH + 1];
sprintf_s(szSearchPath, _countof(szSearchPath), "%s\\*", lpBasePath);
// Search for a table in the CWD
HANDLE hFind = FindFirstFileA(szSearchPath, &findFileData);
do {
if (strcmp(findFileData.cFileName, ".") == 0 || strcmp(findFileData.cFileName, "..") == 0)
continue;
if (findFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
sprintf_s(szSearchPath, _countof(szSearchPath), "%s\\%s", lpBasePath,
findFileData.cFileName);
if (_GameIdSearcher(szSearchPath, lpGameId)) {
FindClose(hFind);
return TRUE;
}
} else {
if (strlen(findFileData.cFileName) == strlen("SAAA_Table.dat") &&
PathMatchSpecA(findFileData.cFileName, "S*_Table.dat")) {
// maimai games have a copy of the R&D table; ignore it.
if (strncmp(findFileData.cFileName, "SBRZ", 4) == 0) continue;
lpGameId[0] = findFileData.cFileName[0];
lpGameId[1] = findFileData.cFileName[1];
lpGameId[2] = findFileData.cFileName[2];
lpGameId[3] = findFileData.cFileName[3];
FindClose(hFind);
return TRUE;
}
if (strlen(findFileData.cFileName) == strlen("SAAA_banner.bmp") &&
PathMatchSpecA(findFileData.cFileName, "S*_banner.bmp")) {
lpGameId[0] = findFileData.cFileName[0];
lpGameId[1] = findFileData.cFileName[1];
lpGameId[2] = findFileData.cFileName[2];
lpGameId[3] = findFileData.cFileName[3];
FindClose(hFind);
return TRUE;
}
if (strlen(findFileData.cFileName) == strlen("SAAA_main.wmv") &&
PathMatchSpecA(findFileData.cFileName, "S*_main.wmv")) {
lpGameId[0] = findFileData.cFileName[0];
lpGameId[1] = findFileData.cFileName[1];
lpGameId[2] = findFileData.cFileName[2];
lpGameId[3] = findFileData.cFileName[3];
FindClose(hFind);
return TRUE;
}
}
} while (FindNextFile(hFind, &findFileData));
FindClose(hFind);
return FALSE;
}
BOOL MiceGuessGameId(char* lpGameId) {
if (_GameIdSearcher(".", lpGameId)) return TRUE;
// TODO: Some more lookups. Exe name is probably not an awful fallback
return FALSE;
}
BOOL g_bIsInDllMain = FALSE;
int main(int argc, char* argv[]) {
// unsigned char spad_new_bytes[16] = {
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x52, 0x06,
// 0x94, 0x87, 0x82, 0x60, 0x37, 0x73, 0x12, 0x13,
// };
// unsigned char spn[16];
// Spad0Encrypt(spn, spad_new_bytes);
// for (int i = 0; i < 8; i++) printf("%02x", spn[i]);
// puts("");
// for (int i = 8; i < 16; i++) printf("%02x", spn[i]);
// puts("");
#if 0
// char buffer[] = "41A800003F000000000000006801";
char* buffer = argv[1];
char local_10[4];
// puts("--");
sscanf_s(buffer, "%08x", local_10, sizeof local_10);
float measure_whole = *(float*)(void*)&local_10;
printf("measure_whole: %f\n", measure_whole);
sscanf_s(buffer + 8, "%08x", local_10, sizeof local_10);
float measure_fraction = *(float*)(void*)&local_10;
printf("measure_fraction: %f\n", measure_fraction);
sscanf_s(buffer + 16, "%08x", local_10, sizeof local_10);
float duration = *(float*)(void*)&local_10;
printf("duration: %f\n", duration);
sscanf_s(buffer + 24, "%01x", local_10, sizeof local_10);
unsigned char location = local_10[0];
printf("location: %d\n", location);
// unsigned char back_out[16];
// Spad0Decrypt(back_out, spn);
// for (int i = 0; i < 8; i++) printf("%02x", back_out[i]);
// puts("");
// for (int i = 8; i < 16; i++) printf("%02x", back_out[i]);
// puts("");
sscanf_s(buffer + 25, "%01x", local_10, sizeof local_10);
unsigned char type = local_10[0];
// unsigned char bng[16] = {
// 0xE6, 0xBC, 0x6D, 0x56, 0x83, 0xF6, 0xB6, 0x48,
// 0x4C, 0x24, 0xE4, 0x83, 0xD5, 0xE8, 0x93, 0x7F,
// };
// Spad0Decrypt(back_out, bng);
// for (int i = 0; i < 8; i++) printf("%02x", back_out[i]);
// puts("");
// for (int i = 8; i < 16; i++) printf("%02x", back_out[i]);
// puts("");
printf("Type: %d\n", local_10[0]);
if (local_10[0] < '\0') {
type = type ^ 0x80;
puts("<0");
// field_0x42 = 1;
}
if ((type & 0x40) != 0) {
puts("&0x40");
type = type ^ 0x40;
// field15_0x18 = 0x40000000;
}
if ((type & 0x20) != 0) {
puts("&0x20");
type = type ^ 0x20;
// field15_0x18 = 0x40800000;
}
printf("TypeO: %01x\n", type);
// return -1;
return 0;
#endif
load_mice_config();
if (!setup_mailslot()) return 1;
if (!MiceIpcSetup(TRUE)) return 1;
_miceIpcData->m_LauncherIsReady = TRUE;
char gameId[4];
if (MiceGuessGameId(gameId)) memcpy(_miceIpcData->m_GameId, gameId, 4);
CreateThread(NULL, 0, MiceIpcMessageWatcher, NULL, 0, NULL);
setup_logging();
log_info(plfBoot, "Micetools version: %s", MICE_VERSION);
commandLine = malloc(nCommandLine);
if (commandLine == NULL) {
log_error(plfBoot, "Fatal: Failed to malloc(commandLine)");
return terminate(-1);
if (_miceIpcData->m_GameId[0] == '\0') {
if (MiceConfig.devices.do_auto) {
log_error(
plfBoot,
"Failed to identify game. Please edit [devices].do_auto to false and restart.");
log_error(plfBoot, "Please also report this.");
return terminate(-1, "Failed to identify game.");
}
log_warning(plfBoot, "Failed to identify game, but proceeding regardless.");
} else {
log_info(plfBoot, "Booting game: %.*s", 4, _miceIpcData->m_GameId);
}
commandLine[0] = '\0';
CHAR workDir[MAX_PATH + 1];
GetCurrentDirectory(MAX_PATH, workDir);
log_info(plfBoot, "Current directory: %s", workDir);
CHAR szPath[MAX_PATH + 1];
GetCurrentDirectory(MAX_PATH, szPath);
szPath[sizeof szPath - 1] = '\0';
log_info(plfBoot, "Current directory: %s", szPath);
if (!parse_cmdline(argc, argv)) return terminate(0);
if (!parse_cmdline(argc, argv)) {
puts("parse_cmdline failed");
return terminate(-2, "parse_cmdline failed");
}
if (exe_name[0] == '\0' && MiceConfig.launcher.game_binary[0] != '\0') {
snprintf(exe_name, sizeof exe_name, "%s", MiceConfig.launcher.game_binary);
@ -237,56 +365,89 @@ int main(int argc, char* argv[]) {
if (exe_name[0] == '\0') {
if (!locate_game(exe_name, MAX_PATH + 1)) {
log_error(plfBoot, "Fatal: Failed to locate a game");
return terminate(0);
return terminate(-3, "Failed to locate a game");
}
} else {
DWORD dwAttrib = GetFileAttributes(exe_name);
if (dwAttrib == INVALID_FILE_ATTRIBUTES || dwAttrib & FILE_ATTRIBUTE_DIRECTORY) {
log_error(plfBoot, "Fatal: %s: no such file found", exe_name);
return terminate(0);
return terminate(-4, "Specified executable not locatable");
}
}
int i;
// Build IPC.m_PathPrefix
{
_miceIpcData->m_PathPrefix[0] = '\0';
for (i = 0; i < sizeof _miceIpcData->m_PathPrefix; i++) {
_miceIpcData->m_PathPrefix[i] = exe_name[i];
if (exe_name[i] == '\0') break;
}
// Find the final slash in the path
for (; i > 0; i--) {
if (_miceIpcData->m_PathPrefix[i] == '/' || _miceIpcData->m_PathPrefix[i] == '\\')
break;
}
_miceIpcData->m_PathPrefix[i] = '\0';
}
strcpy_s(_miceIpcData->m_MiceBase, sizeof _miceIpcData->m_MiceBase, szPath);
if (!SearchPathA(NULL, MiceConfig.launcher.mice_dll, NULL, sizeof _miceIpcData->m_MiceDll,
_miceIpcData->m_MiceDll, NULL)) {
log_error(plfBoot, "Unable to locate micelib. Check your mice_dll setting!");
return terminate(-5, "Unable to locate micelib");
}
_miceIpcData->m_MiceDll[sizeof _miceIpcData->m_MiceDll - 1] = '\0';
_MiceLauncherNextEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
SetConsoleCtrlHandler(MiceHandlerRoutine, TRUE);
spawn_pcp_processes();
log_info(plfBoot, "exec: %s %s", exe_name, commandLine);
char micepath[MAX_PATH + 1];
if (!locate_library(micepath, MAX_PATH + 1)) {
log_error(plfBoot, "Fatal: Failed to locate micelib. Check your mice_dll setting!");
return terminate(0);
while (1) {
if (hJob != INVALID_HANDLE_VALUE) {
CloseHandle(hJob);
hJob = INVALID_HANDLE_VALUE;
}
PROCESS_INFORMATION pi;
if (_MiceLauncherNext == 2) {
if (!StartGame(&pi, NULL))
return terminate(-6, "Start failed. Check console for errors.");
} else if (_MiceLauncherNext == 3 || _MiceLauncherNext == 4) {
// TODO: Boot mode 3 is actually system test. We could do something here?
if (!StartGame(&pi, "gametest"))
return terminate(-7, "Gametest failed. Check console for errors.");
} else {
log_info(plfBoot, "Boot mode %d not supported. Exiting.", _MiceLauncherNext);
return terminate(-8, NULL);
}
HANDLE objects[2];
objects[0] = pi.hProcess;
objects[1] = _MiceLauncherNextEvent;
DWORD waited = WaitForMultipleObjects(_countof(objects), objects, FALSE, INFINITE);
if (FAILED(waited)) {
log_error(plfBoot, "Fatal: WaitForSingleObject failed: %03x", GetLastError());
return terminate(-9, "WFSO failed");
}
if (waited == WAIT_OBJECT_0) {
DWORD exitCode;
if (GetExitCodeProcess(pi.hProcess, &exitCode))
log_info(plfBoot, "Shutting down (ret:%d)", exitCode);
else
log_info(plfBoot, "Shutting down (failed to get exit code)");
CloseHandle(pi.hProcess);
continue;
// return terminate(-10);
} else if (waited == WAIT_OBJECT_0 + 1) {
continue;
} else {
log_error(plfBoot, "Unknown wait object retured: %d", waited);
return terminate(-11, "Unknown wait object!");
}
}
hJob = CreateJobObject(NULL, NULL);
JOBOBJECT_EXTENDED_LIMIT_INFORMATION info;
info.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
SetInformationJobObject(hJob, JobObjectExtendedLimitInformation, &info, sizeof info);
size_t nFullCommandLine = nCommandLine + strlen(exe_name) + 1;
char* fullCommandLine = malloc(nFullCommandLine);
snprintf(fullCommandLine, nFullCommandLine, "%s %s", exe_name, commandLine);
free(commandLine);
char* extra_injections = MiceConfig.launcher.inject;
PROCESS_INFORMATION pi;
if (!start_and_inject(hJob, exe_name, fullCommandLine, micepath, debug_wait, boot_delay,
extra_injections, 0, &pi)) {
free(fullCommandLine);
return terminate(-1);
}
free(fullCommandLine);
SetConsoleCtrlHandler(MiceHandlerRoutine, TRUE);
if (FAILED(WaitForSingleObject(pi.hProcess, INFINITE))) {
log_error(plfBoot, "Fatal: WaitForSingleObject failed: %03x", GetLastError());
} else {
DWORD exitCode;
if (GetExitCodeProcess(pi.hProcess, &exitCode))
log_info(plfBoot, "Shutting down (ret:%d)", exitCode);
else
log_info(plfBoot, "Shutting down (failed to get exit code)");
CloseHandle(pi.hProcess);
}
return terminate(0);
}

View File

@ -1,6 +1,6 @@
rc = import('windows').compile_resources('mice.rc', depend_files: mice_ico)
executable(
'mice',
get_option('win64') ? 'mice64' : 'mice',
win_subsystem: subsystem,
sources: [
'locate.c',
@ -18,5 +18,9 @@ executable(
dummykeychip,
dummymaster,
dummyinstaller,
dummygdeliver,
dummynetwork,
amSerialId,
],
)

View File

@ -1,3 +1,3 @@
#include <winuser.h>
0 ICON "../assets/mice.ico"
0 ICON "../../assets/mice.ico"

View File

@ -3,35 +3,44 @@
#include "../lib/mice/mice.h"
spawn_t mxspawns[3] = {
// { "keychip", SPAWN_DUMMY, MdkThreadProc, MxkThreadProc },
// { "master", SPAWN_DUMMY, MdmThreadProc, NULL },
// { "installer", SPAWN_DUMMY, MdiThreadProc, NULL },
{ "keychip", SPAWN_NONE, MdkThreadProc, MxkThreadProc },
{ "master", SPAWN_NONE, MdmThreadProc, NULL },
{ "installer", SPAWN_NONE, MdiThreadProc, NULL },
spawn_t mxspawns[] = {
{ "keychip", SPAWN_DUMMY, MdkThreadProc, MxkThreadProc },
{ "master", SPAWN_DUMMY, MdmThreadProc, NULL },
{ "installer", SPAWN_DUMMY, MdiThreadProc, NULL },
{ "network", SPAWN_DUMMY, MdnThreadProc, NULL },
{ "gdeliver", SPAWN_DUMMY, MdgdThreadProc, NULL },
};
int mxkMain();
int miceDummyKeychip(unsigned short textPort, unsigned short binaryPort, bool global);
int miceDummyMaster(unsigned short textPort, unsigned short binaryPort, bool global);
int miceDummyInstaller(unsigned short textPort, unsigned short binaryPort, bool global);
int miceDummyNetwork(unsigned short textPort, unsigned short binaryPort, bool global);
int miceDummyGDeliver(unsigned short textPort, unsigned short binaryPort, bool global);
DWORD WINAPI MdkThreadProc(LPVOID lpParameter) {
miceDummyKeychip(40106, 40107, false);
return 0;
};
}
DWORD WINAPI MxkThreadProc(LPVOID lpParameter) {
mxkMain();
return 0;
};
}
DWORD WINAPI MdmThreadProc(LPVOID lpParameter) {
miceDummyMaster(40100, 40101, false);
return 0;
};
}
DWORD WINAPI MdiThreadProc(LPVOID lpParameter) {
miceDummyInstaller(40102, 40103, false);
return 0;
};
}
DWORD WINAPI MdnThreadProc(LPVOID lpParameter) {
miceDummyNetwork(40104, 40105, false);
return 0;
}
DWORD WINAPI MdgdThreadProc(LPVOID lpParameter) {
miceDummyGDeliver(40108, 40112, false);
return 0;
}
static inline void spawn_one(spawn_t* spawn) {
if (spawn->mode == SPAWN_NONE) {

View File

@ -12,11 +12,13 @@ typedef struct {
#define SPAWN_REAL 2
#define SPAWN_BOTH (SPAWN_DUMMY | SPAWN_REAL)
extern spawn_t mxspawns[3];
extern spawn_t mxspawns[5];
DWORD WINAPI MxkThreadProc(LPVOID lpParameter);
DWORD WINAPI MdkThreadProc(LPVOID lpParameter);
DWORD WINAPI MdmThreadProc(LPVOID lpParameter);
DWORD WINAPI MdiThreadProc(LPVOID lpParameter);
DWORD WINAPI MdnThreadProc(LPVOID lpParameter);
DWORD WINAPI MdgdThreadProc(LPVOID lpParameter);
void spawn_pcp_processes(void);

View File

@ -1,5 +1,3 @@
#include "../mice/version_fallback.h"
#define AM_LIB_C_HEADER(name, storage_type) \
int name##DebugLevel = 0; \
struct storage_type name; \

View File

@ -2,7 +2,7 @@
#include <stdio.h>
#include "../dmi/dmi.h"
#include "../mice/dmi.h"
#include "../mice/mice.h"
AM_LIB_C_HEADER(amOemstring, AM_OEMSTRING)

View File

@ -1,6 +0,0 @@
dmi_lib = static_library(
'dmi',
sources: [
'dmi.c'
],
)

View File

@ -1246,7 +1246,6 @@ e_pcpp_t pcppSendBinary(pcpp_t* stream, const unsigned char* send_binary_buffer,
e_pcpp_t pcppIsBusy(pcpp_t* stream, timeout_t timeout) {
size_t* psVar1;
char** send_buf;
undefined4 uVar2;
int iVar3;
e_pcpt_t eVar4;
@ -1688,14 +1687,12 @@ e_pcpp_t pcppIsBusy(pcpp_t* stream, timeout_t timeout) {
} while (stream->field_0x1fc <= stream->recv_binary_buf_len &&
stream->recv_binary_buf_len != stream->field_0x1fc);
}
send_buf = (char**)&stream->send_buf;
psVar1 = &stream->send_buf_len;
stream->state = pcpp_state_send_binary_ack;
*send_buf[0] = PCP_CHAR_BINACK;
*psVar1 = 1;
stream->send_buf[0] = PCP_CHAR_BINACK;
stream->send_buf_len = 1;
local_20 = pcppGetBlockingTime(stream->field_0x20c, uVar11, stream, _amTimeMs(local_18),
&timeout);
eVar4 = pcptSend(&stream->sock, (unsigned char*)*send_buf, psVar1, stream->field_0x204,
eVar4 = pcptSend(&stream->sock, (unsigned char*)stream->send_buf, &stream->send_buf_len, stream->field_0x204,
timeout);
eVar7 = _errT2P(eVar4);
stream->err = eVar7;
@ -1713,9 +1710,9 @@ e_pcpp_t pcppIsBusy(pcpp_t* stream, timeout_t timeout) {
stream->state = pcpp_state_send_binary_ack_wait;
iVar3 = pcppGetBlockingTime(stream->field_0x208, uVar11, stream,
_amTimeMs(local_18), &timeout);
*psVar1 = PCP_SEND_BUF_MAX;
stream->send_buf_len = PCP_SEND_BUF_MAX;
ZERO(stream->send_buf);
eVar4 = pcptRecv(&stream->data_sock, (unsigned char*)*send_buf, psVar1, timeout);
eVar4 = pcptRecv(&stream->data_sock, (unsigned char*)stream->send_buf, &stream->send_buf_len, timeout);
eVar7 = _errT2P(eVar4);
stream->err = eVar7;
if ((iVar3 != 0) && (eVar7 == e_pcpp_to)) {

View File

@ -1,5 +1,4 @@
subdir('util') # This is the only lib that should ever be link_with'd by another lib
subdir('dmi')
subdir('ami')
subdir('libpcp')

View File

@ -6,8 +6,12 @@
#include "../../../../subprojects/inih_dep/ini.h"
#include "../../dll/devices/smb_pca9535.h"
#include "../../dll/drivers/jvs_boards/jvs.h"
#include "../../dll/hooks/files.h"
#include "../../dll/key_config.h"
MICE_JVS _MiceJvsBoards[JVS_IO_MAX];
config_t MiceConfig = {
#define SECTION(s, comment) .s = {
#define CFG_str(s, n, default, comment) .n = default,
@ -24,7 +28,7 @@ config_t MiceConfig = {
._keep_linter_happy = true
};
void fprintf_prefix(FILE *file, const char *prefix, const char *text) {
static void fprintf_prefix(FILE *file, const char *prefix, const char *text) {
char *copy = (char *)malloc(strlen(text) + 1);
memcpy_s(copy, strlen(text) + 1, text, strlen(text) + 1);
@ -38,99 +42,174 @@ void fprintf_prefix(FILE *file, const char *prefix, const char *text) {
free(copy);
}
void make_default_config() {
FILE *config_file;
fopen_s(&config_file, CONFIG_PATH, "w");
if (config_file == NULL) {
puts("Failed to create config file!");
void save_keybinds() {
HANDLE hFile = CreateFileA(KEYBINDS_PATH, GENERIC_WRITE | GENERIC_READ, FILE_SHARE_WRITE, NULL,
CREATE_ALWAYS, 0, NULL);
if (hFile == INVALID_HANDLE_VALUE) {
fprintf(stderr, "Failed to open keybinds file: %d", GetLastError());
return;
};
int first_section = true;
}
#define CFG_str(s, n, default, comment) \
if (strlen(comment) != 0) fprintf_prefix(config_file, "; ", comment); \
fprintf(config_file, "%s = %s ;(string)\n", #n, default);
SetFilePointer(hFile, 8, NULL, 0);
#define CFG_bool(s, n, default, comment) \
if (strlen(comment) != 0) fprintf_prefix(config_file, "; ", comment); \
fprintf(config_file, "%s = %s ;(bool)\n", #n, default ? "true" : "false");
DWORD nWrote;
DWORD totalSize = 0;
WriteFile(hFile, &MiceConfig.keys.board_count, sizeof MiceConfig.keys.board_count, &nWrote,
NULL);
totalSize += nWrote;
#define CFG_int(s, n, default, comment) \
if (strlen(comment) != 0) fprintf_prefix(config_file, "; ", comment); \
fprintf(config_file, "%s = %d ;(int)\n", #n, default);
for (int board = 0; board < MiceConfig.keys.board_count; board++) {
WriteFile(hFile, &_MiceJvsBoards->m_Players, sizeof _MiceJvsBoards->m_Players, &nWrote,
NULL);
totalSize += nWrote;
WriteFile(hFile, &_MiceJvsBoards->m_ButtonsPerPlayer,
sizeof _MiceJvsBoards->m_ButtonsPerPlayer, &nWrote, NULL);
totalSize += nWrote;
WriteFile(hFile, &_MiceJvsBoards->m_Coins, sizeof _MiceJvsBoards->m_Coins, &nWrote, NULL);
totalSize += nWrote;
WriteFile(hFile, &_MiceJvsBoards->m_NumButtons, sizeof _MiceJvsBoards->m_NumButtons,
&nWrote, NULL);
totalSize += nWrote;
#define CFG_hex(s, n, precision, default, comment) \
if (strlen(comment) != 0) fprintf_prefix(config_file, "; ", comment); \
fprintf(config_file, "%s = %.*X ;(hex, %d byte%s)\n", #n, precision, 0x##default, precision, \
precision == 1 ? "" : "s");
WriteFile(hFile, _MiceJvsBoards[board].m_Bindings,
sizeof *_MiceJvsBoards[board].m_Bindings * _MiceJvsBoards->m_NumButtons, &nWrote,
NULL);
totalSize += nWrote;
}
#define CFG_ipv4(s, n, a, b, c, d, comment) \
if (strlen(comment) != 0) fprintf_prefix(config_file, "; ", comment); \
fprintf(config_file, "%s = %hhu.%hhu.%hhu.%hhu ;(ipv4)\n", #n, a, b, c, d);
SetFilePointer(hFile, 0, NULL, 0);
WriteFile(hFile, &totalSize, sizeof totalSize, &nWrote, NULL);
#define SECTION(s, comment) \
if (!first_section) fprintf(config_file, "\n"); \
first_section = false; \
if (strlen(comment) != 0) fprintf_prefix(config_file, "; ", comment); \
fprintf(config_file, "[%s]\n", #s);
amiCrc32RInit();
DWORD readLeft = totalSize;
DWORD crc32 = 0;
SetFilePointer(hFile, 8, NULL, 0);
while (readLeft) {
BYTE readBuf[0x1000];
DWORD toRead = sizeof readBuf;
if (readLeft < toRead) toRead = readLeft;
DWORD nRead;
ReadFile(hFile, readBuf, toRead, &nRead, NULL);
#define COMMENT(comment) \
if (strlen(comment) != 0) fprintf_prefix(config_file, "; ", comment);
if (nRead == 0) {
fprintf(stderr, "Binding saving failed %d\n", GetLastError());
CloseHandle(hFile);
return;
}
crc32 = amiCrc32RCalc(nRead, readBuf, crc32);
readLeft -= nRead;
}
SetFilePointer(hFile, 4, NULL, 0);
WriteFile(hFile, &crc32, sizeof crc32, &nWrote, NULL);
#include "config.def"
CloseHandle(hFile);
}
void load_keybind_config() {
HANDLE hFile =
CreateFileA(KEYBINDS_PATH, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
if (hFile == INVALID_HANDLE_VALUE) return;
fclose(config_file);
DWORD nRead;
DWORD nSize = 0;
ReadFile(hFile, &nSize, sizeof nSize, &nRead, NULL);
SetFilePointer(hFile, 8, NULL, 0);
amiCrc32RInit();
DWORD crc32 = 0;
while (nSize) {
BYTE readBuf[0x1000];
DWORD toRead = sizeof readBuf;
if (nSize < toRead) toRead = nSize;
ReadFile(hFile, readBuf, toRead, &nRead, NULL);
if (nRead == 0) {
fprintf(stderr, "Binding reading failed\n");
CloseHandle(hFile);
return;
}
crc32 = amiCrc32RCalc(nRead, readBuf, crc32);
nSize -= nRead;
}
DWORD savedCrc;
SetFilePointer(hFile, 4, NULL, 0);
ReadFile(hFile, &savedCrc, sizeof savedCrc, &nRead, NULL);
if (savedCrc != crc32) {
fprintf(stderr, "Binding file CRC failed (%08x!=%08x)\n", savedCrc, crc32);
CloseHandle(hFile);
return;
}
ReadFile(hFile, &MiceConfig.keys.board_count, sizeof MiceConfig.keys.board_count, &nRead, NULL);
for (int board = 0; board < MiceConfig.keys.board_count; board++) {
ReadFile(hFile, &_MiceJvsBoards->m_Players, sizeof _MiceJvsBoards->m_Players, &nRead, NULL);
ReadFile(hFile, &_MiceJvsBoards->m_ButtonsPerPlayer,
sizeof _MiceJvsBoards->m_ButtonsPerPlayer, &nRead, NULL);
ReadFile(hFile, &_MiceJvsBoards->m_Coins, sizeof _MiceJvsBoards->m_Coins, &nRead, NULL);
ReadFile(hFile, &_MiceJvsBoards->m_NumButtons, sizeof _MiceJvsBoards->m_NumButtons, &nRead,
NULL);
free(_MiceJvsBoards[board].m_Bindings);
_MiceJvsBoards[board].m_Bindings =
malloc(sizeof *_MiceJvsBoards[board].m_Bindings * _MiceJvsBoards->m_NumButtons);
ReadFile(hFile, _MiceJvsBoards[board].m_Bindings,
sizeof *_MiceJvsBoards[board].m_Bindings * _MiceJvsBoards->m_NumButtons, &nRead,
NULL);
free(_MiceJvsBoards[board].m_ButtonStates);
_MiceJvsBoards[board].m_ButtonStates =
malloc(sizeof *_MiceJvsBoards[board].m_ButtonStates * _MiceJvsBoards->m_NumButtons);
}
CloseHandle(hFile);
}
char keybindBuffer[8192];
void save_current_config() {
// Dump keybind settings
int i = 0;
for (int board = 0; board < MiceConfig.keys.board_count; board++) {
i += snprintf(keybindBuffer + i, _countof(keybindBuffer) - i, "%d,",
jvsKeybindings[board].test);
i += snprintf(keybindBuffer + i, _countof(keybindBuffer) - i, "%d,",
jvsKeybindings[board].notdefault);
for (int n = 0; n < JVS_BUTTON_PAIR_COUNT * 2; n++) {
i += snprintf(keybindBuffer + i, _countof(keybindBuffer) - i, "%d,",
jvsKeybindings[board].buttons[n]);
i += snprintf(keybindBuffer + i, _countof(keybindBuffer) - i, "%d,",
jvsKeybindings[board].invert[n]);
}
}
keybindBuffer[i] = '\0';
free(MiceConfig.keys.keys);
MiceConfig.keys.keys = _strdup(keybindBuffer);
char keybindBuffer[2 * JVS_IO_MAX * (sizeof _MiceJvsBoards[0].m_Bindings[0]) * 32];
void save_current_config(bool writeDefault) {
CreateDirectoryA("mice", NULL); // TODO: A touch nicer?
save_keybinds();
FILE *config_file;
fopen_s(&config_file, CONFIG_PATH, "w");
if (config_file == NULL) {
puts("Failed to create config file!");
return;
};
}
int first_section = true;
#define CFG_str(s, n, default, comment) \
if (strlen(comment) != 0) fprintf_prefix(config_file, "; ", comment); \
fprintf(config_file, "%s = %s ;(string)\n", #n, MiceConfig.s.n);
#define CFG_str(s, n, default, comment) \
if (strlen(comment) != 0) fprintf_prefix(config_file, "; ", comment); \
fprintf(config_file, "; (string) default = %s\n", writeDefault ? MiceConfig.s.n : default); \
fprintf(config_file, "%s = %s\n", #n, MiceConfig.s.n);
#define CFG_bool(s, n, default, comment) \
if (strlen(comment) != 0) fprintf_prefix(config_file, "; ", comment); \
fprintf(config_file, "%s = %s ;(bool)\n", #n, MiceConfig.s.n ? "true" : "false");
#define CFG_bool(s, n, default, comment) \
if (strlen(comment) != 0) fprintf_prefix(config_file, "; ", comment); \
fprintf(config_file, "; (bool) default = %s\n", \
(writeDefault ? MiceConfig.s.n : default) ? "true" : "false"); \
fprintf(config_file, "%s = %s\n", #n, MiceConfig.s.n ? "true" : "false");
#define CFG_int(s, n, default, comment) \
if (strlen(comment) != 0) fprintf_prefix(config_file, "; ", comment); \
fprintf(config_file, "%s = %d ;(int)\n", #n, MiceConfig.s.n);
#define CFG_int(s, n, default, comment) \
if (strlen(comment) != 0) fprintf_prefix(config_file, "; ", comment); \
fprintf(config_file, "; (int) default = %d\n", writeDefault ? MiceConfig.s.n : default); \
fprintf(config_file, "%s = %d\n", #n, MiceConfig.s.n);
#define CFG_hex(s, n, precision, default, comment) \
if (strlen(comment) != 0) fprintf_prefix(config_file, "; ", comment); \
fprintf(config_file, "%s = %.*X ;(hex, %d byte%s)\n", #n, precision, MiceConfig.s.n, \
precision, precision == 1 ? "" : "s");
#define CFG_hex(s, n, precision, default, comment) \
if (strlen(comment) != 0) fprintf_prefix(config_file, "; ", comment); \
fprintf(config_file, "; (hex, %d byte%s) default = %.*X \n", precision, \
precision == 1 ? "" : "s", precision, writeDefault ? MiceConfig.s.n : 0x##default); \
fprintf(config_file, "%s = %.*X\n", #n, precision, MiceConfig.s.n);
#define CFG_ipv4(s, n, a, b, c, d, comment) \
if (strlen(comment) != 0) fprintf_prefix(config_file, "; ", comment); \
fprintf(config_file, "%s = %hhu.%hhu.%hhu.%hhu ;(ipv4)\n", #n, (MiceConfig.s.n >> 24), \
((MiceConfig.s.n >> 16) & 0xff), ((MiceConfig.s.n >> 8) & 0xff), \
#define CFG_ipv4(s, n, a, b, c, d, comment) \
if (strlen(comment) != 0) fprintf_prefix(config_file, "; ", comment); \
fprintf(config_file, "; (ipv4) default = %hhu.%hhu.%hhu.%hhu ;(ipv4)\n", \
writeDefault ? MiceConfig.s.n >> 24 : a, \
writeDefault ? (MiceConfig.s.n >> 16) & 0xff : b, \
writeDefault ? (MiceConfig.s.n >> 8) & 0xff : c, \
writeDefault ? (MiceConfig.s.n & 0xff) : d); \
fprintf(config_file, "%s = %hhu.%hhu.%hhu.%hhu\n", #n, (MiceConfig.s.n >> 24), \
((MiceConfig.s.n >> 16) & 0xff), ((MiceConfig.s.n >> 8) & 0xff), \
(MiceConfig.s.n & 0xff));
#define SECTION(s, comment) \
@ -189,8 +268,26 @@ const unsigned int RES_W[8] = { 640, 640, 1024, 1024, 1280, 1280, 1360, 1920 };
const unsigned int RES_H[8] = { 480, 480, 600, 768, 720, 1024, 768, 1080 };
void load_mice_config() {
if (ini_parse(CONFIG_PATH, handler, &MiceConfig) < 0) {
make_default_config();
printf("Can't load '%s', using defaults\n", CONFIG_PATH);
printf("Loading config defaults\n");
if (MiceConfig.sysconf.serial) free(MiceConfig.sysconf.serial);
MiceConfig.sysconf.serial = malloc(17);
if (MiceConfig.sysconf.keyid) free(MiceConfig.sysconf.keyid);
MiceConfig.sysconf.keyid = malloc(17);
GetSerialNumbers(MiceConfig.sysconf.serial, MiceConfig.sysconf.keyid);
save_current_config(true);
}
if (!MiceConfig.sysconf.serial || strlen(MiceConfig.sysconf.serial) == 0) {
if (MiceConfig.sysconf.serial) free(MiceConfig.sysconf.serial);
MiceConfig.sysconf.serial = malloc(17);
GetSerialNumbers(MiceConfig.sysconf.serial, NULL);
}
if (!MiceConfig.sysconf.keyid || strlen(MiceConfig.sysconf.keyid) == 0) {
if (MiceConfig.sysconf.keyid) free(MiceConfig.sysconf.keyid);
MiceConfig.sysconf.keyid = malloc(17);
GetSerialNumbers(NULL, MiceConfig.sysconf.keyid);
}
if (MiceConfig.window.dipsw) {
@ -214,44 +311,4 @@ void load_mice_config() {
else if (MiceConfig.window.w == 640 && MiceConfig.window.h == 480)
MiceConfig.sysconf.dipsw |= DIPSW_RES_640x480;
}
if (MiceConfig.keys.board_count < 0) MiceConfig.keys.board_count = 0;
if (MiceConfig.keys.board_count > JVS_IO_MAX) MiceConfig.keys.board_count = JVS_IO_MAX;
char *text = MiceConfig.keys.keys;
if (text) {
char *copy = (char *)malloc(strlen(text) + 1);
memcpy_s(copy, strlen(text) + 1, text, strlen(text) + 1);
char *next_token;
char *token = strtok_s(copy, ",", &next_token);
int board = 0;
int state = 0;
int n = 0;
while (token != NULL) {
int val = atoi(token);
if (state == 0) {
jvsKeybindings[board].test = val;
state = 1;
} else if (state == 1) {
jvsKeybindings[board].notdefault = val;
state = 2;
} else {
if (state == 2) {
jvsKeybindings[board].buttons[n] = val;
state = 3;
} else {
jvsKeybindings[board].invert[n] = val;
state = 2;
if (n++ == JVS_BUTTON_PAIR_COUNT * 2) {
n = 0;
state = 0;
if (board++ == JVS_IO_MAX) break;
}
}
}
token = strtok_s(NULL, ",", &next_token);
}
free(copy);
}
}

View File

@ -28,14 +28,20 @@ SECTION(launcher, "These options are only used during initial bootstrapping")
CFG_str(launcher, game_binary, "", "Override binary detection")
CFG_bool(launcher, wait_for_debugger, false, "Wait for a debugger to attach when starting")
CFG_int(launcher, startup_delay, 0, "Pause during startup")
#ifdef _WIN64
CFG_str(launcher, mice_dll, "mice64.dll", "The path to mice's DLL")
#else
CFG_str(launcher, mice_dll, "mice.dll", "The path to mice's DLL")
#endif
CFG_str(launcher, inject, "", "Extra DLLs to inject during boot")
ENDSECTION(launcher)
SECTION(sysconf, "System configuration settings")
CFG_int(sysconf, platform, 2, "System platform. 0 = RingWide, 1 = RingEdge, 2 = RingEdge2")
CFG_int(sysconf, region, 1, "Board region. 1 = Jpn, 2 = USA, 4 = Exp, 8 = Chn")
CFG_bool(sysconf, rental, false, "")
CFG_str(sysconf, serial, "AASE-01A65646203", "")
CFG_str(sysconf, serial, "A000-00000000000", "")
CFG_str(sysconf, keyid, "A000-00000000000", "")
CFG_hex(sysconf, dipsw, 2, 40, "DIP Switch values") // Default 40 = 1280x720
ENDSECTION(sysconf)
@ -58,14 +64,15 @@ CFG_ipv4(network, subnet_mask, 255, 255, 255, 0, "")
CFG_ipv4(network, gateway, 192, 168, 103, 254, "")
CFG_ipv4(network, primary_dns, 192, 168, 103, 254, "")
CFG_ipv4(network, secondary_dns, 0, 0, 0, 0, "")
COMMENT("Emulated DNS records. Routers must be pingable!")
CFG_ipv4(network, naominet_jp, 10, 0, 0, 2, "")
CFG_ipv4(network, ib_naominet_jp, 10, 0, 0, 2, "")
CFG_ipv4(network, aime_naominet_jp, 10, 0, 0, 2, "")
CFG_ipv4(network, tenporouter_loc, 127, 0, 0, 1, "")
CFG_ipv4(network, bbrouter_loc, 127, 0, 0, 1, "")
CFG_ipv4(network, mobirouter_loc, 127, 0, 0, 1, "")
CFG_ipv4(network, dslrouter_loc, 127, 0, 0, 1, "")
CFG_ipv4(network, upstream_dns_server, 0, 0, 0, 0, "")
COMMENT("Emulated DNS records.")
CFG_ipv4(network, naominet_jp, 134, 65, 56, 170, "")
CFG_ipv4(network, ib_naominet_jp, 127, 0, 0, 1, "")
CFG_ipv4(network, aime_naominet_jp, 134, 65, 56, 170, "")
CFG_ipv4(network, tenporouter_loc, 192, 168, 103, 254, "")
CFG_ipv4(network, bbrouter_loc, 192, 168, 103, 254, "")
CFG_ipv4(network, mobirouter_loc, 192, 168, 103, 254, "")
CFG_ipv4(network, dslrouter_loc, 192, 168, 103, 254, "")
COMMENT("Second half of system mac address. The vendor prefix D8:BB:C1: will be prepended")
CFG_hex(network, mac, 6, 0A2F1D, "")
ENDSECTION(network)
@ -100,7 +107,6 @@ SECTION(keys, "Raw keybinding data. Edit this using the built in binding tool!")
CFG_int(keys, test, 0, "")
CFG_int(keys, service, 0, "")
CFG_int(keys, board_count, 1, "")
CFG_str(keys, keys, "", "")
ENDSECTION(keys)
SECTION(devices, "Register attached hardware devices. COM4 is reserved for JVS.")
@ -112,6 +118,7 @@ CFG_str(devices, com5, "", "")
CFG_str(devices, com6, "", "")
CFG_str(devices, com7, "", "")
CFG_str(devices, com8, "", "")
CFG_bool(devices, add_idlers, true, "Monitors for activity on disconnected virtual serial ports")
ENDSECTION(devices)
SECTION(aime, "Aime cards used when a TN32MSEC reader is attached\nSpecify either an access code or FeliCa ID")

View File

@ -3,7 +3,12 @@
#include <stdint.h>
#include <stdbool.h>
#define CONFIG_PATH "mice.ini"
#define CONFIG_PATH MiceIpcRelativePath("config.ini")
#define KEYBINDS_PATH MiceIpcRelativePath("keybinds.bin")
#define MICE_PLATFORM_RINGWIDE 0
#define MICE_PLATFORM_RINGEDGE1 1 // Explictly RingEdge1, to avoid confusion
#define MICE_PLATFORM_RINGEDGE2 2
typedef struct config {
#define SECTION(s, comment) struct {
@ -19,6 +24,6 @@ typedef struct config {
extern config_t MiceConfig;
void make_default_config();
void save_current_config();
void save_current_config(bool writeDefault);
void load_mice_config();
void load_keybind_config();

View File

@ -1,119 +1,147 @@
#include "dmi.h"
#include <stdlib.h>
LPBYTE dmi_table = NULL;
WORD dmi_size = 0;
WORD _dmi_max = 0;
DMI_BIOS default_dmi_bios = {
.Head.Type = DmiTypeBios,
.Head.Length = 0x12,
.Head.Handle = 0x0000,
.Vendor = 0x01, // "American Megatrends Inc."
.Version = 0x02, // "080015 "
.StartSegment = 0x0000, // '00 f0'h
.ReleaseDate = 0x03, // "07/28/2011"
.ROMSize = 0x00, // 03h
.Chars = 0x1f, // '1F 90 DA 8B'h
.VerMajor = 0x08,
.VerMinor = 0x0f,
.ECVerMajor = 0xff,
.ECVerMinor = 0xff,
};
DMI_SYSTEM default_dmi_system = {
.Head.Type = DmiTypeSystem,
.Head.Length = 0x08,
.Head.Handle = 0x0001,
.Manufacturer = 0x01, // "NEC"
.ProductName = 0x02, // "To Be Filled By O.E.M."
.Version = 0x03, // "To Be Filled By O.E.M."
.Serial = 0x04, // "To Be Filled By O.E.M."
};
DMI_STRING default_dmi_string = {
.Head.Type = DmiTypeString,
.Head.Length = 0x05,
.Head.Handle = 0x0002,
.NoStrings = 0x00,
};
static void dmi_init(void) {
if (dmi_table) free(dmi_table);
_dmi_max = 0xff;
dmi_table = (LPBYTE)malloc(_dmi_max);
memset(dmi_table, 0, _dmi_max);
dmi_size = 0;
}
static void dmi_append(void* data, WORD size) {
if (!dmi_table) return;
while (dmi_size + (size + 1) >= _dmi_max) {
LPBYTE new_table = (LPBYTE)realloc(dmi_table, _dmi_max += 0xff);
if (!new_table) return;
dmi_table = new_table;
}
memcpy(dmi_table + dmi_size, data, size);
dmi_size += size;
dmi_table[dmi_size++] = 0;
dmi_table[dmi_size++] = 0;
}
static void dmi_append_with_strings(void* data, WORD size, int num_strings, ...) {
va_list args;
va_start(args, num_strings);
dmi_append(data, size);
dmi_size -= 2;
for (int i = 0; i < num_strings; i++) {
char* str = va_arg(args, char*);
WORD len = strlen(str) & 0xffff;
memcpy((char*)dmi_table + dmi_size, str, len + 1);
dmi_size += len + 1;
dmi_table[dmi_size - 1] = 0;
}
dmi_table[dmi_size++] = 0;
va_end(args);
}
void dmi_build_default() {
dmi_init();
// BIOS version
dmi_append_with_strings(&default_dmi_bios, sizeof default_dmi_bios, 3,
"American Megatrends Inc.", "080015 ", "07/28/2011");
// Platform AAM: Board type one of "Supermicro"(=1) or "Advantech"(=2)
// Platform AAL: Board type one of "NEC"(=0) or "AAL2"(=3)
dmi_append_with_strings(&default_dmi_system, sizeof default_dmi_system, 4, "NEC",
"To Be Filled By O.E.M.", "To Be Filled By O.E.M.",
"To Be Filled By O.E.M.");
default_dmi_string.NoStrings = 5;
dmi_append_with_strings(&default_dmi_string, sizeof default_dmi_string,
// OEM strings:
// 0: ??
// 1: ??
// 2: Platform ID (AAL, AAM)
// AAL = Nvidia drivers
// AAM = AMD drivers
// *** = No dedicated drivers
// 3: ??
// 4: Board type (AAL, NEC, AAL2, " ", AAM, Supermicro, Advantech)
// If present -> makes board = 4
// AAL = 4
// AAM = 4
// Supermicro = 4
// Advantech = 4
// These values are pulled from an 846-5004D
5, "DAC-BJ02", "DAC-BJ02", "AAL", "Advantech", "AAL2");
}
BYTE dmi_calc_checksum(const char* buf, int len) {
int sum = 0;
int a;
for (a = 0; a < len; a++) sum += buf[a];
return (BYTE)(sum == 0);
}
#include "dmi.h"
#include <stdlib.h>
#include "config.h"
LPBYTE dmi_table = NULL;
WORD dmi_size = 0;
WORD _dmi_max = 0;
DMI_BIOS default_dmi_bios = {
.Head.Type = DmiTypeBios,
.Head.Length = 0x12,
.Head.Handle = 0x0000,
.Vendor = 0x01, // "American Megatrends Inc."
.Version = 0x02, // "080015 "
.StartSegment = 0x0000, // '00 f0'h
.ReleaseDate = 0x03, // "07/28/2011"
.ROMSize = 0x00, // 03h
.Chars = 0x1f, // '1F 90 DA 8B'h
.VerMajor = 0x08,
.VerMinor = 0x0f,
.ECVerMajor = 0xff,
.ECVerMinor = 0xff,
};
DMI_SYSTEM default_dmi_system = {
.Head.Type = DmiTypeSystem,
.Head.Length = 0x08,
.Head.Handle = 0x0001,
.Manufacturer = 0x01, // "NEC"
.ProductName = 0x02, // "To Be Filled By O.E.M."
.Version = 0x03, // "To Be Filled By O.E.M."
.Serial = 0x04, // "To Be Filled By O.E.M."
};
DMI_STRING default_dmi_string = {
.Head.Type = DmiTypeString,
.Head.Length = 0x05,
.Head.Handle = 0x0002,
.NoStrings = 0x00,
};
static void dmi_init(void) {
if (dmi_table) free(dmi_table);
_dmi_max = 0xff;
dmi_table = (LPBYTE)malloc(_dmi_max);
memset(dmi_table, 0, _dmi_max);
dmi_size = 0;
}
static void dmi_append(void* data, WORD size) {
if (!dmi_table) return;
while (dmi_size + (size + 1) >= _dmi_max) {
LPBYTE new_table = (LPBYTE)realloc(dmi_table, _dmi_max += 0xff);
if (!new_table) return;
dmi_table = new_table;
}
memcpy(dmi_table + dmi_size, data, size);
dmi_size += size;
dmi_table[dmi_size++] = 0;
dmi_table[dmi_size++] = 0;
}
static void dmi_append_with_strings(void* data, WORD size, int num_strings, ...) {
va_list args;
va_start(args, num_strings);
dmi_append(data, size);
dmi_size -= 2;
for (int i = 0; i < num_strings; i++) {
char* str = va_arg(args, char*);
WORD len = strlen(str) & 0xffff;
memcpy((char*)dmi_table + dmi_size, str, len + 1);
dmi_size += len + 1;
dmi_table[dmi_size - 1] = 0;
}
dmi_table[dmi_size++] = 0;
va_end(args);
}
// Strings are: 0, 1, Platform ID, 3, Board Type
/**
* | | Wide1 | Wide2 | Edge | Edge2 |
* | ------------ | ---------- | --------- | ---- | ----- |
* | Manufacturer | Supermicro | Advantech | NEC | NEC |
* | Platform ID | AAM | AAM | AAL | AAL |
* | Board Type | | | "" | AAL2 |
*/
#define MANUFACTURER_RINGWIDE "Supermicro"
#define MANUFACTURER_RINGEDGE "NEC"
#define MANUFACTURER_RINGEDGE2 MANUFACTURER_RINGEDGE
#define OEM_STRINGS_RINGWIDE "DAC-BJ02", "DAC-BJ02", "AAM", "Supermicro", ""
#define OEM_STRINGS_RINGEDGE "DAC-BJ02", "DAC-BJ02", "AAL", "NEC", ""
#define OEM_STRINGS_RINGEDGE2 "DAC-BJ02", "DAC-BJ02", "AAL", "Advantech", "AAL2"
void dmi_build_default() {
dmi_init();
// BIOS version
dmi_append_with_strings(&default_dmi_bios, sizeof default_dmi_bios, 3,
"American Megatrends Inc.", "080015 ", "07/28/2011");
switch (MiceConfig.sysconf.platform) {
case MICE_PLATFORM_RINGWIDE: {
dmi_append_with_strings(&default_dmi_system, sizeof default_dmi_system, 4,
MANUFACTURER_RINGWIDE, "To Be Filled By O.E.M.",
"To Be Filled By O.E.M.", "To Be Filled By O.E.M.");
default_dmi_string.NoStrings = 5;
dmi_append_with_strings(&default_dmi_string, sizeof default_dmi_string, 5,
OEM_STRINGS_RINGWIDE);
break;
}
case MICE_PLATFORM_RINGEDGE1: {
dmi_append_with_strings(&default_dmi_system, sizeof default_dmi_system, 4,
MANUFACTURER_RINGEDGE, "To Be Filled By O.E.M.",
"To Be Filled By O.E.M.", "To Be Filled By O.E.M.");
default_dmi_string.NoStrings = 5;
dmi_append_with_strings(&default_dmi_string, sizeof default_dmi_string, 5,
OEM_STRINGS_RINGEDGE);
break;
}
case MICE_PLATFORM_RINGEDGE2:
default: {
dmi_append_with_strings(&default_dmi_system, sizeof default_dmi_system, 4,
MANUFACTURER_RINGEDGE2, "To Be Filled By O.E.M.",
"To Be Filled By O.E.M.", "To Be Filled By O.E.M.");
default_dmi_string.NoStrings = 5;
dmi_append_with_strings(&default_dmi_string, sizeof default_dmi_string, 5,
OEM_STRINGS_RINGEDGE2);
break;
}
}
}
BYTE dmi_calc_checksum(const char* buf, int len) {
int sum = 0;
int a;
for (a = 0; a < len; a++) sum += buf[a];
return (BYTE)(sum == 0);
}

View File

@ -1,64 +1,64 @@
#include <Windows.h>
#include <stdint.h>
extern LPBYTE dmi_table;
extern WORD dmi_size;
enum DmiType {
DmiTypeBios = 0,
DmiTypeSystem = 1,
DmiTypeString = 11,
};
typedef BYTE DmiType_t;
#pragma pack(push, 1)
typedef struct {
DmiType_t Type;
BYTE Length;
WORD Handle;
} DMI_SECTION_HEADER;
typedef struct {
CHAR Signature[5];
BYTE Checksum;
WORD StructLength;
DWORD StructAddr;
WORD NumberOfStructs;
BYTE BCDRevision;
BYTE Reserved;
} DMI_HEADER;
typedef struct {
DMI_SECTION_HEADER Head;
BYTE Vendor;
BYTE Version;
WORD StartSegment;
BYTE ReleaseDate;
BYTE ROMSize;
uint64_t Chars;
BYTE VerMajor;
BYTE VerMinor;
BYTE ECVerMajor;
BYTE ECVerMinor;
} DMI_BIOS;
typedef struct {
DMI_SECTION_HEADER Head;
BYTE Manufacturer;
BYTE ProductName;
BYTE Version;
BYTE Serial;
} DMI_SYSTEM;
typedef struct {
DMI_SECTION_HEADER Head;
BYTE NoStrings;
} DMI_STRING;
#pragma pack(pop)
static void dmi_init(void);
static void dmi_append(void* data, WORD size);
static void dmi_append_with_strings(void* data, WORD size, int num_strings, ...);
void dmi_build_default(void);
BYTE dmi_calc_checksum(const char* buf, int len);
#include <Windows.h>
#include <stdint.h>
extern LPBYTE dmi_table;
extern WORD dmi_size;
enum DmiType {
DmiTypeBios = 0,
DmiTypeSystem = 1,
DmiTypeString = 11,
};
typedef BYTE DmiType_t;
#pragma pack(push, 1)
typedef struct {
DmiType_t Type;
BYTE Length;
WORD Handle;
} DMI_SECTION_HEADER;
typedef struct {
CHAR Signature[5];
BYTE Checksum;
WORD StructLength;
DWORD StructAddr;
WORD NumberOfStructs;
BYTE BCDRevision;
BYTE Reserved;
} DMI_HEADER;
typedef struct {
DMI_SECTION_HEADER Head;
BYTE Vendor;
BYTE Version;
WORD StartSegment;
BYTE ReleaseDate;
BYTE ROMSize;
uint64_t Chars;
BYTE VerMajor;
BYTE VerMinor;
BYTE ECVerMajor;
BYTE ECVerMinor;
} DMI_BIOS;
typedef struct {
DMI_SECTION_HEADER Head;
BYTE Manufacturer;
BYTE ProductName;
BYTE Version;
BYTE Serial;
} DMI_SYSTEM;
typedef struct {
DMI_SECTION_HEADER Head;
BYTE NoStrings;
} DMI_STRING;
#pragma pack(pop)
static void dmi_init(void);
static void dmi_append(void* data, WORD size);
static void dmi_append_with_strings(void* data, WORD size, int num_strings, ...);
void dmi_build_default(void);
BYTE dmi_calc_checksum(const char* buf, int len);

View File

@ -4,10 +4,10 @@
#include "log.h"
bool inject_debug_wait(HANDLE process) {
bool inject_debug_wait(HANDLE process, DWORD pid) {
BOOL present;
log_info(plfBoot, "Waiting for debugger to attach.");
log_info(plfBoot, "Waiting for debugger to attach (pid=%d).", pid);
do {
Sleep(1000);
if (FAILED(CheckRemoteDebuggerPresent(process, &present))) {
@ -35,7 +35,7 @@ bool remote_call(HANDLE process, LPVOID function, LPCSTR argument, DWORD* result
HANDLE remote_thread =
CreateRemoteThread(process, NULL, 0, (LPTHREAD_START_ROUTINE)function, arg_addr, 0, NULL);
if (remote_thread == INVALID_HANDLE_VALUE) {
if (remote_thread == NULL) {
log_error(plfProcesses, "CreateRemoteThread failed: %d", GetLastError());
return false;
}
@ -106,15 +106,15 @@ BOOL start_and_inject(HANDLE hJob, LPCSTR path, LPSTR cmdline, LPCSTR inject, BO
flags |= CREATE_SUSPENDED;
if (!CreateProcessA(path, cmdline, NULL, NULL, FALSE, flags, NULL, NULL, &startupInfo,
&processInformation)) {
log_error(plfProcesses, "CreateProcessA(%s, %s) failed: %d", path, cmdline,
GetLastError());
log_error(plfProcesses, "CreateProcessA(%s, %s) failed: %d", path, cmdline, GetLastError());
goto abort;
}
if (hJob != INVALID_HANDLE_VALUE) AssignProcessToJobObject(hJob, processInformation.hProcess);
if (debug_wait)
if (!inject_debug_wait(processInformation.hProcess)) goto abort;
if (!inject_debug_wait(processInformation.hProcess, processInformation.dwProcessId))
goto abort;
if (inject != NULL)
if (!inject_dll(processInformation.hProcess, inject)) goto abort;

View File

@ -6,4 +6,10 @@ BOOL start_and_inject(HANDLE hJob, LPCSTR path, LPSTR cmdline, LPCSTR inject, BO
DWORD delay, LPCSTR extra_injections, DWORD flags,
LPPROCESS_INFORMATION lpProcessInformation);
#ifdef _WIN64
#define MICELIB "mice64.dll"
#define MICEEXE "mice64.exe"
#else
#define MICELIB "mice.dll"
#define MICEEXE "mice.exe"
#endif

View File

@ -0,0 +1,159 @@
#include "ipc.h"
#include <stdio.h>
#include "../util/pid.h"
PMICE_IPC_DATA _miceIpcData = NULL;
static HANDLE hMapFile = NULL;
static HANDLE _miceIpcSendEvent = NULL;
static HANDLE _miceIpcPopEvent = NULL;
static HANDLE _miceIpcMutex = NULL;
BOOL MiceIpcGetGameId(LPSTR lpGameId) {
if (_miceIpcData == NULL) return FALSE;
if (!_miceIpcData->m_LauncherIsReady) return FALSE;
memcpy(lpGameId, _miceIpcData->m_GameId, 4);
return TRUE;
}
BOOL MiceIpcSetup(BOOL isOwner) {
DWORD pid;
if (isOwner)
pid = GetCurrentProcessId();
else
pid = GetOutermostMiceId();
char mapName[MAX_PATH + 1];
sprintf_s(mapName, MAX_PATH, "Local\\MiceMappingObject%d", pid);
SetLastError(0);
if (isOwner)
hMapFile = CreateFileMappingA(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0,
sizeof *_miceIpcData, mapName);
else {
hMapFile = OpenFileMappingA(FILE_MAP_READ | FILE_MAP_WRITE, TRUE, mapName);
}
if (hMapFile == NULL) {
fprintf(stderr, "Opening shared memory failed: %d\n", GetLastError());
return FALSE;
}
SetLastError(0);
_miceIpcData = MapViewOfFile(hMapFile, FILE_MAP_ALL_ACCESS, 0, 0, sizeof *_miceIpcData);
if (_miceIpcData == NULL) {
fprintf(stderr, "Mapping view of memory failed: %d\n", GetLastError());
return FALSE;
}
sprintf_s(mapName, MAX_PATH, "MiceMappingObject-Mutex%d", pid);
_miceIpcMutex = CreateMutexA(NULL, 0, mapName);
sprintf_s(mapName, MAX_PATH, "MiceMappingObject-SendE%d", pid);
_miceIpcSendEvent = CreateEventA(NULL, FALSE, FALSE, mapName);
sprintf_s(mapName, MAX_PATH, "MiceMappingObject-PopE%d", pid);
_miceIpcPopEvent = CreateEventA(NULL, FALSE, FALSE, mapName);
if (isOwner) {
ZeroMemory(_miceIpcData, sizeof *_miceIpcData);
} else {
if (!_miceIpcData->m_LauncherIsReady) {
fprintf(stderr, "IPC connected, but launcher never signalled!\n");
return FALSE;
}
}
return TRUE;
}
void _MiceIpcLock(void) { WaitForSingleObject(_miceIpcMutex, INFINITE); }
void _MiceIpcUnlock(void) { ReleaseMutex(_miceIpcMutex); }
BOOL MiceIpcPushMessage(PMICE_IPC_MESSAGE lpMessage, BOOL bBlocking) {
if (!_miceIpcData->m_LauncherIsReady) return FALSE;
_MiceIpcLock();
if (_miceIpcData->m_MessagesWaiting == MICE_IPC_MAX_MESSAGES) {
if (!bBlocking) {
_MiceIpcUnlock();
return FALSE;
}
do {
_MiceIpcUnlock();
WaitForSingleObject(_miceIpcPopEvent, INFINITE);
_MiceIpcLock();
} while (_miceIpcData->m_MessagesWaiting == MICE_IPC_MAX_MESSAGES);
}
memcpy(&_miceIpcData->m_MessageQueue[_miceIpcData->m_MessageWriteHead], lpMessage,
sizeof *lpMessage);
_miceIpcData->m_MessageWriteHead++;
if (_miceIpcData->m_MessageWriteHead == MICE_IPC_MAX_MESSAGES)
_miceIpcData->m_MessageWriteHead = 0;
_miceIpcData->m_MessagesWaiting++;
SetEvent(_miceIpcSendEvent);
_MiceIpcUnlock();
return TRUE;
}
BOOL MiceIpcPopMessage(PMICE_IPC_MESSAGE lpMessage, BOOL bBlocking) {
_MiceIpcLock();
if (_miceIpcData->m_MessagesWaiting == 0) {
if (!bBlocking) {
_MiceIpcUnlock();
return FALSE;
}
do {
_MiceIpcUnlock();
WaitForSingleObject(_miceIpcSendEvent, INFINITE);
_MiceIpcLock();
} while (_miceIpcData->m_MessagesWaiting == 0);
}
int index = _miceIpcData->m_MessageWriteHead - _miceIpcData->m_MessagesWaiting;
if (index < 0) index += MICE_IPC_MAX_MESSAGES;
// Impossible condition, but guard against it just in case!
if (index < 0 || index >= MICE_IPC_MAX_MESSAGES) {
_MiceIpcUnlock();
return FALSE;
}
memcpy(lpMessage, &_miceIpcData->m_MessageQueue[index],
sizeof _miceIpcData->m_MessageQueue[index]);
_miceIpcData->m_MessagesWaiting--;
// Signal to any pushes waiting that the queue should have more now
SetEvent(_miceIpcPopEvent);
_MiceIpcUnlock();
return TRUE;
}
static CHAR _szMiceRelative[MAX_PATH + 1];
static DWORD _szMiceRelativeN = 0xffffffff;
LPSTR MiceIpcRelativePath(LPSTR lpChild) {
if (_miceIpcData && _miceIpcData->m_LauncherIsReady) {
if (_szMiceRelative[0] == '\0' || _szMiceRelativeN == 0xffffffff) {
strcpy_s(_szMiceRelative, sizeof _szMiceRelative, _miceIpcData->m_MiceBase);
_szMiceRelativeN = strlen(_szMiceRelative);
if (_szMiceRelativeN == 0) {
strcat_s(_szMiceRelative, sizeof _szMiceRelative, "mice\\");
_szMiceRelativeN += 5;
} else {
strcat_s(_szMiceRelative, sizeof _szMiceRelative, "\\mice\\");
_szMiceRelativeN += 6;
}
}
strcpy_s(&_szMiceRelative[_szMiceRelativeN], sizeof _szMiceRelative - _szMiceRelativeN,
lpChild);
} else {
sprintf_s(_szMiceRelative, sizeof _szMiceRelative, ".\\mice\\%s", lpChild);
}
return _szMiceRelative;
}

View File

@ -0,0 +1,40 @@
#pragma once
#include <Windows.h>
#define MICE_IPC_MAX_MESSAGES 160
typedef enum MICE_IPC_TYPE {
MICE_IPC_TYPE_INVALID = 0,
MICE_IPC_TYPE_LOG = 1,
} MICE_IPC_TYPE;
typedef struct MICE_IPC_MESSAGE {
MICE_IPC_TYPE m_Type;
DWORD m_Size;
BYTE m_Message[1024];
} MICE_IPC_MESSAGE, *PMICE_IPC_MESSAGE;
typedef struct MICE_IPC_DATA {
BOOL m_LauncherIsReady;
char m_GameId[4];
char m_PathPrefix[MAX_PATH + 1];
char m_MiceBase[MAX_PATH + 1];
char m_MiceDll[MAX_PATH + 1];
DWORD m_MessageWriteHead;
DWORD m_MessagesWaiting;
MICE_IPC_MESSAGE m_MessageQueue[MICE_IPC_MAX_MESSAGES];
} MICE_IPC_DATA, *PMICE_IPC_DATA;
BOOL MiceIpcSetup(BOOL isOwner);
BOOL MiceIpcGetGameId(LPSTR lpGameId);
void _MiceIpcLock(void);
void _MiceIpcUnlock(void);
BOOL MiceIpcPushMessage(PMICE_IPC_MESSAGE lpMessage, BOOL bBlocking);
BOOL MiceIpcPopMessage(PMICE_IPC_MESSAGE lpMessage, BOOL bBlocking);
LPSTR MiceIpcRelativePath(LPSTR lpChild);
extern PMICE_IPC_DATA _miceIpcData;

View File

@ -9,6 +9,7 @@
#include "../util/pid.h"
#include "config.h"
#include "ipc.h"
#define _LF(category, name, display) \
LOG_FACILITY lf##name = { \
@ -70,8 +71,6 @@ void __stdcall amLogCallback(DWORD level, char* format) {
DWORD pLogcb;
DWORD* ppLogcb;
HANDLE hSlot;
static char log_buf[1024];
int _do_log(BYTE log_level, PLOG_FACILITY facility, const char* format, va_list args) {
// Early-return if we have nothing to do
@ -92,7 +91,7 @@ int _do_log(BYTE log_level, PLOG_FACILITY facility, const char* format, va_list
char prefix = LOG_PREFIXES[log_level];
int col_len = strlen(log_colours[log_level]);
size_t col_len = strlen(log_colours[log_level]);
EnterCriticalSection(&logger_lock);
int log_len = snprintf(log_buf, _countof(log_buf), "%s%s%c:%s:", log_colours[log_level],
@ -101,11 +100,19 @@ int _do_log(BYTE log_level, PLOG_FACILITY facility, const char* format, va_list
log_len += snprintf(log_buf + log_len, _countof(log_buf) - log_len, "%s\n", COLOR_RESET);
log_buf[_countof(log_buf) - 1] = '\0';
if (hSlot != INVALID_HANDLE_VALUE) {
WriteFile(hSlot, log_buf, log_len, NULL, NULL);
MICE_IPC_MESSAGE ipcMessage;
ipcMessage.m_Type = MICE_IPC_TYPE_LOG;
memcpy_s(ipcMessage.m_Message, sizeof ipcMessage.m_Message, log_buf, log_len);
if (log_len < sizeof ipcMessage.m_Message) {
ipcMessage.m_Message[log_len] = '\0';
ipcMessage.m_Size = log_len;
} else {
// This should never happen, but there's no harm being prepared in case it does
WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), log_buf, log_len, NULL, NULL);
ipcMessage.m_Message[sizeof ipcMessage.m_Message - 1] = '\0';
ipcMessage.m_Size = sizeof ipcMessage.m_Message;
}
if (!MiceIpcPushMessage(&ipcMessage, TRUE)) {
fprintf(stderr, "Failed to log: %.*s", log_len, log_buf);
}
LeaveCriticalSection(&logger_lock);
@ -172,19 +179,7 @@ int _log_game(PLOG_FACILITY facility, const char* format, ...) {
return ret;
}
void setup_logging() {
char slotName[MAX_PATH + 1];
sprintf_s(slotName, MAX_PATH, "\\\\.\\mailslot\\micelog%d", GetOutermostMiceId());
hSlot = CreateFile(slotName, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL, NULL);
if (hSlot == INVALID_HANDLE_VALUE) {
fprintf(stderr, "Fatal: Failed to open mailslot %s", slotName);
ExitProcess(2);
}
InitializeCriticalSection(&logger_lock);
}
void setup_logging() { InitializeCriticalSection(&logger_lock); }
void log_stack(PLOG_FACILITY facility) {
char name[MAX_PATH * sizeof(TCHAR)];
@ -195,12 +190,21 @@ void log_stack(PLOG_FACILITY facility) {
RtlCaptureContext(&context);
STACKFRAME64 stack = { 0 };
#ifdef _WIN64
stack.AddrPC.Offset = context.Rip;
stack.AddrPC.Mode = AddrModeFlat;
stack.AddrStack.Offset = context.Rsp;
stack.AddrStack.Mode = AddrModeFlat;
stack.AddrFrame.Offset = context.Rbp;
stack.AddrFrame.Mode = AddrModeFlat;
#else
stack.AddrPC.Offset = context.Eip;
stack.AddrPC.Mode = AddrModeFlat;
stack.AddrStack.Offset = context.Esp;
stack.AddrStack.Mode = AddrModeFlat;
stack.AddrFrame.Offset = context.Ebp;
stack.AddrFrame.Mode = AddrModeFlat;
#endif
HANDLE process = GetCurrentProcess();
HANDLE thread = GetCurrentThread();

View File

@ -43,7 +43,7 @@ void log_stack(PLOG_FACILITY facility);
void setup_logging();
// Disable some logging entirely at build time for speed
#define COMPILE_LOG_LEVEL 6
#define COMPILE_LOG_LEVEL 5
#if COMPILE_LOG_LEVEL >= 6
#define log_trace _log_trace

View File

@ -8,6 +8,7 @@ _LF(Misc, Fprintf, "fprintf")
_LF(Misc, Fprintf_s, "fprintf_s")
_LF(Misc, Vfprintf_s, "vfprintf_s")
_LF(Misc, AmLog, "amLog")
_LF(Misc, DebugLog, "DebugLog")
_LF(Hooks, Processes, "processes")
_LF(Hooks, Registry, "registry")
@ -30,6 +31,7 @@ _LF(Devices, Eeprom, "eeprom")
_LF(Devices, MaiTouch, "maitouch")
_LF(Devices, MaiLED, "mailed")
_LF(Devices, Servo15069, "servo15069")
_LF(Devices, GacchuGuts, "gacchuGuts")
_LF(Drivers, Columba, "columba")
_LF(Drivers, MxJvs, "mxjvs")

View File

@ -7,15 +7,20 @@ mice_lib = static_library(
'ringbuf.c',
'config.c',
'kcf.c',
'micefs.c',
'des.c',
'blowfish.c',
'solitaire.c',
'spad.c',
'dmi.c',
'ipc.c',
'serial.c',
],
link_with: [
inih.get_variable('lib_inih'),
util_lib,
amiCrc,
],
include_directories: [
openssl_inc,
],
)

View File

@ -8,9 +8,12 @@
#include "config.h"
#include "exe.h"
#include "ioctl.h"
#include "ipc.h"
#include "kcf.h"
#include "log.h"
#include "micefs.h"
#include "patch.h"
#include "ringbuf.h"
#include "version_fallback.h"
#define SRAM_PATH MiceIpcRelativePath("sram.bin")
BOOL GetSerialNumbers(LPSTR szMainId, LPSTR szKeyId);

View File

@ -0,0 +1,140 @@
#include <openssl/evp.h>
#include <stdio.h>
#include <wbemidl.h>
#pragma comment(lib, "wbemuuid.lib")
static BOOL PerformWmiQuery(LPCWCH szClass, LPCWCH szProperty, LPWCH lpResult, DWORD nResult) {
HRESULT hres;
IWbemLocator *pLoc = NULL;
IWbemServices *pSvc = NULL;
IEnumWbemClassObject *pEnumerator = NULL;
BOOL bSuccess = FALSE;
hres = CoInitializeEx(0, COINIT_MULTITHREADED);
if (FAILED(hres)) return FALSE;
hres = CoInitializeSecurity(NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_DEFAULT,
RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE, NULL);
if (FAILED(hres)) goto cleanup;
hres = CoCreateInstance(&CLSID_WbemLocator, 0, CLSCTX_INPROC_SERVER, &IID_IWbemLocator,
(LPVOID *)&pLoc);
if (FAILED(hres)) goto cleanup;
hres =
pLoc->lpVtbl->ConnectServer(pLoc, L"ROOT\\CIMV2", NULL, NULL, NULL, 0, NULL, NULL, &pSvc);
if (FAILED(hres)) goto cleanup;
hres = CoSetProxyBlanket((IUnknown *)pSvc, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, NULL,
RPC_C_AUTHN_LEVEL_CALL, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE);
if (FAILED(hres)) goto cleanup;
WCHAR szQuery[128];
swprintf_s(szQuery, _countof(szQuery), L"SELECT * FROM %ls", szClass);
hres = pSvc->lpVtbl->ExecQuery(pSvc, L"WQL", szQuery,
WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, NULL,
&pEnumerator);
if (FAILED(hres)) goto cleanup;
IWbemClassObject *pclsObj = NULL;
ULONG uReturn = 0;
while (pEnumerator) {
HRESULT hr = pEnumerator->lpVtbl->Next(pEnumerator, WBEM_INFINITE, 1, &pclsObj, &uReturn);
if (!uReturn) break;
VARIANT vtProp;
hr = pclsObj->lpVtbl->Get(pclsObj, szProperty, 0, &vtProp, 0, 0);
if (SUCCEEDED(hr) && vtProp.vt != VT_NULL) {
wcscpy_s(lpResult, nResult, vtProp.bstrVal);
bSuccess = TRUE;
}
VariantClear(&vtProp);
pclsObj->lpVtbl->Release(pclsObj);
}
pEnumerator->lpVtbl->Release(pEnumerator);
cleanup:
if (pSvc) pSvc->lpVtbl->Release(pSvc);
if (pLoc) pLoc->lpVtbl->Release(pLoc);
CoUninitialize();
return bSuccess;
}
inline static void alphaNum(CHAR *lpAddr, BYTE val) {
val %= 26 + 10;
if (val < 10)
lpAddr[0] = '0' + val;
else
lpAddr[0] = 'A' + (val - 10);
}
inline static void numeric(CHAR *lpAddr, BYTE val) {
val %= 100;
lpAddr[0] = '0' + (val / 10);
lpAddr[1] = '0' + (val % 10);
}
extern BOOL g_bIsInDllMain;
BOOL GetSerialNumbers(LPSTR szMainId, LPSTR szKeyId) {
// Making WMI queries from within DllMain is not happening. Ever. :D
if (g_bIsInDllMain) return FALSE;
WCHAR szMbSerial[128];
if (!PerformWmiQuery(L"Win32_BaseBoard", L"SerialNumber", szMbSerial, _countof(szMbSerial)))
return FALSE;
szMbSerial[127] = L'\0';
WCHAR szCpuId[128];
if (!PerformWmiQuery(L"Win32_Processor", L"ProcessorId", szCpuId, _countof(szCpuId)))
return FALSE;
szCpuId[127] = L'\0';
BYTE sumOut[20];
unsigned int outlen;
EVP_MD_CTX *ctx;
ctx = EVP_MD_CTX_create();
EVP_DigestInit(ctx, EVP_sha1());
EVP_DigestUpdate(ctx, szMbSerial, wcslen(szMbSerial));
EVP_DigestUpdate(ctx, szCpuId, wcslen(szCpuId));
EVP_DigestFinal_ex(ctx, sumOut, &outlen);
EVP_MD_CTX_destroy(ctx);
if (szMainId) {
szMainId[0] = 'M';
alphaNum(&szMainId[1], sumOut[0]);
alphaNum(&szMainId[2], sumOut[1]);
alphaNum(&szMainId[3], sumOut[2]);
szMainId[4] = '-';
alphaNum(&szMainId[5], sumOut[3]);
alphaNum(&szMainId[6], sumOut[4]);
alphaNum(&szMainId[7], sumOut[5]);
numeric(&szMainId[8], sumOut[6]);
numeric(&szMainId[10], sumOut[7]);
numeric(&szMainId[12], sumOut[8]);
numeric(&szMainId[14], sumOut[9]);
szMainId[16] = '\0';
}
if (szKeyId) {
szKeyId[0] = 'M';
alphaNum(&szKeyId[1], sumOut[10]);
alphaNum(&szKeyId[2], sumOut[11]);
alphaNum(&szKeyId[3], sumOut[12]);
szKeyId[4] = '-';
alphaNum(&szKeyId[5], sumOut[13]);
alphaNum(&szKeyId[6], sumOut[14]);
alphaNum(&szKeyId[7], sumOut[15]);
numeric(&szKeyId[8], sumOut[16]);
numeric(&szKeyId[10], sumOut[17]);
numeric(&szKeyId[12], sumOut[18]);
numeric(&szKeyId[14], sumOut[19]);
szKeyId[16] = '\0';
}
return TRUE;
}

View File

@ -1,3 +0,0 @@
#ifndef MICE_VERSION
#define MICE_VERSION "0.0-pre"
#endif

View File

@ -152,7 +152,7 @@ BOOL mxkFlashRead(unsigned int address, unsigned int nbytes, unsigned char* buff
mxkPacketReqFlashRead(packet, address, nbytes);
if (!mxkSendPacket(packet)) return FALSE;
for (size_t i = 0; i < nbytes; i += 0x100) {
for (unsigned int i = 0; i < nbytes; i += 0x100) {
unsigned int rest = (nbytes - i) > 0x100 ? 0x100 : (nbytes - i);
if (!mxkTransportRecv(buffer + i, rest)) return FALSE;
}

View File

@ -268,7 +268,7 @@ void mxkSignValue(unsigned int value, unsigned char* signature) {
mxkSign(&hash_data, sizeof hash_data, signature);
}
int mxkCryptCalcHashWithHmacSha1(PHmacKey_t key, PHmacSum_t md, size_t* nbuffer,
int mxkCryptCalcHashWithHmacSha1(PHmacKey_t key, PHmacSum_t md, unsigned int* nbuffer,
unsigned char* buffer, size_t nin) {
if (key == NULL || buffer == NULL || md == NULL || nbuffer == NULL) {
amiDebugLog("Error: Invalid param.");

View File

@ -21,7 +21,7 @@ void mxkSwapKeys();
MXK_STATUS mxkCryptInit(void);
int mxkCryptCalcHashWithHmacSha1(PHmacKey_t key, PHmacSum_t md, size_t* nbuffer,
int mxkCryptCalcHashWithHmacSha1(PHmacKey_t key, PHmacSum_t md, unsigned int* nbuffer,
unsigned char* buffer, size_t nin);
void mxkCryptCalcHashWithSha1(unsigned char* data, size_t nbytes, PSha1Sum_t sum);

View File

@ -195,7 +195,7 @@ int mxkN2UtilHmacPacket(PSha1Sum_t packetSha, PHmacSum_t hmacSalt, PN2Nonce_t no
unsigned char data_in[sizeof *packetSha + sizeof *hmacSalt + sizeof *nonce];
size_t count = sizeof *packetSha + sizeof *hmacSalt + sizeof *nonce;
size_t nout = HMAC_SUM_SIZE;
unsigned int nout = HMAC_SUM_SIZE;
mxkN2UtilCatenateData(data_in, &count, 3, packetSha, sizeof *packetSha, hmacSalt,
sizeof *hmacSalt, nonce, sizeof *nonce);

View File

@ -3,6 +3,8 @@
#include <shlwapi.h>
#include <tlhelp32.h>
#include "../mice/exe.h"
#pragma comment(lib, "psapi.lib")
DWORD GetParentProcessIdFor(DWORD pid) {
@ -30,12 +32,14 @@ DWORD GetOutermostMiceId(void) {
CHAR baseName[MAX_PATH + 1];
if (GetModuleFileNameEx(hProcess, NULL, baseName, sizeof baseName)) {
// TODO: Better
if (strcmp(PathFindFileNameA(baseName), "mice.exe") == 0) return pid;
if (stricmp(PathFindFileNameA(baseName), MICEEXE) == 0)
return pid;
}
CloseHandle(hProcess);
}
pid = GetParentProcessIdFor(pid);
} while (pid != (DWORD)-1);
fprintf(stderr, "Likely fatal: Failed to identify parent mouse!");
return (DWORD)-1;
}

View File

@ -87,6 +87,6 @@ void mxkPcpAbSeed(pcpa_t* stream, void* data) {
pcpaAddSendPacket(stream, "port", "40107");
char sSize[16];
sprintf_s(sSize, sizeof sSize, "%d", sizeof mxkKcfConfig.m_Seed);
sprintf_s(sSize, sizeof sSize, "%zd", sizeof mxkKcfConfig.m_Seed);
pcpaAddSendPacket(stream, "size", sSize);
}

Some files were not shown because too many files have changed in this diff Show More