Compare commits

...

9 Commits

22 changed files with 996 additions and 162 deletions

View File

@ -1,5 +1,3 @@
SHELL = /bin/bash
V ?= @ V ?= @
.DEFAULT_GOAL := help .DEFAULT_GOAL := help
@ -7,16 +5,12 @@ V ?= @
BUILD_DIR := build BUILD_DIR := build
BUILD_DIR_32 := $(BUILD_DIR)/build32 BUILD_DIR_32 := $(BUILD_DIR)/build32
BUILD_DIR_64 := $(BUILD_DIR)/build64 BUILD_DIR_64 := $(BUILD_DIR)/build64
BUILD_DIR_DOCKER := $(BUILD_DIR)/docker
BUILD_DIR_ZIP := $(BUILD_DIR)/zip BUILD_DIR_ZIP := $(BUILD_DIR)/zip
DOC_DIR := doc DOC_DIR := doc
DIST_DIR := dist DIST_DIR := dist
DOCKER_CONTAINER_NAME := "segatools-build"
DOCKER_IMAGE_NAME := "segatools:build"
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
# Targets # Targets
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
@ -44,15 +38,6 @@ zip: $(BUILD_DIR_ZIP)/segatools.zip
clean: clean:
$(V)rm -rf $(BUILD_DIR) subprojects/capnhook $(V)rm -rf $(BUILD_DIR) subprojects/capnhook
.PHONY: build-docker # Build the project in a docker container
build-docker:
$(V)docker rm -f $(DOCKER_CONTAINER_NAME) 2> /dev/null || true
$(V)docker build -t $(DOCKER_IMAGE_NAME) -f Dockerfile .
$(V)docker create --name $(DOCKER_CONTAINER_NAME) $(DOCKER_IMAGE_NAME)
$(V)rm -rf $(BUILD_DIR_DOCKER)
$(V)mkdir -p $(BUILD_DIR_DOCKER)
$(V)docker cp $(DOCKER_CONTAINER_NAME):/segatools/$(BUILD_DIR_ZIP) $(BUILD_DIR_DOCKER)
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
# Utility, combo and alias targets # Utility, combo and alias targets
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------

View File

@ -21,9 +21,18 @@ const struct dll_bind_sym carol_dll_syms[] = {
}, { }, {
.sym = "carol_io_touch_init", .sym = "carol_io_touch_init",
.off = offsetof(struct carol_dll, touch_init), .off = offsetof(struct carol_dll, touch_init),
}, {
.sym = "carol_io_ledbd_init",
.off = offsetof(struct carol_dll, ledbd_init),
}, { }, {
.sym = "carol_io_controlbd_init", .sym = "carol_io_controlbd_init",
.off = offsetof(struct carol_dll, controlbd_init), .off = offsetof(struct carol_dll, controlbd_init),
}, {
.sym = "carol_io_touch_start",
.off = offsetof(struct carol_dll, touch_start),
}, {
.sym = "carol_io_touch_stop",
.off = offsetof(struct carol_dll, touch_stop),
} }
}; };

View File

