forked from Hay1tsme/segatools
Compare commits
9 Commits
05e762d3ce
...
4c67843f08
Author | SHA1 | Date |
---|---|---|
Hay1tsme | 4c67843f08 | |
Hay1tsme | 02201dfba5 | |
Hay1tsme | 9113766c22 | |
Hay1tsme | 6fc2482c19 | |
Hay1tsme | 74c8b312c5 | |
Hay1tsme | ef00932c64 | |
Hay1tsme | 8c97dc09c0 | |
Hay1tsme | 301a0e0ce7 | |
Hay1tsme | 5935e322e8 |
15
Makefile
15
Makefile
|
@ -1,5 +1,3 @@
|
|||
SHELL = /bin/bash
|
||||
|
||||
V ?= @
|
||||
|
||||
.DEFAULT_GOAL := help
|
||||
|
@ -7,16 +5,12 @@ V ?= @
|
|||
BUILD_DIR := build
|
||||
BUILD_DIR_32 := $(BUILD_DIR)/build32
|
||||
BUILD_DIR_64 := $(BUILD_DIR)/build64
|
||||
BUILD_DIR_DOCKER := $(BUILD_DIR)/docker
|
||||
BUILD_DIR_ZIP := $(BUILD_DIR)/zip
|
||||
|
||||
DOC_DIR := doc
|
||||
|
||||
DIST_DIR := dist
|
||||
|
||||
DOCKER_CONTAINER_NAME := "segatools-build"
|
||||
DOCKER_IMAGE_NAME := "segatools:build"
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Targets
|
||||
# -----------------------------------------------------------------------------
|
||||
|
@ -44,15 +38,6 @@ zip: $(BUILD_DIR_ZIP)/segatools.zip
|
|||
clean:
|
||||
$(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
|
||||
# -----------------------------------------------------------------------------
|
||||
|
|
|
@ -21,9 +21,18 @@ const struct dll_bind_sym carol_dll_syms[] = {
|
|||
}, {
|
||||
.sym = "carol_io_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",
|
||||
.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),
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -10,7 +10,10 @@ struct carol_dll {
|
|||
void (*jvs_poll)(uint8_t *opbtn, uint8_t *beams);
|
||||
void (*jvs_read_coin_counter)(uint16_t *total);
|
||||
HRESULT (*touch_init)();
|
||||
HRESULT (*ledbd_init)();
|
||||
HRESULT (*controlbd_init)();
|
||||
void (*touch_start)(carol_io_touch_callback_t callback);
|
||||
void (*touch_stop)();
|
||||
};
|
||||
|
||||
struct carol_dll_config {
|
||||
|
|
|
@ -16,4 +16,7 @@ EXPORTS
|
|||
carol_io_jvs_poll
|
||||
carol_io_jvs_read_coin_counter
|
||||
carol_io_touch_init
|
||||
carol_io_ledbd_init
|
||||
carol_io_controlbd_init
|
||||
carol_io_touch_start
|
||||
carol_io_touch_stop
|
||||
|
|
|
@ -58,6 +58,20 @@ void controlbd_config_load(
|
|||
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(
|
||||
struct carol_hook_config *cfg,
|
||||
|
@ -73,4 +87,5 @@ void carol_hook_config_load(
|
|||
gfx_config_load(&cfg->gfx, filename);
|
||||
touch_config_load(&cfg->touch, filename);
|
||||
controlbd_config_load(&cfg->controlbd, filename);
|
||||
ledbd_config_load(&cfg->ledbd, filename);
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include "gfxhook/gfx.h"
|
||||
|
||||
#include "carolhook/touch.h"
|
||||
#include "carolhook/ledbd.h"
|
||||
#include "carolhook/controlbd.h"
|
||||
|
||||
struct carol_hook_config {
|
||||
|
@ -22,6 +23,7 @@ struct carol_hook_config {
|
|||
struct carol_dll_config dll;
|
||||
struct gfx_config gfx;
|
||||
struct touch_config touch;
|
||||
struct ledbd_config ledbd;
|
||||
struct controlbd_config controlbd;
|
||||
};
|
||||
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
#include "hook/iobuf.h"
|
||||
#include "hook/iohook.h"
|
||||
|
||||
#include "hook/table.h"
|
||||
|
||||
#include "carolhook/carol-dll.h"
|
||||
#include "carolhook/controlbd.h"
|
||||
|
||||
|
@ -18,16 +20,57 @@
|
|||
|
||||
static HRESULT controlbd_handle_irp(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_dispatch(struct controlbd_req *dest);
|
||||
static HRESULT controlbd_frame_decode(struct controlbd_req_any *dest, struct iobuf *src);
|
||||
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 struct uart controlbd_uart;
|
||||
static uint8_t controlbd_written_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)
|
||||
{
|
||||
if (!cfg->enable) {
|
||||
|
@ -36,12 +79,18 @@ HRESULT controlbd_hook_init(const struct controlbd_config *cfg)
|
|||
|
||||
InitializeCriticalSection(&controlbd_lock);
|
||||
|
||||
uart_init(&controlbd_uart, 11);
|
||||
uart_init(&controlbd_uart, 12);
|
||||
controlbd_uart.written.bytes = controlbd_written_bytes;
|
||||
controlbd_uart.written.nbytes = sizeof(controlbd_written_bytes);
|
||||
controlbd_uart.readable.bytes = 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");
|
||||
|
||||
return iohook_push_handler(controlbd_handle_irp);
|
||||
|
@ -64,10 +113,49 @@ static HRESULT controlbd_handle_irp(struct irp *irp)
|
|||
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)
|
||||
{
|
||||
struct controlbd_req req;
|
||||
HRESULT hr;
|
||||
struct controlbd_req_any req;
|
||||
|
||||
assert(carol_dll.controlbd_init != NULL);
|
||||
|
||||
|
@ -76,7 +164,7 @@ static HRESULT controlbd_handle_irp_locked(struct irp *irp)
|
|||
hr = carol_dll.controlbd_init();
|
||||
|
||||
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;
|
||||
}
|
||||
|
@ -89,90 +177,251 @@ static HRESULT controlbd_handle_irp_locked(struct irp *irp)
|
|||
}
|
||||
|
||||
for (;;) {
|
||||
if (controlbd_uart.written.bytes[0] == 0xE0) {
|
||||
#if 0
|
||||
dprintf("Control Board: TX Buffer:\n");
|
||||
dump_iobuf(&controlbd_uart.written);
|
||||
dprintf("Control Board: TX Buffer:\n");
|
||||
dump_iobuf(&controlbd_uart.written);
|
||||
#endif
|
||||
hr = controlbd_frame_decode(&req, &controlbd_uart.written);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
dprintf("Control Board: Deframe Error: %x\n", (int) hr);
|
||||
hr = controlbd_frame_decode(&req, &controlbd_uart.written);
|
||||
if (FAILED(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;
|
||||
}
|
||||
|
||||
hr = controlbd_frame_dispatch(&req);
|
||||
if (FAILED(hr)) {
|
||||
dprintf("Control Board: Dispatch Error: %x\n", (int) hr);
|
||||
// The board has a LPC111x bootloader that gets ran over every boot
|
||||
// this is to account for that.
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
static HRESULT controlbd_frame_dispatch(struct controlbd_req *req)
|
||||
static HRESULT controlbd_req_dispatch(const struct controlbd_req_any *req)
|
||||
{
|
||||
switch (req->cmd) {
|
||||
case CONTROLBD_CMD_UNK_11:
|
||||
return controlbd_req_nop(req->cmd);
|
||||
switch (req->hdr.cmd) {
|
||||
case CONTROLBD_CMD_RESET:
|
||||
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:
|
||||
dprintf("Unhandled command %#02x\n", req->cmd);
|
||||
|
||||
return S_OK;
|
||||
dprintf("Unhandled command 0x%02x\n", req->hdr.cmd);
|
||||
return controlbd_req_ack_any(req->hdr.cmd);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
controlbd_uart.readable.bytes[controlbd_uart.readable.pos++] = 0xE0;
|
||||
controlbd_uart.readable.bytes[controlbd_uart.readable.pos++] = 0x01;
|
||||
controlbd_uart.readable.bytes[controlbd_uart.readable.pos++] = 0x11;
|
||||
controlbd_uart.readable.bytes[controlbd_uart.readable.pos++] = 0x03;
|
||||
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;
|
||||
|
||||
resp->sync = CONTROLBD_SYNC_BYTE;
|
||||
resp->dest = 0x01;
|
||||
resp->src = 0x02;
|
||||
resp->len = len;
|
||||
resp->report = 0x01;
|
||||
resp->cmd = cmd;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
/* Decodes the response into a struct that's easier to work with. */
|
||||
static HRESULT controlbd_frame_decode(struct controlbd_req *dest, struct iobuf *iobuf)
|
||||
static uint8_t calc_checksum(void *data, size_t len)
|
||||
{
|
||||
int initial_pos = iobuf->pos;
|
||||
uint8_t check = 0;
|
||||
uint8_t *stuff;
|
||||
stuff = data;
|
||||
uint8_t checksum = 0;
|
||||
uint16_t tmp = 0;
|
||||
|
||||
dest->sync = iobuf->bytes[0];
|
||||
iobuf->pos--;
|
||||
|
||||
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;
|
||||
for (int i = 1; i < len; i++) {
|
||||
tmp = checksum + stuff[i];
|
||||
checksum = tmp & 0xFF;
|
||||
}
|
||||
|
||||
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
|
||||
);
|
||||
}
|
|
@ -1,5 +1,7 @@
|
|||
#pragma once
|
||||
#include <windows.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
@ -7,15 +9,140 @@
|
|||
struct controlbd_config {
|
||||
bool enable;
|
||||
};
|
||||
enum controlbd_cmd {
|
||||
CONTROLBD_CMD_UNK_11 = 0x11
|
||||
};
|
||||
struct controlbd_req {
|
||||
uint8_t sync; // First byte is the sync
|
||||
uint8_t cmd; // Command byte
|
||||
uint8_t data[256]; // Request body goes here
|
||||
uint8_t checksum; // Final byte is all bytes added, except the sync
|
||||
uint8_t data_length; // Size of the data including command byte
|
||||
|
||||
#pragma pack(push, 1)
|
||||
struct controlbd_req_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 cmd;
|
||||
};
|
||||
|
||||
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);
|
|
@ -12,8 +12,8 @@
|
|||
#include "carolhook/carol-dll.h"
|
||||
#include "carolhook/jvs.h"
|
||||
#include "carolhook/touch.h"
|
||||
#include "carolhook/ledbd.h"
|
||||
#include "carolhook/controlbd.h"
|
||||
#include "carolhook/serial.h"
|
||||
|
||||
#include "hook/process.h"
|
||||
|
||||
|
@ -30,17 +30,39 @@ static struct carol_hook_config carol_hook_cfg;
|
|||
|
||||
/*
|
||||
COM Layout
|
||||
01:(?) Touchscreen
|
||||
01: Touchscreen
|
||||
10: Aime reader
|
||||
11: Control board
|
||||
12(?): LED Board
|
||||
11: LED board
|
||||
12: Control Board
|
||||
*/
|
||||
|
||||
static DWORD CALLBACK carol_pre_startup(void)
|
||||
{
|
||||
HRESULT hr;
|
||||
HMODULE d3dc;
|
||||
HMODULE dbghelp;
|
||||
|
||||
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 */
|
||||
|
||||
|
@ -81,9 +103,7 @@ static DWORD CALLBACK carol_pre_startup(void)
|
|||
}
|
||||
|
||||
gfx_hook_init(&carol_hook_cfg.gfx);
|
||||
gfx_d3d9_hook_init(&carol_hook_cfg.gfx, carol_hook_mod);
|
||||
//serial_init();
|
||||
|
||||
gfx_d3d9_hook_init(&carol_hook_cfg.gfx, carol_hook_mod);
|
||||
|
||||
hr = touch_hook_init(&carol_hook_cfg.touch);
|
||||
|
||||
|
@ -91,6 +111,12 @@ static DWORD CALLBACK carol_pre_startup(void)
|
|||
goto fail;
|
||||
}
|
||||
|
||||
hr = ledbd_hook_init(&carol_hook_cfg.ledbd);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
hr = controlbd_hook_init(&carol_hook_cfg.controlbd);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
|
@ -32,7 +32,7 @@ shared_library(
|
|||
'touch.h',
|
||||
'controlbd.c',
|
||||
'controlbd.h',
|
||||
'serial.c',
|
||||
'serial.h',
|
||||
'ledbd.c',
|
||||
'ledbd.h',
|
||||
],
|
||||
)
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -1,5 +0,0 @@
|
|||
#pragma once
|
||||
#include <windows.h>
|
||||
#include <winbase.h>
|
||||
|
||||
void serial_init();
|
|
@ -13,14 +13,36 @@
|
|||
#include "util/dprintf.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_locked(struct irp *irp);
|
||||
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 struct uart touch_uart;
|
||||
static uint8_t touch_written_bytes[520];
|
||||
static uint8_t touch_readable_bytes[520];
|
||||
static uint8_t touch_written_bytes[528];
|
||||
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)
|
||||
{
|
||||
|
@ -71,7 +93,7 @@ static HRESULT touch_handle_irp_locked(struct irp *irp)
|
|||
hr = carol_dll.touch_init();
|
||||
|
||||
if (FAILED(hr)) {
|
||||
dprintf("Touchscreen: Backend DLL error: %x\n", (int) hr);
|
||||
dprintf("Touchscreen: Backend DLL error: %X\n", (int) hr);
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
@ -84,35 +106,133 @@ static HRESULT touch_handle_irp_locked(struct irp *irp)
|
|||
}
|
||||
|
||||
for (;;) {
|
||||
#if 1
|
||||
#if 0
|
||||
dprintf("Touchscreen: TX Buffer:\n");
|
||||
dump_iobuf(&touch_uart.written);
|
||||
#endif
|
||||
hr = touch_frame_decode(&req, &touch_uart.written);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
dprintf("Touchscreen: Deframe Error: %x\n", (int) hr);
|
||||
dprintf("Touchscreen: Deframe Error: %X\n", (int) 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;
|
||||
}
|
||||
}
|
||||
|
||||
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. */
|
||||
static HRESULT touch_frame_decode(struct touch_req *dest, struct iobuf *iobuf)
|
||||
{
|
||||
dest->cmd = iobuf->bytes[0];
|
||||
iobuf->pos--;
|
||||
dest->data_length = iobuf->pos;
|
||||
dest->sync = iobuf->bytes[0];
|
||||
memset(dest->cmd, 0, sizeof(dest->cmd));
|
||||
size_t data_len = 0;
|
||||
|
||||
if (dest->data_length > 0) {
|
||||
for (int i = 1; i < dest->data_length; i++) {
|
||||
dest->data[i-1] = iobuf->bytes[i];
|
||||
}
|
||||
for (int i = 1; i < 255; i++) {
|
||||
if (iobuf->bytes[i] == 0x0D) { break; }
|
||||
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;
|
||||
}
|
|
@ -4,14 +4,35 @@
|
|||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#pragma pack(push, 1)
|
||||
|
||||
struct touch_config {
|
||||
bool enable;
|
||||
};
|
||||
|
||||
// Always starts with 0x01, always ends with 0x0D
|
||||
struct touch_req {
|
||||
uint8_t cmd; // First byte is the command byte
|
||||
uint8_t data[256]; // rest of the data goes here
|
||||
uint8_t data_length; // Size of the data including command byte
|
||||
uint8_t sync; // Always 0x01
|
||||
uint8_t cmd[256]; // rest of the data goes here
|
||||
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);
|
|
@ -8,9 +8,13 @@
|
|||
#include "carolio/carolio.h"
|
||||
#include "carolio/config.h"
|
||||
|
||||
static unsigned int __stdcall carol_io_touch_thread_proc(void *ctx);
|
||||
|
||||
static bool carol_io_coin;
|
||||
static uint16_t carol_io_coins;
|
||||
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)
|
||||
{
|
||||
|
@ -73,7 +77,63 @@ HRESULT carol_io_touch_init()
|
|||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT carol_io_ledbd_init()
|
||||
{
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT carol_io_controlbd_init()
|
||||
{
|
||||
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;
|
||||
}
|
|
@ -5,6 +5,8 @@
|
|||
#include <stdbool.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
|
||||
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
|
||||
|
@ -49,4 +51,10 @@ void carol_io_jvs_read_coin_counter(uint16_t *out);
|
|||
|
||||
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();
|
|
@ -2,7 +2,6 @@
|
|||
setlocal enabledelayedexpansion
|
||||
|
||||
:: Static Environment Variables
|
||||
set BUILD_OUTPUT_PATH=build\docker
|
||||
set IMAGE_NAME=djhackers/segatools-build:latest
|
||||
set CONTAINER_NAME=segatools-build
|
||||
|
||||
|
|
|
@ -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_PathFileExistsA(LPCSTR pszPath);
|
||||
|
||||
static BOOL WINAPI hook_PathFileExistsW(LPCWSTR pszPath);
|
||||
|
||||
/* Link pointers */
|
||||
|
||||
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_PathFileExistsA)(LPCSTR pszPath);
|
||||
|
||||
static BOOL (WINAPI *next_PathFileExistsW)(LPCWSTR pszPath);
|
||||
|
||||
/* Hook table */
|
||||
|
||||
static const struct hook_symbol path_hook_syms[] = {
|
||||
|
@ -244,6 +252,14 @@ static const struct hook_symbol path_hook_syms[] = {
|
|||
.name = "RemoveDirectoryW",
|
||||
.patch = hook_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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@ add_project_arguments(
|
|||
'-DWIN32_LEAN_AND_MEAN',
|
||||
'-D_WIN32_WINNT=_WIN32_WINNT_WIN7',
|
||||
'-DMINGW_HAS_SECURE_API=1',
|
||||
'-Wno-unused',
|
||||
language: 'c',
|
||||
)
|
||||
|
||||
|
|
|
@ -273,6 +273,8 @@ static HRESULT vfs_path_hook(const wchar_t *src, wchar_t *dest, size_t *count)
|
|||
}
|
||||
|
||||
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':
|
||||
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)
|
||||
{
|
||||
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)
|
||||
|
|
Loading…
Reference in New Issue