260 lines
7.2 KiB
C
260 lines
7.2 KiB
C
#include <assert.h>
|
|
#include <stdlib.h>
|
|
|
|
#include "hooklib/fdshark.h"
|
|
#include "hooklib/reg.h"
|
|
|
|
#include "mai2hook/mai2-dll.h"
|
|
#include "mai2hook/touch.h"
|
|
|
|
#include "util/dprintf.h"
|
|
#include "util/dump.h"
|
|
|
|
|
|
static HRESULT read_reg_touch_1p(void *bytes, uint32_t *nbytes)
|
|
{
|
|
return reg_hook_read_wstr(bytes, nbytes, L"COM3");
|
|
}
|
|
|
|
static HRESULT read_reg_touch_2p(void *bytes, uint32_t *nbytes)
|
|
{
|
|
return reg_hook_read_wstr(bytes, nbytes, L"COM4");
|
|
}
|
|
|
|
static const struct reg_hook_val touch_reg_key[] = {
|
|
{
|
|
.name = L"\\Device\\RealTouchBoard0",
|
|
.read = read_reg_touch_1p,
|
|
.type = REG_SZ,
|
|
},
|
|
{
|
|
.name = L"\\Device\\RealTouchBoard1",
|
|
.read = read_reg_touch_2p,
|
|
.type = REG_SZ,
|
|
},
|
|
};
|
|
|
|
const char *sensor_map[34] = {
|
|
"A1", "A2", "A3", "A4", "A5", "A6", "A7", "A8", // 0x41 - 0x48
|
|
"B1", "B2", "B3", "B4", "B5", "B6", "B7", "B8", // 0x49 - 0x50
|
|
"C1", "C2", // 0x51 - 0x52
|
|
"D1", "D2", "D3", "D4", "D5", "D6", "D7", "D8", // 0x53 - 0x5A
|
|
"E1", "E2", "E3", "E4", "E5", "E6", "E7", "E8" // 0x5B - 0x62
|
|
};
|
|
|
|
const char *sensor_to_str(uint8_t sensor)
|
|
{
|
|
if (sensor < 0x41 || sensor > 0x62)
|
|
{
|
|
return "Invalid";
|
|
}
|
|
|
|
return sensor_map[sensor - 0x41];
|
|
}
|
|
|
|
static CRITICAL_SECTION touch_1p_lock;
|
|
static struct uart touch_1p_uart;
|
|
static uint8_t touch_1p_written_bytes[64];
|
|
static uint8_t touch_1p_readable_bytes[64];
|
|
static bool touch_1p_status = false;
|
|
|
|
static CRITICAL_SECTION touch_2p_lock;
|
|
static struct uart touch_2p_uart;
|
|
static uint8_t touch_2p_written_bytes[64];
|
|
static uint8_t touch_2p_readable_bytes[64];
|
|
static bool touch_2p_status = false;
|
|
|
|
HRESULT touch_hook_init(const struct touch_config *cfg)
|
|
{
|
|
assert(cfg != NULL);
|
|
|
|
if (!cfg->enable_1p && !cfg->enable_2p)
|
|
{
|
|
return S_FALSE;
|
|
}
|
|
|
|
HRESULT hr = reg_hook_push_key(HKEY_LOCAL_MACHINE, L"HARDWARE\\DEVICEMAP\\SERIALCOMM", touch_reg_key, _countof(touch_reg_key));
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
return hr;
|
|
}
|
|
|
|
if (cfg->enable_1p)
|
|
{
|
|
dprintf("Mai2 touch 1P: Init.\n");
|
|
|
|
InitializeCriticalSection(&touch_1p_lock);
|
|
uart_init(&touch_1p_uart, 3);
|
|
touch_1p_uart.written.bytes = touch_1p_written_bytes;
|
|
touch_1p_uart.written.nbytes = sizeof(touch_1p_written_bytes);
|
|
touch_1p_uart.readable.bytes = touch_1p_readable_bytes;
|
|
touch_1p_uart.readable.nbytes = sizeof(touch_1p_readable_bytes);
|
|
}
|
|
|
|
if (cfg->enable_2p)
|
|
{
|
|
dprintf("Mai2 touch 2P: Init.\n");
|
|
|
|
InitializeCriticalSection(&touch_2p_lock);
|
|
uart_init(&touch_2p_uart, 4);
|
|
touch_2p_uart.written.bytes = touch_2p_written_bytes;
|
|
touch_2p_uart.written.nbytes = sizeof(touch_2p_written_bytes);
|
|
touch_2p_uart.readable.bytes = touch_2p_readable_bytes;
|
|
touch_2p_uart.readable.nbytes = sizeof(touch_2p_readable_bytes);
|
|
}
|
|
|
|
return iohook_push_handler(touch_handle_irp);
|
|
}
|
|
|
|
static HRESULT touch_handle_irp(struct irp *irp)
|
|
{
|
|
HRESULT hr;
|
|
|
|
assert(irp != NULL);
|
|
|
|
if (uart_match_irp(&touch_1p_uart, irp))
|
|
{
|
|
EnterCriticalSection(&touch_1p_lock);
|
|
hr = touch_handle_irp_locked(irp, &touch_1p_uart);
|
|
LeaveCriticalSection(&touch_1p_lock);
|
|
}
|
|
else if (uart_match_irp(&touch_2p_uart, irp))
|
|
{
|
|
EnterCriticalSection(&touch_2p_lock);
|
|
hr = touch_handle_irp_locked(irp, &touch_2p_uart);
|
|
LeaveCriticalSection(&touch_2p_lock);
|
|
}
|
|
else
|
|
{
|
|
return iohook_invoke_next(irp);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
static HRESULT touch_handle_irp_locked(struct irp *irp, struct uart *uart)
|
|
{
|
|
HRESULT hr;
|
|
|
|
if (irp->op == IRP_OP_OPEN)
|
|
{
|
|
dprintf("Mai2 touch port %d: Starting backend\n", uart->port_no);
|
|
hr = mai2_dll.touch_init(touch_auto_scan);
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
dprintf("Mai2 touch port %d: Backend error: %x\n", uart->port_no, (int)hr);
|
|
return hr;
|
|
}
|
|
}
|
|
|
|
hr = uart_handle_irp(uart, irp);
|
|
|
|
if (FAILED(hr) || irp->op != IRP_OP_WRITE)
|
|
{
|
|
return hr;
|
|
}
|
|
|
|
#if defined(LOG_MAI2_TOUCH)
|
|
dprintf("Mai2 touch port %d WRITE:\n", uart->port_no);
|
|
dump_iobuf(&uart->written);
|
|
#endif
|
|
uint8_t port_no = uart->port_no;
|
|
uint8_t *src = uart->written.bytes;
|
|
uint8_t *dest = uart->readable.bytes;
|
|
|
|
switch (src[3])
|
|
{
|
|
case commandRSET:
|
|
dprintf("Mai2 touch port %d: Reset\n", port_no);
|
|
break;
|
|
|
|
case commandHALT: // Enter Conditioning mode and stop sending touch data.
|
|
dprintf("Mai2 touch port %d: Halt\n", port_no);
|
|
assert(mai2_dll.touch_update != NULL);
|
|
if (port_no == 3)
|
|
{
|
|
EnterCriticalSection(&touch_1p_lock);
|
|
touch_1p_status = false;
|
|
mai2_dll.touch_update(touch_1p_status, touch_2p_status);
|
|
LeaveCriticalSection(&touch_1p_lock);
|
|
}
|
|
else
|
|
{
|
|
EnterCriticalSection(&touch_2p_lock);
|
|
touch_2p_status = false;
|
|
mai2_dll.touch_update(touch_1p_status, touch_2p_status);
|
|
LeaveCriticalSection(&touch_2p_lock);
|
|
}
|
|
break;
|
|
|
|
case commandSTAT: // Exit Conditioning mode and resume sending touch data.
|
|
dprintf("Mai2 touch port %d: Stat\n", port_no);
|
|
assert(mai2_dll.touch_update != NULL);
|
|
if (port_no == 3)
|
|
{
|
|
EnterCriticalSection(&touch_1p_lock);
|
|
touch_1p_status = true;
|
|
mai2_dll.touch_update(touch_1p_status, touch_2p_status);
|
|
LeaveCriticalSection(&touch_1p_lock);
|
|
}
|
|
else
|
|
{
|
|
EnterCriticalSection(&touch_2p_lock);
|
|
touch_2p_status = true;
|
|
mai2_dll.touch_update(touch_1p_status, touch_2p_status);
|
|
LeaveCriticalSection(&touch_2p_lock);
|
|
}
|
|
break;
|
|
|
|
case commandRatio:
|
|
#if defined(LOG_MAI2_TOUCH)
|
|
dprintf("Mai2 touch side %c: set sensor %s ratio to %d\n", src[1], sensor_to_str(src[2]), src[4]);
|
|
#endif
|
|
dest[0] = res_start;
|
|
dest[1] = src[1]; // L,R
|
|
dest[2] = src[2]; // sensor
|
|
dest[3] = commandRatio;
|
|
dest[4] = src[4]; // Ratio
|
|
dest[5] = res_end;
|
|
uart->readable.pos = 6;
|
|
// The Ratio is fixed at 0x72 and does not need to be sent to mai2io for processing.
|
|
break;
|
|
|
|
case commandSens:
|
|
#if defined(LOG_MAI2_TOUCH)
|
|
dprintf("Mai2 touch side %c: set sensor %s sensitivity to %d\n", src[1], sensor_to_str(src[2]), src[4]);
|
|
#endif
|
|
dest[0] = res_start;
|
|
dest[1] = src[1]; // L,R
|
|
dest[2] = src[2]; // sensor
|
|
dest[3] = commandSens;
|
|
dest[4] = src[4]; // Sensitivity
|
|
dest[5] = res_end;
|
|
uart->readable.pos = 6;
|
|
mai2_dll.touch_set_sens(dest);
|
|
break;
|
|
|
|
default:
|
|
dprintf("Mai2 touch port %d: Unknow %02x\n", port_no, src[3]);
|
|
break;
|
|
}
|
|
#if defined(LOG_MAI2_TOUCH)
|
|
dprintf("Mai2 touch port %d READ:\n", uart->port_no);
|
|
dump_iobuf(&uart->readable);
|
|
#endif
|
|
uart->written.pos = 0;
|
|
|
|
return hr;
|
|
}
|
|
|
|
static void touch_auto_scan(const uint8_t player, const uint8_t state[7])
|
|
{
|
|
struct uart *touch_uart = player == 1 ? &touch_1p_uart : &touch_2p_uart;
|
|
touch_uart->readable.bytes[0] = res_start;
|
|
memcpy(&touch_uart->readable.bytes[1], state, 7);
|
|
touch_uart->readable.bytes[8] = res_end;
|
|
touch_uart->readable.pos = 9;
|
|
}
|