@ -10,7 +10,10 @@ struct carol_dll {
void (*jvs_poll)(uint8_t *opbtn, uint8_t *beams); void (*jvs_poll)(uint8_t *opbtn, uint8_t *beams);
void (*jvs_read_coin_counter)(uint16_t *total); void (*jvs_read_coin_counter)(uint16_t *total);
HRESULT (*touch_init)(); HRESULT (*touch_init)();
HRESULT (*ledbd_init)();
HRESULT (*controlbd_init)(); HRESULT (*controlbd_init)();
void (*touch_start)(carol_io_touch_callback_t callback);
void (*touch_stop)();
}; };
struct carol_dll_config { struct carol_dll_config {

View File

@ -16,4 +16,7 @@ EXPORTS
carol_io_jvs_poll carol_io_jvs_poll
carol_io_jvs_read_coin_counter carol_io_jvs_read_coin_counter
carol_io_touch_init carol_io_touch_init
carol_io_ledbd_init
carol_io_controlbd_init carol_io_controlbd_init
carol_io_touch_start
carol_io_touch_stop

View File

@ -58,6 +58,20 @@ void controlbd_config_load(
filename); filename);
} }
void ledbd_config_load(
struct ledbd_config *cfg,
const wchar_t *filename)
{
assert(cfg != NULL);
assert(filename != NULL);
cfg->enable = GetPrivateProfileIntW(
L"ledbd",
L"enable",
1,
filename);
}
void carol_hook_config_load( void carol_hook_config_load(
struct carol_hook_config *cfg, struct carol_hook_config *cfg,
@ -73,4 +87,5 @@ void carol_hook_config_load(
gfx_config_load(&cfg->gfx, filename); gfx_config_load(&cfg->gfx, filename);
touch_config_load(&cfg->touch, filename); touch_config_load(&cfg->touch, filename);
controlbd_config_load(&cfg->controlbd, filename); controlbd_config_load(&cfg->controlbd, filename);
ledbd_config_load(&cfg->ledbd, filename);
} }

View File

@ -13,6 +13,7 @@
#include "gfxhook/gfx.h" #include "gfxhook/gfx.h"
#include "carolhook/touch.h" #include "carolhook/touch.h"
#include "carolhook/ledbd.h"
#include "carolhook/controlbd.h" #include "carolhook/controlbd.h"
struct carol_hook_config { struct carol_hook_config {
@ -22,6 +23,7 @@ struct carol_hook_config {
struct carol_dll_config dll; struct carol_dll_config dll;
struct gfx_config gfx; struct gfx_config gfx;
struct touch_config touch; struct touch_config touch;
struct ledbd_config ledbd;
struct controlbd_config controlbd; struct controlbd_config controlbd;
}; };

View File

@ -8,6 +8,8 @@
#include "hook/iobuf.h" #include "hook/iobuf.h"
#include "hook/iohook.h" #include "hook/iohook.h"
#include "hook/table.h"
#include "carolhook/carol-dll.h" #include "carolhook/carol-dll.h"
#include "carolhook/controlbd.h" #include "carolhook/controlbd.h"
@ -18,16 +20,57 @@
static HRESULT controlbd_handle_irp(struct irp *irp); static HRESULT controlbd_handle_irp(struct irp *irp);
static HRESULT controlbd_handle_irp_locked(struct irp *irp); static HRESULT controlbd_handle_irp_locked(struct irp *irp);
static HRESULT controlbd_frame_decode(struct controlbd_req *dest, struct iobuf *iobuf); static HRESULT controlbd_frame_decode(struct controlbd_req_any *dest, struct iobuf *src);
static HRESULT controlbd_frame_dispatch(struct controlbd_req *dest); static HRESULT controlbd_set_header(struct controlbd_resp_hdr *resp, uint8_t cmd, uint8_t len);
static uint8_t calc_checksum(void *data, size_t len);
static HRESULT controlbd_req_nop(uint8_t cmd); static HRESULT controlbd_req_dispatch(const struct controlbd_req_any *req);
static HRESULT controlbd_req_ack_any(uint8_t cmd);
static HRESULT controlbd_req_reset(void);
static HRESULT controlbd_req_get_board_info(void);
static HRESULT controlbd_req_firmware_checksum(void);
static HRESULT controlbd_req_polling(const struct controlbd_req_any *req);
const uint8_t CONTROLBD_SYNC_BYTE = 0xE0;
static CRITICAL_SECTION controlbd_lock; static CRITICAL_SECTION controlbd_lock;
static struct uart controlbd_uart; static struct uart controlbd_uart;
static uint8_t controlbd_written_bytes[520]; static uint8_t controlbd_written_bytes[520];
static uint8_t controlbd_readable_bytes[520]; static uint8_t controlbd_readable_bytes[520];
static BOOL WINAPI my_CreateProcessA(
LPCSTR lpApplicationName,
LPSTR lpCommandLine,
LPSECURITY_ATTRIBUTES lpProcessAttributes,
LPSECURITY_ATTRIBUTES lpThreadAttributes,
BOOL bInheritHandles,
DWORD dwCreationFlags,
LPVOID lpEnvironment,
LPCSTR lpCurrentDirectory,
LPSTARTUPINFOA lpStartupInfo,
LPPROCESS_INFORMATION lpProcessInformation
);
static BOOL (WINAPI *next_CreateProcessA)(
LPCSTR lpApplicationName,
LPSTR lpCommandLine,
LPSECURITY_ATTRIBUTES lpProcessAttributes,
LPSECURITY_ATTRIBUTES lpThreadAttributes,
BOOL bInheritHandles,
DWORD dwCreationFlags,
LPVOID lpEnvironment,
LPCSTR lpCurrentDirectory,
LPSTARTUPINFOA lpStartupInfo,
LPPROCESS_INFORMATION lpProcessInformation
);
static const struct hook_symbol win32_hooks[] = {
{
.name = "CreateProcessA",
.patch = my_CreateProcessA,
.link = (void **) &next_CreateProcessA
}
};
HRESULT controlbd_hook_init(const struct controlbd_config *cfg) HRESULT controlbd_hook_init(const struct controlbd_config *cfg)
{ {
if (!cfg->enable) { if (!cfg->enable) {
@ -36,12 +79,18 @@ HRESULT controlbd_hook_init(const struct controlbd_config *cfg)
InitializeCriticalSection(&controlbd_lock); InitializeCriticalSection(&controlbd_lock);
uart_init(&controlbd_uart, 11); uart_init(&controlbd_uart, 12);
controlbd_uart.written.bytes = controlbd_written_bytes; controlbd_uart.written.bytes = controlbd_written_bytes;
controlbd_uart.written.nbytes = sizeof(controlbd_written_bytes); controlbd_uart.written.nbytes = sizeof(controlbd_written_bytes);
controlbd_uart.readable.bytes = controlbd_readable_bytes; controlbd_uart.readable.bytes = controlbd_readable_bytes;
controlbd_uart.readable.nbytes = sizeof(controlbd_readable_bytes); controlbd_uart.readable.nbytes = sizeof(controlbd_readable_bytes);
hook_table_apply(
NULL,
"kernel32.dll",
win32_hooks,
_countof(win32_hooks));
dprintf("Control Board: Init\n"); dprintf("Control Board: Init\n");
return iohook_push_handler(controlbd_handle_irp); return iohook_push_handler(controlbd_handle_irp);
@ -64,10 +113,49 @@ static HRESULT controlbd_handle_irp(struct irp *irp)
return hr; return hr;
} }
static HRESULT controlbd_frame_decode(struct controlbd_req_any *req, struct iobuf *src)
{
uint8_t data_len = 0;
uint8_t checksum_pos = src->pos - 1;
uint8_t calculated_checksum = 0;
uint8_t checksum = 0;
if (src->pos < 6) {
dprintf("Control Board: Decode Error, request too short (pos is 0x%08X)\n", (int)src->pos);
return SEC_E_BUFFER_TOO_SMALL;
}
req->hdr.sync = src->bytes[0];
req->hdr.dest = src->bytes[1];
req->hdr.src = src->bytes[2];
req->hdr.len = src->bytes[3];
req->hdr.cmd = src->bytes[4];
data_len = req->hdr.len;
src->pos -= 5;
for (int i = 0; i < data_len; i++) {
if (src->pos == 0) {
break;
}
req->bytes[i] = src->bytes[i + 5];
src->pos --;
}
checksum = src->bytes[checksum_pos];
calculated_checksum = calc_checksum(req, checksum_pos);
if (checksum != calculated_checksum) {
dprintf("Control Board: Decode Error, checksum failure (expected 0x%02X, got 0x%02X)\n", calculated_checksum, checksum);
return HRESULT_FROM_WIN32(ERROR_CRC);
}
return S_OK;
}
static HRESULT controlbd_handle_irp_locked(struct irp *irp) static HRESULT controlbd_handle_irp_locked(struct irp *irp)
{ {
struct controlbd_req req;
HRESULT hr; HRESULT hr;
struct controlbd_req_any req;
assert(carol_dll.controlbd_init != NULL); assert(carol_dll.controlbd_init != NULL);
@ -76,7 +164,7 @@ static HRESULT controlbd_handle_irp_locked(struct irp *irp)
hr = carol_dll.controlbd_init(); hr = carol_dll.controlbd_init();
if (FAILED(hr)) { if (FAILED(hr)) {
dprintf("Control Board: Backend DLL error: %x\n", (int) hr); dprintf("Control Board: Backend DLL error: 0X%X\n", (int) hr);
return hr; return hr;
} }
@ -89,90 +177,251 @@ static HRESULT controlbd_handle_irp_locked(struct irp *irp)
} }
for (;;) { for (;;) {
if (controlbd_uart.written.bytes[0] == 0xE0) {
#if 0 #if 0
dprintf("Control Board: TX Buffer:\n"); dprintf("Control Board: TX Buffer:\n");
dump_iobuf(&controlbd_uart.written); dump_iobuf(&controlbd_uart.written);
#endif #endif
hr = controlbd_frame_decode(&req, &controlbd_uart.written); hr = controlbd_frame_decode(&req, &controlbd_uart.written);
if (FAILED(hr)) {
if (FAILED(hr)) { dprintf("Control Board: Deframe error: %x\n", (int) hr);
dprintf("Control Board: Deframe Error: %x\n", (int) hr); return hr;
}
hr = controlbd_req_dispatch(&req);
if (FAILED(hr)) {
dprintf("Control Board: Dispatch Error: 0X%X\n", (int) hr);
return hr;
}
#if 0
dprintf("Control Board: RX Buffer:\n");
dump_iobuf(&controlbd_uart.readable);
#endif
controlbd_uart.written.pos = 0;
return hr; return hr;
} }
hr = controlbd_frame_dispatch(&req); // The board has a LPC111x bootloader that gets ran over every boot
if (FAILED(hr)) { // this is to account for that.
dprintf("Control Board: Dispatch Error: %x\n", (int) hr); char cmd[255];
strcpy_s(cmd, 255, (char *)controlbd_uart.written.bytes);
cmd[controlbd_uart.written.pos] = '\0';
return hr; if (!strcmp(cmd, "?")) {
dprintf("Control Board: Bootloader Hello\n");
}
else if (!strcmp(cmd, "Synchronized\r\n")) {
iobuf_write(&controlbd_uart.readable, "Synchronized\r\nNG\r\n", 19);
// Set this to OK instead of NG to do an update
}
else if (!strcmp(cmd, "12000\r\n")) {
iobuf_write(&controlbd_uart.readable, "12000\r\nOK\r\n", 12);
}
else {
// Everything other then the two commands above just want 0\r\n
// appended to the request as the response. Given that it only checks sometimes,
// it's safe to just run over the readable buffer every response.
controlbd_uart.readable.pos = 0;
cmd[controlbd_uart.written.pos] = '0';
cmd[controlbd_uart.written.pos + 1] = '\r';
cmd[controlbd_uart.written.pos + 2] = '\n';
cmd[controlbd_uart.written.pos + 3] = '\0';
// dprintf("Control Board: Return %s\n", cmd);
iobuf_write(&controlbd_uart.readable, cmd, controlbd_uart.written.pos + 3);
} }
controlbd_uart.written.pos = 0;
return hr; return hr;
} }
} }
static HRESULT controlbd_frame_dispatch(struct controlbd_req *req) static HRESULT controlbd_req_dispatch(const struct controlbd_req_any *req)
{ {
switch (req->cmd) { switch (req->hdr.cmd) {
case CONTROLBD_CMD_UNK_11: case CONTROLBD_CMD_RESET:
return controlbd_req_nop(req->cmd); return controlbd_req_reset();
case CONTROLBD_CMD_BDINFO:
return controlbd_req_get_board_info();
case CONTROLBD_CMD_FIRM_SUM:
return controlbd_req_firmware_checksum();
case CONTROLBD_CMD_TIMEOUT:
dprintf("Control Board: Acknowledge Timeout\n");
return controlbd_req_ack_any(req->hdr.cmd);
case CONTROLBD_CMD_PORT_SETTING:
dprintf("Control Board: Acknowledge Port Setting\n");
return controlbd_req_ack_any(req->hdr.cmd);
case CONTROLBD_CMD_INITIALIZE:
dprintf("Control Board: Acknowledge Initialize\n");
return controlbd_req_ack_any(req->hdr.cmd);
case CONTROLBD_CMD_POLLING:
return controlbd_req_polling(req);
default: default:
dprintf("Unhandled command %#02x\n", req->cmd); dprintf("Unhandled command 0x%02x\n", req->hdr.cmd);
return controlbd_req_ack_any(req->hdr.cmd);
return S_OK;
} }
} }
static HRESULT controlbd_req_nop(uint8_t cmd) static HRESULT controlbd_set_header(struct controlbd_resp_hdr *resp, uint8_t cmd, uint8_t len)
{ {
dprintf("Control Board: No-op cmd %#02x\n", cmd); resp->sync = CONTROLBD_SYNC_BYTE;
resp->dest = 0x01;
controlbd_uart.readable.bytes[controlbd_uart.readable.pos++] = 0xE0; resp->src = 0x02;
controlbd_uart.readable.bytes[controlbd_uart.readable.pos++] = 0x01; resp->len = len;
controlbd_uart.readable.bytes[controlbd_uart.readable.pos++] = 0x11; resp->report = 0x01;
controlbd_uart.readable.bytes[controlbd_uart.readable.pos++] = 0x03; resp->cmd = cmd;
controlbd_uart.readable.bytes[controlbd_uart.readable.pos++] = 0x01;
controlbd_uart.readable.bytes[controlbd_uart.readable.pos++] = 0x10;
controlbd_uart.readable.bytes[controlbd_uart.readable.pos++] = 0x01;
controlbd_uart.readable.bytes[controlbd_uart.readable.pos++] = 0x27;
return S_OK; return S_OK;
} }
/* Decodes the response into a struct that's easier to work with. */ static uint8_t calc_checksum(void *data, size_t len)
static HRESULT controlbd_frame_decode(struct controlbd_req *dest, struct iobuf *iobuf)
{ {
int initial_pos = iobuf->pos; uint8_t *stuff;
uint8_t check = 0; stuff = data;
uint8_t checksum = 0;
uint16_t tmp = 0;
dest->sync = iobuf->bytes[0]; for (int i = 1; i < len; i++) {
iobuf->pos--; tmp = checksum + stuff[i];
checksum = tmp & 0xFF;
dest->cmd = iobuf->bytes[1];
iobuf->pos--;
check += dest->cmd;
dest->checksum = iobuf->bytes[initial_pos - 1];
iobuf->pos--;
dest->data_length = initial_pos - 3; // sync, cmd, checksum
if (dest->data_length > 0) {
for (int i = 0; i < dest->data_length; i++) {
dest->data[i] = iobuf->bytes[i+2];
check += dest->data[i];
}
}
iobuf->pos -= dest->data_length;
if (dest->sync != 0xe0) {
dprintf("Control Board: Sync error, expected 0xe0, got %x\n", dest->sync);
return E_FAIL;
}
if (dest->checksum != check) {
dprintf("Control Board: Checksum error, expected %x, got %x\n", check, dest->checksum);
return E_FAIL;
} }
return S_OK; return checksum;
}
static HRESULT controlbd_req_reset(void)
{
struct controlbd_resp_reset resp;
dprintf("Control Board: Reset\n");
controlbd_set_header(&resp.hdr, CONTROLBD_CMD_RESET, 2);
resp.checksum = 0;
// No data, just ack
resp.checksum = calc_checksum(&resp, sizeof(resp));
return iobuf_write(&controlbd_uart.readable, &resp, sizeof(resp));
}
static HRESULT controlbd_req_get_board_info(void)
{
struct controlbd_resp_bdinfo resp;
memset(&resp, 0, sizeof(resp));
dprintf("Control Board: Get Board Info\n");
controlbd_set_header(&resp.hdr, CONTROLBD_CMD_BDINFO, 21);
resp.rev = 0x90;
resp.bfr_size = 0x0001;
resp.ack = 1;
strcpy_s(resp.bd_no, sizeof(resp.bd_no), "15312 ");
strcpy_s(resp.chip_no, sizeof(resp.chip_no), "6699 ");
resp.chip_no[5] = 0xFF;
resp.bd_no[8] = 0x0A;
resp.checksum = calc_checksum(&resp, sizeof(resp));
return iobuf_write(&controlbd_uart.readable, &resp, sizeof(resp));
}
static HRESULT controlbd_req_firmware_checksum(void)
{
struct controlbd_resp_fw_checksum resp;
memset(&resp, 0, sizeof(resp));
dprintf("Control Board: Get Firmware Checksum\n");
controlbd_set_header(&resp.hdr, CONTROLBD_CMD_FIRM_SUM, 5);
resp.ack = 1;
resp.fw_checksum = 0x1b36; // This could change with an update... oh well
resp.checksum = calc_checksum(&resp, sizeof(resp));
return iobuf_write(&controlbd_uart.readable, &resp, sizeof(resp));
}
static HRESULT controlbd_req_polling(const struct controlbd_req_any *req)
{
struct controlbd_req_polling req_struct;
memset(&req_struct, 0, sizeof(req_struct));
memcpy_s(&req_struct, sizeof(req_struct), req, sizeof(req_struct));
struct controlbd_resp_polling resp;
memset(&resp, 0, sizeof(resp));
controlbd_set_header(&resp.hdr, CONTROLBD_CMD_POLLING, 16);
// TODO: Figure out output (pen vibration, etc)
resp.ack = 1;
resp.unk7 = 3;
resp.unk8 = 1;
resp.unk9 = 1;
resp.btns_pressed = 0; // bit 1 is pen button, bit 2 is dodge
resp.coord_x = 0x0;
resp.coord_y = 0x0;
resp.checksum = calc_checksum(&resp, sizeof(resp));
return iobuf_write(&controlbd_uart.readable, &resp, sizeof(resp));
}
static HRESULT controlbd_req_ack_any(uint8_t cmd)
{
struct controlbd_resp_any_ack resp;
memset(&resp, 0, sizeof(resp));
controlbd_set_header(&resp.hdr, cmd, 3);
resp.ack = 1;
resp.checksum = calc_checksum(&resp, sizeof(resp));
return iobuf_write(&controlbd_uart.readable, &resp, sizeof(resp));
}
static BOOL WINAPI my_CreateProcessA(
LPCSTR lpApplicationName,
LPSTR lpCommandLine,
LPSECURITY_ATTRIBUTES lpProcessAttributes,
LPSECURITY_ATTRIBUTES lpThreadAttributes,
BOOL bInheritHandles,
DWORD dwCreationFlags,
LPVOID lpEnvironment,
LPCSTR lpCurrentDirectory,
LPSTARTUPINFOA lpStartupInfo,
LPPROCESS_INFORMATION lpProcessInformation
)
{
dprintf("Control Board: my_CreateProcessA Hit! %s\n", lpCommandLine);
if (strncmp(".\\15312firm\\firmupdate_1113.exe", lpCommandLine, 31)) {
return next_CreateProcessA(
lpApplicationName,
lpCommandLine,
lpProcessAttributes,
lpThreadAttributes,
bInheritHandles,
dwCreationFlags,
lpEnvironment,
lpCurrentDirectory,
lpStartupInfo,
lpProcessInformation
);
}
dprintf("Control Board: Hooking child process\n");
char new_cmd[MAX_PATH] = "inject -d -k carolhook.dll ";
strcat_s(new_cmd, MAX_PATH, lpCommandLine);
return next_CreateProcessA(
lpApplicationName,
new_cmd,
lpProcessAttributes,
lpThreadAttributes,
bInheritHandles,
dwCreationFlags,
lpEnvironment,
lpCurrentDirectory,
lpStartupInfo,
lpProcessInformation
);
} }

View File

@ -1,5 +1,7 @@
#pragma once #pragma once
#include <windows.h> #include <windows.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h> #include <stdint.h>
@ -7,15 +9,140 @@
struct controlbd_config { struct controlbd_config {
bool enable; bool enable;
}; };
enum controlbd_cmd {
CONTROLBD_CMD_UNK_11 = 0x11 #pragma pack(push, 1)
}; struct controlbd_req_hdr {
struct controlbd_req { uint8_t sync;
uint8_t sync; // First byte is the sync uint8_t dest; // unsure
uint8_t cmd; // Command byte uint8_t src; // unsure
uint8_t data[256]; // Request body goes here uint8_t len; // length of the rest of the request minus checksum
uint8_t checksum; // Final byte is all bytes added, except the sync uint8_t cmd;
uint8_t data_length; // Size of the data including command byte
}; };
struct controlbd_req_any {
struct controlbd_req_hdr hdr;
uint8_t bytes[255];
};
struct controlbd_req_reset {
struct controlbd_req_hdr hdr;
uint8_t payload;
uint8_t checksum;
};
struct controlbd_req_bdinfo {
struct controlbd_req_hdr hdr;
uint8_t checksum;
};
struct controlbd_req_fw_checksum {
struct controlbd_req_hdr hdr;
uint8_t checksum;
};
struct controlbd_req_timeout {
struct controlbd_req_hdr hdr;
uint8_t unknown;
uint8_t checksum;
};
struct controlbd_req_polling {
struct controlbd_req_hdr hdr;
uint8_t unknown[20];
uint8_t checksum;
};
struct controlbd_resp_hdr {
uint8_t sync;
uint8_t dest; // unsure
uint8_t src; // unsure
uint8_t len; // length of the rest of the request minus checksum
uint8_t report; // 0x01 for success, anything else for failure
uint8_t cmd;
};
struct controlbd_resp_any {
struct controlbd_resp_hdr hdr;
uint8_t bytes[255];
};
struct controlbd_resp_any_ack {
struct controlbd_resp_hdr hdr;
uint8_t ack;
uint8_t checksum;
};
struct controlbd_resp_reset {
struct controlbd_resp_hdr hdr;
uint8_t checksum;
};
struct controlbd_resp_bdinfo {
struct controlbd_resp_hdr hdr;
uint8_t ack;
char bd_no[9];
char chip_no[6];
uint8_t rev;
uint16_t bfr_size;
uint8_t checksum;
};
struct controlbd_resp_fw_checksum {
struct controlbd_resp_hdr hdr;
uint8_t ack;
uint16_t fw_checksum;
uint8_t checksum;
};
struct controlbd_resp_polling {
struct controlbd_resp_hdr hdr;
uint8_t ack;
uint8_t unk7;
uint8_t unk8;
uint8_t unk9;
uint8_t btns_pressed;
uint8_t blob[7];
int8_t coord_x;
int8_t coord_y;
uint8_t checksum;
};
enum {
PEN_BTN_PRESSED_BIT = 1,
DODGE_BTN_PRESSED_BIT = 2
};
enum {
CONTROLBD_CMD_RESET = 0x10,
CONTROLBD_CMD_TIMEOUT = 0x11,
CONTROLBD_CMD_RETRY = 0x12,
CONTROLBD_CMD_GETIN = 0x20,
CONTROLBD_CMD_GETADI = 0x21,
CONTROLBD_CMD_SETOUTPUT = 0x30,
CONTROLBD_CMD_INITIALIZE = 0x80,
CONTROLBD_CMD_POLLING = 0x81,
CONTROLBD_CMD_CUSTOM_PATTERN = 0x82,
CONTROLBD_CMD_DEBUG_CAROL = 0x83,
CONTROLBD_CMD_POLLING_GENERAL = 0x84,
CONTROLBD_CMD_CMD_STATUS = 0x90,
CONTROLBD_CMD_PORT_SETTING = 0x91,
CONTROLBD_CMD_PWM_DUTY = 0x92,
CONTROLBD_CMD_LED_SET = 0x93,
CONTROLBD_CMD_LED_REFRESH = 0x94,
CONTROLBD_CMD_DEBUG_UART = 0xB0,
CONTROLBD_CMD_DEBUG_I2C = 0xB1,
CONTROLBD_CMD_DEBUG_STATUS = 0xC0,
CONTROLBD_CMD_BDINFO = 0xF0,
CONTROLBD_CMD_FIRM_SUM = 0xF2,
CONTROLBD_CMD_PROTOCOL = 0xF3,
CONTROLBD_CMD_UPDATE = 0xFE,
};
#pragma pack(pop)
HRESULT controlbd_hook_init(const struct controlbd_config *cfg); HRESULT controlbd_hook_init(const struct controlbd_config *cfg);

View File

@ -12,8 +12,8 @@
#include "carolhook/carol-dll.h" #include "carolhook/carol-dll.h"
#include "carolhook/jvs.h" #include "carolhook/jvs.h"
#include "carolhook/touch.h" #include "carolhook/touch.h"
#include "carolhook/ledbd.h"
#include "carolhook/controlbd.h" #include "carolhook/controlbd.h"
#include "carolhook/serial.h"
#include "hook/process.h" #include "hook/process.h"
@ -30,17 +30,39 @@ static struct carol_hook_config carol_hook_cfg;
/* /*
COM Layout COM Layout
01:(?) Touchscreen 01: Touchscreen
10: Aime reader 10: Aime reader
11: Control board 11: LED board
12(?): LED Board 12: Control Board
*/ */
static DWORD CALLBACK carol_pre_startup(void) static DWORD CALLBACK carol_pre_startup(void)
{ {
HRESULT hr; HRESULT hr;
HMODULE d3dc;
HMODULE dbghelp;
dprintf("--- Begin carol_pre_startup ---\n"); dprintf("--- Begin carol_pre_startup ---\n");
/* Pin the D3D shader compiler. This makes startup much faster. */
d3dc = LoadLibraryW(L"D3DCompiler_43.dll");
if (d3dc != NULL) {
dprintf("Pinned shader compiler, hMod=%p\n", d3dc);
} else {
dprintf("Failed to load shader compiler!\n");
}
/* Pin dbghelp so the path hooks apply to it. */
dbghelp = LoadLibraryW(L"dbghelp.dll");
if (dbghelp != NULL) {
dprintf("Pinned debug helper library, hMod=%p\n", dbghelp);
} else {
dprintf("Failed to load debug helper library!\n");
}
/* Config load */ /* Config load */
@ -81,9 +103,7 @@ static DWORD CALLBACK carol_pre_startup(void)
} }
gfx_hook_init(&carol_hook_cfg.gfx); gfx_hook_init(&carol_hook_cfg.gfx);
gfx_d3d9_hook_init(&carol_hook_cfg.gfx, carol_hook_mod); gfx_d3d9_hook_init(&carol_hook_cfg.gfx, carol_hook_mod);
//serial_init();
hr = touch_hook_init(&carol_hook_cfg.touch); hr = touch_hook_init(&carol_hook_cfg.touch);
@ -91,6 +111,12 @@ static DWORD CALLBACK carol_pre_startup(void)
goto fail; goto fail;
} }
hr = ledbd_hook_init(&carol_hook_cfg.ledbd);
if (FAILED(hr)) {
goto fail;
}
hr = controlbd_hook_init(&carol_hook_cfg.controlbd); hr = controlbd_hook_init(&carol_hook_cfg.controlbd);
if (FAILED(hr)) { if (FAILED(hr)) {

168
carolhook/ledbd.c Normal file
View File

@ -0,0 +1,168 @@
#include <windows.h>
#include <assert.h>
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#include "hook/iobuf.h"
#include "hook/iohook.h"
#include "carolhook/carol-dll.h"
#include "carolhook/ledbd.h"
#include "hooklib/uart.h"
#include "util/dprintf.h"
#include "util/dump.h"
#include "board/slider-frame.h"
#include "board/slider-cmd.h"
static HRESULT ledbd_handle_irp(struct irp *irp);
static HRESULT ledbd_handle_irp_locked(struct irp *irp);
static HRESULT ledbd_frame_dispatch(const union slider_req_any *dest);
static HRESULT ledbd_req_noop(uint8_t cmd);
static HRESULT ledbd_req_unk7c(uint8_t cmd);
static HRESULT ledbd_req_unkF0(uint8_t cmd);
static CRITICAL_SECTION ledbd_lock;
static struct uart ledbd_uart;
static uint8_t ledbd_written_bytes[520];
static uint8_t ledbd_readable_bytes[520];
HRESULT ledbd_hook_init(const struct ledbd_config *cfg)
{
if (!cfg->enable) {
return S_OK;
}
InitializeCriticalSection(&ledbd_lock);
uart_init(&ledbd_uart, 11);
ledbd_uart.written.bytes = ledbd_written_bytes;
ledbd_uart.written.nbytes = sizeof(ledbd_written_bytes);
ledbd_uart.readable.bytes = ledbd_readable_bytes;
ledbd_uart.readable.nbytes = sizeof(ledbd_readable_bytes);
dprintf("LED Board: Init\n");
return iohook_push_handler(ledbd_handle_irp);
}
static HRESULT ledbd_handle_irp(struct irp *irp)
{
HRESULT hr;
assert(irp != NULL);
if (!uart_match_irp(&ledbd_uart, irp)) {
return iohook_invoke_next(irp);
}
EnterCriticalSection(&ledbd_lock);
hr = ledbd_handle_irp_locked(irp);
LeaveCriticalSection(&ledbd_lock);
return hr;
}
static HRESULT ledbd_handle_irp_locked(struct irp *irp)
{
union slider_req_any req;
struct iobuf req_iobuf;
HRESULT hr;
assert(carol_dll.ledbd_init != NULL);
if (irp->op == IRP_OP_OPEN) {
dprintf("LED Board: Starting backend DLL\n");
hr = carol_dll.ledbd_init();
if (FAILED(hr)) {
dprintf("LED Board: Backend DLL error: 0X%X\n", (int) hr);
return hr;
}
}
hr = uart_handle_irp(&ledbd_uart, irp);
if (FAILED(hr) || irp->op != IRP_OP_WRITE) {
return hr;
}
for (;;) {
#if 0
dprintf("LED Board: TX Buffer:\n");
dump_iobuf(&ledbd_uart.written);
#endif
req_iobuf.bytes = req.bytes;
req_iobuf.nbytes = sizeof(req.bytes);
req_iobuf.pos = 0;
hr = slider_frame_decode(&req_iobuf, &ledbd_uart.written);
if (FAILED(hr)) {
dprintf("LED Board: Deframe Error: 0X%X\n", (int) hr);
return hr;
}
hr = ledbd_frame_dispatch(&req);
if (FAILED(hr)) {
dprintf("LED Board: Dispatch Error: 0X%X\n", (int) hr);
return hr;
}
return hr;
}
}
static HRESULT ledbd_frame_dispatch(const union slider_req_any *req)
{
switch (req->hdr.cmd) {
case LEDBD_CMD_UNK_10:
return ledbd_req_noop(req->hdr.cmd);
case LEDBD_CMD_UNK_7C:
return ledbd_req_unk7c(req->hdr.cmd);
case LEDBD_CMD_UNK_F0:
return ledbd_req_unkF0(req->hdr.cmd);
case LEDBD_CMD_UNK_30:
return ledbd_req_noop(req->hdr.cmd);
default:
//dprintf("Unhandled command 0x%02X\n", req->cmd);
return ledbd_req_noop(req->hdr.cmd);
}
}
static HRESULT ledbd_req_noop(uint8_t cmd)
{
//dprintf("LED Board: Noop cmd 0x%02X\n", cmd);
uint8_t resp[] = { 0xE0, 0x01, 0x11, 0x03, 0x01, 0x00, 0x01, 0x17 };
resp[5] = cmd;
resp[7] = 0x17 + cmd;
iobuf_write(&ledbd_uart.readable, resp, 8);
return S_OK;
}
static HRESULT ledbd_req_unk7c(uint8_t cmd)
{
//dprintf("LED Board: Cmd 0x7C\n");
uint8_t resp[] = { 0xE0, 0x01, 0x11, 0x04, 0x01, 0x7C, 0x01, 0x07, 0x9B };
iobuf_write(&ledbd_uart.readable, resp, 9);
return S_OK;
}
static HRESULT ledbd_req_unkF0(uint8_t cmd)
{
//dprintf("LED Board: Cmd 0xF0\n");
uint8_t resp[] = { 0xE0, 0x01, 0x11, 0x0A, 0x01, 0xF0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E };
iobuf_write(&ledbd_uart.readable, resp, 16);
return S_OK;
}

28
carolhook/ledbd.h Normal file
View File

@ -0,0 +1,28 @@
#pragma once
#include <windows.h>
#include <stdbool.h>
#include <stdint.h>
struct ledbd_config {
bool enable;
};
enum ledbd_cmd {
LEDBD_CMD_UNK_10 = 0x10,
LEDBD_CMD_UNK_7C = 0x7C,
LEDBD_CMD_UNK_30 = 0x30,
LEDBD_CMD_UNK_F0 = 0xF0,
};
struct ledbd_req {
uint8_t sync; // Sync byte, always 0xE0
uint8_t dest; // command destination id?
uint8_t src; // command source id?
uint8_t data_len; // length of the proceeding data bytes
uint8_t cmd; // might be the command byte?
uint8_t data[255]; // rest of the data, len = data_len - 1
uint8_t checksum; // final byte is all bytes (excluding sync) added
};
HRESULT ledbd_hook_init(const struct ledbd_config *cfg);

View File

@ -32,7 +32,7 @@ shared_library(
'touch.h', 'touch.h',
'controlbd.c', 'controlbd.c',
'controlbd.h', 'controlbd.h',
'serial.c', 'ledbd.c',
'serial.h', 'ledbd.h',
], ],
) )

