From 6fc2482c19f7c921fb0b550f4719c0b81053f66b Mon Sep 17 00:00:00 2001 From: Kevin Trocolli Date: Fri, 28 Apr 2023 04:25:47 -0400 Subject: [PATCH 1/4] carol: add control board emulation, document touch board more --- carolhook/controlbd.c | 341 ++++++++++++++++++++++++++++++++++++++++-- carolhook/controlbd.h | 137 +++++++++++++++++ carolhook/dllmain.c | 25 +++- carolhook/ledbd.c | 99 +++--------- carolhook/meson.build | 2 - carolhook/serial.c | 39 ----- carolhook/serial.h | 5 - carolhook/touch.c | 82 ++++++++-- carolhook/touch.h | 8 +- 9 files changed, 587 insertions(+), 151 deletions(-) delete mode 100644 carolhook/serial.c delete mode 100644 carolhook/serial.h diff --git a/carolhook/controlbd.c b/carolhook/controlbd.c index c39eb83..a59fe65 100644 --- a/carolhook/controlbd.c +++ b/carolhook/controlbd.c @@ -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_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_noop(uint8_t cmd); -static HRESULT controlbd_req_unk7c(uint8_t cmd); -static HRESULT controlbd_req_unkF0(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) { @@ -42,12 +85,17 @@ HRESULT controlbd_hook_init(const struct controlbd_config *cfg) 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); } - static HRESULT controlbd_handle_irp(struct irp *irp) { HRESULT hr; @@ -65,9 +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) { HRESULT hr; + struct controlbd_req_any req; assert(carol_dll.controlbd_init != NULL); @@ -89,24 +177,251 @@ static HRESULT controlbd_handle_irp_locked(struct irp *irp) } for (;;) { -#if 1 - dprintf("Control Board: TX Buffer:\n"); - dump_iobuf(&controlbd_uart.written); + if (controlbd_uart.written.bytes[0] == 0xE0) { +#if 0 + 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); + return hr; + } - if (FAILED(hr)) { - dprintf("Control Board: Deframe Error: 0X%X\n", (int) 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; } - if (FAILED(hr)) { - dprintf("Control Board: Dispatch Error: 0X%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_req_dispatch(const struct controlbd_req_any *req) +{ + 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 0x%02x\n", req->hdr.cmd); + return controlbd_req_ack_any(req->hdr.cmd); + } +} + +static HRESULT controlbd_set_header(struct controlbd_resp_hdr *resp, uint8_t cmd, uint8_t len) +{ + resp->sync = CONTROLBD_SYNC_BYTE; + resp->dest = 0x01; + resp->src = 0x02; + resp->len = len; + resp->report = 0x01; + resp->cmd = cmd; + return S_OK; +} + +static uint8_t calc_checksum(void *data, size_t len) +{ + uint8_t *stuff; + stuff = data; + uint8_t checksum = 0; + uint16_t tmp = 0; + + for (int i = 1; i < len; i++) { + tmp = checksum + stuff[i]; + checksum = tmp & 0xFF; + } + + 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 + ); } \ No newline at end of file diff --git a/carolhook/controlbd.h b/carolhook/controlbd.h index 15f04ac..5f160d3 100644 --- a/carolhook/controlbd.h +++ b/carolhook/controlbd.h @@ -1,5 +1,7 @@ #pragma once #include +#include +#include #include #include @@ -8,4 +10,139 @@ struct controlbd_config { bool enable; }; +#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); \ No newline at end of file diff --git a/carolhook/dllmain.c b/carolhook/dllmain.c index 608ca49..55608c7 100644 --- a/carolhook/dllmain.c +++ b/carolhook/dllmain.c @@ -13,7 +13,6 @@ #include "carolhook/jvs.h" #include "carolhook/touch.h" #include "carolhook/ledbd.h" -#include "carolhook/serial.h" #include "carolhook/controlbd.h" #include "hook/process.h" @@ -34,14 +33,36 @@ COM Layout 01: Touchscreen 10: Aime reader 11: LED board -12: 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 */ diff --git a/carolhook/ledbd.c b/carolhook/ledbd.c index 18b9aab..1513359 100644 --- a/carolhook/ledbd.c +++ b/carolhook/ledbd.c @@ -16,10 +16,12 @@ #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_decode(struct ledbd_req *dest, struct iobuf *iobuf); -static HRESULT ledbd_frame_dispatch(struct ledbd_req *dest); +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); @@ -68,7 +70,8 @@ static HRESULT ledbd_handle_irp(struct irp *irp) static HRESULT ledbd_handle_irp_locked(struct irp *irp) { - struct ledbd_req req; + union slider_req_any req; + struct iobuf req_iobuf; HRESULT hr; assert(carol_dll.ledbd_init != NULL); @@ -95,7 +98,11 @@ static HRESULT ledbd_handle_irp_locked(struct irp *irp) dprintf("LED Board: TX Buffer:\n"); dump_iobuf(&ledbd_uart.written); #endif - hr = ledbd_frame_decode(&req, &ledbd_uart.written); + 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); @@ -114,26 +121,26 @@ static HRESULT ledbd_handle_irp_locked(struct irp *irp) } } -static HRESULT ledbd_frame_dispatch(struct ledbd_req *req) +static HRESULT ledbd_frame_dispatch(const union slider_req_any *req) { - switch (req->cmd) { + switch (req->hdr.cmd) { case LEDBD_CMD_UNK_10: - return ledbd_req_noop(req->cmd); + return ledbd_req_noop(req->hdr.cmd); case LEDBD_CMD_UNK_7C: - return ledbd_req_unk7c(req->cmd); + return ledbd_req_unk7c(req->hdr.cmd); case LEDBD_CMD_UNK_F0: - return ledbd_req_unkF0(req->cmd); + return ledbd_req_unkF0(req->hdr.cmd); case LEDBD_CMD_UNK_30: - return ledbd_req_noop(req->cmd); + return ledbd_req_noop(req->hdr.cmd); default: - dprintf("Unhandled command 0x%02X\n", req->cmd); - return ledbd_req_noop(req->cmd); + //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); + //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; @@ -144,7 +151,7 @@ static HRESULT ledbd_req_noop(uint8_t cmd) static HRESULT ledbd_req_unk7c(uint8_t cmd) { - dprintf("LED Board: Cmd 0x7C\n"); + //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); @@ -153,71 +160,9 @@ static HRESULT ledbd_req_unk7c(uint8_t cmd) static HRESULT ledbd_req_unkF0(uint8_t cmd) { - dprintf("LED Board: Cmd 0xF0\n"); + //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; -} - -/* Decodes the response into a struct that's easier to work with. TODO: Further validation */ -static HRESULT ledbd_frame_decode(struct ledbd_req *dest, struct iobuf *iobuf) -{ - int initial_pos = iobuf->pos; - int processed_pos = 0; - uint8_t check = 0; - bool escape = false; - - dest->sync = iobuf->bytes[0]; - - dest->dest = iobuf->bytes[1]; - check += dest->dest; - - dest->src = iobuf->bytes[2]; - check += dest->src; - - dest->data_len = iobuf->bytes[3]; - check += dest->data_len; - - dest->cmd = iobuf->bytes[4]; - check += dest->cmd; - - for (int i = 0; i < dest->data_len - 1; i++) { - if (iobuf->bytes[i+5] == 0xD0) { - escape = true; - check += 0xD0; - continue; - } - - dest->data[i] = iobuf->bytes[i+5]; - - if (escape) { - dest->data[i]++; - escape = false; - } - - check += iobuf->bytes[i+5]; - } - - dest->checksum = iobuf->bytes[iobuf->pos - 1]; - if (escape) { - dest->checksum++; - escape = false; - } - - iobuf->pos = 0; - - if (dest->sync != 0xe0) { - dprintf("LED Board: Sync error, expected 0xe0, got 0X%02X\n", dest->sync); - dump_iobuf(iobuf); - return E_FAIL; - } - - if (dest->checksum != (check & 0xFF)) { - dprintf("LED Board: Checksum error, expected 0X%02X, got 0X%02X\n", dest->checksum, check); - dump_iobuf(iobuf); - return E_FAIL; - } - return S_OK; } \ No newline at end of file diff --git a/carolhook/meson.build b/carolhook/meson.build index d62c897..cba763c 100644 --- a/carolhook/meson.build +++ b/carolhook/meson.build @@ -34,7 +34,5 @@ shared_library( 'controlbd.h', 'ledbd.c', 'ledbd.h', - 'serial.c', - 'serial.h', ], ) diff --git a/carolhook/serial.c b/carolhook/serial.c deleted file mode 100644 index 3a50907..0000000 --- a/carolhook/serial.c +++ /dev/null @@ -1,39 +0,0 @@ -#include -#include - -#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); -} \ No newline at end of file diff --git a/carolhook/serial.h b/carolhook/serial.h deleted file mode 100644 index 8a682ac..0000000 --- a/carolhook/serial.h +++ /dev/null @@ -1,5 +0,0 @@ -#pragma once -#include -#include - -void serial_init(); \ No newline at end of file diff --git a/carolhook/touch.c b/carolhook/touch.c index 9a5ab03..c062e90 100644 --- a/carolhook/touch.c +++ b/carolhook/touch.c @@ -13,14 +13,31 @@ #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 CRITICAL_SECTION touch_lock; static struct uart touch_uart; static uint8_t touch_written_bytes[520]; static uint8_t touch_readable_bytes[520]; +static bool should_stream = false; HRESULT touch_hook_init(const struct touch_config *cfg) { @@ -84,7 +101,7 @@ 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 @@ -96,24 +113,69 @@ static HRESULT touch_handle_irp_locked(struct irp *irp) return hr; } - touch_uart.written.pos = 0; + 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); + should_stream = true; // possibly send stuff after we get this? + } + else if (!strcmp("NM", (char *)req.cmd)) { + hr = handle_touch_name_cmd(&req); + } + else if (!strcmp("R", (char *)req.cmd)) { + should_stream = false; + 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); +} + /* 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; } \ No newline at end of file diff --git a/carolhook/touch.h b/carolhook/touch.h index 6881b8f..2ae3031 100644 --- a/carolhook/touch.h +++ b/carolhook/touch.h @@ -8,10 +8,12 @@ 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 }; HRESULT touch_hook_init(const struct touch_config *cfg); \ No newline at end of file From 9113766c224db11cfb348800bf9d0ddf49969e30 Mon Sep 17 00:00:00 2001 From: Kevin Trocolli Date: Wed, 24 May 2023 01:07:56 -0400 Subject: [PATCH 2/4] vfs: add D drive hooks --- platform/vfs.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/platform/vfs.c b/platform/vfs.c index d356d7f..7bd2953 100644 --- a/platform/vfs.c +++ b/platform/vfs.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) From 02201dfba5a37122ed93888b0bdca09f963cc5f8 Mon Sep 17 00:00:00 2001 From: Kevin Trocolli Date: Wed, 24 May 2023 01:08:08 -0400 Subject: [PATCH 3/4] path: add hooks for PathFileExistsA/W --- hooklib/path.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/hooklib/path.c b/hooklib/path.c index 0c6fe42..1d1d4d2 100644 --- a/hooklib/path.c +++ b/hooklib/path.c @@ -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; +} From 4c67843f086933e5a34778ebe2ec4201a2781a63 Mon Sep 17 00:00:00 2001 From: Kevin Trocolli Date: Wed, 31 May 2023 04:54:38 -0400 Subject: [PATCH 4/4] carol: add touch dll functions --- carolhook/carol-dll.c | 6 ++++ carolhook/carol-dll.h | 2 ++ carolhook/carolhook.def | 2 ++ carolhook/touch.c | 65 ++++++++++++++++++++++++++++++++++++++--- carolhook/touch.h | 19 ++++++++++++ carolio/carolio.c | 55 ++++++++++++++++++++++++++++++++++ carolio/carolio.h | 8 ++++- 7 files changed, 152 insertions(+), 5 deletions(-) diff --git a/carolhook/carol-dll.c b/carolhook/carol-dll.c index 9aa1484..ce3adf9 100644 --- a/carolhook/carol-dll.c +++ b/carolhook/carol-dll.c @@ -27,6 +27,12 @@ const struct dll_bind_sym carol_dll_syms[] = { }, { .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), } }; diff --git a/carolhook/carol-dll.h b/carolhook/carol-dll.h index d56df64..9f8c7ff 100644 --- a/carolhook/carol-dll.h +++ b/carolhook/carol-dll.h @@ -12,6 +12,8 @@ struct carol_dll { 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 { diff --git a/carolhook/carolhook.def b/carolhook/carolhook.def index 260058e..5102937 100644 --- a/carolhook/carolhook.def +++ b/carolhook/carolhook.def @@ -18,3 +18,5 @@ EXPORTS carol_io_touch_init carol_io_ledbd_init carol_io_controlbd_init + carol_io_touch_start + carol_io_touch_stop diff --git a/carolhook/touch.c b/carolhook/touch.c index c062e90..46527b8 100644 --- a/carolhook/touch.c +++ b/carolhook/touch.c @@ -32,12 +32,17 @@ 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) { @@ -118,13 +123,13 @@ static HRESULT touch_handle_irp_locked(struct irp *irp) } else if (!strcmp("OI", (char *)req.cmd)) { hr = handle_touch_id_cmd(&req); - should_stream = true; // possibly send stuff after we get this? + //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)) { - should_stream = false; + carol_dll.touch_stop(); dprintf("Touch: Reset\n"); hr = handle_touch_ack_cmd(&req); } @@ -154,6 +159,58 @@ static HRESULT handle_touch_id_cmd(const struct touch_req *req) 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) { diff --git a/carolhook/touch.h b/carolhook/touch.h index 2ae3031..a815cd1 100644 --- a/carolhook/touch.h +++ b/carolhook/touch.h @@ -4,6 +4,8 @@ #include #include +#pragma pack(push, 1) + struct touch_config { bool enable; }; @@ -16,4 +18,21 @@ struct touch_req { 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); \ No newline at end of file diff --git a/carolio/carolio.c b/carolio/carolio.c index 67339c9..3f4339b 100644 --- a/carolio/carolio.c +++ b/carolio/carolio.c @@ -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) { @@ -81,4 +85,55 @@ HRESULT carol_io_ledbd_init() 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; } \ No newline at end of file diff --git a/carolio/carolio.h b/carolio/carolio.h index 7310f54..6c85e3d 100644 --- a/carolio/carolio.h +++ b/carolio/carolio.h @@ -5,6 +5,8 @@ #include #include +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 @@ -51,4 +53,8 @@ HRESULT carol_io_touch_init(); HRESULT carol_io_ledbd_init(); -HRESULT carol_io_controlbd_init(); \ No newline at end of file +HRESULT carol_io_controlbd_init(); + +void carol_io_touch_start(carol_io_touch_callback_t callback); + +void carol_io_touch_stop(); \ No newline at end of file