forked from TeamTofuShop/segatools
Compare commits
11 Commits
2024-05-16
...
develop
Author | SHA1 | Date | |
---|---|---|---|
ccb655a12b | |||
ded89f6343 | |||
f3e31fc2ae
|
|||
965126c68a
|
|||
050951e56f
|
|||
7e5e0f132e
|
|||
4e58d3b9a2
|
|||
7d3cab256b | |||
b0f307f427
|
|||
7aa996193c | |||
9353c9872f |
3
.gitignore
vendored
3
.gitignore
vendored
@ -18,3 +18,6 @@ build/
|
||||
|
||||
# External dependencies
|
||||
subprojects/capnhook
|
||||
|
||||
# For enabling debug logging on local builds
|
||||
MesonLocalOptions.mk
|
||||
|
9
Makefile
9
Makefile
@ -11,6 +11,11 @@ DOC_DIR := doc
|
||||
|
||||
DIST_DIR := dist
|
||||
|
||||
# Add "-D[option]=[value]" here as necessary
|
||||
MESON_OPTIONS :=
|
||||
# For options that shouldn't be committed
|
||||
-include MesonLocalOptions.mk
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Targets
|
||||
# -----------------------------------------------------------------------------
|
||||
@ -19,9 +24,9 @@ include Package.mk
|
||||
|
||||
.PHONY: build # Build the project
|
||||
build:
|
||||
$(V)meson --cross cross-mingw-32.txt $(BUILD_DIR_32)
|
||||
$(V)meson setup $(MESON_OPTIONS) --cross cross-mingw-32.txt $(BUILD_DIR_32)
|
||||
$(V)ninja -C $(BUILD_DIR_32)
|
||||
$(V)meson --cross cross-mingw-64.txt $(BUILD_DIR_64)
|
||||
$(V)meson setup $(MESON_OPTIONS) --cross cross-mingw-64.txt $(BUILD_DIR_64)
|
||||
$(V)ninja -C $(BUILD_DIR_64)
|
||||
|
||||
.PHONY: dist # Build and create a zip distribution package
|
||||
|
@ -185,14 +185,14 @@ static HRESULT jvs_ioctl_sense(struct irp *irp)
|
||||
|
||||
static HRESULT jvs_ioctl_transact(struct irp *irp)
|
||||
{
|
||||
#if 0
|
||||
#if defined(LOG_JVS)
|
||||
dprintf("\nJVS Port: Outbound frame:\n");
|
||||
dump_const_iobuf(&irp->write);
|
||||
#endif
|
||||
|
||||
jvs_bus_transact(jvs_root, irp->write.bytes, irp->write.nbytes, &irp->read);
|
||||
|
||||
#if 0
|
||||
#if defined(LOG_JVS)
|
||||
dprintf("JVS Port: Inbound frame:\n");
|
||||
dump_iobuf(&irp->read);
|
||||
dprintf("\n");
|
||||
|
@ -230,7 +230,7 @@ static HRESULT io3_cmd(
|
||||
|
||||
case JVS_CMD_READ_ANALOGS:
|
||||
return io3_cmd_read_analogs(io3, req, resp);
|
||||
|
||||
|
||||
case JVS_CMD_READ_ROTARYS:
|
||||
return io3_cmd_read_rotarys(io3, req, resp);
|
||||
|
||||
@ -390,7 +390,7 @@ static HRESULT io3_cmd_read_switches(
|
||||
return hr;
|
||||
}
|
||||
|
||||
#if 0
|
||||
#if defined(LOG_IO3)
|
||||
dprintf("JVS I/O: Read switches, np=%i, bpp=%i\n",
|
||||
req.num_players,
|
||||
req.bytes_per_player);
|
||||
|
81
board/led15070-cmd.h
Normal file
81
board/led15070-cmd.h
Normal file
@ -0,0 +1,81 @@
|
||||
#pragma once
|
||||
|
||||
#include "board/led15070-frame.h"
|
||||
|
||||
/* Command IDs */
|
||||
|
||||
enum {
|
||||
LED_15070_CMD_RESET = 0x10,
|
||||
LED_15070_CMD_SET_INPUT = 0x28, // No known use case
|
||||
LED_15070_CMD_SET_NORMAL_12BIT = 0x30, // TODO
|
||||
LED_15070_CMD_SET_NORMAL_8BIT = 0x31,
|
||||
LED_15070_CMD_SET_MULTI_FLASH_8BIT = 0x32,
|
||||
LED_15070_CMD_SET_MULTI_FADE_8BIT = 0x33,
|
||||
LED_15070_CMD_SET_PALETTE_7_NORMAL_LED = 0x34, // No known use case
|
||||
LED_15070_CMD_SET_PALETTE_6_FLASH_LED = 0x35, // No known use case
|
||||
LED_15070_CMD_SET_15DC_OUT = 0x36, // No known use case
|
||||
LED_15070_CMD_SET_15GS_OUT = 0x37, // No known use case
|
||||
LED_15070_CMD_SET_PSC_MAX = 0x38, // No known use case
|
||||
LED_15070_CMD_SET_FET_OUTPUT = 0x39,
|
||||
LED_15070_CMD_SET_GS_PALETTE = 0x3A,
|
||||
LED_15070_CMD_DC_UPDATE = 0x3B,
|
||||
LED_15070_CMD_GS_UPDATE = 0x3C,
|
||||
LED_15070_CMD_ROTATE = 0x3E, // No known use case, wtf is this?
|
||||
LED_15070_CMD_SET_DC_DATA = 0x3F,
|
||||
LED_15070_CMD_EEPROM_WRITE = 0x7B,
|
||||
LED_15070_CMD_EEPROM_READ = 0x7C,
|
||||
LED_15070_CMD_ACK_ON = 0x7D,
|
||||
LED_15070_CMD_ACK_OFF = 0x7E,
|
||||
LED_15070_CMD_BOARD_INFO = 0xF0,
|
||||
LED_15070_CMD_BOARD_STATUS = 0xF1,
|
||||
LED_15070_CMD_FW_SUM = 0xF2,
|
||||
LED_15070_CMD_PROTOCOL_VER = 0xF3,
|
||||
LED_15070_CMD_TO_BOOT_MODE = 0xFD,
|
||||
LED_15070_CMD_FW_UPDATE = 0xFE,
|
||||
};
|
||||
|
||||
/* Response codes */
|
||||
|
||||
enum {
|
||||
LED_15070_STATUS_OK = 0x01,
|
||||
LED_15070_STATUS_SUM_ERR = 0x02,
|
||||
LED_15070_STATUS_PARITY_ERR = 0x03,
|
||||
LED_15070_STATUS_FRAMING_ERR = 0x04,
|
||||
LED_15070_STATUS_OVERRUN_ERR = 0x05,
|
||||
LED_15070_STATUS_BUFFER_OVERFLOW = 0x06,
|
||||
};
|
||||
|
||||
enum {
|
||||
LED_15070_REPORT_OK = 0x01,
|
||||
LED_15070_REPORT_WAIT = 0x02,
|
||||
LED_15070_REPORT_ERR1 = 0x03,
|
||||
LED_15070_REPORT_ERR2 = 0x04,
|
||||
};
|
||||
|
||||
/* Request data structures */
|
||||
|
||||
struct led15070_req_any {
|
||||
struct led15070_hdr hdr;
|
||||
uint8_t cmd;
|
||||
uint8_t payload[256];
|
||||
};
|
||||
|
||||
/* Response data structures */
|
||||
|
||||
struct led15070_resp_any {
|
||||
struct led15070_hdr hdr;
|
||||
uint8_t status;
|
||||
uint8_t cmd;
|
||||
uint8_t report;
|
||||
uint8_t data[32];
|
||||
};
|
||||
|
||||
struct led15070_resp_board_info {
|
||||
struct led15070_hdr hdr;
|
||||
uint8_t status;
|
||||
uint8_t cmd;
|
||||
uint8_t report;
|
||||
char board_num[8];
|
||||
uint8_t endcode; // Always 0xFF
|
||||
uint8_t fw_ver;
|
||||
};
|
194
board/led15070-frame.c
Normal file
194
board/led15070-frame.c
Normal file
@ -0,0 +1,194 @@
|
||||
#include <windows.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "board/led15070-frame.h"
|
||||
|
||||
#include "hook/iobuf.h"
|
||||
|
||||
static void led15070_frame_sync(struct iobuf *src);
|
||||
static HRESULT led15070_frame_accept(const struct iobuf *dest);
|
||||
static HRESULT led15070_frame_encode_byte(struct iobuf *dest, uint8_t byte);
|
||||
|
||||
/* Frame structure:
|
||||
|
||||
[0] Sync byte (0xE0)
|
||||
[1] Destination address
|
||||
[2] Source Address
|
||||
[3] Length of data/payload
|
||||
[4] Data/payload
|
||||
For requests (host to board):
|
||||
[0] Command
|
||||
... Payload
|
||||
For responses (board to host):
|
||||
[0] Status
|
||||
[1] Command
|
||||
[2] Report
|
||||
... Payload
|
||||
[n] Checksum: Sum of all prior bytes (excluding sync byte)
|
||||
|
||||
Byte stuffing:
|
||||
|
||||
0xD0 is an escape byte. Un-escape the subsequent byte by adding 1. */
|
||||
|
||||
static void led15070_frame_sync(struct iobuf *src)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0 ; i < src->pos && src->bytes[i] != 0xE0 ; i++);
|
||||
|
||||
src->pos -= i;
|
||||
memmove(&src->bytes[0], &src->bytes[i], i);
|
||||
}
|
||||
|
||||
static HRESULT led15070_frame_accept(const struct iobuf *dest)
|
||||
{
|
||||
uint8_t checksum;
|
||||
size_t i;
|
||||
|
||||
if (dest->pos < 3 || dest->pos != dest->bytes[3] + 5) {
|
||||
return S_FALSE;
|
||||
}
|
||||
|
||||
checksum = 0;
|
||||
|
||||
for (i = 1 ; i < dest->pos - 1 ; i++) {
|
||||
checksum += dest->bytes[i];
|
||||
}
|
||||
|
||||
//dprintf("LED checksum %02x, expected %02x\n", checksum, dest->bytes[dest->pos - 1]);
|
||||
|
||||
if (checksum != dest->bytes[dest->pos - 1]) {
|
||||
return HRESULT_FROM_WIN32(ERROR_CRC);
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT led15070_frame_decode(struct iobuf *dest, struct iobuf *src)
|
||||
{
|
||||
uint8_t byte;
|
||||
bool escape;
|
||||
size_t i;
|
||||
HRESULT hr;
|
||||
|
||||
assert(dest != NULL);
|
||||
assert(dest->bytes != NULL || dest->nbytes == 0);
|
||||
assert(dest->pos <= dest->nbytes);
|
||||
assert(src != NULL);
|
||||
assert(src->bytes != NULL || src->nbytes == 0);
|
||||
assert(src->pos <= src->nbytes);
|
||||
|
||||
led15070_frame_sync(src);
|
||||
|
||||
dest->pos = 0;
|
||||
escape = false;
|
||||
|
||||
for (i = 0, hr = S_FALSE ; i < src->pos && hr == S_FALSE ; i++) {
|
||||
/* Step the FSM to unstuff another byte */
|
||||
|
||||
byte = src->bytes[i];
|
||||
|
||||
if (dest->pos >= dest->nbytes) {
|
||||
hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
|
||||
} else if (i == 0) {
|
||||
dest->bytes[dest->pos++] = byte;
|
||||
} else if (byte == 0xE0) {
|
||||
hr = E_FAIL;
|
||||
} else if (byte == 0xD0) {
|
||||
if (escape) {
|
||||
hr = E_FAIL;
|
||||
}
|
||||
|
||||
escape = true;
|
||||
} else if (escape) {
|
||||
dest->bytes[dest->pos++] = byte + 1;
|
||||
escape = false;
|
||||
} else {
|
||||
dest->bytes[dest->pos++] = byte;
|
||||
}
|
||||
|
||||
/* Try to accept the packet we've built up so far */
|
||||
|
||||
if (SUCCEEDED(hr)) {
|
||||
hr = led15070_frame_accept(dest);
|
||||
}
|
||||
}
|
||||
|
||||
/* Handle FSM terminal state */
|
||||
|
||||
if (hr != S_FALSE) {
|
||||
/* Frame was either accepted or rejected, remove it from src */
|
||||
memmove(&src->bytes[0], &src->bytes[i], src->pos - i);
|
||||
src->pos -= i;
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
HRESULT led15070_frame_encode(
|
||||
struct iobuf *dest,
|
||||
const void *ptr,
|
||||
size_t nbytes)
|
||||
{
|
||||
const uint8_t *src;
|
||||
uint8_t checksum;
|
||||
uint8_t byte;
|
||||
size_t i;
|
||||
HRESULT hr;
|
||||
|
||||
assert(dest != NULL);
|
||||
assert(dest->bytes != NULL || dest->nbytes == 0);
|
||||
assert(dest->pos <= dest->nbytes);
|
||||
assert(ptr != NULL);
|
||||
|
||||
src = ptr;
|
||||
|
||||
assert(nbytes >= 3 && src[0] == 0xE0 && src[3] + 4 == nbytes);
|
||||
|
||||
if (dest->pos >= dest->nbytes) {
|
||||
return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
|
||||
}
|
||||
|
||||
dest->bytes[dest->pos++] = 0xE0;
|
||||
checksum = 0;
|
||||
// dprintf("%02x ", 0xe0);
|
||||
|
||||
for (i = 1 ; i < nbytes ; i++) {
|
||||
byte = src[i];
|
||||
checksum += byte;
|
||||
// dprintf("%02x ", byte);
|
||||
|
||||
hr = led15070_frame_encode_byte(dest, byte);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
}
|
||||
// dprintf("%02x \n", checksum);
|
||||
|
||||
return led15070_frame_encode_byte(dest, checksum);
|
||||
}
|
||||
|
||||
static HRESULT led15070_frame_encode_byte(struct iobuf *dest, uint8_t byte)
|
||||
{
|
||||
if (byte == 0xE0 || byte == 0xD0) {
|
||||
if (dest->pos + 2 > dest->nbytes) {
|
||||
return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
|
||||
}
|
||||
|
||||
dest->bytes[dest->pos++] = 0xD0;
|
||||
dest->bytes[dest->pos++] = byte - 1;
|
||||
} else {
|
||||
if (dest->pos + 1 > dest->nbytes) {
|
||||
return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
|
||||
}
|
||||
|
||||
dest->bytes[dest->pos++] = byte;
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
26
board/led15070-frame.h
Normal file
26
board/led15070-frame.h
Normal file
@ -0,0 +1,26 @@
|
||||
#pragma once
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "hook/iobuf.h"
|
||||
|
||||
enum {
|
||||
LED_15070_FRAME_SYNC = 0xE0,
|
||||
};
|
||||
|
||||
struct led15070_hdr {
|
||||
uint8_t sync;
|
||||
uint8_t dest_adr;
|
||||
uint8_t src_adr;
|
||||
uint8_t nbytes;
|
||||
};
|
||||
|
||||
HRESULT led15070_frame_decode(struct iobuf *dest, struct iobuf *src);
|
||||
|
||||
HRESULT led15070_frame_encode(
|
||||
struct iobuf *dest,
|
||||
const void *ptr,
|
||||
size_t nbytes);
|
1250
board/led15070.c
Normal file
1250
board/led15070.c
Normal file
File diff suppressed because it is too large
Load Diff
29
board/led15070.h
Normal file
29
board/led15070.h
Normal file
@ -0,0 +1,29 @@
|
||||
#pragma once
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
struct led15070_config {
|
||||
bool enable;
|
||||
unsigned int port_no;
|
||||
char board_number[8];
|
||||
uint8_t fw_ver;
|
||||
uint16_t fw_sum;
|
||||
wchar_t eeprom_path[MAX_PATH];
|
||||
};
|
||||
|
||||
typedef HRESULT (*io_led_init_t)(void);
|
||||
typedef void (*io_led_set_fet_output_t)(const uint8_t *rgb);
|
||||
typedef void (*io_led_dc_update_t)(const uint8_t *rgb);
|
||||
typedef void (*io_led_gs_update_t)(const uint8_t *rgb);
|
||||
|
||||
HRESULT led15070_hook_init(
|
||||
const struct led15070_config *cfg,
|
||||
io_led_init_t _led_init,
|
||||
io_led_set_fet_output_t _led_set_fet_output,
|
||||
io_led_dc_update_t _led_dc_update,
|
||||
io_led_gs_update_t _led_gs_update,
|
||||
unsigned int first_port,
|
||||
unsigned int num_boards);
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
SEGA 837-15093-XX LED Controller Board emulator
|
||||
|
||||
|
||||
Supported variants:
|
||||
|
||||
837-15093
|
||||
@ -106,7 +106,7 @@ static uint8_t led15093_host_adr = 1;
|
||||
static io_led_init_t led_init;
|
||||
static io_led_set_leds_t set_leds;
|
||||
|
||||
HRESULT led15093_hook_init(const struct led15093_config *cfg, io_led_init_t _led_init,
|
||||
HRESULT led15093_hook_init(const struct led15093_config *cfg, io_led_init_t _led_init,
|
||||
io_led_set_leds_t _set_leds, unsigned int first_port, unsigned int num_boards, uint8_t board_adr, uint8_t host_adr)
|
||||
{
|
||||
|
||||
@ -236,12 +236,12 @@ static HRESULT led15093_handle_irp_locked(int board, struct irp *irp)
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
if (irp->op == IRP_OP_OPEN) {
|
||||
dprintf("LED 15093: Starting backend DLL\n");
|
||||
// int res = led_init();
|
||||
hr = led_init();
|
||||
|
||||
|
||||
/*
|
||||
if (res != 0) {
|
||||
dprintf("LED 15093: Backend error, LED board disconnected: "
|
||||
@ -267,7 +267,7 @@ static HRESULT led15093_handle_irp_locked(int board, struct irp *irp)
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
#if 0
|
||||
#if defined(LOG_LED15093)
|
||||
dprintf("TX Buffer:\n");
|
||||
dump_iobuf(&boarduart->written);
|
||||
#endif
|
||||
@ -294,7 +294,7 @@ static HRESULT led15093_handle_irp_locked(int board, struct irp *irp)
|
||||
return hr;
|
||||
}
|
||||
|
||||
#if 0
|
||||
#if defined(LOG_LED15093)
|
||||
dprintf("Deframe Buffer:\n");
|
||||
dump_iobuf(&req_iobuf);
|
||||
#endif
|
||||
@ -717,7 +717,7 @@ static HRESULT led15093_req_set_imm_led(int board, const struct led15093_req_set
|
||||
resp.status = v->status_code;
|
||||
if (req->cmd == LED_15093_CMD_SET_IMM_LED) {
|
||||
resp.cmd = LED_15093_CMD_SET_IMM_LED;
|
||||
}
|
||||
}
|
||||
// else {
|
||||
// resp.cmd = LED_15093_CMD_SET_IMM_LED_LEGACY;
|
||||
// }
|
||||
|
@ -25,6 +25,11 @@ board_lib = static_library(
|
||||
'led15093-frame.h',
|
||||
'led15093.c',
|
||||
'led15093.h',
|
||||
'led15070-cmd.h',
|
||||
'led15070-frame.c',
|
||||
'led15070-frame.h',
|
||||
'led15070.c',
|
||||
'led15070.h',
|
||||
'sg-cmd.c',
|
||||
'sg-cmd.h',
|
||||
'sg-frame.c',
|
||||
|
@ -420,7 +420,7 @@ static HRESULT sg_nfc_cmd_felica_encap(
|
||||
f_res.nbytes = sizeof(res->payload);
|
||||
f_res.pos = 1;
|
||||
|
||||
#if 0
|
||||
#if defined(LOG_NFC)
|
||||
dprintf("FELICA OUTBOUND:\n");
|
||||
dump_const_iobuf(&f_req);
|
||||
#endif
|
||||
@ -434,7 +434,7 @@ static HRESULT sg_nfc_cmd_felica_encap(
|
||||
sg_res_init(&res->res, &req->req, f_res.pos);
|
||||
res->payload[0] = f_res.pos;
|
||||
|
||||
#if 0
|
||||
#if defined(LOG_NFC)
|
||||
dprintf("FELICA INBOUND:\n");
|
||||
dump_iobuf(&f_res);
|
||||
#endif
|
||||
|
@ -115,14 +115,14 @@ static HRESULT sg_reader_handle_irp_locked(struct irp *irp)
|
||||
{
|
||||
HRESULT hr;
|
||||
|
||||
#if 0
|
||||
#if defined(LOG_NFC)
|
||||
if (irp->op == IRP_OP_WRITE) {
|
||||
dprintf("WRITE:\n");
|
||||
dump_const_iobuf(&irp->write);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
#if defined(LOG_NFC)
|
||||
if (irp->op == IRP_OP_READ) {
|
||||
dprintf("READ:\n");
|
||||
dump_iobuf(&sg_reader_uart.readable);
|
||||
|
@ -78,7 +78,7 @@ static HRESULT controlbd_frame_decode(struct controlbd_req_any *req, struct iobu
|
||||
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;
|
||||
@ -137,7 +137,7 @@ static HRESULT controlbd_handle_irp_locked(struct irp *irp)
|
||||
|
||||
for (;;) {
|
||||
if (controlbd_uart.written.bytes[0] == 0xE0) {
|
||||
#if 0
|
||||
#if defined(LOG_CAROL_CONTROL_BD)
|
||||
dprintf("Control Board: TX Buffer:\n");
|
||||
dump_iobuf(&controlbd_uart.written);
|
||||
#endif
|
||||
@ -147,12 +147,12 @@ static HRESULT controlbd_handle_irp_locked(struct irp *irp)
|
||||
return hr;
|
||||
}
|
||||
|
||||
hr = controlbd_req_dispatch(&req);
|
||||
hr = controlbd_req_dispatch(&req);
|
||||
if (FAILED(hr)) {
|
||||
dprintf("Control Board: Dispatch Error: 0X%X\n", (int) hr);
|
||||
return hr;
|
||||
}
|
||||
#if 0
|
||||
#if defined(LOG_CAROL_CONTROL_BD)
|
||||
dprintf("Control Board: RX Buffer:\n");
|
||||
dump_iobuf(&controlbd_uart.readable);
|
||||
#endif
|
||||
@ -206,7 +206,7 @@ static HRESULT controlbd_req_dispatch(const struct controlbd_req_any *req)
|
||||
case CONTROLBD_CMD_FIRM_SUM:
|
||||
return controlbd_req_firmware_checksum();
|
||||
|
||||
case CONTROLBD_CMD_TIMEOUT:
|
||||
case CONTROLBD_CMD_TIMEOUT:
|
||||
dprintf("Control Board: Acknowledge Timeout\n");
|
||||
return controlbd_req_ack_any(req->hdr.cmd);
|
||||
|
||||
@ -278,7 +278,7 @@ static HRESULT controlbd_req_get_board_info(void)
|
||||
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;
|
||||
@ -317,7 +317,7 @@ static HRESULT controlbd_req_polling(const struct controlbd_req_any *req)
|
||||
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;
|
||||
|
@ -1,3 +1,31 @@
|
||||
/*
|
||||
"Wonderland Wars" (carol*) hook
|
||||
|
||||
Devices:
|
||||
|
||||
JVS: 837-14572 "Type 3" I/O Board
|
||||
|
||||
[Satellite]
|
||||
|
||||
USB: "WinTouch" Controller Board
|
||||
^ (DIPSW2 ON, Version 5.xx.xx or above)
|
||||
COM1: 3M Touch Systems 78-0011-2353-4 Touch Controller Board
|
||||
^ (DIPSW2 OFF)
|
||||
COM10: TN32MSEC003S "Gen 1" Aime Reader
|
||||
OR
|
||||
837-15286 "Gen 2" Aime Reader
|
||||
^ (Version 1.6x.xx or above)
|
||||
COM11: 837-15070-02 LED Controller Board
|
||||
COM12: 837-15312 Pen Controller I/O Board
|
||||
|
||||
[Terminal]
|
||||
|
||||
COM10: 837-15286 "Gen 2" Aime Reader
|
||||
|
||||
*: SEGA's abbreviation for Lewis Carroll, author of Alice's Adventures in
|
||||
Wonderland.
|
||||
*/
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
|
@ -94,7 +94,7 @@ static HRESULT ledbd_handle_irp_locked(struct irp *irp)
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
#if 0
|
||||
#if defined(LOG_CAROL_LED_BD)
|
||||
dprintf("LED Board: TX Buffer:\n");
|
||||
dump_iobuf(&ledbd_uart.written);
|
||||
#endif
|
||||
@ -165,4 +165,4 @@ static HRESULT ledbd_req_unkF0(uint8_t cmd)
|
||||
iobuf_write(&ledbd_uart.readable, resp, 16);
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
}
|
||||
|
@ -54,7 +54,7 @@ HRESULT touch_hook_init(const struct touch_config *cfg)
|
||||
if (!cfg->enable) {
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
InitializeCriticalSection(&touch_lock);
|
||||
|
||||
uart_init(&touch_uart, 1);
|
||||
@ -112,7 +112,7 @@ static HRESULT touch_handle_irp_locked(struct irp *irp)
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
#if 0
|
||||
#if defined(LOG_CAROL_TOUCH)
|
||||
dprintf("Touchscreen: TX Buffer:\n");
|
||||
dump_iobuf(&touch_uart.written);
|
||||
#endif
|
||||
@ -188,7 +188,7 @@ static void touch_scan_auto(const bool is_pressed, const uint16_t mouse_x, const
|
||||
resp.touches[0].touch_id = 1;
|
||||
tmp_x = mouse_x & 0x7FFF;
|
||||
tmp_y = mouse_y & 0x7FFF;
|
||||
|
||||
|
||||
resp.touches[0].x1 = tmp_x & 0x7F;
|
||||
resp.touches[0].x2 = (tmp_x >> 7) & 0x7F;
|
||||
resp.touches[0].y1 = tmp_y & 0x7F;
|
||||
@ -201,7 +201,7 @@ static void touch_scan_auto(const bool is_pressed, const uint16_t mouse_x, const
|
||||
dprintf("Touch: Mouse down! x %02X %02X y: %02X %02X\n", resp.touches[0].x1, resp.touches[0].x2, resp.touches[0].y1, resp.touches[0].y2);
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
last_x1 = resp.touches[0].x1;
|
||||
last_x2 = resp.touches[0].x2;
|
||||
last_y1 = resp.touches[0].y1;
|
||||
@ -220,7 +220,7 @@ static void touch_scan_auto(const bool is_pressed, const uint16_t mouse_x, const
|
||||
iobuf_write(&touch_uart.readable, &resp, sizeof(resp));
|
||||
LeaveCriticalSection(&touch_lock);
|
||||
|
||||
#if 0
|
||||
#if defined(LOG_CAROL_TOUCH)
|
||||
dprintf("Touch: RX Buffer: (pos %08x)\n", (uint32_t)touch_uart.readable.pos);
|
||||
dump_iobuf(&touch_uart.readable);
|
||||
#endif
|
||||
|
@ -1,3 +1,15 @@
|
||||
/*
|
||||
"CHUNITHM" (chuni) hook
|
||||
|
||||
Devices
|
||||
|
||||
JVS: 837-14572 "Type 3" I/O Board
|
||||
COM1: 837-15330 Ground Slider
|
||||
COM10: 837-15093-06 LED Controller Board
|
||||
COM11: 837-15093-06 LED Controller Board
|
||||
COM12: TN32MSEC003S "Gen 1" Aime Reader
|
||||
*/
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
|
@ -98,7 +98,7 @@ static HRESULT slider_handle_irp_locked(struct irp *irp)
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
#if 0
|
||||
#if defined(LOG_CHUNI_SLIDER)
|
||||
dprintf("TX Buffer:\n");
|
||||
dump_iobuf(&slider_uart.written);
|
||||
#endif
|
||||
@ -117,7 +117,7 @@ static HRESULT slider_handle_irp_locked(struct irp *irp)
|
||||
return hr;
|
||||
}
|
||||
|
||||
#if 0
|
||||
#if defined(LOG_CHUNI_SLIDER)
|
||||
dprintf("Deframe Buffer:\n");
|
||||
dump_iobuf(&req_iobuf);
|
||||
#endif
|
||||
|
@ -1,3 +1,27 @@
|
||||
/*
|
||||
"CHUNITHM NEW" (chusan) hook
|
||||
|
||||
Devices
|
||||
|
||||
USB: 837-15257-02 "Type 4" I/O Board
|
||||
COM1: 837-15330 Ground Slider
|
||||
|
||||
[CVT mode (DIPSW2 ON)]
|
||||
|
||||
COM2: 837-15093-06 LED Controller Board
|
||||
COM3: 837-15093-06 LED Controller Board
|
||||
COM4: 837-15286 "Gen 2" Aime Reader
|
||||
|
||||
[SP mode (DIPSW2 OFF)]
|
||||
|
||||
USB: 837-15067-02 USB Serial I/F Board
|
||||
connected to
|
||||
837-15093-06 LED Controller Board (COM20)
|
||||
837-15093-06 LED Controller Board (COM21)
|
||||
COM2: 200-6275 VFD GP1232A02A FUTABA Board
|
||||
COM4: 837-15396 "Gen 3" Aime Reader
|
||||
*/
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include <stddef.h>
|
||||
|
@ -98,7 +98,7 @@ static HRESULT slider_handle_irp_locked(struct irp *irp)
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
#if 0
|
||||
#if defined(LOG_CHUSAN_SLIDER)
|
||||
dprintf("TX Buffer:\n");
|
||||
dump_iobuf(&slider_uart.written);
|
||||
#endif
|
||||
@ -117,7 +117,7 @@ static HRESULT slider_handle_irp_locked(struct irp *irp)
|
||||
return hr;
|
||||
}
|
||||
|
||||
#if 0
|
||||
#if defined(LOG_CHUSAN_SLIDER)
|
||||
dprintf("Deframe Buffer:\n");
|
||||
dump_iobuf(&req_iobuf);
|
||||
#endif
|
||||
|
@ -1,3 +1,16 @@
|
||||
/*
|
||||
"Card Maker" (cm) hook
|
||||
|
||||
Devices
|
||||
|
||||
USB: 837-15257-01 "Type 4" I/O Board
|
||||
USB: 838-20006 "WinTouch" Controller Board
|
||||
USB: 630-00009 Sinfonia CHC-C310 Printer
|
||||
COM1: 837-15396 "Gen 3" Aime Reader
|
||||
COM2: 200-6275 VFD GP1232A02A FUTABA Board
|
||||
COM3: 220-5872 AS-6DB Coin Selector
|
||||
*/
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
@ -55,6 +68,12 @@ static DWORD CALLBACK cm_pre_startup(void)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
hr = cm_dll_init(&cm_hook_cfg.dll, cm_hook_mod);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
hr = sg_reader_hook_init(&cm_hook_cfg.aime, 1, 1, cm_hook_mod);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
@ -67,12 +86,6 @@ static DWORD CALLBACK cm_pre_startup(void)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
hr = cm_dll_init(&cm_hook_cfg.dll, cm_hook_mod);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
hr = cm_io4_hook_init(&cm_hook_cfg.io4);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
|
1
dist/chusan/segatools.ini
vendored
1
dist/chusan/segatools.ini
vendored
@ -43,6 +43,7 @@ default=127.0.0.1
|
||||
; Chunithm is extremely picky about its LAN environment, so leaving this
|
||||
; setting enabled is strongly recommended.
|
||||
enable=1
|
||||
|
||||
; The final octet of the local host's IP address on the virtualized subnet (so,
|
||||
; if the keychip subnet is `192.168.32.0` and this value is set to `11`, then the
|
||||
; local host's virtualized LAN IP is `192.168.32.11`).
|
||||
|
19
dist/idac/segatools.ini
vendored
19
dist/idac/segatools.ini
vendored
@ -75,6 +75,25 @@ dipsw3=0
|
||||
dipsw4=0
|
||||
dipsw5=0
|
||||
|
||||
; -----------------------------------------------------------------------------
|
||||
; LED settings
|
||||
; -----------------------------------------------------------------------------
|
||||
|
||||
[led15070]
|
||||
; Enable emulation of the 837-15070-02 controlled lights, which handle the
|
||||
; cabinet and seat LEDs.
|
||||
enable=1
|
||||
|
||||
; -----------------------------------------------------------------------------
|
||||
; Misc. hooks settings
|
||||
; -----------------------------------------------------------------------------
|
||||
|
||||
[indrun]
|
||||
; Hooks to patch GameProject-Win64-Shipping.exe and IndRun.dll. This is needed
|
||||
; to boot version 1.60.00 and up. The hooks are not needed for version 1.50.00
|
||||
; and below.
|
||||
enable=1
|
||||
|
||||
; -----------------------------------------------------------------------------
|
||||
; Custom IO settings
|
||||
; -----------------------------------------------------------------------------
|
||||
|
@ -1,3 +1,14 @@
|
||||
/*
|
||||
"Hatsune Miku Project DIVA Arcade " (diva) hook
|
||||
|
||||
Devices
|
||||
|
||||
JVS: 837-14572 "Type 3" I/O Board
|
||||
COM1: 3M Touch Systems 78-0011-2353-4 Touch Controller Board
|
||||
COM10: TN32MSEC003S "Gen 1" Aime Reader
|
||||
COM11: 837-15275 Touch Slider
|
||||
*/
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
|
@ -99,7 +99,7 @@ static HRESULT slider_handle_irp_locked(struct irp *irp)
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
#if 0
|
||||
#if defined(LOG_DIVA_SLIDER)
|
||||
dprintf("TX Buffer:\n");
|
||||
dump_iobuf(&slider_uart.written);
|
||||
#endif
|
||||
@ -118,7 +118,7 @@ static HRESULT slider_handle_irp_locked(struct irp *irp)
|
||||
return hr;
|
||||
}
|
||||
|
||||
#if 0
|
||||
#if defined(LOG_DIVA_SLIDER)
|
||||
dprintf("Deframe Buffer:\n");
|
||||
dump_iobuf(&req_iobuf);
|
||||
#endif
|
||||
|
@ -352,7 +352,7 @@ Enable keychip emulation. Disable to use a real keychip.
|
||||
Default: `A69E-01A88888888`
|
||||
|
||||
Keychip serial number. Keychip serials observed in the wild follow this
|
||||
pattern: `A6xE-01Ayyyyyyyy`.
|
||||
pattern: `A\d{2}(E|X)-(01|20)[ABCDU]\d{8}`.
|
||||
|
||||
### `gameId`
|
||||
|
||||
|
@ -1,3 +1,20 @@
|
||||
/*
|
||||
"Fate Grand/Order Arcade" (fgo) hook
|
||||
|
||||
Devices
|
||||
|
||||
USB: 837-15257 "Type 4" I/O Board
|
||||
USB: 838-15405 "WinTouch" Controller Board
|
||||
USB: 630-00008 Sinfonia CHC-C330 Printer
|
||||
USB: 837-14509-02 USB-SER I/F BD Mini-B FTDI Board
|
||||
connected to
|
||||
837-15093-06 LED Controller Board
|
||||
COM1: 200-6275 VFD GP1232A02A FUTABA Board
|
||||
COM2: 837-15345 RFID Deck Reader Noard
|
||||
COM3: 837-15396 "Gen 3" Aime Reader
|
||||
COM4: 837-15347 RFID Reader/Writer Board (inside the printer)
|
||||
*/
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
|
@ -13,6 +13,43 @@
|
||||
#include "platform/config.h"
|
||||
#include "platform/platform.h"
|
||||
|
||||
|
||||
void led15070_config_load(struct led15070_config *cfg, const wchar_t *filename)
|
||||
{
|
||||
assert(cfg != NULL);
|
||||
assert(filename != NULL);
|
||||
|
||||
wchar_t tmpstr[16];
|
||||
|
||||
cfg->enable = GetPrivateProfileIntW(L"led15070", L"enable", 1, filename);
|
||||
cfg->port_no = GetPrivateProfileIntW(L"led15070", L"portNo", 0, filename);
|
||||
cfg->fw_ver = GetPrivateProfileIntW(L"led15070", L"fwVer", 0x90, filename);
|
||||
/* TODO: Unknown, no firmware file available */
|
||||
cfg->fw_sum = GetPrivateProfileIntW(L"led15070", L"fwSum", 0x0000, filename);
|
||||
|
||||
GetPrivateProfileStringW(
|
||||
L"led15070",
|
||||
L"boardNumber",
|
||||
L"15070-02",
|
||||
tmpstr,
|
||||
_countof(tmpstr),
|
||||
filename);
|
||||
|
||||
size_t n = wcstombs(cfg->board_number, tmpstr, sizeof(cfg->board_number));
|
||||
for (int i = n; i < sizeof(cfg->board_number); i++)
|
||||
{
|
||||
cfg->board_number[i] = ' ';
|
||||
}
|
||||
|
||||
GetPrivateProfileStringW(
|
||||
L"led15070",
|
||||
L"eepromPath",
|
||||
L"DEVICE",
|
||||
cfg->eeprom_path,
|
||||
_countof(cfg->eeprom_path),
|
||||
filename);
|
||||
}
|
||||
|
||||
void idac_dll_config_load(
|
||||
struct idac_dll_config *cfg,
|
||||
const wchar_t *filename)
|
||||
@ -29,6 +66,16 @@ void idac_dll_config_load(
|
||||
filename);
|
||||
}
|
||||
|
||||
void indrun_config_load(
|
||||
struct indrun_config *cfg,
|
||||
const wchar_t *filename)
|
||||
{
|
||||
assert(cfg != NULL);
|
||||
assert(filename != NULL);
|
||||
|
||||
cfg->enable = GetPrivateProfileIntW(L"indrun", L"enable", 1, filename);
|
||||
}
|
||||
|
||||
void idac_hook_config_load(
|
||||
struct idac_hook_config *cfg,
|
||||
const wchar_t *filename)
|
||||
@ -42,6 +89,8 @@ void idac_hook_config_load(
|
||||
zinput_config_load(&cfg->zinput, filename);
|
||||
dvd_config_load(&cfg->dvd, filename);
|
||||
io4_config_load(&cfg->io4, filename);
|
||||
led15070_config_load(&cfg->led15070, filename);
|
||||
indrun_config_load(&cfg->indrun, filename);
|
||||
}
|
||||
|
||||
void zinput_config_load(struct zinput_config *cfg, const wchar_t *filename)
|
||||
|
@ -4,11 +4,13 @@
|
||||
#include <stddef.h>
|
||||
|
||||
#include "board/config.h"
|
||||
#include "board/led15070.h"
|
||||
|
||||
#include "hooklib/dvd.h"
|
||||
|
||||
#include "idachook/idac-dll.h"
|
||||
#include "idachook/zinput.h"
|
||||
#include "idachook/indrun.h"
|
||||
|
||||
#include "platform/platform.h"
|
||||
|
||||
@ -19,6 +21,8 @@ struct idac_hook_config {
|
||||
struct io4_config io4;
|
||||
struct idac_dll_config dll;
|
||||
struct zinput_config zinput;
|
||||
struct led15070_config led15070;
|
||||
struct indrun_config indrun;
|
||||
};
|
||||
|
||||
void idac_dll_config_load(
|
||||
@ -29,4 +33,10 @@ void idac_hook_config_load(
|
||||
struct idac_hook_config *cfg,
|
||||
const wchar_t *filename);
|
||||
|
||||
void zinput_config_load(struct zinput_config *cfg, const wchar_t *filename);
|
||||
void zinput_config_load(
|
||||
struct zinput_config *cfg,
|
||||
const wchar_t *filename);
|
||||
|
||||
void indrun_config_load(
|
||||
struct indrun_config *cfg,
|
||||
const wchar_t *filename);
|
||||
|
@ -1,3 +1,16 @@
|
||||
/*
|
||||
"Initial D THE ARCADE" (idac) hook
|
||||
|
||||
Devices
|
||||
|
||||
USB: 837-15257 "Type 4" I/O Board
|
||||
COM1: 838-15069 MOTOR DRIVE BD RS232/422 Board
|
||||
COM2: 837-15070-02 IC BD LED Controller Board
|
||||
COM3: 837-15286 "Gen 2" Aime Reader (DIPSW2 OFF)
|
||||
OR
|
||||
837-15396 "Gen 3" Aime Reader (DIPSW2 ON)
|
||||
*/
|
||||
|
||||
#include <windows.h>
|
||||
#include <shlwapi.h>
|
||||
|
||||
@ -53,13 +66,13 @@ static DWORD CALLBACK idac_pre_startup(void)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
hr = sg_reader_hook_init(&idac_hook_cfg.aime, 3, 3, idac_hook_mod);
|
||||
hr = idac_dll_init(&idac_hook_cfg.dll, idac_hook_mod);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
hr = idac_dll_init(&idac_hook_cfg.dll, idac_hook_mod);
|
||||
hr = sg_reader_hook_init(&idac_hook_cfg.aime, 3, 3, idac_hook_mod);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
goto fail;
|
||||
@ -71,6 +84,20 @@ static DWORD CALLBACK idac_pre_startup(void)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
hr = led15070_hook_init(&idac_hook_cfg.led15070, idac_dll.led_init,
|
||||
idac_dll.led_set_fet_output, NULL, idac_dll.led_gs_update, 2, 1);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Initialize native plugin DLL hooks
|
||||
|
||||
There seems to be an issue with other DLL hooks if `LoadLibraryW` is
|
||||
hooked earlier in the initialization. */
|
||||
|
||||
indrun_hook_init(&idac_hook_cfg.indrun);
|
||||
|
||||
/* Initialize debug helpers */
|
||||
|
||||
spike_hook_init(L".\\segatools.ini");
|
||||
|
@ -24,6 +24,18 @@ const struct dll_bind_sym idac_dll_syms[] = {
|
||||
}, {
|
||||
.sym = "idac_io_get_analogs",
|
||||
.off = offsetof(struct idac_dll, get_analogs),
|
||||
}, {
|
||||
.sym = "idac_io_led_init",
|
||||
.off = offsetof(struct idac_dll, led_init),
|
||||
}, {
|
||||
.sym = "idac_io_led_set_fet_output",
|
||||
.off = offsetof(struct idac_dll, led_set_fet_output),
|
||||
}, {
|
||||
.sym = "idac_io_led_gs_update",
|
||||
.off = offsetof(struct idac_dll, led_gs_update),
|
||||
}, {
|
||||
.sym = "idac_io_led_set_leds",
|
||||
.off = offsetof(struct idac_dll, led_set_leds),
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -11,6 +11,10 @@ struct idac_dll {
|
||||
void (*get_gamebtns)(uint8_t *gamebtn);
|
||||
void (*get_shifter)(uint8_t *gear);
|
||||
void (*get_analogs)(struct idac_io_analog_state *out);
|
||||
HRESULT (*led_init)(void);
|
||||
void (*led_set_fet_output)(const uint8_t *rgb);
|
||||
void (*led_gs_update)(const uint8_t *rgb);
|
||||
void (*led_set_leds)(const uint8_t *rgb);
|
||||
};
|
||||
|
||||
struct idac_dll_config {
|
||||
|
@ -17,3 +17,7 @@ EXPORTS
|
||||
idac_io_get_gamebtns
|
||||
idac_io_get_shifter
|
||||
idac_io_get_analogs
|
||||
idac_io_led_init
|
||||
idac_io_led_set_fet_output
|
||||
idac_io_led_gs_update
|
||||
idac_io_led_set_leds
|
||||
|
260
idachook/indrun.c
Normal file
260
idachook/indrun.c
Normal file
@ -0,0 +1,260 @@
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "hook/table.h"
|
||||
|
||||
#include "hooklib/dll.h"
|
||||
|
||||
#include "util/dprintf.h"
|
||||
|
||||
#include "indrun.h"
|
||||
|
||||
static const wchar_t *target_modules[] = {
|
||||
L"IndRun.dll",
|
||||
};
|
||||
|
||||
static const size_t target_modules_len = _countof(target_modules);
|
||||
|
||||
static void dll_hook_insert_hooks(HMODULE target);
|
||||
static void app_hook_insert_hooks(HMODULE target);
|
||||
|
||||
static HMODULE WINAPI hook_LoadLibraryW(const wchar_t *name);
|
||||
static HMODULE (WINAPI *next_LoadLibraryW)(const wchar_t *name);
|
||||
|
||||
static int WINAPI hook_GetSystemMetrics(int nIndex);
|
||||
static int (WINAPI *next_GetSystemMetrics)(int nIndex);
|
||||
|
||||
static BOOL WINAPI hook_GetComputerNameW(LPWSTR lpBuffer, LPDWORD nSize);
|
||||
static DWORD WINAPI hook_GetCurrentDirectoryW( DWORD nBufferLength, LPWSTR lpBuffer);
|
||||
static BOOL WINAPI hook_GetVersionExW(LPOSVERSIONINFOW lpVersionInformation);
|
||||
static int (WINAPI *next_GetVersionExW)(LPOSVERSIONINFOW lpVersionInformation);
|
||||
static BOOL WINAPI hook_VerifyVersionInfoW(LPOSVERSIONINFOEXW lpVersionInformation, DWORD dwTypeMask, DWORDLONG dwlConditionMask);
|
||||
static BOOL (WINAPI *next_VerifyVersionInfoW)(LPOSVERSIONINFOEXW lpVersionInformation, DWORD dwTypeMask, DWORDLONG dwlConditionMask);
|
||||
static BOOL WINAPI hook_K32EnumProcesses(DWORD *lpidProcess, DWORD cb, LPDWORD lpcbNeeded);
|
||||
static BOOL (WINAPI *next_K32EnumProcesses)(DWORD *lpidProcess, DWORD cb, LPDWORD lpcbNeeded);
|
||||
|
||||
static BOOL WINAPI hook_GetUserNameW(LPWSTR lpBuffer, LPDWORD pcbBuffer);
|
||||
|
||||
static const struct hook_symbol idac_app_user32_syms[] = {
|
||||
{
|
||||
.name = "GetSystemMetrics",
|
||||
.patch = hook_GetSystemMetrics,
|
||||
.link = (void **) &next_GetSystemMetrics,
|
||||
}
|
||||
};
|
||||
|
||||
static const struct hook_symbol idac_app_kernel32_syms[] = {
|
||||
{
|
||||
.name = "GetComputerNameW",
|
||||
.patch = hook_GetComputerNameW,
|
||||
},
|
||||
{
|
||||
.name = "GetCurrentDirectoryW",
|
||||
.patch = hook_GetCurrentDirectoryW,
|
||||
},
|
||||
{
|
||||
.name = "GetVersionExW",
|
||||
.patch = hook_GetVersionExW,
|
||||
.link = (void **) &next_GetVersionExW,
|
||||
},
|
||||
{
|
||||
.name = "VerifyVersionInfoW",
|
||||
.patch = hook_VerifyVersionInfoW,
|
||||
.link = (void **) &next_VerifyVersionInfoW,
|
||||
},
|
||||
{
|
||||
.name = "K32EnumProcesses",
|
||||
.patch = hook_K32EnumProcesses,
|
||||
.link = (void **) &next_K32EnumProcesses,
|
||||
}
|
||||
};
|
||||
|
||||
static const struct hook_symbol idac_app_advapi32_syms[] = {
|
||||
{
|
||||
.name = "GetUserNameW",
|
||||
.patch = hook_GetUserNameW,
|
||||
}
|
||||
};
|
||||
|
||||
static const struct hook_symbol indrun_kernel32_syms[] = {
|
||||
{
|
||||
.name = "LoadLibraryW",
|
||||
.patch = hook_LoadLibraryW,
|
||||
.link = (void **) &next_LoadLibraryW,
|
||||
}
|
||||
};
|
||||
|
||||
void indrun_hook_init(struct indrun_config *cfg)
|
||||
{
|
||||
assert(cfg != NULL);
|
||||
|
||||
if (!cfg->enable) {
|
||||
return;
|
||||
}
|
||||
|
||||
dprintf("IDAC: Hooks enabled.\n");
|
||||
|
||||
// GameProject-Win64-Shipping.exe hooks
|
||||
app_hook_insert_hooks(NULL);
|
||||
|
||||
// IndRun.dll hooks
|
||||
dll_hook_insert_hooks(NULL);
|
||||
}
|
||||
|
||||
static void dll_hook_insert_hooks(HMODULE target) {
|
||||
hook_table_apply(
|
||||
target,
|
||||
"kernel32.dll",
|
||||
indrun_kernel32_syms,
|
||||
_countof(indrun_kernel32_syms));
|
||||
}
|
||||
|
||||
void app_hook_insert_hooks(HMODULE target) {
|
||||
hook_table_apply(
|
||||
target,
|
||||
"user32.dll",
|
||||
idac_app_user32_syms,
|
||||
_countof(idac_app_user32_syms));
|
||||
|
||||
hook_table_apply(
|
||||
target,
|
||||
"kernel32.dll",
|
||||
idac_app_kernel32_syms,
|
||||
_countof(idac_app_kernel32_syms));
|
||||
|
||||
hook_table_apply(
|
||||
target,
|
||||
"advapi32.dll",
|
||||
idac_app_advapi32_syms,
|
||||
_countof(idac_app_advapi32_syms));
|
||||
}
|
||||
|
||||
static HMODULE WINAPI hook_LoadLibraryW(const wchar_t *name)
|
||||
{
|
||||
const wchar_t *name_end;
|
||||
const wchar_t *target_module;
|
||||
bool already_loaded;
|
||||
HMODULE result;
|
||||
size_t name_len;
|
||||
size_t target_module_len;
|
||||
|
||||
if (name == NULL) {
|
||||
SetLastError(ERROR_INVALID_PARAMETER);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Check if the module is already loaded
|
||||
already_loaded = GetModuleHandleW(name) != NULL;
|
||||
|
||||
// Must call the next handler so the DLL reference count is incremented
|
||||
result = next_LoadLibraryW(name);
|
||||
|
||||
if (!already_loaded && result != NULL) {
|
||||
name_len = wcslen(name);
|
||||
|
||||
for (size_t i = 0; i < target_modules_len; i++) {
|
||||
target_module = target_modules[i];
|
||||
target_module_len = wcslen(target_module);
|
||||
|
||||
// Check if the newly loaded library is at least the length of
|
||||
// the name of the target module
|
||||
if (name_len < target_module_len) {
|
||||
continue;
|
||||
}
|
||||
|
||||
name_end = &name[name_len - target_module_len];
|
||||
|
||||
// Check if the name of the newly loaded library is one of the
|
||||
// modules the path hooks should be injected into
|
||||
if (_wcsicmp(name_end, target_module) != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
dprintf("IDAC: Hooked %S\n", target_module);
|
||||
|
||||
dll_hook_insert_hooks(result);
|
||||
app_hook_insert_hooks(result);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static int WINAPI hook_GetSystemMetrics(int nIndex) {
|
||||
int ret = next_GetSystemMetrics(nIndex);
|
||||
|
||||
// Disable mouse buttons detection
|
||||
if (nIndex == SM_CMOUSEBUTTONS) {
|
||||
dprintf("IDAC: GetSystemMetrics(%d) -> 0\n", nIndex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static BOOL WINAPI hook_GetComputerNameW(LPWSTR lpBuffer, LPDWORD nSize) {
|
||||
dprintf("IDAC: GetComputerNameW -> ACAE01A99999999\n");
|
||||
|
||||
// Fake the computer name as ACAE01A999999999
|
||||
wcscpy(lpBuffer, L"ACAE01A999999999");
|
||||
*nSize = _countof(L"ACAE01A99999999");
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static DWORD WINAPI hook_GetCurrentDirectoryW(DWORD nBufferLength, LPWSTR lpBuffer) {
|
||||
dprintf("IDAC: GetCurrentDirectoryW -> X:\\\n");
|
||||
|
||||
// Fake the current diretory as X:
|
||||
wcscpy(lpBuffer, L"X");
|
||||
return 1;
|
||||
}
|
||||
|
||||
static BOOL WINAPI hook_GetVersionExW(LPOSVERSIONINFOW lpVersionInformation) {
|
||||
int result = next_GetVersionExW(lpVersionInformation);
|
||||
|
||||
// Fake the version as Windows 10 1809
|
||||
if (result) {
|
||||
dprintf("IDAC: GetVersionExW -> Windows 10 1809\n");
|
||||
lpVersionInformation->dwMajorVersion = 10;
|
||||
lpVersionInformation->dwMinorVersion = 0;
|
||||
lpVersionInformation->dwBuildNumber = 17763;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static BOOL WINAPI hook_GetUserNameW(LPWSTR lpBuffer, LPDWORD pcbBuffer) {
|
||||
dprintf("IDAC: GetUserNameW -> AppUser\n");
|
||||
|
||||
// Fake the user name as AppUser
|
||||
wcscpy(lpBuffer, L"AppUser");
|
||||
*pcbBuffer = _countof(L"AppUser");
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL WINAPI hook_VerifyVersionInfoW(LPOSVERSIONINFOEXW lpVersionInformation, DWORD dwTypeMask, DWORDLONG dwlConditionMask) {
|
||||
BOOL result = next_VerifyVersionInfoW(lpVersionInformation, dwTypeMask, dwlConditionMask);
|
||||
|
||||
// Fake the version as Windows 10 1809
|
||||
if (lpVersionInformation->dwBuildNumber == 17763) {
|
||||
dprintf("IDAC: VerifyVersionInfoW -> Windows 10 1809\n");
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static BOOL WINAPI hook_K32EnumProcesses(DWORD *lpidProcess, DWORD cb, LPDWORD lpcbNeeded) {
|
||||
BOOL result = next_K32EnumProcesses(lpidProcess, cb, lpcbNeeded);
|
||||
|
||||
// Rteurn an empy process list
|
||||
dprintf("IDAC: K32EnumProcesses -> NULL\n");
|
||||
lpidProcess = NULL;
|
||||
*lpcbNeeded = 0;
|
||||
|
||||
return TRUE;
|
||||
}
|
9
idachook/indrun.h
Normal file
9
idachook/indrun.h
Normal file
@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
struct indrun_config {
|
||||
bool enable;
|
||||
};
|
||||
|
||||
void indrun_hook_init(struct indrun_config *cfg);
|
@ -11,10 +11,12 @@
|
||||
#include "util/dprintf.h"
|
||||
|
||||
static HRESULT idac_io4_poll(void *ctx, struct io4_state *state);
|
||||
static HRESULT idac_io4_write_gpio(uint8_t* payload, size_t len);
|
||||
static uint16_t coins;
|
||||
|
||||
static const struct io4_ops idac_io4_ops = {
|
||||
.poll = idac_io4_poll,
|
||||
.write_gpio = idac_io4_write_gpio
|
||||
};
|
||||
|
||||
static const uint16_t idac_gear_signals[] = {
|
||||
@ -128,3 +130,34 @@ static HRESULT idac_io4_poll(void *ctx, struct io4_state *state)
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static HRESULT idac_io4_write_gpio(uint8_t* payload, size_t len)
|
||||
{
|
||||
// Just fast fail if there aren't enough bytes in the payload
|
||||
if (len < 3)
|
||||
return S_OK;
|
||||
|
||||
// This command is used for lights in IDAC, but it only contains button lights,
|
||||
// and only in the first 3 bytes of the payload; everything else is padding to
|
||||
// make the payload 62 bytes. The rest of the cabinet lights and the side button
|
||||
// lights are handled separately, by the 15070 lights controller.
|
||||
uint32_t lights_data = (uint32_t) ((uint8_t)(payload[0]) << 24 |
|
||||
(uint8_t)(payload[1]) << 16 |
|
||||
(uint8_t)(payload[2]) << 8);
|
||||
|
||||
// Since Sega uses an odd ordering for the first part of the bitfield,
|
||||
// let's normalize the data and just send over bytes for the receiver
|
||||
// to interpret as ON/OFF values.
|
||||
uint8_t rgb_out[6] = {
|
||||
lights_data & IDAC_IO_LED_START ? 0xFF : 0x00,
|
||||
lights_data & IDAC_IO_LED_VIEW_CHANGE ? 0xFF : 0x00,
|
||||
lights_data & IDAC_IO_LED_UP ? 0xFF : 0x00,
|
||||
lights_data & IDAC_IO_LED_DOWN ? 0xFF : 0x00,
|
||||
lights_data & IDAC_IO_LED_RIGHT ? 0xFF : 0x00,
|
||||
lights_data & IDAC_IO_LED_LEFT ? 0xFF : 0x00,
|
||||
};
|
||||
|
||||
idac_dll.led_set_leds(rgb_out);
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
@ -28,5 +28,7 @@ shared_library(
|
||||
'io4.h',
|
||||
'zinput.c',
|
||||
'zinput.h',
|
||||
'indrun.c',
|
||||
'indrun.h',
|
||||
],
|
||||
)
|
||||
|
@ -19,7 +19,7 @@ static bool idac_io_coin;
|
||||
|
||||
uint16_t idac_io_get_api_version(void)
|
||||
{
|
||||
return 0x0100;
|
||||
return 0x0101;
|
||||
}
|
||||
|
||||
HRESULT idac_io_init(void)
|
||||
@ -118,3 +118,44 @@ void idac_io_get_analogs(struct idac_io_analog_state *out)
|
||||
out->accel = tmp.accel;
|
||||
out->brake = tmp.brake;
|
||||
}
|
||||
|
||||
HRESULT idac_io_led_init(void)
|
||||
{
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
void idac_io_led_set_fet_output(const uint8_t *rgb)
|
||||
{
|
||||
#if 0
|
||||
dprintf("IDAC LED: LEFT SEAT LED: %02X\n", rgb[0]);
|
||||
dprintf("IDAC LED: RIGHT SEAT LED: %02X\n", rgb[1]);
|
||||
#endif
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void idac_io_led_gs_update(const uint8_t *rgb)
|
||||
{
|
||||
#if 0
|
||||
for (int i = 0; i < 9; i++) {
|
||||
dprintf("IDAC LED: LED %d: %02X %02X %02X Speed: %02X\n",
|
||||
i, rgb[i * 4], rgb[i * 4 + 1], rgb[i * 4 + 2], rgb[i * 4 + 3]);
|
||||
}
|
||||
#endif
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void idac_io_led_set_leds(const uint8_t *rgb)
|
||||
{
|
||||
#if 0
|
||||
dprintf("IDAC LED: START: %02X\n", rgb[0]);
|
||||
dprintf("IDAC LED: VIEW CHANGE: %02X\n", rgb[1]);
|
||||
dprintf("IDAC LED: UP: %02X\n", rgb[2]);
|
||||
dprintf("IDAC LED: DOWN: %02X\n", rgb[3]);
|
||||
dprintf("IDAC LED: RIGHT: %02X\n", rgb[4]);
|
||||
dprintf("IDAC LED: LEFT: %02X\n", rgb[5]);
|
||||
#endif
|
||||
|
||||
return;
|
||||
}
|
||||
|
@ -6,3 +6,7 @@ EXPORTS
|
||||
idac_io_get_gamebtns
|
||||
idac_io_get_shifter
|
||||
idac_io_get_analogs
|
||||
idac_io_led_init
|
||||
idac_io_led_set_fet_output
|
||||
idac_io_led_gs_update
|
||||
idac_io_led_set_leds
|
||||
|
@ -19,6 +19,17 @@ enum {
|
||||
IDAC_IO_GAMEBTN_VIEW_CHANGE = 0x20,
|
||||
};
|
||||
|
||||
enum {
|
||||
/* These are the bitmasks to use when checking which
|
||||
lights are triggered on incoming IO4 GPIO writes. */
|
||||
IDAC_IO_LED_START = 1 << 31,
|
||||
IDAC_IO_LED_VIEW_CHANGE = 1 << 30,
|
||||
IDAC_IO_LED_UP = 1 << 25,
|
||||
IDAC_IO_LED_DOWN = 1 << 24,
|
||||
IDAC_IO_LED_LEFT = 1 << 23,
|
||||
IDAC_IO_LED_RIGHT = 1 << 22,
|
||||
};
|
||||
|
||||
struct idac_io_analog_state {
|
||||
/* Current steering wheel position, where zero is the centered position.
|
||||
|
||||
@ -92,4 +103,60 @@ void idac_io_get_analogs(struct idac_io_analog_state *out);
|
||||
|
||||
Minimum API version: 0x0100 */
|
||||
|
||||
void idac_io_get_shifter(uint8_t *gear);
|
||||
void idac_io_get_shifter(uint8_t *gear);
|
||||
|
||||
/* Initialize LED emulation. This function will be called before any
|
||||
other idac_io_led_*() function calls.
|
||||
|
||||
All subsequent calls may originate from arbitrary threads and some may
|
||||
overlap with each other. Ensuring synchronization inside your IO DLL is
|
||||
your responsibility.
|
||||
|
||||
Minimum API version: 0x0101 */
|
||||
|
||||
HRESULT idac_io_led_init(void);
|
||||
|
||||
/* Update the FET outputs. rgb is a pointer to an array up to 3 bytes.
|
||||
|
||||
The following bits are used to control the FET outputs:
|
||||
[0]: LEFT SEAT LED
|
||||
[1]: RIGHT SEAT LED
|
||||
|
||||
The LED is truned on when the byte is 255 and turned off when the byte is 0.
|
||||
|
||||
Minimum API version: 0x0101 */
|
||||
|
||||
void idac_io_led_set_fet_output(const uint8_t *rgb);
|
||||
|
||||
/* Update the RGB LEDs. rgb is a pointer to an array up to 32 * 4 = 128 bytes.
|
||||
|
||||
The LEDs are laid out as follows:
|
||||
[0]: LEFT UP LED
|
||||
[1-2]: LEFT CENTER LED
|
||||
[3]: LEFT DOWN LED
|
||||
[5]: RIGHT UP LED
|
||||
[6-7]: RIGHT CENTER LED
|
||||
[8]: RIGHT DOWN LED
|
||||
|
||||
Each rgb value is comprised for 4 bytes in the order of R, G, B, Speed.
|
||||
Speed is a value from 0 to 255, where 0 is the fastest speed and 255 is the slowest.
|
||||
|
||||
Minimum API version: 0x0101 */
|
||||
|
||||
void idac_io_led_gs_update(const uint8_t *rgb);
|
||||
|
||||
/* Update the cabinet button LEDs. rgb is a pointer to an array up to 6 bytes.
|
||||
|
||||
The LEDs are laid out as follows:
|
||||
[0]: START LED
|
||||
[1]: VIEW CHANGE LED
|
||||
[2]: UP LED
|
||||
[3]: DOWN LED
|
||||
[4]: RIGHT LED
|
||||
[5]: LEFT LED
|
||||
|
||||
The LED is turned on when the byte is 255 and turned off when the byte is 0.
|
||||
|
||||
Minimum API version: 0x0101 */
|
||||
|
||||
void idac_io_led_set_leds(const uint8_t *rgb);
|
||||
|
@ -1,3 +1,14 @@
|
||||
/*
|
||||
"Initial D ARCADE STAGE Zero" (idz) hook
|
||||
|
||||
Devices
|
||||
|
||||
JVS: 837-15257 "Type 4" I/O Board
|
||||
COM1: 838-15069 MOTOR DRIVE BD RS232/422 Board
|
||||
COM10: 837-15286 "Gen 2" Aime Reader
|
||||
COM11: 837-15070-02 IC BD LED Controller Board
|
||||
*/
|
||||
|
||||
#include <windows.h>
|
||||
#include <shlwapi.h>
|
||||
|
||||
|
@ -46,7 +46,7 @@ void jvs_crack_request(
|
||||
return;
|
||||
}
|
||||
|
||||
#if 0
|
||||
#if defined(LOG_JVS)
|
||||
dprintf("Decoded request:\n");
|
||||
dump_iobuf(&decode);
|
||||
#endif
|
||||
@ -96,7 +96,7 @@ void jvs_crack_request(
|
||||
resp_bytes[2] = 0x01; /* Status: Success */
|
||||
}
|
||||
|
||||
#if 0
|
||||
#if defined(LOG_JVS)
|
||||
dprintf("Encoding response:\n");
|
||||
dump_iobuf(&encode);
|
||||
#endif
|
||||
|
@ -1,3 +1,22 @@
|
||||
/*
|
||||
"maimai DX" (mai2) hook
|
||||
|
||||
Devices
|
||||
|
||||
USB: 837-15257-01 "Type 4" I/O Board
|
||||
USB: 2 * 601-13216 USB "QR Code" Camera (SDEZ2, SDEZ3)
|
||||
USB: 601-13249 USB "Player" Camera (SDEZ1)
|
||||
USB: 837-15067-02 IC BD USB to Serial 232
|
||||
connected to
|
||||
837-15070-04 LED Board Controller (COM21)
|
||||
837-15070-04 LED Board Controller (COM23)
|
||||
|
||||
COM1: 837-15396 "Gen 3" Aime Reader
|
||||
COM2: 200-6275 VFD GP1232A02A FUTABA Board
|
||||
COM3: 509-6483 Touch Panel Controller
|
||||
COM4: 509-6483 Touch Panel Controller
|
||||
*/
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include "board/io4.h"
|
||||
@ -5,6 +24,8 @@
|
||||
#include "board/vfd.h"
|
||||
|
||||
#include "hook/process.h"
|
||||
#include "hook/table.h"
|
||||
#include "hook/iohook.h"
|
||||
|
||||
#include "hooklib/serial.h"
|
||||
#include "hooklib/spike.h"
|
||||
|
@ -1,3 +1,16 @@
|
||||
/*
|
||||
"WACCA" (mercury) hook
|
||||
|
||||
Devices
|
||||
|
||||
USB: 837-15257-01 "Type 4" I/O Board
|
||||
USB: 14-1497-R "Elisabeth" LED Board Controller
|
||||
COM1: 837-15396 "Gen 3" Aime Reader
|
||||
COM2: 200-6275 VFD GP1232A02A FUTABA Board
|
||||
COM3: PSS-7135-L02-01 "Left Side" Touch Board
|
||||
COM4: PSS-7135-L02-01 "Right Sdde" Touch Board
|
||||
*/
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include "board/io4.h"
|
||||
|
@ -130,7 +130,7 @@ static HRESULT touch0_handle_irp_locked(struct irp *irp)
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
#if 0
|
||||
#if defined(LOG_MERCURY_SLIDER)
|
||||
dprintf("TX0 Buffer:\n");
|
||||
dump_iobuf(&touch0_uart.written);
|
||||
#endif
|
||||
@ -177,7 +177,7 @@ static HRESULT touch1_handle_irp_locked(struct irp *irp)
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
#if 0
|
||||
#if defined(LOG_MERCURY_SLIDER)
|
||||
dprintf("TX1 Buffer:\n");
|
||||
dump_iobuf(&touch1_uart.written);
|
||||
#endif
|
||||
@ -305,11 +305,11 @@ static HRESULT touch_handle_get_unit_board_ver(const struct touch_req *req)
|
||||
resp.cmd = 0xa8;
|
||||
resp.checksum = 0;
|
||||
|
||||
if (req->side == 0) {
|
||||
if (req->side == 0) {
|
||||
resp.version[6] = 'R';
|
||||
resp.checksum = calc_checksum(&resp, sizeof(resp));
|
||||
|
||||
#if 0
|
||||
#if defined(LOG_MERCURY_SLIDER)
|
||||
for (int i = 0; i < sizeof(resp.version); i++) {
|
||||
dprintf("0x%02x ", resp.version[i]);
|
||||
}
|
||||
@ -322,7 +322,7 @@ static HRESULT touch_handle_get_unit_board_ver(const struct touch_req *req)
|
||||
resp.version[6] = 'L';
|
||||
resp.checksum = calc_checksum(&resp, sizeof(resp));
|
||||
|
||||
#if 0
|
||||
#if defined(LOG_MERCURY_SLIDER)
|
||||
for (int i = 0; i < sizeof(resp.version); i++) {
|
||||
dprintf("0x%02x ", resp.version[i]);
|
||||
}
|
||||
@ -370,7 +370,7 @@ static HRESULT touch_handle_mystery2(const struct touch_req *req)
|
||||
|
||||
if (req->side == 0) {
|
||||
hr = iobuf_write(&touch0_uart.readable, &resp, sizeof(resp));
|
||||
}
|
||||
}
|
||||
else {
|
||||
hr = iobuf_write(&touch1_uart.readable, &resp, sizeof(resp));
|
||||
}
|
||||
@ -388,7 +388,7 @@ static HRESULT touch_handle_start_auto_scan(const struct touch_req *req)
|
||||
|
||||
dprintf("Wacca Touch%d: Start Auto", req->side);
|
||||
|
||||
#if 0
|
||||
#if defined(LOG_MERCURY_SLIDER)
|
||||
for (int i = 0; i < req->data_length; i++)
|
||||
dprintf("0x%02x ", req->data[i]);
|
||||
#endif
|
||||
@ -451,13 +451,13 @@ static void touch_res_auto_scan(const bool *state)
|
||||
counter++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
memcpy(frame0.data1, dataR, sizeof(dataR));
|
||||
memcpy(frame0.data2, data2, sizeof(data2));
|
||||
|
||||
memcpy(frame1.data1, dataL, sizeof(dataL));
|
||||
memcpy(frame1.data2, data2, sizeof(data2));
|
||||
|
||||
|
||||
frame0.checksum = 0;
|
||||
frame0.checksum = calc_checksum(&frame0, sizeof(frame0));
|
||||
|
||||
|
37
meson.build
37
meson.build
@ -39,6 +39,43 @@ if cc.get_id() != 'msvc'
|
||||
)
|
||||
endif
|
||||
|
||||
if get_option('log_all') or get_option('log_jvs')
|
||||
add_project_arguments('-DLOG_JVS', language: 'c')
|
||||
endif
|
||||
if get_option('log_all') or get_option('log_io3')
|
||||
add_project_arguments('-DLOG_IO3', language: 'c')
|
||||
endif
|
||||
if get_option('log_all') or get_option('log_led15093')
|
||||
add_project_arguments('-DLOG_LED15093', language: 'c')
|
||||
endif
|
||||
if get_option('log_all') or get_option('log_nfc')
|
||||
add_project_arguments('-DLOG_NFC', language: 'c')
|
||||
endif
|
||||
if get_option('log_all') or get_option('log_carol_control_bd')
|
||||
add_project_arguments('-DLOG_CAROL_CONTROL_BD', language: 'c')
|
||||
endif
|
||||
if get_option('log_all') or get_option('log_carol_led_bd')
|
||||
add_project_arguments('-DLOG_CAROL_LED_BD', language: 'c')
|
||||
endif
|
||||
if get_option('log_all') or get_option('log_carol_touch')
|
||||
add_project_arguments('-DLOG_CAROL_TOUCH', language: 'c')
|
||||
endif
|
||||
if get_option('log_all') or get_option('log_chuni_slider')
|
||||
add_project_arguments('-DLOG_CHUNI_SLIDER', language: 'c')
|
||||
endif
|
||||
if get_option('log_all') or get_option('log_chusan_slider')
|
||||
add_project_arguments('-DLOG_CHUSAN_SLIDER', language: 'c')
|
||||
endif
|
||||
if get_option('log_all') or get_option('log_diva_slider')
|
||||
add_project_arguments('-DLOG_DIVA_SLIDER', language: 'c')
|
||||
endif
|
||||
if get_option('log_all') or get_option('log_mercury_slider')
|
||||
add_project_arguments('-DLOG_MERCURY_SLIDER', language: 'c')
|
||||
endif
|
||||
if get_option('log_all') or get_option('log_clock')
|
||||
add_project_arguments('-DLOG_CLOCK', language: 'c')
|
||||
endif
|
||||
|
||||
shlwapi_lib = cc.find_library('shlwapi')
|
||||
dinput8_lib = cc.find_library('dinput8')
|
||||
dxguid_lib = cc.find_library('dxguid')
|
||||
|
65
meson_options.txt
Normal file
65
meson_options.txt
Normal file
@ -0,0 +1,65 @@
|
||||
option('log_all',
|
||||
type : 'boolean',
|
||||
value : false,
|
||||
description : 'Enables all of the subsequent debug logging options'
|
||||
)
|
||||
option('log_jvs',
|
||||
type : 'boolean',
|
||||
value : false,
|
||||
description : 'Enable debug logging for JVS'
|
||||
)
|
||||
option('log_io3',
|
||||
type : 'boolean',
|
||||
value : false,
|
||||
description : 'Enable debug logging for JVS'
|
||||
)
|
||||
option('log_led15093',
|
||||
type : 'boolean',
|
||||
value : false,
|
||||
description : 'Enable debug logging for the 15093 LED board emulation'
|
||||
)
|
||||
option('log_nfc',
|
||||
type : 'boolean',
|
||||
value : false,
|
||||
description : 'Enable debug logging for NFC'
|
||||
)
|
||||
option('log_carol_control_bd',
|
||||
type : 'boolean',
|
||||
value : false,
|
||||
description : 'Enable debug logging for the Carlo Control Board'
|
||||
)
|
||||
option('log_carol_led_bd',
|
||||
type : 'boolean',
|
||||
value : false,
|
||||
description : 'Enable debug logging for the Carlo LED Board'
|
||||
)
|
||||
option('log_carol_touch',
|
||||
type : 'boolean',
|
||||
value : false,
|
||||
description : 'Enable debug logging for the Carlo Touchscreen'
|
||||
)
|
||||
option('log_chuni_slider',
|
||||
type : 'boolean',
|
||||
value : false,
|
||||
description : 'Enable debug logging for the Chunithm Slider'
|
||||
)
|
||||
option('log_chusan_slider',
|
||||
type : 'boolean',
|
||||
value : false,
|
||||
description : 'Enable debug logging for the Chusan Slider'
|
||||
)
|
||||
option('log_diva_slider',
|
||||
type : 'boolean',
|
||||
value : false,
|
||||
description : 'Enable debug logging for the Diva Slider'
|
||||
)
|
||||
option('log_mercury_slider',
|
||||
type : 'boolean',
|
||||
value : false,
|
||||
description : 'Enable debug logging for the WACCA Slider'
|
||||
)
|
||||
option('log_clock',
|
||||
type : 'boolean',
|
||||
value : false,
|
||||
description : 'Enable debug logging for clock APIs'
|
||||
)
|
@ -1,3 +1,15 @@
|
||||
/*
|
||||
"O.N.G.E.K.I." (mu3) hook
|
||||
|
||||
Devices
|
||||
|
||||
USB: 837-15257-01 "Type 4" I/O Board
|
||||
USB: 3 * 601-13216 USB "QR Code" Camera (SDDT1-SDDT3)
|
||||
COM1: 837-15396 "Gen 3" Aime Reader
|
||||
COM2: 200-6275 VFD GP1232A02A FUTABA Board
|
||||
COM3: 837-15093-06 LED Controller Board
|
||||
*/
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
|
@ -151,7 +151,7 @@ HRESULT mu3_io_led_init(void);
|
||||
that the board 0 is called from mu3 and the board 1 is called from amdaemon.
|
||||
So the library must be able to handle both calls, using shared memory f.e.
|
||||
This is up to the developer to decide how to handle this, recommended way is
|
||||
to use the amdaemon process as the main one and the mu3 call as a sub one.
|
||||
to use the amdaemon process as the main one and the mu3 process as a sub one.
|
||||
|
||||
Minimum API version: 0x0101 */
|
||||
|
||||
|
@ -158,7 +158,7 @@ static BOOL WINAPI my_GetSystemTime(SYSTEMTIME *out)
|
||||
return ok;
|
||||
}
|
||||
|
||||
#if 0
|
||||
#if defined(LOG_CLOCK)
|
||||
static int last_second;
|
||||
|
||||
if (out->wSecond != last_second) {
|
||||
|
@ -105,6 +105,21 @@ HRESULT dns_platform_hook_init(const struct dns_config *cfg)
|
||||
|
||||
hr = dns_hook_push(L"shop.tfps.thincacloud.com", cfg->startup);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
// CHN
|
||||
// PowerOn
|
||||
hr = dns_hook_push(L"at.sys-all.cn", cfg->startup);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
// WeChat AimeDB Server
|
||||
hr = dns_hook_push(L"ai.sys-all.cn", cfg->aimedb);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
|
@ -76,7 +76,7 @@ HRESULT platform_hook_init(
|
||||
return hr;
|
||||
}
|
||||
|
||||
hr = vfs_hook_init(&cfg->vfs);
|
||||
hr = vfs_hook_init(&cfg->vfs, game_id);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
|
@ -9,6 +9,9 @@
|
||||
#include "hooklib/path.h"
|
||||
#include "hooklib/reg.h"
|
||||
|
||||
#include "hook/procaddr.h"
|
||||
#include "hook/table.h"
|
||||
|
||||
#include "platform/vfs.h"
|
||||
|
||||
#include "util/dprintf.h"
|
||||
@ -31,6 +34,26 @@ static HRESULT vfs_path_hook_option(
|
||||
static HRESULT vfs_reg_read_amfs(void *bytes, uint32_t *nbytes);
|
||||
static HRESULT vfs_reg_read_appdata(void *bytes, uint32_t *nbytes);
|
||||
|
||||
static wchar_t* hook_System_getAppRootPath();
|
||||
static wchar_t* (*next_System_getAppRootPath)();
|
||||
|
||||
static wchar_t* hook_AppImage_getOptionMountRootPath();
|
||||
static wchar_t* (*next_AppImage_getOptionMountRootPath)();
|
||||
|
||||
static const struct hook_symbol amdaemon_syms[] = {
|
||||
{
|
||||
.name = "System_getAppRootPath",
|
||||
.patch = hook_System_getAppRootPath,
|
||||
.link = (void **) &next_System_getAppRootPath,
|
||||
},
|
||||
{
|
||||
.name = "AppImage_getOptionMountRootPath",
|
||||
.patch = hook_AppImage_getOptionMountRootPath,
|
||||
.link = (void **) &next_AppImage_getOptionMountRootPath,
|
||||
},
|
||||
};
|
||||
|
||||
static wchar_t game[5] = {0};
|
||||
static wchar_t vfs_nthome_real[MAX_PATH];
|
||||
static const wchar_t vfs_nthome[] = L"C:\\Documents and Settings\\AppUser";
|
||||
static const size_t vfs_nthome_len = _countof(vfs_nthome) - 1;
|
||||
@ -55,7 +78,7 @@ static const struct reg_hook_val vfs_reg_vals[] = {
|
||||
|
||||
static struct vfs_config vfs_config;
|
||||
|
||||
HRESULT vfs_hook_init(const struct vfs_config *config)
|
||||
HRESULT vfs_hook_init(const struct vfs_config *config, const char* game_id)
|
||||
{
|
||||
wchar_t temp[MAX_PATH];
|
||||
size_t nthome_len;
|
||||
@ -68,6 +91,8 @@ HRESULT vfs_hook_init(const struct vfs_config *config)
|
||||
return S_FALSE;
|
||||
}
|
||||
|
||||
mbstowcs(game, game_id, 4);
|
||||
|
||||
if (config->amfs[0] == L'\0') {
|
||||
dprintf("Vfs: FATAL: AMFS path not specified in INI file\n");
|
||||
|
||||
@ -175,6 +200,13 @@ HRESULT vfs_hook_init(const struct vfs_config *config)
|
||||
return hr;
|
||||
}
|
||||
|
||||
proc_addr_table_push(
|
||||
NULL,
|
||||
"amdaemon_api.dll",
|
||||
amdaemon_syms,
|
||||
_countof(amdaemon_syms)
|
||||
);
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
@ -287,8 +319,6 @@ 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;
|
||||
@ -479,3 +509,21 @@ static HRESULT vfs_reg_read_appdata(void *bytes, uint32_t *nbytes)
|
||||
{
|
||||
return reg_hook_read_wstr(bytes, nbytes, L"Y:\\");
|
||||
}
|
||||
|
||||
static wchar_t* hook_System_getAppRootPath()
|
||||
{
|
||||
wchar_t *path = malloc(sizeof(wchar_t) * MAX_PATH);
|
||||
wcscpy_s(path, MAX_PATH, vfs_config.appdata);
|
||||
wcscat_s(path, MAX_PATH, game);
|
||||
wcscat_s(path, MAX_PATH, L"\\");
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
static wchar_t* hook_AppImage_getOptionMountRootPath()
|
||||
{
|
||||
wchar_t *path = malloc(sizeof(wchar_t) * MAX_PATH);
|
||||
wcscpy_s(path, MAX_PATH, vfs_config.option);
|
||||
|
||||
return path;
|
||||
}
|
||||
|
@ -12,4 +12,4 @@ struct vfs_config {
|
||||
wchar_t option[MAX_PATH];
|
||||
};
|
||||
|
||||
HRESULT vfs_hook_init(const struct vfs_config *config);
|
||||
HRESULT vfs_hook_init(const struct vfs_config *config, const char* game_id);
|
||||
|
456
segatools.md
456
segatools.md
@ -1,456 +0,0 @@
|
||||
# Segatools common configuration settings
|
||||
|
||||
This file describes configuration settings for Segatools that are common to
|
||||
all games.
|
||||
|
||||
Keyboard binding settings use
|
||||
[Virtual-Key Codes](https://docs.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes).
|
||||
|
||||
## `[aimeio]`
|
||||
|
||||
Controls the card reader driver.
|
||||
|
||||
### `path`
|
||||
|
||||
Specify a path for a third-party card reader driver DLL. Default is empty
|
||||
(use built-in emulation based on text files and keyboard input).
|
||||
|
||||
In previous versions of Segatools this was accomplished by replacing the
|
||||
AIMEIO.DLL file that came with Segatools. Segatools no longer ships with a
|
||||
separate AIMEIO.DLL file (its functionality is now built into the various hook
|
||||
DLLs).
|
||||
|
||||
## `[aime]`
|
||||
|
||||
Controls emulation of the Aime card reader assembly.
|
||||
|
||||
### `enable`
|
||||
|
||||
Default: `1`
|
||||
|
||||
Enable Aime card reader assembly emulation. Disable to use a real SEGA Aime
|
||||
reader (COM port number varies by game).
|
||||
|
||||
### `aimePath`
|
||||
|
||||
Default: `DEVICE\aime.txt`
|
||||
|
||||
Path to a text file containing a classic Aime IC card ID. **This does not
|
||||
currently work**.
|
||||
|
||||
### `felicaPath`
|
||||
|
||||
Default: `DEVICE\felica.txt`
|
||||
|
||||
Path to a text file containing a FeliCa e-cash card IDm serial number.
|
||||
|
||||
### `felicaGen`
|
||||
|
||||
Default: `1`
|
||||
|
||||
Whether to generate a random FeliCa ID if the file at `felicaPath` does not
|
||||
exist.
|
||||
|
||||
### `scan`
|
||||
|
||||
Default: `0x0D` (`VK_RETURN`)
|
||||
|
||||
Virtual-key code. If this button is **held** then the emulated IC card reader
|
||||
emulates an IC card in its proximity. A variety of different IC cards can be
|
||||
emulated; the exact choice of card that is emulated depends on the presence or
|
||||
absence of the configured card ID files.
|
||||
|
||||
## `[amvideo]`
|
||||
|
||||
Controls the `amvideo.dll` stub built into Segatools. This is a DLL that is
|
||||
normally present on the SEGA operating system image which is responsible for
|
||||
changing screen resolution and orientation.
|
||||
|
||||
### `enable`
|
||||
|
||||
Default: `1`
|
||||
|
||||
Enable stub `amvideo.dll`. Disable to use a real `amvideo.dll` build. Note that
|
||||
you must have the correct registry settings installed and you must use the
|
||||
version of `amvideo.dll` that matches your GPU vendor (since these DLLs make
|
||||
use of vendor-specific APIs).
|
||||
|
||||
## `[clock]`
|
||||
|
||||
Controls hooks for Windows time-of-day APIs.
|
||||
|
||||
### `timezone`
|
||||
|
||||
Default: `1`
|
||||
|
||||
Make the system time zone appear to be JST. SEGA games malfunction in strange
|
||||
ways if the system time zone is not JST. There should not be any reason to
|
||||
disable this hook other than possible implementation bugs, but the option is
|
||||
provided if you need it.
|
||||
|
||||
### `timewarp`
|
||||
|
||||
Default: `0`
|
||||
|
||||
Experimental time-of-day warping hook that skips over the hardcoded server
|
||||
maintenance period. Causes an incorrect in-game time-of-day to be reported.
|
||||
Better solutions for this problem exist and this feature will probably be
|
||||
removed soon.
|
||||
|
||||
### `writeable`
|
||||
|
||||
Default: `0`
|
||||
|
||||
Allow game to adjust system clock and time zone settings. This should normally
|
||||
be left at `0`, but the option is provided if you need it.
|
||||
|
||||
## `[dns]`
|
||||
|
||||
Controls redirection of network server hostname lookups
|
||||
|
||||
### `default`
|
||||
|
||||
Default: `localhost`
|
||||
|
||||
Controls hostname of all of the common network services servers, unless
|
||||
overriden by a specific setting below. Most users will only need to change this
|
||||
setting. Also, loopback addresses are specifically checked for and rejected by
|
||||
the games themselves; this needs to be a LAN or WAN IP (or a hostname that
|
||||
resolves to one).
|
||||
|
||||
### `router`
|
||||
|
||||
Default: Empty string (i.e. use value from `default` setting)
|
||||
|
||||
Overrides the target of the `tenporouter.loc` and `bbrouter.loc` hostname
|
||||
lookups.
|
||||
|
||||
### `startup`
|
||||
|
||||
Default: Empty string (i.e. use value from `default` setting)
|
||||
|
||||
Overrides the target of the `naominet.jp` host lookup.
|
||||
|
||||
### `billing`
|
||||
|
||||
Default: Empty string (i.e. use value from `default` setting)
|
||||
|
||||
Overrides the target of the `ib.naominet.jp` host lookup.
|
||||
|
||||
### `aimedb`
|
||||
|
||||
Default: Empty string (i.e. use value from `default` setting)
|
||||
|
||||
Overrides the target of the `aime.naominet.jp` host lookup.
|
||||
|
||||
## `[ds]`
|
||||
|
||||
Controls emulation of the "DS (Dallas Semiconductor) EEPROM" chip on the AMEX
|
||||
PCIe board. This is a small (32 byte) EEPROM that contains serial number and
|
||||
region code information. It is not normally written to outside of inital
|
||||
factory provisioning of a Sega Nu.
|
||||
|
||||
### `enable`
|
||||
|
||||
Default: `1`
|
||||
|
||||
Enable DS EEPROM emulation. Disable to use the DS EEPROM chip on a real AMEX.
|
||||
|
||||
### `region`
|
||||
|
||||
Default: `1`
|
||||
|
||||
AMEX Board region code. This appears to be a bit mask?
|
||||
|
||||
- `1`: Japan
|
||||
- `2`: USA? (Dead code, not used)
|
||||
- `4`: Export
|
||||
- `8`: China
|
||||
|
||||
### `serialNo`
|
||||
|
||||
Default `AAVE-01A99999999`
|
||||
|
||||
"MAIN ID" serial number. First three characters are hardware series:
|
||||
|
||||
- `AAV`: Nu-series
|
||||
- `AAW`: NuSX-series
|
||||
- `ACA`: ALLS-series
|
||||
|
||||
## `[eeprom]`
|
||||
|
||||
Controls emulation of the bulk EEPROM on the AMEX PCIe board. This chip stores
|
||||
status and configuration information.
|
||||
|
||||
### `enable`
|
||||
|
||||
Default: `1`
|
||||
|
||||
Enable bulk EEPROM emulation. Disable to use the bulk EEPROM chip on a real
|
||||
AMEX.
|
||||
|
||||
### `path`
|
||||
|
||||
Default: `DEVICE\eeprom.bin`
|
||||
|
||||
Path to the storage file for EEPROM emulation. This file is automatically
|
||||
created and initialized with a suitable number of zero bytes if it does not
|
||||
already exist.
|
||||
|
||||
## `[gpio]`
|
||||
|
||||
Configure emulation of the AMEX PCIe GPIO (General Purpose Input Output)
|
||||
controller.
|
||||
|
||||
### `enable`
|
||||
|
||||
Default: `1`
|
||||
|
||||
Enable GPIO emulation. Disable to use the GPIO controller on a real AMEX.
|
||||
|
||||
### `sw1`
|
||||
|
||||
Default `0x70` (`VK_F1`)
|
||||
|
||||
Keyboard binding for Nu chassis SW1 button (alternative Test)
|
||||
|
||||
### `sw2`
|
||||
|
||||
Default `0x71` (`VK_F2`)
|
||||
|
||||
Keyboard binding for Nu chassis SW2 button (alternative Service)
|
||||
|
||||
### `dipsw1` .. `dipsw8`
|
||||
|
||||
Defaults: `1`, `0`, `0`, `0`, `0`, `0`, `0`, `0`
|
||||
|
||||
Nu chassis DIP switch settings:
|
||||
|
||||
- Switch 1: Game-specific, but usually controls the "distribution server"
|
||||
setting. Exactly one arcade machine on a cabinet router must be set to the
|
||||
Server setting.
|
||||
- `0`: Client
|
||||
- `1`: Server
|
||||
- Switch 2,3: Game-specific.
|
||||
- Used by Mario&Sonic to configure cabinet ID, possibly other games.
|
||||
- Switch 4: Screen orientation. Only used by the Nu system startup program.
|
||||
- `0`: YOKO/Horizontal
|
||||
- `1`: TATE/Vertical
|
||||
- Switch 5,6,7: Screen resolution. Only used by the Nu system startup program.
|
||||
- `000`: No change
|
||||
- `100`: 640x480
|
||||
- `010`: 1024x600
|
||||
- `110`: 1024x768
|
||||
- `001`: 1280x720
|
||||
- `101`: 1280x1024
|
||||
- `110`: 1360x768
|
||||
- `111`: 1920x1080
|
||||
- Switch 8: Game-specific. Not used in any shipping game.
|
||||
|
||||
## `[hwmon]`
|
||||
|
||||
Configure stub implementation of the platform hardware monitor driver. The
|
||||
real implementation of this driver monitors CPU temperatures by reading from
|
||||
Intel Model Specific Registers, which is an action that is only permitted from
|
||||
kernel mode.
|
||||
|
||||
### `enable`
|
||||
|
||||
Default `1`
|
||||
|
||||
Enable hwmon emulation. Disable to use the real hwmon driver.
|
||||
|
||||
## `[jvs]`
|
||||
|
||||
Configure emulation of the AMEX PCIe JVS *controller* (not IO board!)
|
||||
|
||||
### `enable`
|
||||
|
||||
Default `1`
|
||||
|
||||
Enable JVS port emulation. Disable to use the JVS port on a real AMEX.
|
||||
|
||||
## `[keychip]`
|
||||
|
||||
Configure keychip emulation.
|
||||
|
||||
### `enable`
|
||||
|
||||
Enable keychip emulation. Disable to use a real keychip.
|
||||
|
||||
### `id`
|
||||
|
||||
Default: `A69E-01A88888888`
|
||||
|
||||
Keychip serial number. Keychip serials observed in the wild follow this
|
||||
pattern: `A\d{2}(E01|X20)[ABCDU]\d{8}`.
|
||||
|
||||
### `gameId`
|
||||
|
||||
Default: (Varies depending on game)
|
||||
|
||||
Override the game's four-character model code. Changing this from the game's
|
||||
expected value will probably just cause a system error.
|
||||
|
||||
### `platformId`
|
||||
|
||||
Default: (Varies depending on game)
|
||||
|
||||
Override the game's four-character platform code (e.g. `AAV2` for Nu 2). This
|
||||
is actually supposed to be a separate three-character `platformId` and
|
||||
integer `modelType` setting, but they are combined here for convenience. Valid
|
||||
values include:
|
||||
|
||||
- `AAV0`: Nu 1 (Project DIVA)
|
||||
- `AAV1`: Nu 1.1 (Chunithm)
|
||||
- `AAV2`: Nu 2 (Initial D Zero)
|
||||
- `AAW0`: NuSX 1
|
||||
- `AAW1`: NuSX 1.1
|
||||
- `ACA0`: ALLS UX
|
||||
- `ACA1`: ALLS HX
|
||||
- `ACA2`: ALLS UX (without dedicated GPU)
|
||||
- `ACA4`: ALLS MX
|
||||
|
||||
### `region`
|
||||
|
||||
Default: `1`
|
||||
|
||||
Override the keychip's region code. Most games seem to pay attention to the
|
||||
DS EEPROM region code and not the keychip region code, and this seems to be
|
||||
a bit mask that controls which Nu PCB region codes this keychip is authorized
|
||||
for. So it probably only affects the system software and not the game software.
|
||||
Bit values are:
|
||||
|
||||
- 1: JPN: Japan
|
||||
- 2: USA (unused)
|
||||
- 3: EXP: Export (for Asian markets)
|
||||
- 4: CHS: China (Simplified Chinese?)
|
||||
|
||||
### `systemFlag`
|
||||
|
||||
Default: `0x64`
|
||||
|
||||
An 8-bit bitfield of unclear meaning. The least significant bit indicates a
|
||||
developer dongle, I think? Changing this doesn't seem to have any effect on
|
||||
anything other than Project DIVA.
|
||||
|
||||
Other values observed in the wild:
|
||||
|
||||
- `0x04`: SDCH, SDCA
|
||||
- `0x20`: SDCA
|
||||
|
||||
### `subnet`
|
||||
|
||||
Default `192.168.100.0`
|
||||
|
||||
The LAN IP range that the game will expect. The prefix length is hardcoded into
|
||||
the game program: for some games this is `/24`, for others it is `/20`.
|
||||
|
||||
## `[netenv]`
|
||||
|
||||
Configure network environment virtualization. This module helps bypass various
|
||||
restrictions placed upon the game's LAN environment.
|
||||
|
||||
### `enable`
|
||||
|
||||
Default `1`
|
||||
|
||||
Enable network environment virtualization. You may need to disable this if
|
||||
you want to do any head-to-head play on your LAN.
|
||||
|
||||
Note: The virtualized LAN IP range is taken from the emulated keychip's
|
||||
`subnet` setting.
|
||||
|
||||
### `addrSuffix`
|
||||
|
||||
Default: `11`
|
||||
|
||||
The final octet of the local host's IP address on the virtualized subnet (so,
|
||||
if the keychip subnet is `192.168.32.0` and this value is set to `11`, then the
|
||||
local host's virtualized LAN IP is `192.168.32.11`).
|
||||
|
||||
### `routerSuffix`
|
||||
|
||||
Default: `1`
|
||||
|
||||
The final octet of the default gateway's IP address on the virtualized subnet.
|
||||
|
||||
### `macAddr`
|
||||
|
||||
Default: `01:02:03:04:05:06`
|
||||
|
||||
The MAC address of the virtualized Ethernet adapter. The exact value shouldn't
|
||||
ever matter.
|
||||
|
||||
## `[pcbid]`
|
||||
|
||||
Configure Windows host name virtualization. The ALLS-series platform no longer
|
||||
has an AMEX board, so the MAIN ID serial number is stored in the Windows
|
||||
hostname.
|
||||
|
||||
### `enable`
|
||||
|
||||
Default: `1`
|
||||
|
||||
Enable Windows host name virtualization. This is only needed for ALLS-platform
|
||||
games (since the ALLS lacks an AMEX and therefore has no DS EEPROM, so it needs
|
||||
another way to store the PCB serial), but it does no harm on games that run on
|
||||
earlier hardware.
|
||||
|
||||
### `serialNo`
|
||||
|
||||
Default: `ACAE01A99999999`
|
||||
|
||||
Set the Windows host name. This should be an ALLS MAIN ID, without the
|
||||
hyphen (which is not a valid character in a Windows host name).
|
||||
|
||||
## `[sram]`
|
||||
|
||||
Configure emulation of the AMEX PCIe battery-backed SRAM. This stores
|
||||
bookkeeping state and settings. This file is automatically created and
|
||||
initialized with a suitable number of zero bytes if it does not already exist.
|
||||
|
||||
### `enable`
|
||||
|
||||
Default `1`
|
||||
|
||||
Enable SRAM emulation. Disable to use the SRAM on a real AMEX.
|
||||
|
||||
### `path`
|
||||
|
||||
Default `DEVICE\sram.bin`
|
||||
|
||||
Path to the storage file for SRAM emulation.
|
||||
|
||||
## `[vfs]`
|
||||
|
||||
Configure Windows path redirection hooks.
|
||||
|
||||
### `enable`
|
||||
|
||||
Default: `1`
|
||||
|
||||
Enable path redirection.
|
||||
|
||||
### `amfs`
|
||||
|
||||
Default: Empty string (causes a startup error)
|
||||
|
||||
Configure the location of the SEGA AMFS volume. Stored on the `E` partition on
|
||||
real hardware.
|
||||
|
||||
### `appdata`
|
||||
|
||||
Default: Empty string (causes a startup error)
|
||||
|
||||
Configure the location of the SEGA "APPDATA" volume (nothing to do with the
|
||||
Windows user's `%APPDATA%` directory). Stored on the `Y` partition on real
|
||||
hardware.
|
||||
|
||||
### `option`
|
||||
|
||||
Default: Empty string
|
||||
|
||||
Configure the location of the "Option" data mount point. This mount point is
|
||||
optional (hence the name, probably) and contains directories which contain
|
||||
minor over-the-air content updates.
|
@ -1,3 +1,18 @@
|
||||
/*
|
||||
"SEGA World Drivers Championship" (swdc) hook
|
||||
|
||||
Devices
|
||||
|
||||
USB: 837-15257 "Type 4" I/O Board
|
||||
USB: 838-15415 Indicator BD Main Board (COM21)
|
||||
WITH
|
||||
838-15416 Indicator BD LED Board
|
||||
COM1: 838-15069 MOTOR DRIVE BD RS232/422 board
|
||||
COM2: 837-15396 "Gen 3" Aime reader
|
||||
COM3: 837-15070-04 IC BD LED controller board
|
||||
COM4: 200-6275 VFD GP1232A02A FUTABA board
|
||||
*/
|
||||
|
||||
#include <windows.h>
|
||||
#include <shlwapi.h>
|
||||
|
||||
|
@ -24,11 +24,13 @@ static const wchar_t *target_modules[] = {
|
||||
L"mono.dll",
|
||||
L"mono-2.0-bdwgc.dll",
|
||||
L"cri_ware_unity.dll",
|
||||
L"amdaemon_api.dll",
|
||||
L"SerialPortAPI.dll",
|
||||
L"C300usb.dll",
|
||||
L"C300FWDLusb.dll",
|
||||
L"apmled.dll",
|
||||
L"apmmount.dll",
|
||||
L"HKBSys_api.dll",
|
||||
L"amptw.dll"
|
||||
};
|
||||
|
||||
static const size_t target_modules_len = _countof(target_modules);
|
||||
@ -138,9 +140,7 @@ static HMODULE WINAPI hook_LoadLibraryW(const wchar_t *name)
|
||||
path_hook_insert_hooks(result);
|
||||
|
||||
// printer_hook_insert_hooks(result);
|
||||
|
||||
reg_hook_insert_hooks(result);
|
||||
|
||||
proc_addr_insert_hooks(result);
|
||||
serial_hook_apply_hooks(result);
|
||||
iohook_apply_hooks(result);
|
||||
|
Reference in New Issue
Block a user