View File

@ -1,39 +0,0 @@
#include <windows.h>
#include <winbase.h>
#include "hook/table.h"
#include "util/dprintf.h"
static BOOL WINAPI my_SetCommState(HANDLE hFile, LPDCB lpDCB);
static BOOL (WINAPI *next_SetCommState)(HANDLE hFile, LPDCB lpDCB);
static void com_hook_insert_hooks(HMODULE target);
static const struct hook_symbol win32_hooks[] = {
{
.name = "SetCommState",
.patch = my_SetCommState,
.link = (void **) &next_SetCommState
}
};
void serial_init()
{
com_hook_insert_hooks(NULL);
dprintf("Serial: Spy init\n");
}
static void com_hook_insert_hooks(HMODULE target)
{
hook_table_apply(
target,
"kernel32.dll",
win32_hooks,
_countof(win32_hooks));
}
static BOOL WINAPI my_SetCommState(HANDLE hFile, LPDCB lpDCB)
{
dprintf("Serial: my_SetCommState with baudrate %ld\n", lpDCB->BaudRate);
return next_SetCommState(hFile, lpDCB);
}

View File

@ -1,5 +0,0 @@
#pragma once
#include <windows.h>
#include <winbase.h>
void serial_init();

View File

@ -13,14 +13,36 @@
#include "util/dprintf.h" #include "util/dprintf.h"
#include "util/dump.h" #include "util/dump.h"
/**
* CMDS for M3 EX series
* CX -> Calibrate Extend, preform callibration
* MS -> Mode Stream, enters stream mode
* R -> Reset, resets the device
* RD -> Reset Default, Resets the device to factory
* Z -> Null, keepalive command
* NM -> Name, return the name of the device (not documented?)
* OI -> Output Identity, output unique device identity, SC followed by 4 characters
* UT -> Unit Type, returns controller unit type + status
*/
static HRESULT touch_handle_irp(struct irp *irp); static HRESULT touch_handle_irp(struct irp *irp);
static HRESULT touch_handle_irp_locked(struct irp *irp); static HRESULT touch_handle_irp_locked(struct irp *irp);
static HRESULT touch_frame_decode(struct touch_req *dest, struct iobuf *iobuf); static HRESULT touch_frame_decode(struct touch_req *dest, struct iobuf *iobuf);
static HRESULT handle_touch_ack_cmd(const struct touch_req *req);
static HRESULT handle_touch_name_cmd(const struct touch_req *req);
static HRESULT handle_touch_id_cmd(const struct touch_req *req);
static void touch_scan_auto(const bool is_pressed, const uint32_t mouse_x, const uint32_t mouse_y);
static CRITICAL_SECTION touch_lock; static CRITICAL_SECTION touch_lock;
static struct uart touch_uart; static struct uart touch_uart;
static uint8_t touch_written_bytes[520]; static uint8_t touch_written_bytes[528];
static uint8_t touch_readable_bytes[520]; static uint8_t touch_readable_bytes[528];
static bool should_stream = false;
static bool last_pressed;
static uint16_t last_x;
static uint16_t last_y;
HRESULT touch_hook_init(const struct touch_config *cfg) HRESULT touch_hook_init(const struct touch_config *cfg)
{ {
@ -71,7 +93,7 @@ static HRESULT touch_handle_irp_locked(struct irp *irp)
hr = carol_dll.touch_init(); hr = carol_dll.touch_init();
if (FAILED(hr)) { if (FAILED(hr)) {
dprintf("Touchscreen: Backend DLL error: %x\n", (int) hr); dprintf("Touchscreen: Backend DLL error: %X\n", (int) hr);
return hr; return hr;
} }
@ -84,35 +106,133 @@ static HRESULT touch_handle_irp_locked(struct irp *irp)
} }
for (;;) { for (;;) {
#if 1 #if 0
dprintf("Touchscreen: TX Buffer:\n"); dprintf("Touchscreen: TX Buffer:\n");
dump_iobuf(&touch_uart.written); dump_iobuf(&touch_uart.written);
#endif #endif
hr = touch_frame_decode(&req, &touch_uart.written); hr = touch_frame_decode(&req, &touch_uart.written);
if (FAILED(hr)) { if (FAILED(hr)) {
dprintf("Touchscreen: Deframe Error: %x\n", (int) hr); dprintf("Touchscreen: Deframe Error: %X\n", (int) hr);
return hr; return hr;
} }
if (!strcmp("Z", (char *)req.cmd)) {
hr = handle_touch_ack_cmd(&req);
}
else if (!strcmp("OI", (char *)req.cmd)) {
hr = handle_touch_id_cmd(&req);
//carol_dll.touch_start(touch_scan_auto);
}
else if (!strcmp("NM", (char *)req.cmd)) {
hr = handle_touch_name_cmd(&req);
}
else if (!strcmp("R", (char *)req.cmd)) {
carol_dll.touch_stop();
dprintf("Touch: Reset\n");
hr = handle_touch_ack_cmd(&req);
}
else {
dprintf("Touchscreen: Unhandled cmd %s\n", (char *)req.cmd);
hr = handle_touch_ack_cmd(&req);
}
return hr; return hr;
} }
} }
static HRESULT handle_touch_ack_cmd(const struct touch_req *req)
{
return iobuf_write(&touch_uart.readable, "\0010\015", 3);
}
static HRESULT handle_touch_name_cmd(const struct touch_req *req)
{
dprintf("Touch: Get Name\n");
return iobuf_write(&touch_uart.readable, "\001EX1234 EX1234\015", 15);
}
static HRESULT handle_touch_id_cmd(const struct touch_req *req)
{
dprintf("Touch: Get ID\n");
return iobuf_write(&touch_uart.readable, "\001EX1234\015", 8);
}
static void touch_scan_auto(const bool is_pressed, const uint32_t mouse_x, const uint32_t mouse_y)
{
struct touch_auto_resp resp;
uint16_t tmp_x;
uint16_t tmp_y;
bool flg = false;
memset(&resp, 0, sizeof(resp));
resp.rep_id = 0x17;
resp.touches[0].status = 0x04;
resp.count = 1;
if (is_pressed) {
resp.touches[0].status = 0x07;
resp.touches[0].touch_id = 1;
tmp_x = mouse_x & 0x7FFF;
tmp_y = mouse_y & 0x7FFF;
// flip
resp.touches[0].x = (tmp_x << 8) | (tmp_x >> 8);
resp.touches[0].y = (tmp_y << 8) | (tmp_y >> 8);
flg = resp.touches[0].x != last_x || resp.touches[0].y != last_y;
#if 1
if (flg)
dprintf("Touch: Mouse down! x %04X y: %04X\n", resp.touches[0].x, resp.touches[0].y);
#endif
last_x = resp.touches[0].x;
last_y = resp.touches[0].y;
} else if (last_pressed) {
resp.touches[0].x = last_x;
resp.touches[0].y = last_y;
}
last_pressed = is_pressed;
EnterCriticalSection(&touch_lock);
iobuf_write(&touch_uart.readable, &resp, sizeof(resp));
LeaveCriticalSection(&touch_lock);
#if 1
//if (flg) {
dprintf("Touch: RX Buffer: (pos %08x)\n", (uint32_t)touch_uart.readable.pos);
dump_iobuf(&touch_uart.readable);
//}
#endif
}
/* Decodes the response into a struct that's easier to work with. */ /* Decodes the response into a struct that's easier to work with. */
static HRESULT touch_frame_decode(struct touch_req *dest, struct iobuf *iobuf) static HRESULT touch_frame_decode(struct touch_req *dest, struct iobuf *iobuf)
{ {
dest->cmd = iobuf->bytes[0]; dest->sync = iobuf->bytes[0];
iobuf->pos--; memset(dest->cmd, 0, sizeof(dest->cmd));
dest->data_length = iobuf->pos; size_t data_len = 0;
if (dest->data_length > 0) { for (int i = 1; i < 255; i++) {
for (int i = 1; i < dest->data_length; i++) { if (iobuf->bytes[i] == 0x0D) { break; }
dest->data[i-1] = iobuf->bytes[i]; dest->cmd[i - 1] = iobuf->bytes[i];
} data_len++;
}
dest->tail = iobuf->bytes[data_len + 1];
dest->data_len = data_len;
iobuf->pos = 0;
if (dest->sync != 1 || dest->tail != 0x0D) {
dprintf("Touch: Data recieve error, sync: 0x%02X (expected 0x01) tail: 0x%02X (expected 0x0D)", dest->sync, dest->tail);
return E_FAIL;
} }
iobuf->pos -= dest->data_length;
return S_OK; return S_OK;
} }

