bananatools/board/usio.c

376 lines
7.9 KiB
C

#include <windows.h>
#include <devioctl.h>
#include <hidclass.h>
#include <winusb.h>
#include <assert.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include "board/config.h"
#include "board/guid.h"
#include "board/usio.h"
#include "hook/iobuf.h"
#include "hook/iohook.h"
#include "hook/table.h"
#include "hook/iohook.h"
#include "hooklib/setupapi.h"
#include "hook/procaddr.h"
#include "util/dprintf.h"
#include "util/dump.h"
static const wchar_t usio_path[] = L"$usio";
static const wchar_t usio_name[] = L"NBGI.REAL_USIO";
static int my_bnusio_Open();
static int my_bnusio_Close();
static int my_bnusio_GetFirmwareVersion();
static int my_bnusio_SetSystemError(uint16_t err);
static int my_bnusio_ClearSram();
static BOOL my_bnusio_ResetIoBoard();
static int my_bnusio_Communication(uint64_t com);
static int my_bnusio_GetSystemError();
static void my_bnusio_SetPLCounter(uint16_t pl_ct);
static int my_bnusio_SetGout(uint8_t id, uint8_t value);
static int my_bnusio_GetAnalogIn(uint8_t id);
static int my_bnusio_GetSwIn();
static int my_bnusio_SetCoinLock(uint8_t id, char value);
static int my_bnusio_GetCoin(uint8_t id);
static int my_bnusio_GetCoinError(uint8_t id);
static int my_bnusio_GetService(uint8_t id);
static int my_bnusio_GetServiceError(uint8_t id);
static intptr_t my_bnusio_GetIoBoardName();
static struct hook_symbol usio_syms[] = {
{
.name = "bnusio_Open",
.patch = my_bnusio_Open
},
{
.name = "bnusio_GetFirmwareVersion",
.patch = my_bnusio_GetFirmwareVersion
},
{
.name = "bnusio_Close",
.patch = my_bnusio_Close
},
{
.name = "bnusio_SetSystemError",
.patch = my_bnusio_SetSystemError
},
{
.name = "bnusio_ClearSram",
.patch = my_bnusio_ClearSram
},
{
.name = "bnusio_ResetIoBoard",
.patch = my_bnusio_ResetIoBoard
},
{
.name = "bnusio_Communication",
.patch = my_bnusio_Communication
},
{
.name = "bnusio_GetSystemError",
.patch = my_bnusio_GetSystemError
},
{
.name = "bnusio_SetPLCounter",
.patch = my_bnusio_SetPLCounter
},
{
.name = "bnusio_SetGout",
.patch = my_bnusio_SetGout
},
{
.name = "bnusio_GetAnalogIn",
.patch = my_bnusio_GetAnalogIn
},
{
.name = "bnusio_GetSwIn",
.patch = my_bnusio_GetSwIn
},
{
.name = "bnusio_SetCoinLock",
.patch = my_bnusio_SetCoinLock
},
{
.name = "bnusio_GetCoin",
.patch = my_bnusio_GetCoin
},
{
.name = "bnusio_GetCoinError",
.patch = my_bnusio_GetCoinError
},
{
.name = "bnusio_GetService",
.patch = my_bnusio_GetService
},
{
.name = "bnusio_GetServiceError",
.patch = my_bnusio_GetServiceError
},
{
.name = "bnusio_GetIoBoardName",
.patch = my_bnusio_GetIoBoardName
},
{
.name = "Open",
.patch = my_bnusio_Open
},
{
.name = "GetFirmwareVersion",
.patch = my_bnusio_GetFirmwareVersion
},
{
.name = "Close",
.patch = my_bnusio_Close
},
{
.name = "SetSystemError",
.patch = my_bnusio_SetSystemError
},
{
.name = "ClearSram",
.patch = my_bnusio_ClearSram
},
{
.name = "ResetIoBoard",
.patch = my_bnusio_ResetIoBoard
},
{
.name = "Communication",
.patch = my_bnusio_Communication
},
{
.name = "GetSystemError",
.patch = my_bnusio_GetSystemError
},
{
.name = "SetPLCounter",
.patch = my_bnusio_SetPLCounter
},
{
.name = "SetGout",
.patch = my_bnusio_SetGout
},
{
.name = "GetAnalogIn",
.patch = my_bnusio_GetAnalogIn
},
{
.name = "GetSwIn",
.patch = my_bnusio_GetSwIn
},
{
.name = "SetCoinLock",
.patch = my_bnusio_SetCoinLock
},
{
.name = "GetCoin",
.patch = my_bnusio_GetCoin
},
{
.name = "GetCoinError",
.patch = my_bnusio_GetCoinError
},
{
.name = "GetService",
.patch = my_bnusio_GetService
},
{
.name = "GetServiceError",
.patch = my_bnusio_GetServiceError
},
{
.name = "GetIoBoardName",
.patch = my_bnusio_GetIoBoardName
}
};
static HANDLE usio_fd;
static const struct usio_ops *usio_ops;
static void *usio_ops_ctx;
static struct usio_state state;
HRESULT usio_hook_init(
const struct usio_config *cfg,
const struct usio_ops *ops,
void *ctx,
HMODULE target)
{
HRESULT hr;
assert(cfg != NULL);
assert(ops != NULL);
if (!cfg->enable) {
return S_FALSE;
}
usio_ops = ops;
usio_ops_ctx = ctx;
hook_table_apply(target, "bnusio.dll", usio_syms, _countof(usio_syms));
memset(&state, 0, sizeof(state));
dprintf("USIO: Init\n");
return S_OK;
}
HRESULT usio_hook_proc_addr(HMODULE target)
{
if (usio_ops != NULL)
return proc_addr_table_push(target, "bnusio.dll", usio_syms, _countof(usio_syms));
return S_OK;
}
static int my_bnusio_Open()
{
dprintf("USIO: Open\n");
return 0;
}
static int my_bnusio_GetFirmwareVersion()
{
dprintf("USIO: GetFirmwareVersion\n");
return 126;
}
static int my_bnusio_Close()
{
dprintf("USIO: Close\n");
return 0;
}
static int my_bnusio_SetSystemError(uint16_t err)
{
dprintf("USIO: SetSystemError %d\n", err);
state.err = err;
return 0;
}
static int my_bnusio_ClearSram()
{
dprintf("USIO: ClearSram\n");
return 0;
}
static BOOL my_bnusio_ResetIoBoard()
{
dprintf("USIO: ResetIoBoard\n");
return false;
}
static int my_bnusio_Communication(uint64_t com)
{
//dprintf("USIO: Communication\n");
return 0;
}
static int my_bnusio_GetSystemError()
{
dprintf("USIO: GetSystemError\n");
return state.err;
}
static void my_bnusio_SetPLCounter(uint16_t pl_ct)
{
//dprintf("USIO: SetPLCounter\n");
state.pl_count = pl_ct;
}
static int my_bnusio_SetGout(uint8_t id, uint8_t value)
{
//dprintf("USIO: SetGout ID %d Val %d\n", id, value);
if (id <= 32) {
state.gpio[id - 1] = value;
return 0;
}
return 0xFFFFFFEA;
}
static int my_bnusio_SetCoinLock(uint8_t id, char value)
{
dprintf("USIO: SetCoinLock %d %x\n", id, value);
state.coins[id].is_lock = value;
return 0;
}
static int my_bnusio_GetCoin(uint8_t id)
{
//dprintf("USIO: GetCoin ID %d\n", id);
usio_ops->poll(usio_ops_ctx, &state);
if (id < 2) {
return state.coins[id].current_coin_count;
}
return 0;
}
static int my_bnusio_GetCoinError(uint8_t id)
{
//dprintf("USIO: GetCoinErrorID %d\n", id);
if (id >= _countof(state.coins)) {
return 0;
}
return state.coins[id].err;
}
static int my_bnusio_GetService(uint8_t id)
{
//dprintf("USIO: GetService ID %d\n", id);
usio_ops->poll(usio_ops_ctx, &state);
if (id < 1) {
return state.service.current_coin_count;
}
return 0;
}
static int my_bnusio_GetServiceError(uint8_t id)
{
// TODO: multiple service switches?
//dprintf("USIO: GetServiceError ID %d\n", id);
if (id < 1) {
return state.service.err;
}
return 0;
}
static int my_bnusio_GetAnalogIn(uint8_t id)
{
//dprintf("USIO: GetAnalogIn ID %d\n", id);
uint8_t gamebtns = 0;
usio_ops->poll(usio_ops_ctx, &state);
if (id < 8) {
return state.analog[id];
}
return 0;
}
static int my_bnusio_GetSwIn()
{
//dprintf("USIO: GetSwitchIn\n");
uint32_t opbtn_out = 0;
usio_ops->poll(usio_ops_ctx, &state);
opbtn_out = (state.p2_btns << 16) | (state.p1_btns << 8) | state.op_btns;
return opbtn_out;
}
static intptr_t my_bnusio_GetIoBoardName()
{
intptr_t ret = (intptr_t)malloc(sizeof(usio_name) / 2);
wcstombs((char *)ret, usio_name, sizeof(usio_name) / 2);
return ret;
}