View File

@ -4,14 +4,35 @@
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h> #include <stdint.h>
#pragma pack(push, 1)
struct touch_config { struct touch_config {
bool enable; bool enable;
}; };
// Always starts with 0x01, always ends with 0x0D
struct touch_req { struct touch_req {
uint8_t cmd; // First byte is the command byte uint8_t sync; // Always 0x01
uint8_t data[256]; // rest of the data goes here uint8_t cmd[256]; // rest of the data goes here
uint8_t data_length; // Size of the data including command byte uint8_t tail; // Always 0x0D
size_t data_len; // length of data
}; };
struct touch_report {
uint8_t status;
uint8_t touch_id;
uint16_t x;
uint16_t y;
};
struct touch_auto_resp {
uint8_t rep_id;
struct touch_report touches[10];
uint8_t count;
uint16_t scan_time;
//uint8_t padding[456];
};
#pragma pack(pop)
HRESULT touch_hook_init(const struct touch_config *cfg); HRESULT touch_hook_init(const struct touch_config *cfg);

View File

@ -8,9 +8,13 @@
#include "carolio/carolio.h" #include "carolio/carolio.h"
#include "carolio/config.h" #include "carolio/config.h"
static unsigned int __stdcall carol_io_touch_thread_proc(void *ctx);
static bool carol_io_coin; static bool carol_io_coin;
static uint16_t carol_io_coins; static uint16_t carol_io_coins;
static struct carol_io_config carol_io_cfg; static struct carol_io_config carol_io_cfg;
static bool carol_io_touch_stop_flag;
static HANDLE carol_io_touch_thread;
uint16_t carol_io_get_api_version(void) uint16_t carol_io_get_api_version(void)
{ {
@ -73,7 +77,63 @@ HRESULT carol_io_touch_init()
return S_OK; return S_OK;
} }
HRESULT carol_io_ledbd_init()
{
return S_OK;
}
HRESULT carol_io_controlbd_init() HRESULT carol_io_controlbd_init()
{ {
return S_OK; return S_OK;
}
void carol_io_touch_start(carol_io_touch_callback_t callback)
{
if (carol_io_touch_thread != NULL) {
return;
}
carol_io_touch_stop_flag = false;
carol_io_touch_thread = (HANDLE) _beginthreadex(
NULL,
0,
carol_io_touch_thread_proc,
callback,
0,
NULL
);
}
void carol_io_touch_stop()
{
carol_io_touch_stop_flag = true;
}
static unsigned int __stdcall carol_io_touch_thread_proc(void *ctx)
{
carol_io_touch_callback_t callback;
bool mouse_is_down = false;
uint32_t mX = 0;
uint32_t mY = 0;
POINT lpPoint;
callback = ctx;
while (!carol_io_touch_stop_flag) {
if (GetAsyncKeyState(VK_LBUTTON) & 0x8000) {
mouse_is_down = true;
if (GetCursorPos(&lpPoint)) {
mX = lpPoint.x;
mY = lpPoint.y;
}
} else {
mouse_is_down = false;
}
callback(mouse_is_down, mX, mY);
Sleep(1);
}
return 0;
} }

View File

@ -5,6 +5,8 @@
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h> #include <stdint.h>
typedef void (*carol_io_touch_callback_t)(const bool is_pressed, const uint32_t mouse_x, const uint32_t mouse_y);
/* Get the version of the Project carol IO API that this DLL supports. This /* Get the version of the Project carol IO API that this DLL supports. This
function should return a positive 16-bit integer, where the high byte is function should return a positive 16-bit integer, where the high byte is
the major version and the low byte is the minor version (as defined by the the major version and the low byte is the minor version (as defined by the
@ -49,4 +51,10 @@ void carol_io_jvs_read_coin_counter(uint16_t *out);
HRESULT carol_io_touch_init(); HRESULT carol_io_touch_init();
HRESULT carol_io_controlbd_init(); HRESULT carol_io_ledbd_init();
HRESULT carol_io_controlbd_init();
void carol_io_touch_start(carol_io_touch_callback_t callback);
void carol_io_touch_stop();

View File

@ -2,7 +2,6 @@
setlocal enabledelayedexpansion setlocal enabledelayedexpansion
:: Static Environment Variables :: Static Environment Variables
set BUILD_OUTPUT_PATH=build\docker
set IMAGE_NAME=djhackers/segatools-build:latest set IMAGE_NAME=djhackers/segatools-build:latest
set CONTAINER_NAME=segatools-build set CONTAINER_NAME=segatools-build

View File

@ -97,6 +97,10 @@ static BOOL WINAPI hook_RemoveDirectoryA(const char *lpFileName);
static BOOL WINAPI hook_RemoveDirectoryW(const wchar_t *lpFileName); static BOOL WINAPI hook_RemoveDirectoryW(const wchar_t *lpFileName);
static BOOL WINAPI hook_PathFileExistsA(LPCSTR pszPath);
static BOOL WINAPI hook_PathFileExistsW(LPCWSTR pszPath);
/* Link pointers */ /* Link pointers */
static BOOL (WINAPI *next_CreateDirectoryA)( static BOOL (WINAPI *next_CreateDirectoryA)(
@ -177,6 +181,10 @@ static BOOL (WINAPI *next_RemoveDirectoryA)(const char *lpFileName);
static BOOL (WINAPI *next_RemoveDirectoryW)(const wchar_t *lpFileName); static BOOL (WINAPI *next_RemoveDirectoryW)(const wchar_t *lpFileName);
static BOOL (WINAPI *next_PathFileExistsA)(LPCSTR pszPath);
static BOOL (WINAPI *next_PathFileExistsW)(LPCWSTR pszPath);
/* Hook table */ /* Hook table */
static const struct hook_symbol path_hook_syms[] = { static const struct hook_symbol path_hook_syms[] = {
@ -244,6 +252,14 @@ static const struct hook_symbol path_hook_syms[] = {
.name = "RemoveDirectoryW", .name = "RemoveDirectoryW",
.patch = hook_RemoveDirectoryW, .patch = hook_RemoveDirectoryW,
.link = (void **) &next_RemoveDirectoryW, .link = (void **) &next_RemoveDirectoryW,
}, {
.name = "PathFileExistsA",
.patch = hook_PathFileExistsA,
.link = (void **) &next_PathFileExistsA,
}, {
.name = "PathFileExistsW",
.patch = hook_PathFileExistsW,
.link = (void **) &next_PathFileExistsW,
} }
}; };
@ -854,3 +870,39 @@ static BOOL WINAPI hook_RemoveDirectoryW(const wchar_t *lpFileName)
return ok; return ok;
} }
static BOOL WINAPI hook_PathFileExistsA(LPCSTR pszPath)
{
char *trans;
BOOL ok;
ok = path_transform_a(&trans, pszPath);
if (!ok) {
return FALSE;
}
ok = next_PathFileExistsA(trans ? trans : pszPath);
free(trans);
return ok;
}
static BOOL WINAPI hook_PathFileExistsW(LPCWSTR pszPath)
{
wchar_t *trans;
BOOL ok;
ok = path_transform_w(&trans, pszPath);
if (!ok) {
return FALSE;
}
ok = next_PathFileExistsW(trans ? trans : pszPath);
free(trans);
return ok;
}

View File

@ -13,6 +13,7 @@ add_project_arguments(
'-DWIN32_LEAN_AND_MEAN', '-DWIN32_LEAN_AND_MEAN',
'-D_WIN32_WINNT=_WIN32_WINNT_WIN7', '-D_WIN32_WINNT=_WIN32_WINNT_WIN7',
'-DMINGW_HAS_SECURE_API=1', '-DMINGW_HAS_SECURE_API=1',
'-Wno-unused',
language: 'c', language: 'c',
) )

View File

@ -273,6 +273,8 @@ static HRESULT vfs_path_hook(const wchar_t *src, wchar_t *dest, size_t *count)
} }
switch (src[0]) { switch (src[0]) {
case L'D': // later AMDaemon versions default to D: for AMFS if it can't find it
case L'd':
case L'e': case L'e':
case L'E': case L'E':
redir = vfs_config.amfs; redir = vfs_config.amfs;
@ -404,7 +406,7 @@ static HRESULT vfs_path_hook_option(
static HRESULT vfs_reg_read_amfs(void *bytes, uint32_t *nbytes) static HRESULT vfs_reg_read_amfs(void *bytes, uint32_t *nbytes)
{ {
return reg_hook_read_wstr(bytes, nbytes, vfs_config.amfs); return reg_hook_read_wstr(bytes, nbytes, vfs_config.amfs); // seems to be busted?
} }
static HRESULT vfs_reg_read_appdata(void *bytes, uint32_t *nbytes) static HRESULT vfs_reg_read_appdata(void *bytes, uint32_t *nbytes)