refactor all common parts and games

This commit is contained in:
Dniel97
2025-04-17 20:04:17 +02:00
parent a6126bf290
commit 66a53dd2de
496 changed files with 233 additions and 344 deletions
+353
View File
@@ -0,0 +1,353 @@
#include <windows.h>
#include <assert.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "aimeio/aimeio.h"
#include "util/crc.h"
#include "util/dprintf.h"
#include "util/env.h"
struct aime_io_config {
wchar_t aime_path[MAX_PATH];
wchar_t felica_path[MAX_PATH];
bool felica_gen;
bool aime_gen;
uint8_t vk_scan;
};
static struct aime_io_config aime_io_cfg;
static uint8_t aime_io_aime_id[10];
static uint8_t aime_io_felica_id[8];
static bool aime_io_aime_id_present;
static bool aime_io_felica_id_present;
static void aime_io_config_read(
struct aime_io_config *cfg,
const wchar_t *filename);
static HRESULT aime_io_read_id_file(
const wchar_t *path,
uint8_t *bytes,
size_t nbytes);
static HRESULT aime_io_generate_felica(
const wchar_t *path,
uint8_t *bytes,
size_t nbytes);
static HRESULT aime_io_generate_aime(
const wchar_t *path,
uint8_t *bytes,
size_t nbytes);
static void aime_io_config_read(
struct aime_io_config *cfg,
const wchar_t *filename)
{
assert(cfg != NULL);
assert(filename != NULL);
GetPrivateProfileStringW(
L"aime",
L"aimePath",
L"DEVICE\\aime.txt",
cfg->aime_path,
_countof(cfg->aime_path),
filename);
GetPrivateProfileStringW(
L"aime",
L"felicaPath",
L"DEVICE\\felica.txt",
cfg->felica_path,
_countof(cfg->felica_path),
filename);
cfg->felica_gen = GetPrivateProfileIntW(
L"aime",
L"felicaGen",
0,
filename);
cfg->aime_gen = GetPrivateProfileIntW(
L"aime",
L"aimeGen",
1,
filename);
cfg->vk_scan = GetPrivateProfileIntW(
L"aime",
L"scan",
VK_RETURN,
filename);
}
static HRESULT aime_io_read_id_file(
const wchar_t *path,
uint8_t *bytes,
size_t nbytes)
{
HRESULT hr;
FILE *f;
size_t i;
int byte;
int r;
f = _wfopen(path, L"r");
if (f == NULL) {
return S_FALSE;
}
memset(bytes, 0, nbytes);
for (i = 0 ; i < nbytes ; i++) {
r = fscanf(f, "%02x ", &byte);
if (r != 1) {
hr = E_FAIL;
dprintf("AimeIO DLL: %S: fscanf[%i] failed: %i\n",
path,
(int) i,
r);
goto end;
}
bytes[i] = byte;
}
hr = S_OK;
end:
if (f != NULL) {
fclose(f);
}
return hr;
}
static HRESULT aime_io_generate_felica(
const wchar_t *path,
uint8_t *bytes,
size_t nbytes)
{
size_t i;
FILE *f;
assert(path != NULL);
assert(bytes != NULL);
assert(nbytes > 0);
srand(time(NULL));
for (i = 0; i < nbytes; i++) {
bytes[i] = rand();
}
/* FeliCa IDm values should have a 0 in their high nibble. I think. */
bytes[0] &= 0x0F;
f = _wfopen(path, L"w");
if (f == NULL) {
dprintf("AimeIO DLL: %S: fopen failed: %i\n", path, (int) errno);
return E_FAIL;
}
for (i = 0; i < nbytes; i++) {
fprintf(f, "%02X", bytes[i]);
}
fprintf(f, "\n");
fclose(f);
dprintf("AimeIO DLL: Generated random FeliCa ID\n");
return S_OK;
}
static HRESULT aime_io_generate_aime(
const wchar_t *path,
uint8_t *bytes,
size_t nbytes)
{
size_t i;
FILE *f;
assert(path != NULL);
assert(bytes != NULL);
assert(nbytes > 0);
srand(time(NULL));
/* AiMe IDs should not start with 3, due to a missing check for BananaPass IDs */
do {
for (i = 0; i < nbytes; i++) {
bytes[i] = rand() % 10 << 4 | rand() % 10;
}
} while (bytes[0] >> 4 == 3);
f = _wfopen(path, L"w");
if (f == NULL) {
dprintf("AimeIO DLL: %S: fopen failed: %i\n", path, (int) errno);
return E_FAIL;
}
for (i = 0; i < nbytes; i++) {
fprintf(f, "%02x", bytes[i]);
}
fprintf(f, "\n");
fclose(f);
dprintf("AimeIO DLL: Generated random AiMe ID\n");
return S_OK;
}
uint16_t aime_io_get_api_version(void)
{
return 0x0100;
}
HRESULT aime_io_init(void)
{
aime_io_config_read(&aime_io_cfg, get_config_path());
return S_OK;
}
HRESULT aime_io_nfc_poll(uint8_t unit_no)
{
bool sense;
HRESULT hr;
if (unit_no != 0) {
return S_OK;
}
/* Reset presence flags */
aime_io_aime_id_present = false;
aime_io_felica_id_present = false;
/* Don't do anything more if the scan key is not held */
sense = GetAsyncKeyState(aime_io_cfg.vk_scan) & 0x8000;
if (!sense) {
return S_OK;
}
/* Try AiMe IC */
hr = aime_io_read_id_file(
aime_io_cfg.aime_path,
aime_io_aime_id,
sizeof(aime_io_aime_id));
if (SUCCEEDED(hr) && hr != S_FALSE) {
aime_io_aime_id_present = true;
return S_OK;
}
/* Try generating AiMe IC (if enabled) */
if (aime_io_cfg.aime_gen) {
hr = aime_io_generate_aime(
aime_io_cfg.aime_path,
aime_io_aime_id,
sizeof(aime_io_aime_id));
if (FAILED(hr)) {
return hr;
}
aime_io_aime_id_present = true;
return S_OK;
}
/* Try FeliCa IC */
hr = aime_io_read_id_file(
aime_io_cfg.felica_path,
aime_io_felica_id,
sizeof(aime_io_felica_id));
if (SUCCEEDED(hr) && hr != S_FALSE) {
aime_io_felica_id_present = true;
return S_OK;
}
/* Try generating FeliCa IC (if enabled) */
if (aime_io_cfg.felica_gen) {
hr = aime_io_generate_felica(
aime_io_cfg.felica_path,
aime_io_felica_id,
sizeof(aime_io_felica_id));
if (FAILED(hr)) {
return hr;
}
aime_io_felica_id_present = true;
}
return S_OK;
}
HRESULT aime_io_nfc_get_aime_id(
uint8_t unit_no,
uint8_t *luid,
size_t luid_size)
{
assert(luid != NULL);
assert(luid_size == sizeof(aime_io_aime_id));
if (unit_no != 0 || !aime_io_aime_id_present) {
return S_FALSE;
}
memcpy(luid, aime_io_aime_id, luid_size);
return S_OK;
}
HRESULT aime_io_nfc_get_felica_id(uint8_t unit_no, uint64_t *IDm)
{
uint64_t val;
size_t i;
assert(IDm != NULL);
if (unit_no != 0 || !aime_io_felica_id_present) {
return S_FALSE;
}
val = 0;
for (i = 0 ; i < 8 ; i++) {
val = (val << 8) | aime_io_felica_id[i];
}
*IDm = val;
return S_OK;
}
void aime_io_led_set_color(uint8_t unit_no, uint8_t r, uint8_t g, uint8_t b)
{}
+87
View File
@@ -0,0 +1,87 @@
#pragma once
#include <windows.h>
#include <stddef.h>
#include <stdint.h>
/*
Get the version of the Aime IO API that this DLL supports. This function
should return a positive 16-bit integer, where the high byte is the major
version and the low byte is the minor version (as defined by the Semantic
Versioning standard).
The latest API version as of this writing is 0x0100.
*/
uint16_t aime_io_get_api_version(void);
/*
Initialize Aime IO provider DLL. Only called once, before any other
functions exported from this DLL are called (except for
aime_io_get_api_version).
Minimum API version: 0x0100
*/
HRESULT aime_io_init(void);
/*
Poll for IC cards in the vicinity.
- unit_no: Always 0 as of the current API version
Minimum API version: 0x0100
*/
HRESULT aime_io_nfc_poll(uint8_t unit_no);
/*
Attempt to read out a classic Aime card ID
- unit_no: Always 0 as of the current API version
- luid: Pointer to a ten-byte buffer that will receive the ID
- luid_size: Size of the buffer at *luid. Always 10.
Returns:
- S_OK if a classic Aime is present and was read successfully
- S_FALSE if no classic Aime card is present (*luid will be ignored)
- Any HRESULT error if an error occured.
Minimum API version: 0x0100
*/
HRESULT aime_io_nfc_get_aime_id(
uint8_t unit_no,
uint8_t *luid,
size_t luid_size);
/*
Attempt to read out a FeliCa card ID ("IDm"). The following are examples
of FeliCa cards:
- Amuse IC (which includes new-style Aime-branded cards, among others)
- Smartphones with FeliCa NFC capability (uncommon outside Japan)
- Various Japanese e-cash cards and train passes
Parameters:
- unit_no: Always 0 as of the current API version
- IDm: Output parameter that will receive the card ID
Returns:
- S_OK if a FeliCa device is present and was read successfully
- S_FALSE if no FeliCa device is present (*IDm will be ignored)
- Any HRESULT error if an error occured.
Minimum API version: 0x0100
*/
HRESULT aime_io_nfc_get_felica_id(uint8_t unit_no, uint64_t *IDm);
/*
Change the color and brightness of the card reader's RGB lighting
- unit_no: Always 0 as of the current API version
- r, g, b: Primary color intensity, from 0 to 255 inclusive.
Minimum API version: 0x0100
*/
void aime_io_led_set_color(uint8_t unit_no, uint8_t r, uint8_t g, uint8_t b);
+12
View File
@@ -0,0 +1,12 @@
aimeio_lib = static_library(
'aimeio',
name_prefix : '',
include_directories: inc,
implicit_include_directories : false,
link_with : [
util_lib,
],
sources : [
'aimeio.c',
],
)
+49
View File
@@ -0,0 +1,49 @@
#include <windows.h>
#include "amex/amex.h"
#include "amex/ds.h"
#include "amex/eeprom.h"
#include "amex/gpio.h"
#include "amex/jvs.h"
#include "amex/sram.h"
#include <assert.h>
HRESULT amex_hook_init(const struct amex_config *cfg, jvs_provider_t jvs)
{
HRESULT hr;
assert(cfg != NULL);
hr = ds_hook_init(&cfg->ds);
if (FAILED(hr)) {
return hr;
}
hr = eeprom_hook_init(&cfg->eeprom);
if (FAILED(hr)) {
return hr;
}
hr = gpio_hook_init(&cfg->gpio);
if (FAILED(hr)) {
return hr;
}
hr = jvs_hook_init(&cfg->jvs, jvs);
if (FAILED(hr)) {
return hr;
}
hr = sram_hook_init(&cfg->sram);
if (FAILED(hr)) {
return hr;
}
return S_OK;
}
+21
View File
@@ -0,0 +1,21 @@
#pragma once
#include <windows.h>
#include "amex/ds.h"
#include "amex/eeprom.h"
#include "amex/gpio.h"
#include "amex/jvs.h"
#include "amex/sram.h"
struct amex_config {
struct ds_config ds;
struct eeprom_config eeprom;
struct gpio_config gpio;
struct jvs_config jvs;
struct sram_config sram;
};
HRESULT amex_hook_init(
const struct amex_config *cfg,
jvs_provider_t jvs);
+104
View File
@@ -0,0 +1,104 @@
#include <windows.h>
#include <assert.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
#include "amex/amex.h"
#include "amex/config.h"
#include "amex/ds.h"
#include "amex/eeprom.h"
#include "amex/gpio.h"
#include "amex/jvs.h"
#include "amex/sram.h"
void ds_config_load(struct ds_config *cfg, const wchar_t *filename)
{
assert(cfg != NULL);
assert(filename != NULL);
cfg->enable = GetPrivateProfileIntW(L"ds", L"enable", 1, filename);
cfg->region = GetPrivateProfileIntW(L"ds", L"region", 1, filename);
GetPrivateProfileStringW(
L"ds",
L"serialNo",
L"AAVE-01A99999999",
cfg->serial_no,
_countof(cfg->serial_no),
filename);
}
void eeprom_config_load(struct eeprom_config *cfg, const wchar_t *filename)
{
assert(cfg != NULL);
assert(filename != NULL);
cfg->enable = GetPrivateProfileIntW(L"eeprom", L"enable", 1, filename);
GetPrivateProfileStringW(
L"eeprom",
L"path",
L"DEVICE\\eeprom.bin",
cfg->path,
_countof(cfg->path),
filename);
}
void gpio_config_load(struct gpio_config *cfg, const wchar_t *filename)
{
wchar_t name[7];
size_t i;
assert(cfg != NULL);
assert(filename != NULL);
cfg->enable = GetPrivateProfileIntW(L"gpio", L"enable", 1, filename);
cfg->vk_sw1 = GetPrivateProfileIntW(L"gpio", L"sw1", VK_F1, filename);
cfg->vk_sw2 = GetPrivateProfileIntW(L"gpio", L"sw2", VK_F2, filename);
wcscpy_s(name, _countof(name), L"dipsw0");
for (i = 0 ; i < 8 ; i++) {
name[5] = L'1' + i;
cfg->dipsw[i] = GetPrivateProfileIntW(L"gpio", name, 0, filename);
}
}
void jvs_config_load(struct jvs_config *cfg, const wchar_t *filename)
{
assert(cfg != NULL);
assert(filename != NULL);
cfg->enable = GetPrivateProfileIntW(L"jvs", L"enable", 1, filename);
}
void sram_config_load(struct sram_config *cfg, const wchar_t *filename)
{
assert(cfg != NULL);
assert(filename != NULL);
cfg->enable = GetPrivateProfileIntW(L"sram", L"enable", 1, filename);
GetPrivateProfileStringW(
L"sram",
L"path",
L"DEVICE\\sram.bin",
cfg->path,
_countof(cfg->path),
filename);
}
void amex_config_load(struct amex_config *cfg, const wchar_t *filename)
{
assert(cfg != NULL);
assert(filename != NULL);
ds_config_load(&cfg->ds, filename);
eeprom_config_load(&cfg->eeprom, filename);
gpio_config_load(&cfg->gpio, filename);
jvs_config_load(&cfg->jvs, filename);
sram_config_load(&cfg->sram, filename);
}
+21
View File
@@ -0,0 +1,21 @@
#pragma once
#include <windows.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include "amex/amex.h"
#include "amex/ds.h"
#include "amex/eeprom.h"
#include "amex/gpio.h"
#include "amex/jvs.h"
#include "amex/sram.h"
void ds_config_load(struct ds_config *cfg, const wchar_t *filename);
void eeprom_config_load(struct eeprom_config *cfg, const wchar_t *filename);
void gpio_config_load(struct gpio_config *cfg, const wchar_t *filename);
void jvs_config_load(struct jvs_config *cfg, const wchar_t *filename);
void sram_config_load(struct sram_config *cfg, const wchar_t *filename);
void amex_config_load(struct amex_config *cfg, const wchar_t *filename);
+213
View File
@@ -0,0 +1,213 @@
#include <windows.h>
#include <devioctl.h>
#include <winioctl.h>
#include <assert.h>
#include <ctype.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include "amex/ds.h"
#include "amex/nvram.h"
#include "hook/iobuf.h"
#include "hook/iohook.h"
#include "hooklib/setupapi.h"
#include "util/crc.h"
#include "util/dprintf.h"
#include "util/str.h"
#define DS_IOCTL_GET_ABI_VERSION CTL_CODE(0x8000, 0x800, METHOD_BUFFERED, FILE_READ_ACCESS)
#define DS_IOCTL_SETUP CTL_CODE(0x8000, 0x801, METHOD_BUFFERED, FILE_READ_ACCESS)
#define DS_IOCTL_READ_SECTOR CTL_CODE(0x8000, 0x804, METHOD_BUFFERED, FILE_READ_ACCESS)
#pragma pack(push, 1)
struct ds_eeprom {
uint32_t crc32;
uint8_t unk_04[4];
uint8_t region;
char serial_no[17];
uint8_t unk_1A[6];
};
static_assert(sizeof(struct ds_eeprom) == 0x20, "DS EEPROM size");
#pragma pack(pop)
static HRESULT ds_handle_irp(struct irp *irp);
static HRESULT ds_handle_open(struct irp *irp);
static HRESULT ds_handle_close(struct irp *irp);
static HRESULT ds_handle_ioctl(struct irp *irp);
static HRESULT ds_ioctl_get_geometry(struct irp *irp);
static HRESULT ds_ioctl_get_abi_version(struct irp *irp);
static HRESULT ds_ioctl_setup(struct irp *irp);
static HRESULT ds_ioctl_read_sector(struct irp *irp);
static struct ds_eeprom ds_eeprom;
static HANDLE ds_fd;
HRESULT ds_hook_init(const struct ds_config *cfg)
{
HRESULT hr;
assert(cfg != NULL);
if (!cfg->enable) {
return S_FALSE;
}
memset(&ds_eeprom, 0, sizeof(ds_eeprom));
wcstombs_s(
NULL,
ds_eeprom.serial_no,
_countof(ds_eeprom.serial_no),
cfg->serial_no,
_countof(cfg->serial_no) - 1);
ds_eeprom.region = cfg->region;
ds_eeprom.crc32 = crc32(&ds_eeprom.unk_04, 0x1C, 0);
hr = iohook_push_handler(ds_handle_irp);
if (FAILED(hr)) {
return hr;
}
hr = setupapi_add_phantom_dev(&ds_guid, L"$ds");
if (FAILED(hr)) {
return hr;
}
hr = iohook_open_nul_fd(&ds_fd);
if (FAILED(hr)) {
return hr;
}
return S_OK;
}
static HRESULT ds_handle_irp(struct irp *irp)
{
assert(irp != NULL);
if (irp->op != IRP_OP_OPEN && irp->fd != ds_fd) {
return iohook_invoke_next(irp);
}
switch (irp->op) {
case IRP_OP_OPEN: return ds_handle_open(irp);
case IRP_OP_CLOSE: return ds_handle_close(irp);
case IRP_OP_IOCTL: return ds_handle_ioctl(irp);
default: return HRESULT_FROM_WIN32(ERROR_INVALID_FUNCTION);
}
}
static HRESULT ds_handle_open(struct irp *irp)
{
if (!wstr_eq(irp->open_filename, L"$ds")) {
return iohook_invoke_next(irp);
}
dprintf("DS: Open device\n");
irp->fd = ds_fd;
return S_OK;
}
static HRESULT ds_handle_close(struct irp *irp)
{
dprintf("DS: Close device\n");
return S_OK;
}
static HRESULT ds_handle_ioctl(struct irp *irp)
{
switch (irp->ioctl) {
case IOCTL_DISK_GET_DRIVE_GEOMETRY:
return ds_ioctl_get_geometry(irp);
case DS_IOCTL_GET_ABI_VERSION:
return ds_ioctl_get_abi_version(irp);
case DS_IOCTL_SETUP:
return ds_ioctl_setup(irp);
case DS_IOCTL_READ_SECTOR:
return ds_ioctl_read_sector(irp);
default:
dprintf("DS: Unknown ioctl %08x, write %i read %i\n",
irp->ioctl,
(int) irp->write.nbytes,
(int) irp->read.nbytes);
return HRESULT_FROM_WIN32(ERROR_INVALID_FUNCTION);
}
}
static HRESULT ds_ioctl_get_geometry(struct irp *irp)
{
DISK_GEOMETRY out;
HRESULT hr;
dprintf("DS: Get geometry\n");
memset(&out, 0, sizeof(out));
out.Cylinders.QuadPart = 1;
out.MediaType = 0;
out.TracksPerCylinder = 1;
out.SectorsPerTrack = 2;
out.BytesPerSector = 32;
hr = iobuf_write(&irp->read, &out, sizeof(out));
if (FAILED(hr)) {
dprintf("DS: Get geometry failed: %08x\n", (int) hr);
}
return hr;
}
static HRESULT ds_ioctl_get_abi_version(struct irp *irp)
{
return iobuf_write_le16(&irp->read, 256);
}
static HRESULT ds_ioctl_setup(struct irp *irp)
{
dprintf("DS: Setup IOCTL\n");
return S_OK;
}
static HRESULT ds_ioctl_read_sector(struct irp *irp)
{
struct const_iobuf src;
uint32_t sector_no;
HRESULT hr;
hr = iobuf_read_le32(&irp->write, &sector_no);
if (FAILED(hr)) {
return hr;
}
dprintf("DS: Read sector %08x\n", sector_no);
src.bytes = (const uint8_t *) &ds_eeprom;
src.nbytes = sizeof(ds_eeprom);
src.pos = 0;
iobuf_move(&irp->read, &src);
return S_OK;
}
+22
View File
@@ -0,0 +1,22 @@
#pragma once
#include <windows.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
struct ds_config {
bool enable;
uint8_t region;
wchar_t serial_no[17];
};
DEFINE_GUID(
ds_guid,
0x279A9F67,
0x348F,
0x41C9,
0xA4, 0xC4, 0xDF, 0xDB, 0x8A, 0xE8, 0xE5, 0xE0);
HRESULT ds_hook_init(const struct ds_config *cfg);
+192
View File
@@ -0,0 +1,192 @@
#include <windows.h>
#ifdef __GNUC__
#include <ntdef.h>
#else
#include <winnt.h>
#endif
#include <devioctl.h>
#include <winioctl.h>
#include <assert.h>
#include "amex/eeprom.h"
#include "amex/nvram.h"
#include "hook/iohook.h"
#include "hooklib/setupapi.h"
#include "util/dprintf.h"
#include "util/str.h"
#define EEPROM_IOCTL_GET_ABI_VERSION CTL_CODE(0x8000, 0x800, METHOD_BUFFERED, FILE_READ_ACCESS)
static HRESULT eeprom_handle_irp(struct irp *irp);
static HRESULT eeprom_handle_open(struct irp *irp);
static HRESULT eeprom_handle_close(struct irp *irp);
static HRESULT eeprom_handle_ioctl(struct irp *irp);
static HRESULT eeprom_handle_read(struct irp *irp);
static HRESULT eeprom_handle_write(struct irp *irp);
static HRESULT eeprom_ioctl_get_geometry(struct irp *irp);
static HRESULT eeprom_ioctl_get_abi_version(struct irp *irp);
static struct eeprom_config eeprom_config;
static HANDLE eeprom_file;
HRESULT eeprom_hook_init(const struct eeprom_config *cfg)
{
HRESULT hr;
assert(cfg != NULL);
if (!cfg->enable) {
return S_FALSE;
}
memcpy(&eeprom_config, cfg, sizeof(*cfg));
hr = iohook_push_handler(eeprom_handle_irp);
if (FAILED(hr)) {
return hr;
}
hr = setupapi_add_phantom_dev(&eeprom_guid, L"$eeprom");
if (FAILED(hr)) {
return hr;
}
return S_OK;
}
static HRESULT eeprom_handle_irp(struct irp *irp)
{
assert(irp != NULL);
if (irp->op != IRP_OP_OPEN && irp->fd != eeprom_file) {
return iohook_invoke_next(irp);
}
switch (irp->op) {
case IRP_OP_OPEN: return eeprom_handle_open(irp);
case IRP_OP_CLOSE: return eeprom_handle_close(irp);
case IRP_OP_IOCTL: return eeprom_handle_ioctl(irp);
case IRP_OP_READ: return eeprom_handle_read(irp);
case IRP_OP_WRITE: return eeprom_handle_write(irp);
default: return iohook_invoke_next(irp);
}
}
static HRESULT eeprom_handle_open(struct irp *irp)
{
HRESULT hr;
if (!wstr_eq(irp->open_filename, L"$eeprom") != 0) {
return iohook_invoke_next(irp);
}
if (eeprom_file != NULL) {
dprintf("EEPROM: Already open\n");
return HRESULT_FROM_WIN32(ERROR_SHARING_VIOLATION);
}
dprintf("EEPROM: Open device\n");
hr = nvram_open_file(&eeprom_file, eeprom_config.path, 0x2000);
if (FAILED(hr)) {
return hr;
}
irp->fd = eeprom_file;
return S_OK;
}
static HRESULT eeprom_handle_close(struct irp *irp)
{
dprintf("EEPROM: Close device\n");
eeprom_file = NULL;
return iohook_invoke_next(irp);
}
static HRESULT eeprom_handle_ioctl(struct irp *irp)
{
switch (irp->ioctl) {
case IOCTL_DISK_GET_DRIVE_GEOMETRY:
return eeprom_ioctl_get_geometry(irp);
case EEPROM_IOCTL_GET_ABI_VERSION:
return eeprom_ioctl_get_abi_version(irp);
default:
dprintf("EEPROM: Unknown ioctl %x, write %i read %i\n",
irp->ioctl,
(int) irp->write.nbytes,
(int) irp->read.nbytes);
return HRESULT_FROM_WIN32(ERROR_INVALID_FUNCTION);
}
}
static HRESULT eeprom_ioctl_get_geometry(struct irp *irp)
{
DISK_GEOMETRY out;
HRESULT hr;
dprintf("EEPROM: Get geometry\n");
memset(&out, 0, sizeof(out));
out.Cylinders.QuadPart = 1;
out.MediaType = FixedMedia;
out.TracksPerCylinder = 224;
out.SectorsPerTrack = 32;
out.BytesPerSector = 1;
hr = iobuf_write(&irp->read, &out, sizeof(out));
if (FAILED(hr)) {
dprintf("EEPROM: Get geometry failed: %08x\n", (int) hr);
}
return hr;
}
static HRESULT eeprom_ioctl_get_abi_version(struct irp *irp)
{
return iobuf_write_le16(&irp->read, 256);
}
static HRESULT eeprom_handle_read(struct irp *irp)
{
if (irp->ovl == NULL) {
dprintf("EEPROM: Synchronous read..?\n");
return E_UNEXPECTED;
}
dprintf("EEPROM: Read off %x len %x\n",
(int) irp->ovl->Offset,
(int) irp->read.nbytes);
return iohook_invoke_next(irp);
}
static HRESULT eeprom_handle_write(struct irp *irp)
{
if (irp->ovl == NULL) {
dprintf("EEPROM: Synchronous write..?\n");
return E_UNEXPECTED;
}
dprintf("EEPROM: Write off %x len %x\n",
(int) irp->ovl->Offset,
(int) irp->write.nbytes);
return iohook_invoke_next(irp);
}
+20
View File
@@ -0,0 +1,20 @@
#pragma once
#include <windows.h>
#include <stdbool.h>
#include <stddef.h>
struct eeprom_config {
bool enable;
wchar_t path[MAX_PATH];
};
DEFINE_GUID(
eeprom_guid,
0xB7970F0C,
0x31C4,
0x45FF,
0x96, 0x18, 0x0A, 0x24, 0x00, 0x94, 0xB2, 0x71);
HRESULT eeprom_hook_init(const struct eeprom_config *cfg);
+226
View File
@@ -0,0 +1,226 @@
#include <windows.h>
#include <winioctl.h>
#include <assert.h>
#include <string.h>
#include "amex/gpio.h"
#include "hook/iohook.h"
#include "hooklib/setupapi.h"
#include "util/dprintf.h"
#include "util/str.h"
#define GPIO_IOCTL_SET_LEDS CTL_CODE(0x8000, 0x801, METHOD_BUFFERED, FILE_WRITE_ACCESS)
#define GPIO_IOCTL_GET_PSW CTL_CODE(0x8000, 0x802, METHOD_BUFFERED, FILE_READ_ACCESS)
#define GPIO_IOCTL_GET_DIPSW CTL_CODE(0x8000, 0x803, METHOD_BUFFERED, FILE_READ_ACCESS)
#define GPIO_IOCTL_DESCRIBE CTL_CODE(0x8000, 0x805, METHOD_BUFFERED, FILE_READ_ACCESS)
enum {
GPIO_TYPE_NONE = 0,
GPIO_TYPE_LED = 1,
GPIO_TYPE_DIPSW = 2,
GPIO_TYPE_PSW = 3,
};
#pragma pack(push, 1)
struct gpio_port {
uint8_t unknown;
/* Number of distinct instances of this thing..? */
uint8_t count;
/* Type of GPIO port */
uint16_t type;
};
struct gpio_ports {
uint8_t unknown; /* Maybe a count of valid items in the array idk */
struct gpio_port ports[32];
};
#pragma pack(pop)
static HRESULT gpio_handle_irp(struct irp *irp);
static HRESULT gpio_handle_open(struct irp *irp);
static HRESULT gpio_handle_close(struct irp *irp);
static HRESULT gpio_handle_ioctl(struct irp *irp);
static HRESULT gpio_ioctl_get_psw(struct irp *irp);
static HRESULT gpio_ioctl_get_dipsw(struct irp *irp);
static HRESULT gpio_ioctl_describe(struct irp *irp);
static HRESULT gpio_ioctl_set_leds(struct irp *irp);
static const struct gpio_ports gpio_ports = {
.ports = {
{
.type = GPIO_TYPE_LED,
.count = 2,
}, {
.type = GPIO_TYPE_DIPSW,
.count = 8,
}, {
.type = GPIO_TYPE_PSW,
.count = 2,
}
},
};
static_assert(sizeof(gpio_ports) == 129, "GPIO port map size");
static HANDLE gpio_fd;
static struct gpio_config gpio_config;
HRESULT gpio_hook_init(const struct gpio_config *cfg)
{
HRESULT hr;
assert(cfg != NULL);
if (!cfg->enable) {
return S_FALSE;
}
memcpy(&gpio_config, cfg, sizeof(*cfg));
hr = iohook_open_nul_fd(&gpio_fd);
if (FAILED(hr)) {
return hr;
}
hr = iohook_push_handler(gpio_handle_irp);
if (FAILED(hr)) {
return hr;
}
hr = setupapi_add_phantom_dev(&gpio_guid, L"$gpio");
if (FAILED(hr)) {
return hr;
}
return S_OK;
}
static HRESULT gpio_handle_irp(struct irp *irp)
{
assert(irp != NULL);
if (irp->op != IRP_OP_OPEN && irp->fd != gpio_fd) {
return iohook_invoke_next(irp);
}
switch (irp->op) {
case IRP_OP_OPEN: return gpio_handle_open(irp);
case IRP_OP_CLOSE: return gpio_handle_close(irp);
case IRP_OP_IOCTL: return gpio_handle_ioctl(irp);
default: return HRESULT_FROM_WIN32(ERROR_INVALID_FUNCTION);
}
}
static HRESULT gpio_handle_open(struct irp *irp)
{
if (!wstr_eq(irp->open_filename, L"$gpio")) {
return iohook_invoke_next(irp);
}
dprintf("GPIO: Open device\n");
irp->fd = gpio_fd;
return S_OK;
}
static HRESULT gpio_handle_close(struct irp *irp)
{
dprintf("GPIO: Close device\n");
return S_OK;
}
static HRESULT gpio_handle_ioctl(struct irp *irp)
{
switch (irp->ioctl) {
case GPIO_IOCTL_SET_LEDS:
return gpio_ioctl_set_leds(irp);
case GPIO_IOCTL_GET_PSW:
return gpio_ioctl_get_psw(irp);
case GPIO_IOCTL_GET_DIPSW:
return gpio_ioctl_get_dipsw(irp);
case GPIO_IOCTL_DESCRIBE:
return gpio_ioctl_describe(irp);
default:
dprintf("GPIO: Unknown ioctl %08x, write %i read %i\n",
irp->ioctl,
(int) irp->write.nbytes,
(int) irp->read.nbytes);
return HRESULT_FROM_WIN32(ERROR_INVALID_FUNCTION);
}
}
static HRESULT gpio_ioctl_get_dipsw(struct irp *irp)
{
uint32_t dipsw;
size_t i;
dipsw = 0;
for (i = 0 ; i < 8 ; i++) {
if (gpio_config.dipsw[i]) {
dipsw |= 1 << i;
}
}
//dprintf("GPIO: Get dipsw %08x\n", dipsw);
return iobuf_write_le32(&irp->read, dipsw);
}
static HRESULT gpio_ioctl_get_psw(struct irp *irp)
{
uint32_t result;
result = 0;
/* Bit 0 == SW1 == Alt. Test */
/* Bit 1 == SW2 == Alt. Service */
if (GetAsyncKeyState(gpio_config.vk_sw1) & 0x8000) {
result |= 1 << 0;
}
if (GetAsyncKeyState(gpio_config.vk_sw2) & 0x8000) {
result |= 1 << 1;
}
return iobuf_write_le32(&irp->read, result);
}
static HRESULT gpio_ioctl_describe(struct irp *irp)
{
HRESULT hr;
dprintf("GPIO: Describe GPIO ports\n");
hr = iobuf_write(&irp->read, &gpio_ports, sizeof(gpio_ports));
if (FAILED(hr)) {
dprintf("GPIO: Describe GPIO ports failed: %08x\n", (int) hr);
}
return hr;
}
static HRESULT gpio_ioctl_set_leds(struct irp *irp)
{
return S_OK;
}
+22
View File
@@ -0,0 +1,22 @@
#pragma once
#include <windows.h>
#include <stdbool.h>
#include <stdint.h>
struct gpio_config {
bool enable;
uint8_t vk_sw1;
uint8_t vk_sw2;
bool dipsw[8];
};
DEFINE_GUID(
gpio_guid,
0xE9A26688,
0xF522,
0x44FA,
0xBF, 0xEE, 0x59, 0xDD, 0x16, 0x15, 0x56, 0x6C);
HRESULT gpio_hook_init(const struct gpio_config *cfg);
+8
View File
@@ -0,0 +1,8 @@
#include <windows.h>
#include <initguid.h>
#include "amex/ds.h"
#include "amex/eeprom.h"
#include "amex/gpio.h"
#include "amex/jvs.h"
#include "amex/sram.h"
+217
View File
@@ -0,0 +1,217 @@
#define WIN32_NO_STATUS
#include <windows.h>
#undef WIN32_NO_STATUS
#include <winternl.h>
#include <ntstatus.h>
#include <winioctl.h>
#include <assert.h>
#include <stddef.h>
#include "amex/jvs.h"
#include "hook/iobuf.h"
#include "hook/iohook.h"
#include "hooklib/setupapi.h"
#include "jvs/jvs-bus.h"
#include "util/dprintf.h"
#include "util/dump.h"
#include "util/str.h"
#define JVS_IOCTL_HELLO CTL_CODE(0x8000, 0x801, METHOD_BUFFERED, FILE_READ_ACCESS)
#define JVS_IOCTL_TRANSACT CTL_CODE(0x8000, 0x802, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
#define JVS_IOCTL_SENSE CTL_CODE(0x8000, 0x803, METHOD_BUFFERED, FILE_READ_ACCESS)
static HRESULT jvs_handle_irp(struct irp *irp);
static HRESULT jvs_handle_open(struct irp *irp);
static HRESULT jvs_handle_close(struct irp *irp);
static HRESULT jvs_handle_ioctl(struct irp *irp);
static HRESULT jvs_ioctl_hello(struct irp *irp);
static HRESULT jvs_ioctl_sense(struct irp *irp);
static HRESULT jvs_ioctl_transact(struct irp *irp);
static HANDLE jvs_fd;
static struct jvs_node *jvs_root;
static jvs_provider_t jvs_provider;
HRESULT jvs_hook_init(const struct jvs_config *cfg, jvs_provider_t provider)
{
HRESULT hr;
assert(cfg != NULL);
if (!cfg->enable) {
return S_FALSE;
}
hr = iohook_push_handler(jvs_handle_irp);
if (FAILED(hr)) {
return hr;
}
hr = setupapi_add_phantom_dev(&jvs_guid, L"$jvs");
if (FAILED(hr)) {
return hr;
}
jvs_provider = provider;
return S_OK;
}
static HRESULT jvs_handle_irp(struct irp *irp)
{
assert(irp != NULL);
if (irp->op != IRP_OP_OPEN && irp->fd != jvs_fd) {
return iohook_invoke_next(irp);
}
switch (irp->op) {
case IRP_OP_OPEN: return jvs_handle_open(irp);
case IRP_OP_CLOSE: return jvs_handle_close(irp);
case IRP_OP_IOCTL: return jvs_handle_ioctl(irp);
default: return HRESULT_FROM_WIN32(ERROR_INVALID_FUNCTION);
}
}
static HRESULT jvs_handle_open(struct irp *irp)
{
struct jvs_node *root;
HRESULT hr;
if (!wstr_eq(irp->open_filename, L"$jvs")) {
return iohook_invoke_next(irp);
}
if (jvs_fd != NULL) {
dprintf("JVS Port: Already open\n");
return HRESULT_FROM_WIN32(ERROR_SHARING_VIOLATION);
}
hr = iohook_open_nul_fd(&jvs_fd);
if (FAILED(hr)) {
return hr;
}
dprintf("JVS Port: Open device\n");
if (jvs_provider != NULL) {
hr = jvs_provider(&root);
if (SUCCEEDED(hr)) {
jvs_root = root;
}
}
irp->fd = jvs_fd;
return S_OK;
}
static HRESULT jvs_handle_close(struct irp *irp)
{
dprintf("JVS Port: Close device\n");
jvs_fd = NULL;
return iohook_invoke_next(irp);
}
static HRESULT jvs_handle_ioctl(struct irp *irp)
{
switch (irp->ioctl) {
case JVS_IOCTL_HELLO:
return jvs_ioctl_hello(irp);
case JVS_IOCTL_SENSE:
return jvs_ioctl_sense(irp);
case JVS_IOCTL_TRANSACT:
return jvs_ioctl_transact(irp);
default:
dprintf("JVS Port: Unknown ioctl %#x\n", irp->ioctl);
return HRESULT_FROM_WIN32(ERROR_INVALID_FUNCTION);
}
}
static HRESULT jvs_ioctl_hello(struct irp *irp)
{
HRESULT hr;
// uuh fucked if i know
dprintf("JVS Port: Port startup (?)\n");
iobuf_write_8(&irp->read, 0);
hr = iobuf_write_8(&irp->read, 0);
return hr;
}
static HRESULT jvs_ioctl_sense(struct irp *irp)
{
uint8_t code;
bool sense;
if (jvs_root != NULL) {
sense = jvs_root->sense(jvs_root);
if (sense) {
dprintf("JVS Port: Sense line 2.5 V (address unassigned)\n");
code = 3;
} else {
dprintf("JVS Port: Sense line 0.0 V (address assigned)\n");
code = 2;
}
} else {
dprintf("JVS Port: Sense line 5.0 V (no downstream PCB)\n");
code = 1;
}
return iobuf_write_8(&irp->read, code);
}
static HRESULT jvs_ioctl_transact(struct irp *irp)
{
#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 defined(LOG_JVS)
dprintf("JVS Port: Inbound frame:\n");
dump_iobuf(&irp->read);
dprintf("\n");
#endif
if (irp->read.pos == 0) {
/* The un-acked JVS reset command must return ERROR_NO_DATA_DETECTED,
and this error must always be returned asynchronously. And since
async I/O comes from the NT kernel, we have to return that win32
error as the equivalent NTSTATUS. */
if (irp->ovl == NULL || irp->ovl->hEvent == NULL) {
return HRESULT_FROM_WIN32(ERROR_NO_DATA_DETECTED);
}
irp->ovl->Internal = STATUS_NO_DATA_DETECTED;
SetEvent(irp->ovl->hEvent);
return HRESULT_FROM_WIN32(ERROR_IO_PENDING);
} else {
return S_OK;
}
}
+22
View File
@@ -0,0 +1,22 @@
#pragma once
#include <windows.h>
#include <stdbool.h>
#include "jvs/jvs-bus.h"
DEFINE_GUID(
jvs_guid,
0xDB6BBB45,
0xCC96,
0x4288,
0xAA, 0x00, 0x6C, 0x00, 0xD7, 0x67, 0xBD, 0xBF);
struct jvs_config {
bool enable;
};
typedef HRESULT (*jvs_provider_t)(struct jvs_node **root);
HRESULT jvs_hook_init(const struct jvs_config *cfg, jvs_provider_t provider);
+27
View File
@@ -0,0 +1,27 @@
amex_lib = static_library(
'amex',
include_directories : inc,
implicit_include_directories : false,
dependencies : [
capnhook.get_variable('hook_dep'),
],
sources : [
'amex.c',
'amex.h',
'config.c',
'config.h',
'ds.c',
'ds.h',
'eeprom.c',
'eeprom.h',
'gpio.c',
'gpio.h',
'guid.c',
'jvs.c',
'jvs.h',
'nvram.c',
'nvram.h',
'sram.c',
'sram.h',
],
)
+81
View File
@@ -0,0 +1,81 @@
#include <windows.h>
#include <assert.h>
#include <stddef.h>
#include <stdint.h>
#include "amex/nvram.h"
#include "util/dprintf.h"
HRESULT nvram_open_file(HANDLE *out, const wchar_t *path, size_t size)
{
LARGE_INTEGER cur_size;
LARGE_INTEGER pos;
HANDLE file;
HRESULT hr;
BOOL ok;
assert(out != NULL);
assert(path != NULL);
*out = NULL;
file = CreateFileW(
path,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ,
NULL,
OPEN_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (file == INVALID_HANDLE_VALUE) {
hr = HRESULT_FROM_WIN32(GetLastError());
dprintf("%S: Error opening backing store: %x\n", path, (int) hr);
goto end;
}
ok = GetFileSizeEx(file, &cur_size);
if (!ok) {
hr = HRESULT_FROM_WIN32(GetLastError());
dprintf("%S: GetFileSizeEx failed: %x\n", path, (int) hr);
goto end;
}
if (cur_size.QuadPart != (uint64_t) size) {
pos.QuadPart = (uint64_t) size;
ok = SetFilePointerEx(file, pos, NULL, FILE_BEGIN);
if (!ok) {
hr = HRESULT_FROM_WIN32(GetLastError());
dprintf("%S: SetFilePointerEx failed: %x\n", path, (int) hr);
goto end;
}
ok = SetEndOfFile(file);
if (!ok) {
hr = HRESULT_FROM_WIN32(GetLastError());
dprintf("%S: SetEndOfFile failed: %x\n", path, (int) hr);
goto end;
}
}
*out = file;
file = INVALID_HANDLE_VALUE;
hr = S_OK;
end:
if (file != INVALID_HANDLE_VALUE) {
CloseHandle(file);
}
return hr;
}
+7
View File
@@ -0,0 +1,7 @@
#pragma once
#include <windows.h>
#include <stddef.h>
HRESULT nvram_open_file(HANDLE *out, const wchar_t *path, size_t size);
+158
View File
@@ -0,0 +1,158 @@
#include <windows.h>
#ifdef __GNUC__
#include <ntdef.h>
#else
#include <winnt.h>
#endif
#include <devioctl.h>
#include <winioctl.h>
#include <assert.h>
#include "amex/sram.h"
#include "amex/nvram.h"
#include "hook/iohook.h"
#include "hooklib/setupapi.h"
#include "util/dprintf.h"
#include "util/str.h"
#define SRAM_IOCTL_GET_ABI_VERSION CTL_CODE(0x8000, 0x800, METHOD_BUFFERED, FILE_READ_ACCESS)
static HRESULT sram_handle_irp(struct irp *irp);
static HRESULT sram_handle_open(struct irp *irp);
static HRESULT sram_handle_close(struct irp *irp);
static HRESULT sram_handle_ioctl(struct irp *irp);
static HRESULT sram_ioctl_get_geometry(struct irp *irp);
static HRESULT sram_ioctl_get_abi_version(struct irp *irp);
static struct sram_config sram_config;
static HANDLE sram_file;
HRESULT sram_hook_init(const struct sram_config *cfg)
{
HRESULT hr;
assert(cfg != NULL);
if (!cfg->enable) {
return S_FALSE;
}
memcpy(&sram_config, cfg, sizeof(*cfg));
hr = iohook_push_handler(sram_handle_irp);
if (FAILED(hr)) {
return hr;
}
hr = setupapi_add_phantom_dev(&sram_guid, L"$sram");
if (FAILED(hr)) {
return hr;
}
return S_OK;
}
static HRESULT sram_handle_irp(struct irp *irp)
{
assert(irp != NULL);
if (irp->op != IRP_OP_OPEN && irp->fd != sram_file) {
return iohook_invoke_next(irp);
}
switch (irp->op) {
case IRP_OP_OPEN: return sram_handle_open(irp);
case IRP_OP_CLOSE: return sram_handle_close(irp);
case IRP_OP_IOCTL: return sram_handle_ioctl(irp);
default: return iohook_invoke_next(irp);
}
}
static HRESULT sram_handle_open(struct irp *irp)
{
HRESULT hr;
if (!wstr_eq(irp->open_filename, L"$sram")) {
return iohook_invoke_next(irp);
}
if (sram_file != NULL) {
dprintf("SRAM: Already open\n");
return HRESULT_FROM_WIN32(ERROR_SHARING_VIOLATION);
}
dprintf("SRAM: Open device\n");
hr = nvram_open_file(&sram_file, sram_config.path, 0x80000);
if (FAILED(hr)) {
return hr;
}
irp->fd = sram_file;
return S_OK;
}
static HRESULT sram_handle_close(struct irp *irp)
{
dprintf("SRAM: Close device\n");
sram_file = NULL;
return iohook_invoke_next(irp);
}
static HRESULT sram_handle_ioctl(struct irp *irp)
{
switch (irp->ioctl) {
case IOCTL_DISK_GET_DRIVE_GEOMETRY:
return sram_ioctl_get_geometry(irp);
case SRAM_IOCTL_GET_ABI_VERSION:
return sram_ioctl_get_abi_version(irp);
default:
dprintf("SRAM: Unknown ioctl %x, write %i read %i\n",
irp->ioctl,
(int) irp->write.nbytes,
(int) irp->read.nbytes);
return HRESULT_FROM_WIN32(ERROR_INVALID_FUNCTION);
}
}
static HRESULT sram_ioctl_get_geometry(struct irp *irp)
{
DISK_GEOMETRY out;
HRESULT hr;
dprintf("SRAM: Get geometry\n");
memset(&out, 0, sizeof(out));
out.Cylinders.QuadPart = 0x20000;
out.MediaType = 0;
out.TracksPerCylinder = 1;
out.SectorsPerTrack = 1;
out.BytesPerSector = 4;
hr = iobuf_write(&irp->read, &out, sizeof(out));
if (FAILED(hr)) {
dprintf("SRAM: Get geometry failed: %08x\n", (int) hr);
}
return hr;
}
static HRESULT sram_ioctl_get_abi_version(struct irp *irp)
{
return iobuf_write_le16(&irp->read, 256);
}
+20
View File
@@ -0,0 +1,20 @@
#pragma once
#include <windows.h>
#include <stdbool.h>
#include <stddef.h>
struct sram_config {
bool enable;
wchar_t path[MAX_PATH];
};
DEFINE_GUID(
sram_guid,
0x741B5FCA,
0x4635,
0x4443,
0xA7, 0xA0, 0x57, 0xCA, 0x7B, 0x50, 0x6A, 0x49);
HRESULT sram_hook_init(const struct sram_config *cfg);
+112
View File
@@ -0,0 +1,112 @@
#include <windows.h>
#include <assert.h>
#include <stdlib.h>
#include "board/aime-dll.h"
#include "util/dll-bind.h"
#include "util/dprintf.h"
const struct dll_bind_sym aime_dll_syms[] = {
{
.sym = "aime_io_init",
.off = offsetof(struct aime_dll, init),
}, {
.sym = "aime_io_nfc_poll",
.off = offsetof(struct aime_dll, nfc_poll),
}, {
.sym = "aime_io_nfc_get_aime_id",
.off = offsetof(struct aime_dll, nfc_get_aime_id),
}, {
.sym = "aime_io_nfc_get_felica_id",
.off = offsetof(struct aime_dll, nfc_get_felica_id),
}, {
.sym = "aime_io_led_set_color",
.off = offsetof(struct aime_dll, led_set_color),
}
};
struct aime_dll aime_dll;
// Copypasta DLL binding and diagnostic message boilerplate.
// Not much of this lends itself to being easily factored out. Also there
// will be a lot of API-specific branching code here eventually as new API
// versions get defined, so even though these functions all look the same
// now this won't remain the case forever.
HRESULT aime_dll_init(const struct aime_dll_config *cfg, HINSTANCE self)
{
uint16_t (*get_api_version)(void);
const struct dll_bind_sym *sym;
HINSTANCE owned;
HINSTANCE src;
HRESULT hr;
assert(cfg != NULL);
assert(self != NULL);
if (cfg->path[0] != L'\0') {
owned = LoadLibraryW(cfg->path);
if (owned == NULL) {
hr = HRESULT_FROM_WIN32(GetLastError());
dprintf("NFC Assembly: Failed to load IO DLL: %lx: %S\n",
hr,
cfg->path);
goto end;
}
dprintf("NFC Assembly: Using custom IO DLL: %S\n", cfg->path);
src = owned;
} else {
owned = NULL;
src = self;
}
get_api_version = (void *) GetProcAddress(src, "aime_io_get_api_version");
if (get_api_version != NULL) {
aime_dll.api_version = get_api_version();
} else {
aime_dll.api_version = 0x0100;
dprintf("Custom IO DLL does not expose aime_io_get_api_version, "
"assuming API version 1.0.\n"
"Please ask the developer to update their DLL.\n");
}
if (aime_dll.api_version >= 0x0200) {
hr = E_NOTIMPL;
dprintf("NFC Assembly: Custom IO DLL implements an unsupported "
"API version (%#04x). Please update Segatools.\n",
aime_dll.api_version);
goto end;
}
sym = aime_dll_syms;
hr = dll_bind(&aime_dll, src, &sym, _countof(aime_dll_syms));
if (FAILED(hr)) {
if (src != self) {
dprintf("NFC Assembly: Custom IO DLL does not provide function "
"\"%s\". Please contact your IO DLL's developer for "
"further assistance.\n",
sym->sym);
goto end;
} else {
dprintf("Internal error: could not reflect \"%s\"\n", sym->sym);
}
}
owned = NULL;
end:
if (owned != NULL) {
FreeLibrary(owned);
}
return hr;
}
+27
View File
@@ -0,0 +1,27 @@
#pragma once
#include <windows.h>
#include <stdbool.h>
#include "aimeio/aimeio.h"
struct aime_dll {
uint16_t api_version;
HRESULT (*init)(void);
HRESULT (*nfc_poll)(uint8_t unit_no);
HRESULT (*nfc_get_aime_id)(
uint8_t unit_no,
uint8_t *luid,
size_t luid_size);
HRESULT (*nfc_get_felica_id)(uint8_t unit_no, uint64_t *IDm);
void (*led_set_color)(uint8_t unit_no, uint8_t r, uint8_t g, uint8_t b);
};
struct aime_dll_config {
wchar_t path[MAX_PATH];
bool path64;
};
extern struct aime_dll aime_dll;
HRESULT aime_dll_init(const struct aime_dll_config *cfg, HINSTANCE self);
+113
View File
@@ -0,0 +1,113 @@
#include <windows.h>
#include <assert.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdlib.h>
#include "board/aime-dll.h"
#include "board/config.h"
#include "board/sg-reader.h"
#include "board/vfd.h"
#include "util/dprintf.h"
// Check windows
#if _WIN32 || _WIN64
#if _WIN64
#define ENV64BIT
#else
#define ENV32BIT
#endif
#endif
// Check GCC
#if __GNUC__
#if __x86_64__ || __ppc64__
#define ENV64BIT
#else
#define ENV32BIT
#endif
#endif
static void aime_dll_config_load(struct aime_dll_config *cfg, const wchar_t *filename)
{
assert(cfg != NULL);
assert(filename != NULL);
// Workaround for x64/x86 external IO dlls
// path32 for 32bit, path64 for 64bit
// for else.. is that possible? idk
if (cfg->path64) {
#if defined(ENV32BIT)
// Always empty, due to amdaemon being 64 bit in 32 bit mode
memset(cfg->path, 0, sizeof(cfg->path));
#elif defined(ENV64BIT)
GetPrivateProfileStringW(
L"aimeio",
L"path",
L"",
cfg->path,
_countof(cfg->path),
filename);
#else
#error "Unknown environment"
#endif
} else {
GetPrivateProfileStringW(
L"aimeio",
L"path",
L"",
cfg->path,
_countof(cfg->path),
filename);
}
}
void aime_config_load(struct aime_config *cfg, const wchar_t *filename)
{
assert(cfg != NULL);
assert(filename != NULL);
aime_dll_config_load(&cfg->dll, filename);
cfg->enable = GetPrivateProfileIntW(L"aime", L"enable", 1, filename);
cfg->port_no = GetPrivateProfileIntW(L"aime", L"portNo", 0, filename);
cfg->high_baudrate = GetPrivateProfileIntW(L"aime", L"highBaud", 1, filename);
cfg->gen = GetPrivateProfileIntW(L"aime", L"gen", 0, filename);
cfg->proxy_flag = GetPrivateProfileIntW(L"aime", L"proxyFlag", 2, filename);
GetPrivateProfileStringW(
L"aime",
L"authdataPath",
L"DEVICE\\authdata.bin",
cfg->authdata_path,
_countof(cfg->authdata_path),
filename);
}
void io4_config_load(struct io4_config *cfg, const wchar_t *filename)
{
assert(cfg != NULL);
assert(filename != NULL);
cfg->enable = GetPrivateProfileIntW(L"io4", L"enable", 1, filename);
}
void vfd_config_load(struct vfd_config *cfg, const wchar_t *filename)
{
assert(cfg != NULL);
assert(filename != NULL);
cfg->enable = GetPrivateProfileIntW(L"vfd", L"enable", 1, filename);
cfg->port_no = GetPrivateProfileIntW(L"vfd", L"portNo", 0, filename);
cfg->utf_conversion = GetPrivateProfileIntW(L"vfd", L"utfConversion", 0, filename);
}
void ffb_config_load(struct ffb_config *cfg, const wchar_t *filename)
{
assert(cfg != NULL);
assert(filename != NULL);
cfg->enable = GetPrivateProfileIntW(L"ffb", L"enable", 1, filename);
}
+14
View File
@@ -0,0 +1,14 @@
#pragma once
#include <stdbool.h>
#include <stddef.h>
#include "board/io4.h"
#include "board/sg-reader.h"
#include "board/vfd.h"
#include "board/ffb.h"
void aime_config_load(struct aime_config *cfg, const wchar_t *filename);
void io4_config_load(struct io4_config *cfg, const wchar_t *filename);
void vfd_config_load(struct vfd_config *cfg, const wchar_t *filename);
void ffb_config_load(struct ffb_config *cfg, const wchar_t *filename);
+235
View File
@@ -0,0 +1,235 @@
/*
Force Feedback Board (FFB)
This board is used by many SEGA games to provide force feedback to the player.
It is driven by the game software over a serial connection and is used by many
games such as SEGA World Drivers Championship, Initial D Arcade, ...
Part number in schematics is "838-15069 MOTOR DRIVE BD RS232/422 Board".
Some observations:
The maximal strength for any effect is 127, except Damper which maxes out at 40.
The period for rumble effects is in the range 0-40.
*/
#include "board/ffb.h"
#include <assert.h>
#include <stdint.h>
#include <windows.h>
#include "hook/iohook.h"
#include "hooklib/uart.h"
#include "util/dprintf.h"
#include "util/dump.h"
// request format:
// 0x?? - sync + command
// 0x?? - direction/additional command
// 0x?? - strength
// 0x?? - checksum (sum of everything except the sync byte)
enum {
FFB_CMD_TOGGLE = 0x80,
FFB_CMD_CONSTANT_FORCE = 0x84,
FFB_CMD_RUMBLE = 0x85,
FFB_CMD_DAMPER = 0x86,
};
struct ffb_hdr {
uint8_t cmd;
};
union ffb_req_any {
struct ffb_hdr hdr;
uint8_t bytes[3];
};
static HRESULT ffb_handle_irp(struct irp *irp);
static HRESULT ffb_req_dispatch(const union ffb_req_any *req);
static HRESULT ffb_req_toggle(const uint8_t *bytes);
static HRESULT ffb_req_constant_force(const uint8_t *bytes);
static HRESULT ffb_req_rumble(const uint8_t *bytes);
static HRESULT ffb_req_damper(const uint8_t *bytes);
static const struct ffb_ops *ffb_ops;
static struct uart ffb_uart;
static bool ffb_started;
static HRESULT ffb_start_hr;
static uint8_t ffb_written[4];
static uint8_t ffb_readable[4];
/* Static variables to store maximum strength values */
static uint8_t max_constant_force = 0;
static uint8_t max_rumble = 0;
static uint8_t max_period = 0;
static uint8_t max_damper = 0;
HRESULT ffb_hook_init(
const struct ffb_config *cfg,
const struct ffb_ops *ops,
unsigned int port_no)
{
assert(cfg != NULL);
assert(ops != NULL);
if (!cfg->enable) {
return S_FALSE;
}
ffb_ops = ops;
uart_init(&ffb_uart, port_no);
ffb_uart.written.bytes = ffb_written;
ffb_uart.written.nbytes = sizeof(ffb_written);
ffb_uart.readable.bytes = ffb_readable;
ffb_uart.readable.nbytes = sizeof(ffb_readable);
dprintf("FFB: hook enabled.\n");
return iohook_push_handler(ffb_handle_irp);
}
static HRESULT ffb_handle_irp(struct irp *irp)
{
HRESULT hr;
assert(irp != NULL);
if (!uart_match_irp(&ffb_uart, irp)) {
return iohook_invoke_next(irp);
}
hr = uart_handle_irp(&ffb_uart, irp);
if (FAILED(hr) || irp->op != IRP_OP_WRITE) {
return hr;
}
assert(&ffb_uart.written != NULL);
assert(ffb_uart.written.bytes != NULL || ffb_uart.written.nbytes == 0);
assert(ffb_uart.written.pos <= ffb_uart.written.nbytes);
// dprintf("FFB TX:\n");
hr = ffb_req_dispatch((const union ffb_req_any *) ffb_uart.written.bytes);
if (FAILED(hr)) {
dprintf("FFB: Processing error: %x\n", (int)hr);
}
// dump_iobuf(&ffb_uart.written);
ffb_uart.written.pos = 0;
return hr;
}
static HRESULT ffb_req_dispatch(const union ffb_req_any *req)
{
switch (req->hdr.cmd) {
case FFB_CMD_TOGGLE:
return ffb_req_toggle(req->bytes);
case FFB_CMD_CONSTANT_FORCE:
return ffb_req_constant_force(req->bytes);
case FFB_CMD_RUMBLE:
return ffb_req_rumble(req->bytes);
case FFB_CMD_DAMPER:
return ffb_req_damper(req->bytes);
/* There are some test mode specfic commands which doesn't seem to be used in
game at all. The same is true for the initialization phase. */
default:
dprintf("FFB: Unhandled command %02x\n", req->hdr.cmd);
return S_OK;
}
}
static HRESULT ffb_req_toggle(const uint8_t *bytes)
{
uint8_t activate = bytes[2];
if (activate == 0x01) {
dprintf("FFB: Activated\n");
} else {
dprintf("FFB: Deactivated\n");
}
if (ffb_ops->toggle != NULL) {
ffb_ops->toggle(activate == 0x01);
}
return S_OK;
}
static HRESULT ffb_req_constant_force(const uint8_t *bytes)
{
// dprintf("FFB: Constant force\n");
uint8_t direction = bytes[1];
uint8_t force = bytes[2];
if (direction == 0x0) {
// Right
force = 128 - force;
}
// Update max strength if the current force is greater
if (force > max_constant_force) {
max_constant_force = force;
}
// dprintf("FFB: Constant Force Strength: %d (Max: %d)\n", force, max_constant_force);
if (ffb_ops->constant_force != NULL) {
ffb_ops->constant_force(direction, force);
}
return S_OK;
}
static HRESULT ffb_req_rumble(const uint8_t *bytes)
{
// dprintf("FFB: Rumble\n");
uint8_t force = bytes[1];
uint8_t period = bytes[2];
// Update max strength if the current force is greater
if (force > max_rumble) {
max_rumble = force;
}
if (period > max_period) {
max_period = period;
}
// dprintf("FFB: Rumble Period: %d (Max %d), Strength: %d (Max: %d)\n", period, max_period, force, max_rumble);
if (ffb_ops->rumble != NULL) {
ffb_ops->rumble(force, period);
}
return S_OK;
}
static HRESULT ffb_req_damper(const uint8_t *bytes)
{
// dprintf("FFB: Damper\n");
uint8_t force = bytes[2];
// Update max strength if the current force is greater
if (force > max_damper) {
max_damper = force;
}
// dprintf("FFB: Damper Strength: %d (Max: %d)\n", force, max_damper);
if (ffb_ops->damper != NULL) {
ffb_ops->damper(force);
}
return S_OK;
}
+21
View File
@@ -0,0 +1,21 @@
#pragma once
#include <windows.h>
#include <stdbool.h>
#include <stdint.h>
struct ffb_config {
bool enable;
};
struct ffb_ops {
void (*toggle)(bool active);
void (*constant_force)(uint8_t direction, uint8_t force);
void (*rumble)(uint8_t force, uint8_t period);
void (*damper)(uint8_t force);
};
HRESULT ffb_hook_init(
const struct ffb_config *cfg,
const struct ffb_ops *ops,
unsigned int port_no);
+3
View File
@@ -0,0 +1,3 @@
#include <initguid.h>
#include "board/guid.h"
+10
View File
@@ -0,0 +1,10 @@
#pragma once
#include <windows.h>
DEFINE_GUID(
hid_guid,
0x4D1E55B2L,
0xF16F,
0x11CF,
0x88, 0xCB, 0x00, 0x11, 0x11, 0x00, 0x00, 0x30);
+713
View File
@@ -0,0 +1,713 @@
/*
Sega "Type 3" JVS I/O emulator
Credits:
Protocol docs:
https://github.com/TheOnlyJoey/openjvs/wiki/ (a/o October 2018)
Capability dumps:
https://wiki.arcadeotaku.com/w/JVS#Sega_837-14572 (a/o October 2018)
*/
#include <windows.h>
#include <assert.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
#include "board/io3.h"
#include "jvs/jvs-bus.h"
#include "jvs/jvs-cmd.h"
#include "jvs/jvs-util.h"
#include "util/dprintf.h"
#include "util/dump.h"
static void io3_transact(
struct jvs_node *node,
const void *bytes,
size_t nbytes,
struct iobuf *resp);
static bool io3_sense(struct jvs_node *node);
static HRESULT io3_cmd(
void *ctx,
struct const_iobuf *req,
struct iobuf *resp);
static HRESULT io3_cmd_read_id(
struct io3 *io3,
struct const_iobuf *req_buf,
struct iobuf *resp_buf);
static HRESULT io3_cmd_get_cmd_version(
struct io3 *io3,
struct const_iobuf *req_buf,
struct iobuf *resp_buf);
static HRESULT io3_cmd_get_jvs_version(
struct io3 *io3,
struct const_iobuf *req_buf,
struct iobuf *resp_buf);
static HRESULT io3_cmd_get_comm_version(
struct io3 *io3,
struct const_iobuf *req_buf,
struct iobuf *resp_buf);
static HRESULT io3_cmd_get_features(
struct io3 *io3,
struct const_iobuf *req_buf,
struct iobuf *resp_buf);
static HRESULT io3_cmd_read_switches(
struct io3 *io3,
struct const_iobuf *req_buf,
struct iobuf *resp_buf);
static HRESULT io3_cmd_read_coin(
struct io3 *io3,
struct const_iobuf *req_buf,
struct iobuf *resp_buf);
static HRESULT io3_cmd_read_analogs(
struct io3 *io3,
struct const_iobuf *req_buf,
struct iobuf *resp_buf);
static HRESULT io3_cmd_read_rotarys(
struct io3 *io3,
struct const_iobuf *req_buf,
struct iobuf *resp_buf);
static HRESULT io3_cmd_write_gpio(
struct io3 *io3,
struct const_iobuf *req_buf,
struct iobuf *resp_buf);
static HRESULT io3_cmd_reset(struct io3 *io3, struct const_iobuf *buf);
static HRESULT io3_cmd_assign_addr(
struct io3 *io3,
struct const_iobuf *req_buf,
struct iobuf *resp_buf);
static const uint8_t io3_ident[] =
"SEGA CORPORATION;I/O BD JVS;837-14572;Ver1.00;2005/10";
static uint8_t io3_features[] = {
/* Feature : 0x01 : Players and switches
Param1 : 2 : Number of players
Param2 : 14 : Number of switches per player
Param3 : 0 : N/A */
0x01, 2, 14, 0,
/* Feature : 0x02 : Coin slots
Param1 : 2 : Number of coin slots
Param2 : 0 : N/A
Param3 : 0 : N/A */
0x02, 2, 0, 0,
/* Feature : 0x03 : Analog inputs
Param1 : 8 : Number of ADC channels
Param2 : 10 : Effective bits of resolution per ADC
Param3 : 0 : N/A */
0x03, 8, 10, 0,
/* Feature : 0x04 : Rotary inputs
Param1 : 4 : Number of rotary channels
Param2 : 0 : N/A
Param3 : 0 : N/A */
0x04, 4, 0, 0,
/* Feature : 0x12 : GPIO outputs
Param1 : 3 : Number of ports (8 bits per port)
Param2 : 0 : N/A
Param3 : 0 : N/A
NOTE: This particular port count is what an IO-4 attached over JVS
advertises, an IO-3 only advertises 3. Still, this seems to be backwards
compatible with games that expect an IO-3, and the protocols seem to be
identical otherwise. */
0x12, 20, 0, 0,
/* Feature : 0x00 : End of capabilities */
0x00,
};
void io3_init(
struct io3 *io3,
struct jvs_node *next,
const struct io3_ops *ops,
void *ops_ctx)
{
assert(io3 != NULL);
assert(ops != NULL);
io3->jvs.next = next;
io3->jvs.transact = io3_transact;
io3->jvs.sense = io3_sense;
io3->addr = 0xFF;
io3->ops = ops;
io3->ops_ctx = ops_ctx;
}
struct jvs_node *io3_to_jvs_node(struct io3 *io3)
{
assert(io3 != NULL);
return &io3->jvs;
}
static void io3_transact(
struct jvs_node *node,
const void *bytes,
size_t nbytes,
struct iobuf *resp)
{
struct io3 *io3;
assert(node != NULL);
assert(bytes != NULL);
assert(resp != NULL);
io3 = CONTAINING_RECORD(node, struct io3, jvs);
jvs_crack_request(bytes, nbytes, resp, io3->addr, io3_cmd, io3);
}
static bool io3_sense(struct jvs_node *node)
{
struct io3 *io3;
assert(node != NULL);
io3 = CONTAINING_RECORD(node, struct io3, jvs);
return io3->addr == 0xFF;
}
static HRESULT io3_cmd(
void *ctx,
struct const_iobuf *req,
struct iobuf *resp)
{
struct io3 *io3;
io3 = ctx;
switch (req->bytes[req->pos]) {
case JVS_CMD_READ_ID:
return io3_cmd_read_id(io3, req, resp);
case JVS_CMD_GET_CMD_VERSION:
return io3_cmd_get_cmd_version(io3, req, resp);
case JVS_CMD_GET_JVS_VERSION:
return io3_cmd_get_jvs_version(io3, req, resp);
case JVS_CMD_GET_COMM_VERSION:
return io3_cmd_get_comm_version(io3, req, resp);
case JVS_CMD_GET_FEATURES:
return io3_cmd_get_features(io3, req, resp);
case JVS_CMD_READ_SWITCHES:
return io3_cmd_read_switches(io3, req, resp);
case JVS_CMD_READ_COIN:
return io3_cmd_read_coin(io3, req, resp);
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);
case JVS_CMD_WRITE_GPIO:
return io3_cmd_write_gpio(io3, req, resp);
case JVS_CMD_RESET:
return io3_cmd_reset(io3, req);
case JVS_CMD_ASSIGN_ADDR:
return io3_cmd_assign_addr(io3, req, resp);
default:
dprintf("JVS I/O: Node %02x: Unhandled command byte %02x\n",
io3->addr,
req->bytes[req->pos]);
return E_NOTIMPL;
}
}
static HRESULT io3_cmd_read_id(
struct io3 *io3,
struct const_iobuf *req_buf,
struct iobuf *resp_buf)
{
uint8_t req;
HRESULT hr;
hr = iobuf_read_8(req_buf, &req);
if (FAILED(hr)) {
return hr;
}
dprintf("JVS I/O: Read ID\n");
/* Write report byte */
hr = iobuf_write_8(resp_buf, 0x01);
if (FAILED(hr)) {
return hr;
}
/* Write the identification string. The NUL terminator at the end of this C
string is also sent, and it naturally terminates the response chunk. */
return iobuf_write(resp_buf, io3_ident, sizeof(io3_ident));
}
static HRESULT io3_cmd_get_cmd_version(
struct io3 *io3,
struct const_iobuf *req_buf,
struct iobuf *resp_buf)
{
uint8_t req;
uint8_t resp[2];
HRESULT hr;
hr = iobuf_read_8(req_buf, &req);
if (FAILED(hr)) {
return hr;
}
dprintf("JVS I/O: Get command format version\n");
resp[0] = 0x01; /* Report byte */
resp[1] = 0x13; /* Command format version BCD */
return iobuf_write(resp_buf, resp, sizeof(resp));
}
static HRESULT io3_cmd_get_jvs_version(
struct io3 *io3,
struct const_iobuf *req_buf,
struct iobuf *resp_buf)
{
uint8_t req;
uint8_t resp[2];
HRESULT hr;
hr = iobuf_read_8(req_buf, &req);
if (FAILED(hr)) {
return hr;
}
dprintf("JVS I/O: Get JVS version\n");
resp[0] = 0x01; /* Report byte */
resp[1] = 0x20; /* JVS version BCD */
return iobuf_write(resp_buf, resp, sizeof(resp));
}
static HRESULT io3_cmd_get_comm_version(
struct io3 *io3,
struct const_iobuf *req_buf,
struct iobuf *resp_buf)
{
uint8_t req;
uint8_t resp[2];
HRESULT hr;
hr = iobuf_read_8(req_buf, &req);
if (FAILED(hr)) {
return hr;
}
dprintf("JVS I/O: Get communication version\n");
resp[0] = 0x01; /* Report byte */
resp[1] = 0x10; /* "Communication version" BCD */
return iobuf_write(resp_buf, resp, sizeof(resp));
}
static HRESULT io3_cmd_get_features(
struct io3 *io3,
struct const_iobuf *req_buf,
struct iobuf *resp_buf)
{
uint8_t req;
HRESULT hr;
hr = iobuf_read_8(req_buf, &req);
if (FAILED(hr)) {
return hr;
}
dprintf("JVS I/O: Get features\n");
hr = iobuf_write_8(resp_buf, 0x01); /* Write report byte */
if (FAILED(hr)) {
return hr;
}
return iobuf_write(resp_buf, io3_features, sizeof(io3_features));
}
static HRESULT io3_cmd_read_switches(
struct io3 *io3,
struct const_iobuf *req_buf,
struct iobuf *resp_buf)
{
struct jvs_req_read_switches req;
struct io3_switch_state state;
HRESULT hr;
/* Read req */
hr = iobuf_read(req_buf, &req, sizeof(req));
if (FAILED(hr)) {
return hr;
}
#if defined(LOG_IO3)
dprintf("JVS I/O: Read switches, np=%i, bpp=%i\n",
req.num_players,
req.bytes_per_player);
#endif
if (req.num_players > 2 || req.bytes_per_player != 2) {
dprintf("JVS I/O: Invalid read size "
"num_players=%i "
"bytes_per_player=%i\n",
req.num_players,
req.bytes_per_player);
hr = iobuf_write_8(resp_buf, 0x02);
if (FAILED(hr)) {
return hr;
}
return E_FAIL;
}
/* Build response */
hr = iobuf_write_8(resp_buf, 0x01); /* Report byte */
if (FAILED(hr)) {
return hr;
}
memset(&state, 0, sizeof(state));
if (io3->ops != NULL) {
io3->ops->read_switches(io3->ops_ctx, &state);
}
hr = iobuf_write_8(resp_buf, state.system); /* Test, Tilt lines */
if (FAILED(hr)) {
return hr;
}
if (req.num_players > 0) {
hr = iobuf_write_be16(resp_buf, state.p1);
if (FAILED(hr)) {
return hr;
}
}
if (req.num_players > 1) {
hr = iobuf_write_be16(resp_buf, state.p2);
if (FAILED(hr)) {
return hr;
}
}
return hr;
}
static HRESULT io3_cmd_read_coin(
struct io3 *io3,
struct const_iobuf *req_buf,
struct iobuf *resp_buf)
{
struct jvs_req_read_coin req;
uint16_t ncoins;
uint8_t i;
HRESULT hr;
/* Read req */
hr = iobuf_read(req_buf, &req, sizeof(req));
if (FAILED(hr)) {
return hr;
}
//dprintf("JVS I/O: Read coin, nslots=%i\n", req.nslots);
/* Write report byte */
hr = iobuf_write_8(resp_buf, 0x01);
if (FAILED(hr)) {
return hr;
}
/* Write slot detail */
for (i = 0 ; i < req.nslots ; i++) {
ncoins = 0;
if (io3->ops->read_coin_counter != NULL) {
io3->ops->read_coin_counter(io3->ops_ctx, i, &ncoins);
}
hr = iobuf_write_be16(resp_buf, ncoins);
if (FAILED(hr)) {
return hr;
}
}
return hr;
}
static HRESULT io3_cmd_read_analogs(
struct io3 *io3,
struct const_iobuf *req_buf,
struct iobuf *resp_buf)
{
struct jvs_req_read_analogs req;
uint16_t analogs[8];
uint8_t i;
HRESULT hr;
/* Read req */
hr = iobuf_read(req_buf, &req, sizeof(req));
if (FAILED(hr)) {
return hr;
}
if (req.nanalogs > _countof(analogs)) {
dprintf("JVS I/O: Invalid analog count %i\n", req.nanalogs);
return E_FAIL;
}
//dprintf("JVS I/O: Read analogs, nanalogs=%i\n", req.nanalogs);
/* Write report byte */
hr = iobuf_write_8(resp_buf, 0x01);
if (FAILED(hr)) {
return hr;
}
/* Write analogs */
memset(analogs, 0, sizeof(analogs));
if (io3->ops->read_analogs != NULL) {
io3->ops->read_analogs(io3->ops_ctx, analogs, req.nanalogs);
}
for (i = 0 ; i < req.nanalogs ; i++) {
hr = iobuf_write_be16(resp_buf, analogs[i]);
if (FAILED(hr)) {
return hr;
}
}
return hr;
}
static HRESULT io3_cmd_read_rotarys(
struct io3 *io3,
struct const_iobuf *req_buf,
struct iobuf *resp_buf)
{
struct jvs_req_read_rotarys req;
uint16_t rotarys[4];
uint8_t i;
HRESULT hr;
/* Read req */
hr = iobuf_read(req_buf, &req, sizeof(req));
if (FAILED(hr)) {
return hr;
}
if (req.nrotarys > _countof(rotarys)) {
dprintf("JVS I/O: Invalid analog count %i\n", req.nrotarys);
return E_FAIL;
}
//dprintf("JVS I/O: Read rotarys, nrotarys=%i\n", req.nrotarys);
/* Write report byte */
hr = iobuf_write_8(resp_buf, 0x01);
if (FAILED(hr)) {
return hr;
}
/* Write analogs */
memset(rotarys, 0, sizeof(rotarys));
if (io3->ops->read_rotarys != NULL) {
io3->ops->read_rotarys(io3->ops_ctx, rotarys, req.nrotarys);
}
for (i = 0 ; i < req.nrotarys ; i++) {
hr = iobuf_write_be16(resp_buf, rotarys[i]);
if (FAILED(hr)) {
return hr;
}
}
return hr;
}
static HRESULT io3_cmd_write_gpio(
struct io3 *io3,
struct const_iobuf *req_buf,
struct iobuf *resp_buf)
{
uint8_t cmd;
uint8_t nbytes;
uint8_t bytes[3];
HRESULT hr;
/* Read request header */
hr = iobuf_read_8(req_buf, &cmd);
if (FAILED(hr)) {
return hr;
}
hr = iobuf_read_8(req_buf, &nbytes);
if (FAILED(hr)) {
return hr;
}
if (nbytes > 3) {
dprintf("JVS I/O: Invalid GPIO write size %i\n", nbytes);
hr = iobuf_write_8(resp_buf, 0x02);
if (FAILED(hr)) {
return hr;
}
return E_FAIL;
}
/* Read payload */
memset(bytes, 0, sizeof(bytes));
hr = iobuf_read(req_buf, bytes, nbytes);
if (FAILED(hr)) {
return hr;
}
if (io3->ops->write_gpio != NULL) {
io3->ops->write_gpio(
io3->ops_ctx,
bytes[0] | (bytes[1] << 8) | (bytes[2] << 16));
}
/* Write report byte */
return iobuf_write_8(resp_buf, 0x01);
}
static HRESULT io3_cmd_reset(struct io3 *io3, struct const_iobuf *req_buf)
{
struct jvs_req_reset req;
HRESULT hr;
hr = iobuf_read(req_buf, &req, sizeof(req));
if (FAILED(hr)) {
return hr;
}
dprintf("JVS I/O: Reset (param %02x)\n", req.unknown);
io3->addr = 0xFF;
if (io3->ops->reset != NULL) {
io3->ops->reset(io3->ops_ctx);
}
/* No ack for this since it really is addressed to everybody */
return S_OK;
}
static HRESULT io3_cmd_assign_addr(
struct io3 *io3,
struct const_iobuf *req_buf,
struct iobuf *resp_buf)
{
struct jvs_req_assign_addr req;
bool sense;
HRESULT hr;
hr = iobuf_read(req_buf, &req, sizeof(req));
if (FAILED(hr)) {
return hr;
}
sense = jvs_node_sense(io3->jvs.next);
dprintf("JVS I/O: Assign addr %02x sense %i\n", req.addr, sense);
if (sense) {
/* That address is for somebody else */
return S_OK;
}
io3->addr = req.addr;
return iobuf_write_8(resp_buf, 0x01);
}
+38
View File
@@ -0,0 +1,38 @@
#pragma once
#include <stdint.h>
#include "jvs/jvs-bus.h"
struct io3_switch_state {
/* Note: this struct is host-endian. The IO3 emulator handles the conversion
to protocol-endian. */
uint8_t system;
uint16_t p1;
uint16_t p2;
};
struct io3_ops {
void (*reset)(void *ctx);
void (*write_gpio)(void *ctx, uint32_t state);
void (*read_switches)(void *ctx, struct io3_switch_state *out);
void (*read_analogs)(void *ctx, uint16_t *analogs, uint8_t nanalogs);
void (*read_rotarys)(void *ctx, uint16_t *rotaries, uint8_t nrotaries);
void (*read_coin_counter)(void *ctx, uint8_t slot_no, uint16_t *out);
};
struct io3 {
struct jvs_node jvs;
uint8_t addr;
const struct io3_ops *ops;
void *ops_ctx;
};
void io3_init(
struct io3 *io3,
struct jvs_node *next,
const struct io3_ops *ops,
void *ops_ctx);
struct jvs_node *io3_to_jvs_node(struct io3 *io3);
+358
View File
@@ -0,0 +1,358 @@
#include <windows.h>
#include <devioctl.h>
#include <hidclass.h>
#include <assert.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <stdlib.h>
#include "board/config.h"
#include "board/guid.h"
#include "board/io4.h"
#include "hook/iobuf.h"
#include "hook/iohook.h"
#include "hooklib/setupapi.h"
#include "util/async.h"
#include "util/dprintf.h"
#pragma pack(push, 1)
enum {
IO4_CMD_SET_COMM_TIMEOUT = 0x01,
IO4_CMD_SET_SAMPLING_COUNT = 0x02,
IO4_CMD_CLEAR_BOARD_STATUS = 0x03,
IO4_CMD_SET_GENERAL_OUTPUT = 0x04,
IO4_CMD_SET_PWM_OUTPUT = 0x05,
IO4_CMD_SET_UNIQUE_OUTPUT = 0x41,
IO4_CMD_UPDATE_FIRMWARE = 0x85,
};
struct io4_report_in {
uint8_t report_id;
uint16_t adcs[8];
uint16_t spinners[4];
uint16_t chutes[2];
uint16_t buttons[2];
uint8_t system_status;
uint8_t usb_status;
uint8_t unique_input[29];
};
static_assert(sizeof(struct io4_report_in) == 0x40, "IO4 IN report size");
struct io4_report_out {
uint8_t report_id;
uint8_t cmd;
uint8_t payload[IO4_REPORT_OUT_PAYLOAD_LEN];
};
static_assert(sizeof(struct io4_report_out) == 0x40, "IO4 OUT report size");
#pragma pack(pop)
static HRESULT io4_handle_irp(struct irp *irp);
static HRESULT io4_handle_open(struct irp *irp);
static HRESULT io4_handle_close(struct irp *irp);
static HRESULT io4_handle_read(struct irp *irp);
static HRESULT io4_handle_write(struct irp *irp);
static HRESULT io4_handle_ioctl(struct irp *irp);
static HRESULT io4_ioctl_get_manufacturer_string(struct irp *irp);
static HRESULT io4_ioctl_get_product_string(struct irp *irp);
static HRESULT io4_async_poll(void *ctx, struct irp *irp);
/* Device node path must contain substring "vid_0ca3" (case-insensitive). */
static const wchar_t io4_path[] = L"$io4\\vid_0ca3";
static const wchar_t io4_manf[] = L"SEGA";
static const wchar_t io4_prod[] =
/* "Product" (N.B. numbers are in hex) */
L"I/O CONTROL BD;" /* Board type */
L"15257;" /* Board number */
L"01;" /* "Mode" (prob. USB vs JVS?) */
L"90;" /* Firmware revision */
L"1831;" /* Firmware checksum */
L"6679A;" /* "Custom chip no" */
L"00;" /* "Config" */
/* "Function" (N.B. all values are in hex) */
L"GOUT=14_" /* General-purpose output */
L"ADIN=8,E_" /* ADC inputs */
L"ROTIN=4_" /* Rotary inputs */
L"COININ=2_" /* Coin inputs */
L"SWIN=2,E_" /* Switch inputs */
L"UQ1=41,6" /* "Unique function 1" */
;
static HANDLE io4_fd;
static struct async io4_async;
static uint8_t io4_system_status;
static const struct io4_ops *io4_ops;
static void *io4_ops_ctx;
HRESULT io4_hook_init(
const struct io4_config *cfg,
const struct io4_ops *ops,
void *ctx)
{
HRESULT hr;
assert(cfg != NULL);
assert(ops != NULL);
if (!cfg->enable) {
return S_FALSE;
}
async_init(&io4_async, NULL);
hr = iohook_open_nul_fd(&io4_fd);
if (FAILED(hr)) {
return hr;
}
io4_ops = ops;
io4_ops_ctx = ctx;
io4_system_status = 0x02; /* idk */
iohook_push_handler(io4_handle_irp);
hr = setupapi_add_phantom_dev(&hid_guid, io4_path);
if (FAILED(hr)) {
return hr;
}
return S_OK;
}
static HRESULT io4_handle_irp(struct irp *irp)
{
assert(irp != NULL);
if (irp->op != IRP_OP_OPEN && irp->fd != io4_fd) {
return iohook_invoke_next(irp);
}
switch (irp->op) {
case IRP_OP_OPEN: return io4_handle_open(irp);
case IRP_OP_CLOSE: return io4_handle_close(irp);
case IRP_OP_READ: return io4_handle_read(irp);
case IRP_OP_WRITE: return io4_handle_write(irp);
case IRP_OP_IOCTL: return io4_handle_ioctl(irp);
default: return HRESULT_FROM_WIN32(ERROR_INVALID_FUNCTION);
}
}
static HRESULT io4_handle_open(struct irp *irp)
{
if (wcscmp(irp->open_filename, io4_path) != 0) {
return iohook_invoke_next(irp);
}
dprintf("USB I/O: Device opened\n");
irp->fd = io4_fd;
return S_OK;
}
static HRESULT io4_handle_close(struct irp *irp)
{
dprintf("USB I/O: Device closed\n");
return S_OK;
}
static HRESULT io4_handle_read(struct irp *irp)
{
/* The amdaemon USBIO driver will continuously poll the IO until the IO
call returns an async operation in progress. We have to return and then
signal the OVERLAPPED event object "a little bit later" in order to avoid
an infinite loop. */
return async_submit(&io4_async, irp, io4_async_poll);
}
static HRESULT io4_handle_write(struct irp *irp)
{
struct io4_report_out out;
HRESULT hr;
hr = iobuf_read(&irp->write, &out, sizeof(out));
if (FAILED(hr)) {
return hr;
}
if (out.report_id != 0x10) {
dprintf("USB I/O: OUT Report ID is incorrect");
return E_FAIL;
}
switch (out.cmd) {
case IO4_CMD_SET_COMM_TIMEOUT:
dprintf("USB I/O: Set comm timeout\n");
// Ongeki Summer expects the system status to be 0x30 at this point
io4_system_status = 0x30;
return S_OK;
case IO4_CMD_SET_SAMPLING_COUNT:
dprintf("USB I/O: Set sampling count\n");
// Ongeki Summer expects the system status to be 0x30 at this point
io4_system_status = 0x30;
return S_OK;
case IO4_CMD_CLEAR_BOARD_STATUS:
dprintf("USB I/O: Clear board status\n");
io4_system_status = 0x00;
return S_OK;
case IO4_CMD_SET_GENERAL_OUTPUT:
// dprintf("USB I/O: GPIO Out\n");
if (io4_ops->write_gpio != NULL) {
return io4_ops->write_gpio(out.payload, IO4_REPORT_OUT_PAYLOAD_LEN);
}
return S_OK;
case IO4_CMD_SET_PWM_OUTPUT:
dprintf("USB I/O: PWM Out\n");
return S_OK;
case IO4_CMD_SET_UNIQUE_OUTPUT:
// dprintf("USB I/O: Unique Out\n");
return S_OK;
case IO4_CMD_UPDATE_FIRMWARE:
dprintf("USB I/O: Update firmware..?\n");
return E_FAIL;
default:
dprintf("USB I/O: Unknown command %02x\n", out.cmd);
return E_FAIL;
}
}
static HRESULT io4_handle_ioctl(struct irp *irp)
{
switch (irp->ioctl) {
case IOCTL_HID_GET_MANUFACTURER_STRING:
return io4_ioctl_get_manufacturer_string(irp);
case IOCTL_HID_GET_PRODUCT_STRING:
return io4_ioctl_get_product_string(irp);
case IOCTL_HID_GET_INPUT_REPORT:
dprintf("USB I/O: Control IN (untested!!)\n");
return io4_handle_read(irp);
case IOCTL_HID_SET_OUTPUT_REPORT:
dprintf("USB I/O: Control OUT (untested!!)\n");
return io4_handle_write(irp);
default:
dprintf("USB I/O: Unknown ioctl %#08x, write %i read %i\n",
irp->ioctl,
(int) irp->write.nbytes,
(int) irp->read.nbytes);
return HRESULT_FROM_WIN32(ERROR_INVALID_FUNCTION);
}
}
static HRESULT io4_ioctl_get_manufacturer_string(struct irp *irp)
{
dprintf("USB I/O: Get manufacturer string\n");
if (irp->read.nbytes < sizeof(io4_manf)) {
return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
}
memcpy(irp->read.bytes, io4_manf, sizeof(io4_manf));
irp->read.pos = sizeof(io4_manf);
return S_OK;
}
static HRESULT io4_ioctl_get_product_string(struct irp *irp)
{
dprintf("USB I/O: Get product string\n");
if (irp->read.nbytes < sizeof(io4_prod)) {
return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
}
memcpy(irp->read.bytes, io4_prod, sizeof(io4_prod));
irp->read.pos = sizeof(io4_prod);
return S_OK;
}
static HRESULT io4_async_poll(void *ctx, struct irp *irp)
{
struct io4_report_in in;
struct io4_state state;
HRESULT hr;
size_t i;
/* Delay long enough for the instigating thread in amdaemon to be satisfied
that all queued-up reports have been drained. */
// Sleep(1);
/* Call into ops to poll the underlying inputs */
memset(&state, 0, sizeof(state));
hr = io4_ops->poll(io4_ops_ctx, &state);
if (FAILED(hr)) {
return hr;
}
/* Construct IN report. Values are all little-endian, unlike JVS. */
memset(&in, 0, sizeof(in));
in.report_id = 0x01;
in.system_status = io4_system_status;
for (i = 0 ; i < 8 ; i++) {
in.adcs[i] = state.adcs[i];
}
for (i = 0 ; i < 4 ; i++) {
in.spinners[i] = state.spinners[i];
}
for (i = 0 ; i < 2 ; i++) {
in.chutes[i] = state.chutes[i];
}
for (i = 0 ; i < 2 ; i++) {
in.buttons[i] = state.buttons[i];
}
return iobuf_write(&irp->read, &in, sizeof(in));
}
+36
View File
@@ -0,0 +1,36 @@
#pragma once
#include <windows.h>
#include <stdint.h>
#include <stdbool.h>
#define IO4_REPORT_OUT_PAYLOAD_LEN 62
enum {
/* System buttons in button[0] */
IO4_BUTTON_TEST = 1 << 9,
IO4_BUTTON_SERVICE = 1 << 6,
};
struct io4_config {
bool enable;
};
struct io4_state {
uint16_t adcs[8];
uint16_t spinners[4];
uint16_t chutes[2];
uint16_t buttons[2];
};
struct io4_ops {
HRESULT (*poll)(void *ctx, struct io4_state *state);
HRESULT (*write_gpio)(uint8_t* payload, size_t len);
};
HRESULT io4_hook_init(
const struct io4_config *cfg,
const struct io4_ops *ops,
void *ctx);
+81
View 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
View 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
View 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);
File diff suppressed because it is too large Load Diff
+28
View File
@@ -0,0 +1,28 @@
#pragma once
#include <windows.h>
#include <stdbool.h>
#include <stdint.h>
struct led15070_config {
bool enable;
unsigned int port_no[2];
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)(uint8_t board, const uint8_t *rgb);
typedef void (*io_led_dc_update_t)(uint8_t board, const uint8_t *rgb);
typedef void (*io_led_gs_update_t)(uint8_t board, 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 port_no[2]);
+222
View File
@@ -0,0 +1,222 @@
#pragma once
#include "board/led15093-frame.h"
/* Command IDs */
enum {
LED_15093_CMD_RESET = 0x10,
LED_15093_CMD_SET_TIMEOUT = 0x11,
LED_15093_CMD_UNK1 = 0x12,
LED_15093_CMD_SET_DISABLE_RESPONSE = 0x14,
LED_15093_CMD_SET_ID = 0x18,
LED_15093_CMD_CLEAR_ID = 0x19,
LED_15093_CMD_SET_MAX_BRIGHT = 0x3F, // TODO
LED_15093_CMD_UPDATE_LED = 0x80,
LED_15093_CMD_SET_LED = 0x81,
LED_15093_CMD_SET_IMM_LED = 0x82,
LED_15093_CMD_SET_FADE_LED = 0x83,
LED_15093_CMD_SET_FADE_LEVEL = 0x84,
LED_15093_CMD_SET_FADE_SHIFT = 0x85,
LED_15093_CMD_SET_AUTO_SHIFT = 0x86,
LED_15093_CMD_GET_BOARD_INFO = 0xF0,
LED_15093_CMD_GET_BOARD_STATUS = 0xF1,
LED_15093_CMD_GET_FW_SUM = 0xF2,
LED_15093_CMD_GET_PROTOCOL_VER = 0xF3,
LED_15093_CMD_SET_BOOTMODE = 0xFD,
LED_15093_CMD_FW_UPDATE = 0xFE,
};
/* Response codes */
enum {
LED_15093_STATUS_OK = 0x01,
LED_15093_STATUS_ERR_SUM = 0x02,
LED_15093_STATUS_ERR_PARITY = 0x03,
LED_15093_STATUS_ERR_FRAMING = 0x04,
LED_15093_STATUS_ERR_OVERRUN = 0x05,
LED_15093_STATUS_ERR_BUFFER_OVERFLOW = 0x06,
};
enum {
LED_15093_REPORT_OK = 0x01,
LED_15093_REPORT_WAIT = 0x02,
LED_15093_REPORT_ERR1 = 0x03,
LED_15093_REPORT_ERR2 = 0x04,
};
/* Status bitmasks */
enum {
LED_15093_STATUS_UART_ERR_SUM = 0x01,
LED_15093_STATUS_UART_ERR_PARITY = 0x02,
LED_15093_STATUS_UART_ERR_FRAMING = 0x04,
LED_15093_STATUS_UART_ERR_OVERRUN = 0x08,
LED_15093_STATUS_UART_ERR_BUFFER_OVERFLOW = 0x10,
};
enum {
LED_15093_STATUS_BOARD_ERR_WDT = 0x01,
LED_15093_STATUS_BOARD_ERR_TIMEOUT = 0x02,
LED_15093_STATUS_BOARD_ERR_RESET = 0x04,
LED_15093_STATUS_BOARD_ERR_BOR = 0x08,
};
enum {
LED_15093_STATUS_CMD_ERR_BUSY = 0x01,
LED_15093_STATUS_CMD_ERR_UNKNOWN = 0x02,
LED_15093_STATUS_CMD_ERR_PARAM = 0x04,
LED_15093_STATUS_CMD_ERR_EXE = 0x08,
};
/* Status types for internal use */
enum {
LED_15093_STATUS_TYPE_BOARD = 1,
LED_15093_STATUS_TYPE_UART = 2,
LED_15093_STATUS_TYPE_CMD = 3,
};
/* Request data structures */
struct led15093_req_reset {
struct led15093_req_hdr hdr;
uint8_t cmd;
uint8_t r_type;
};
struct led15093_req_set_timeout {
struct led15093_req_hdr hdr;
uint8_t cmd;
uint16_t count;
};
struct led15093_req_set_disable_response {
struct led15093_req_hdr hdr;
uint8_t cmd;
bool sw;
};
struct led15093_req_set_id {
struct led15093_req_hdr hdr;
uint8_t cmd;
uint8_t id;
};
struct led15093_req_set_led {
struct led15093_req_hdr hdr;
uint8_t cmd;
uint8_t data[198];
};
struct led15093_req_set_fade_level {
struct led15093_req_hdr hdr;
uint8_t cmd;
uint8_t depth;
uint8_t cycle;
};
struct led15093_req_set_fade_shift {
struct led15093_req_hdr hdr;
uint8_t cmd;
uint8_t target;
};
struct led15093_req_set_auto_shift {
struct led15093_req_hdr hdr;
uint8_t cmd;
uint8_t count;
uint8_t target;
};
struct led15093_req_get_board_status {
struct led15093_req_hdr hdr;
uint8_t cmd;
bool clear;
};
union led15093_req_any {
struct led15093_req_hdr hdr;
struct led15093_req_reset reset;
struct led15093_req_set_timeout set_timeout;
struct led15093_req_set_disable_response set_disable_response;
struct led15093_req_set_id set_id;
struct led15093_req_set_led set_led;
struct led15093_req_set_fade_level set_fade_level;
struct led15093_req_set_fade_shift set_fade_shift;
struct led15093_req_set_auto_shift set_auto_shift;
struct led15093_req_get_board_status get_board_status;
uint8_t payload[256];
};
/* Response data structures */
struct led15093_resp_any {
struct led15093_resp_hdr hdr;
uint8_t status;
uint8_t cmd;
uint8_t report;
uint8_t data[32];
};
struct led15093_resp_timeout {
struct led15093_resp_hdr hdr;
uint8_t status;
uint8_t cmd;
uint8_t report;
uint8_t count_upper;
uint8_t count_lower;
};
struct led15093_resp_fw_sum {
struct led15093_resp_hdr hdr;
uint8_t status;
uint8_t cmd;
uint8_t report;
uint8_t sum_upper;
uint8_t sum_lower;
};
struct led15093_resp_board_info_legacy {
struct led15093_resp_hdr hdr;
uint8_t status;
uint8_t cmd;
uint8_t report;
char board_num[8];
uint8_t lf; // 0x0A (ASCII LF)
char chip_num[5];
uint8_t endcode; // Always 0xFF
uint8_t fw_ver;
};
struct led15093_resp_board_info {
struct led15093_resp_hdr hdr;
uint8_t status;
uint8_t cmd;
uint8_t report;
char board_num[8];
uint8_t lf; // 0x0A (ASCII LF)
char chip_num[5];
uint8_t endcode; // Always 0xFF
uint8_t fw_ver;
uint16_t rx_buf;
};
struct led15093_resp_protocol_ver {
struct led15093_resp_hdr hdr;
uint8_t status;
uint8_t cmd;
uint8_t report;
uint8_t mode;
uint8_t major_ver;
uint8_t minor_ver;
};
struct led15093_resp_set_auto_shift {
struct led15093_resp_hdr hdr;
uint8_t status;
uint8_t cmd;
uint8_t report;
uint8_t count;
uint8_t target;
};
+196
View File
@@ -0,0 +1,196 @@
#include <windows.h>
#include <assert.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include "board/led15093-frame.h"
#include "hook/iobuf.h"
static void led15093_frame_sync(struct iobuf *src);
static HRESULT led15093_frame_accept(const struct iobuf *dest);
static HRESULT led15093_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 led15093_frame_sync(struct iobuf *src)
{
size_t i;
for (i = 0 ; i < src->pos && src->bytes[i] != LED_15093_FRAME_SYNC ; i++);
src->pos -= i;
memmove(&src->bytes[0], &src->bytes[i], i);
}
static HRESULT led15093_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 led15093_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);
led15093_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 == LED_15093_FRAME_SYNC) {
hr = E_FAIL;
} else if (byte == LED_15093_FRAME_ESC) {
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 = led15093_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 led15093_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] == LED_15093_FRAME_SYNC &&
src[3] + 4 == nbytes);
if (dest->pos >= dest->nbytes) {
return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
}
dest->bytes[dest->pos++] = LED_15093_FRAME_SYNC;
checksum = 0;
// dprintf("%02x ", LED_15093_FRAME_SYNC);
for (i = 1 ; i < nbytes ; i++) {
byte = src[i];
checksum += byte;
// dprintf("%02x ", byte);
hr = led15093_frame_encode_byte(dest, byte);
if (FAILED(hr)) {
return hr;
}
}
// dprintf("%02x \n", checksum);
return led15093_frame_encode_byte(dest, checksum);
}
static HRESULT led15093_frame_encode_byte(struct iobuf *dest, uint8_t byte)
{
if (byte == LED_15093_FRAME_SYNC || byte == LED_15093_FRAME_ESC) {
if (dest->pos + 2 > dest->nbytes) {
return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
}
dest->bytes[dest->pos++] = LED_15093_FRAME_ESC;
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;
}
+34
View File
@@ -0,0 +1,34 @@
#pragma once
#include <windows.h>
#include <stddef.h>
#include <stdint.h>
#include "hook/iobuf.h"
enum {
LED_15093_FRAME_SYNC = 0xE0,
LED_15093_FRAME_ESC = 0xD0,
};
struct led15093_req_hdr {
uint8_t sync;
uint8_t dest_adr;
uint8_t src_adr;
uint8_t nbytes;
};
struct led15093_resp_hdr {
uint8_t sync;
uint8_t dest_adr;
uint8_t src_adr;
uint8_t nbytes;
};
HRESULT led15093_frame_decode(struct iobuf *dest, struct iobuf *src);
HRESULT led15093_frame_encode(
struct iobuf *dest,
const void *ptr,
size_t nbytes);
File diff suppressed because it is too large Load Diff
+24
View File
@@ -0,0 +1,24 @@
#pragma once
#include <windows.h>
#include <stdbool.h>
#include <stdint.h>
struct led15093_config {
bool enable;
bool high_baudrate;
unsigned int port_no[2];
char board_number[8];
char chip_number[5];
char boot_chip_number[5];
uint8_t fw_ver;
uint16_t fw_sum;
};
typedef HRESULT (*io_led_init_t)(void);
typedef void (*io_led_set_leds_t)(uint8_t board, uint8_t *rgb);
HRESULT led15093_hook_init(const struct led15093_config *cfg, io_led_init_t _led_init,
io_led_set_leds_t _set_leds, unsigned int port_no[2]);
+55
View File
@@ -0,0 +1,55 @@
board_lib = static_library(
'board',
include_directories : inc,
implicit_include_directories : false,
dependencies : [
capnhook.get_variable('hook_dep'),
],
link_with : [
iccard_lib,
],
sources : [
'aime-dll.c',
'aime-dll.h',
'config.c',
'config.h',
'guid.c',
'guid.h',
'io3.c',
'io3.h',
'io4.c',
'io4.h',
'led15093-cmd.h',
'led15093-frame.c',
'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',
'sg-frame.h',
'sg-led.c',
'sg-led.h',
'sg-led-cmd.h',
'sg-nfc.c',
'sg-nfc.h',
'sg-nfc-cmd.h',
'sg-reader.c',
'sg-reader.h',
'slider-cmd.h',
'slider-frame.c',
'slider-frame.h',
'vfd.c',
'vfd.h',
'vfd-cmd.h',
'vfd-frame.c',
'vfd-frame.h',
'ffb.c',
'ffb.h'
],
)
+134
View File
@@ -0,0 +1,134 @@
#include <assert.h>
#include "board/sg-cmd.h"
#include "board/sg-frame.h"
#include "hook/iobuf.h"
#include "util/dprintf.h"
union sg_req_any {
struct sg_req_header req;
uint8_t bytes[256];
};
union sg_res_any {
struct sg_res_header res;
uint8_t bytes[256];
};
static HRESULT sg_req_validate(const void *ptr, size_t nbytes);
static void sg_res_error(
struct sg_res_header *res,
const struct sg_req_header *req);
static HRESULT sg_req_validate(const void *ptr, size_t nbytes)
{
const struct sg_req_header *req;
size_t payload_len;
assert(ptr != NULL);
if (nbytes < sizeof(*req)) {
dprintf("SG Cmd: Request header truncated\n");
return E_FAIL;
}
req = ptr;
if (req->hdr.frame_len != nbytes) {
dprintf("SG Cmd: Frame length mismatch: got %i exp %i\n",
req->hdr.frame_len,
(int) nbytes);
return E_FAIL;
}
payload_len = req->hdr.frame_len - sizeof(*req);
if (req->payload_len != payload_len) {
dprintf("SG Cmd: Payload length mismatch: got %i exp %i\n",
req->payload_len,
(int) payload_len);
return E_FAIL;
}
return S_OK;
}
void sg_req_transact(
struct iobuf *res_frame,
const uint8_t *req_bytes,
size_t req_nbytes,
sg_dispatch_fn_t dispatch,
void *ctx)
{
struct iobuf req_span;
union sg_req_any req;
union sg_res_any res;
HRESULT hr;
assert(res_frame != NULL);
assert(req_bytes != NULL);
assert(dispatch != NULL);
req_span.bytes = req.bytes;
req_span.nbytes = sizeof(req.bytes);
req_span.pos = 0;
hr = sg_frame_decode(&req_span, req_bytes, req_nbytes);
if (FAILED(hr)) {
return;
}
hr = sg_req_validate(req.bytes, req_span.pos);
if (FAILED(hr)) {
return;
}
hr = dispatch(ctx, &req, &res);
if (hr != S_FALSE) {
if (FAILED(hr)) {
sg_res_error(&res.res, &req.req);
}
sg_frame_encode(res_frame, res.bytes, res.res.hdr.frame_len);
}
}
void sg_res_init(
struct sg_res_header *res,
const struct sg_req_header *req,
size_t payload_len)
{
assert(res != NULL);
assert(req != NULL);
res->hdr.frame_len = sizeof(*res) + payload_len;
res->hdr.addr = req->hdr.addr;
res->hdr.seq_no = req->hdr.seq_no;
res->hdr.cmd = req->hdr.cmd;
res->status = 0;
res->payload_len = payload_len;
}
static void sg_res_error(
struct sg_res_header *res,
const struct sg_req_header *req)
{
assert(res != NULL);
assert(req != NULL);
res->hdr.frame_len = sizeof(*res);
res->hdr.addr = req->hdr.addr;
res->hdr.seq_no = req->hdr.seq_no;
res->hdr.cmd = req->hdr.cmd;
res->status = 1;
res->payload_len = 0;
}
+50
View File
@@ -0,0 +1,50 @@
#pragma once
#include <windows.h>
#include <stddef.h>
#include <stdint.h>
#include "hook/iobuf.h"
struct sg_header {
uint8_t frame_len;
uint8_t addr;
uint8_t seq_no;
uint8_t cmd;
};
struct sg_req_header {
struct sg_header hdr;
uint8_t payload_len;
};
struct sg_res_header {
struct sg_header hdr;
uint8_t status;
uint8_t payload_len;
};
/* struct to save the version string with its length
to fix NUL terminator issues */
struct version_info {
const char *version;
uint8_t length;
};
typedef HRESULT (*sg_dispatch_fn_t)(
void *ctx,
const void *req,
void *res);
void sg_req_transact(
struct iobuf *res_frame,
const uint8_t *req_bytes,
size_t req_nbytes,
sg_dispatch_fn_t dispatch,
void *ctx);
void sg_res_init(
struct sg_res_header *res,
const struct sg_req_header *req,
size_t payload_len);
+165
View File
@@ -0,0 +1,165 @@
#include <windows.h>
#include <assert.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include "board/sg-frame.h"
#include "hook/iobuf.h"
#include "util/dprintf.h"
static HRESULT sg_frame_accept(struct iobuf *dest);
static HRESULT sg_frame_encode_byte(struct iobuf *dest, uint8_t byte);
/* Frame structure:
[0] Sync byte (0xE0)
[1] Frame size (including self)
[2] Address
[3] Sequence no
... Body
[n] Checksum: Sum of all non-framing bytes
Byte stuffing:
0xD0 is an escape byte. Un-escape the subsequent byte by adding 1. */
static HRESULT sg_frame_accept(struct iobuf *dest)
{
uint8_t checksum;
size_t i;
if (dest->pos < 1 || dest->pos != dest->bytes[0] + 1) {
dprintf("SG Frame: Size mismatch\n");
return S_FALSE;
}
checksum = 0;
for (i = 0 ; i < dest->pos - 1 ; i++) {
checksum += dest->bytes[i];
}
if (checksum != dest->bytes[dest->pos - 1]) {
dprintf("SG Frame: Checksum mismatch\n");
return HRESULT_FROM_WIN32(ERROR_CRC);
}
/* Discard checksum */
dest->pos--;
return S_OK;
}
HRESULT sg_frame_decode(struct iobuf *dest, const uint8_t *bytes, size_t nbytes)
{
uint8_t byte;
size_t i;
assert(dest != NULL);
assert(dest->bytes != NULL || dest->nbytes == 0);
assert(dest->pos <= dest->nbytes);
assert(bytes != NULL);
if (nbytes < 1 || bytes[0] != 0xE0) {
dprintf("SG Frame: Bad sync\n");
return E_FAIL;
}
dest->pos = 0;
i = 1;
while (i < nbytes) {
if (dest->pos >= dest->nbytes) {
return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
}
byte = bytes[i++];
if (byte == 0xE0) {
dprintf("SG Frame: Unescaped sync\n");
return E_FAIL;
} else if (byte == 0xD0) {
if (i >= nbytes) {
dprintf("SG Frame: Trailing escape\n");
return E_FAIL;
}
byte = bytes[i++];
dest->bytes[dest->pos++] = byte + 1;
} else {
dest->bytes[dest->pos++] = byte;
}
}
return sg_frame_accept(dest);
}
HRESULT sg_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 != 0 && src[0] == nbytes);
if (dest->pos >= dest->nbytes) {
return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
}
dest->bytes[dest->pos++] = 0xE0;
checksum = 0;
for (i = 0 ; i < nbytes ; i++) {
byte = src[i];
checksum += byte;
hr = sg_frame_encode_byte(dest, byte);
if (FAILED(hr)) {
return hr;
}
}
return sg_frame_encode_byte(dest, checksum);
}
static HRESULT sg_frame_encode_byte(struct iobuf *dest, uint8_t byte)
{
if (byte == 0xD0 || byte == 0xE0) {
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;
}
+15
View File
@@ -0,0 +1,15 @@
#pragma once
#include <windows.h>
#include <stddef.h>
#include <stdint.h>
#include "hook/iobuf.h"
HRESULT sg_frame_decode(
struct iobuf *dest,
const uint8_t *bytes,
size_t nbytes);
HRESULT sg_frame_encode(struct iobuf *dest, const void *ptr, size_t nbytes);
+39
View File
@@ -0,0 +1,39 @@
#pragma once
#include <stdint.h>
#include "board/sg-cmd.h"
enum {
SG_RGB_CMD_SET_COLOR = 0x81,
SG_RGB_CMD_RESET = 0xF5,
SG_RGB_CMD_GET_INFO = 0xF0,
};
struct sg_led_res_reset {
struct sg_res_header res;
uint8_t payload;
};
struct sg_led_res_get_info {
struct sg_res_header res;
char payload[12];
};
struct sg_led_req_set_color {
struct sg_req_header req;
uint8_t payload[3];
};
union sg_led_req_any {
uint8_t bytes[256];
struct sg_req_header simple;
struct sg_led_req_set_color set_color;
};
union sg_led_res_any {
uint8_t bytes[256];
struct sg_res_header simple;
struct sg_led_res_reset reset;
struct sg_led_res_get_info get_info;
};
+186
View File
@@ -0,0 +1,186 @@
#include <windows.h>
#include <assert.h>
#include "board/sg-cmd.h"
#include "board/sg-led.h"
#include "board/sg-led-cmd.h"
#include "util/dprintf.h"
static HRESULT sg_led_dispatch(
void *ctx,
const void *v_req,
void *v_res);
static HRESULT sg_led_cmd_reset(
const struct sg_led *led,
const struct sg_req_header *req,
struct sg_led_res_reset *res);
static HRESULT sg_led_cmd_get_info(
const struct sg_led *led,
const struct sg_req_header *req,
struct sg_led_res_get_info *res);
static HRESULT sg_led_cmd_set_color(
const struct sg_led *led,
const struct sg_led_req_set_color *req);
static const struct version_info led_version[] = {
{"15084\xFF\x10\x00\x12", 9},
{"000-00000\xFF\x11\x40", 12},
// maybe the same?
{"000-00000\xFF\x11\x40", 12}
};
void sg_led_init(
struct sg_led *led,
uint8_t addr,
const struct sg_led_ops *ops,
unsigned int gen,
void *ctx)
{
assert(led != NULL);
assert(ops != NULL);
led->ops = ops;
led->ops_ctx = ctx;
led->addr = addr;
led->gen = gen;
}
void sg_led_transact(
struct sg_led *led,
struct iobuf *res_frame,
const void *req_bytes,
size_t req_nbytes)
{
assert(led != NULL);
assert(res_frame != NULL);
assert(req_bytes != NULL);
sg_req_transact(res_frame, req_bytes, req_nbytes, sg_led_dispatch, led);
}
#ifdef NDEBUG
#define sg_led_dprintfv(led, fmt, ap)
#define sg_led_dprintf(led, fmt, ...)
#else
static void sg_led_dprintfv(
const struct sg_led *led,
const char *fmt,
va_list ap)
{
dprintf("RGB LED %02x: ", led->addr);
dprintfv(fmt, ap);
}
static void sg_led_dprintf(
const struct sg_led *led,
const char *fmt,
...)
{
va_list ap;
va_start(ap, fmt);
sg_led_dprintfv(led, fmt, ap);
va_end(ap);
}
#endif
static HRESULT sg_led_dispatch(
void *ctx,
const void *v_req,
void *v_res)
{
const struct sg_led *led;
const union sg_led_req_any *req;
union sg_led_res_any *res;
led = ctx;
req = v_req;
res = v_res;
if (req->simple.hdr.addr != led->addr) {
/* Not addressed to us, don't send a response */
return S_FALSE;
}
switch (req->simple.hdr.cmd) {
case SG_RGB_CMD_RESET:
return sg_led_cmd_reset(led, &req->simple, &res->reset);
case SG_RGB_CMD_GET_INFO:
return sg_led_cmd_get_info(led, &req->simple, &res->get_info);
case SG_RGB_CMD_SET_COLOR:
return sg_led_cmd_set_color(led, &req->set_color);
default:
sg_led_dprintf(led, "Unimpl command %02x\n", req->simple.hdr.cmd);
return E_NOTIMPL;
}
}
static HRESULT sg_led_cmd_reset(
const struct sg_led *led,
const struct sg_req_header *req,
struct sg_led_res_reset *res)
{
HRESULT hr;
sg_led_dprintf(led, "Reset\n");
sg_res_init(&res->res, req, sizeof(res->payload));
res->payload = 0;
if (led->ops->reset != NULL) {
hr = led->ops->reset(led->ops_ctx);
} else {
hr = S_OK;
}
if (FAILED(hr)) {
sg_led_dprintf(led, "led->ops->reset: Error %x\n", hr);
return hr;
}
return S_OK;
}
static HRESULT sg_led_cmd_get_info(
const struct sg_led *led,
const struct sg_req_header *req,
struct sg_led_res_get_info *res)
{
sg_led_dprintf(led, "Get info\n");
const struct version_info *fw = &led_version[led->gen - 1];
sg_res_init(&res->res, req, fw->length);
memcpy(res->payload, fw->version, fw->length);
return S_OK;
}
static HRESULT sg_led_cmd_set_color(
const struct sg_led *led,
const struct sg_led_req_set_color *req)
{
if (req->req.payload_len != sizeof(req->payload)) {
sg_led_dprintf(led, "%s: Payload size is incorrect\n", __func__);
goto fail;
}
led->ops->set_color(
led->ops_ctx,
req->payload[0],
req->payload[1],
req->payload[2]);
fail:
/* No response */
return S_FALSE;
}
+32
View File
@@ -0,0 +1,32 @@
#pragma once
#include <windows.h>
#include <stdint.h>
#include "hook/iobuf.h"
struct sg_led_ops {
HRESULT (*reset)(void *ctx);
void (*set_color)(void *ctx, uint8_t r, uint8_t g, uint8_t b);
};
struct sg_led {
const struct sg_led_ops *ops;
void *ops_ctx;
uint8_t addr;
unsigned int gen;
};
void sg_led_init(
struct sg_led *led,
uint8_t addr,
const struct sg_led_ops *ops,
unsigned int gen,
void *ctx);
void sg_led_transact(
struct sg_led *led,
struct iobuf *res_frame,
const void *req_bytes,
size_t req_nbytes);
+118
View File
@@ -0,0 +1,118 @@
#pragma once
#include <stdint.h>
#pragma pack(push, 1)
enum {
SG_NFC_CMD_GET_FW_VERSION = 0x30,
SG_NFC_CMD_GET_HW_VERSION = 0x32,
SG_NFC_CMD_RADIO_ON = 0x40,
SG_NFC_CMD_RADIO_OFF = 0x41,
SG_NFC_CMD_POLL = 0x42,
SG_NFC_CMD_MIFARE_SELECT_TAG = 0x43,
SG_NFC_CMD_MIFARE_SET_KEY_AIME = 0x50,
SG_NFC_CMD_MIFARE_AUTHENTICATE_AIME = 0x51,
SG_NFC_CMD_MIFARE_READ_BLOCK = 0x52,
SG_NFC_CMD_MIFARE_SET_KEY_BANA = 0x54,
SG_NFC_CMD_MIFARE_AUTHENTICATE_BANA = 0x55,
SG_NFC_CMD_TO_UPDATE_MODE = 0x60,
SG_NFC_CMD_SEND_HEX_DATA = 0x61,
SG_NFC_CMD_RESET = 0x62,
SG_NFC_CMD_FELICA_ENCAP = 0x71,
};
struct sg_nfc_res_get_fw_version {
struct sg_res_header res;
char version[23];
};
struct sg_nfc_res_get_hw_version {
struct sg_res_header res;
char version[23];
};
struct sg_nfc_req_mifare_set_key {
struct sg_req_header req;
uint8_t key[6];
};
struct sg_nfc_req_mifare_50 {
struct sg_req_header req;
uint8_t payload[6];
};
struct sg_nfc_req_poll_40 {
struct sg_req_header req;
uint8_t payload;
};
struct sg_nfc_poll_mifare {
uint8_t type;
uint8_t id_len;
uint32_t uid;
};
struct sg_nfc_poll_felica {
uint8_t type;
uint8_t id_len;
uint64_t IDm;
uint64_t PMm;
};
struct sg_nfc_res_poll {
struct sg_res_header res;
uint8_t count;
uint8_t payload[250];
};
struct sg_nfc_req_mifare_select_tag {
struct sg_res_header res;
uint32_t uid;
};
struct sg_nfc_req_mifare_read_block {
struct sg_req_header req;
struct {
uint32_t uid;
uint8_t block_no;
} payload;
};
struct sg_nfc_res_mifare_read_block {
struct sg_res_header res;
uint8_t block[16];
};
struct sg_nfc_req_felica_encap {
struct sg_req_header req;
uint64_t IDm;
uint8_t payload[243];
};
struct sg_nfc_res_felica_encap {
struct sg_res_header res;
uint8_t payload[250];
};
union sg_nfc_req_any {
uint8_t bytes[256];
struct sg_req_header simple;
struct sg_nfc_req_mifare_set_key mifare_set_key;
struct sg_nfc_req_mifare_read_block mifare_read_block;
struct sg_nfc_req_mifare_50 mifare_50;
struct sg_nfc_req_poll_40 poll_40;
struct sg_nfc_req_felica_encap felica_encap;
};
union sg_nfc_res_any {
uint8_t bytes[256];
struct sg_res_header simple;
struct sg_nfc_res_get_fw_version get_fw_version;
struct sg_nfc_res_get_hw_version get_hw_version;
struct sg_nfc_res_poll poll;
struct sg_nfc_res_mifare_read_block mifare_read_block;
struct sg_nfc_res_felica_encap felica_encap;
};
#pragma pack(pop)
+529
View File
@@ -0,0 +1,529 @@
#include <windows.h>
#include <assert.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include "board/sg-cmd.h"
#include "board/sg-nfc.h"
#include "board/sg-nfc-cmd.h"
#include "iccard/aime.h"
#include "iccard/felica.h"
#include "util/dprintf.h"
#include "util/dump.h"
#include "util/slurp.h"
static HRESULT sg_nfc_dispatch(
void *ctx,
const void *v_req,
void *v_res);
static HRESULT sg_nfc_cmd_reset(
struct sg_nfc *nfc,
const struct sg_req_header *req,
struct sg_res_header *res);
static HRESULT sg_nfc_cmd_get_fw_version(
struct sg_nfc *nfc,
const struct sg_req_header *req,
struct sg_nfc_res_get_fw_version *res);
static HRESULT sg_nfc_cmd_get_hw_version(
struct sg_nfc *nfc,
const struct sg_req_header *req,
struct sg_nfc_res_get_hw_version *res);
static HRESULT sg_nfc_cmd_poll(
struct sg_nfc *nfc,
const struct sg_req_header *req,
struct sg_nfc_res_poll *res);
static HRESULT sg_nfc_poll_aime(
struct sg_nfc *nfc,
struct sg_nfc_poll_mifare *mifare);
static HRESULT sg_nfc_poll_felica(
struct sg_nfc *nfc,
struct sg_nfc_poll_felica *felica);
static HRESULT sg_nfc_cmd_mifare_read_block(
struct sg_nfc *nfc,
const struct sg_nfc_req_mifare_read_block *req,
struct sg_nfc_res_mifare_read_block *res);
static HRESULT sg_nfc_cmd_felica_encap(
struct sg_nfc *nfc,
const struct sg_nfc_req_felica_encap *req,
struct sg_nfc_res_felica_encap *res);
static HRESULT sg_nfc_cmd_send_hex_data(
struct sg_nfc *nfc,
const struct sg_req_header *req,
struct sg_res_header *res);
static HRESULT sg_nfc_cmd_dummy(
struct sg_nfc *nfc,
const struct sg_req_header *req,
struct sg_res_header *res);
static const struct version_info hw_version[] = {
{"TN32MSEC003S H/W Ver3.0", 23},
{"837-15286", 9},
{"837-15396", 9}
};
static const struct version_info fw_version[] = {
{"TN32MSEC003S F/W Ver1.2", 23},
{"\x94", 1},
{"\x94", 1}
};
void sg_nfc_init(
struct sg_nfc *nfc,
uint8_t addr,
const struct sg_nfc_ops *ops,
unsigned int gen,
unsigned int proxy_flag,
const wchar_t* authdata_path,
void *ops_ctx)
{
assert(nfc != NULL);
assert(ops != NULL);
nfc->ops = ops;
nfc->ops_ctx = ops_ctx;
nfc->addr = addr;
nfc->gen = gen;
nfc->proxy_flag = proxy_flag;
nfc->authdata_path = authdata_path;
}
#ifdef NDEBUG
#define sg_nfc_dprintfv(nfc, fmt, ap)
#define sg_nfc_dprintf(nfc, fmt, ...)
#else
static void sg_nfc_dprintfv(
const struct sg_nfc *nfc,
const char *fmt,
va_list ap)
{
dprintf("NFC %02x: ", nfc->addr);
dprintfv(fmt, ap);
}
static void sg_nfc_dprintf(
const struct sg_nfc *nfc,
const char *fmt,
...)
{
va_list ap;
va_start(ap, fmt);
sg_nfc_dprintfv(nfc, fmt, ap);
va_end(ap);
}
#endif
void sg_nfc_transact(
struct sg_nfc *nfc,
struct iobuf *res_frame,
const void *req_bytes,
size_t req_nbytes)
{
assert(nfc != NULL);
assert(res_frame != NULL);
assert(req_bytes != NULL);
sg_req_transact(res_frame, req_bytes, req_nbytes, sg_nfc_dispatch, nfc);
}
static HRESULT sg_nfc_dispatch(
void *ctx,
const void *v_req,
void *v_res)
{
struct sg_nfc *nfc;
const union sg_nfc_req_any *req;
union sg_nfc_res_any *res;
nfc = ctx;
req = v_req;
res = v_res;
if (req->simple.hdr.addr != nfc->addr) {
/* Not addressed to us, don't send a response */
return S_FALSE;
}
switch (req->simple.hdr.cmd) {
case SG_NFC_CMD_RESET:
return sg_nfc_cmd_reset(nfc, &req->simple, &res->simple);
case SG_NFC_CMD_GET_FW_VERSION:
return sg_nfc_cmd_get_fw_version(
nfc,
&req->simple,
&res->get_fw_version);
case SG_NFC_CMD_GET_HW_VERSION:
return sg_nfc_cmd_get_hw_version(
nfc,
&req->simple,
&res->get_hw_version);
case SG_NFC_CMD_POLL:
return sg_nfc_cmd_poll(
nfc,
&req->simple,
&res->poll);
case SG_NFC_CMD_MIFARE_READ_BLOCK:
return sg_nfc_cmd_mifare_read_block(
nfc,
&req->mifare_read_block,
&res->mifare_read_block);
case SG_NFC_CMD_FELICA_ENCAP:
return sg_nfc_cmd_felica_encap(
nfc,
&req->felica_encap,
&res->felica_encap);
case SG_NFC_CMD_MIFARE_AUTHENTICATE_AIME:
case SG_NFC_CMD_MIFARE_AUTHENTICATE_BANA:
case SG_NFC_CMD_SEND_HEX_DATA:
return sg_nfc_cmd_send_hex_data(nfc, &req->simple, &res->simple);
case SG_NFC_CMD_MIFARE_SELECT_TAG:
case SG_NFC_CMD_MIFARE_SET_KEY_AIME:
case SG_NFC_CMD_MIFARE_SET_KEY_BANA:
case SG_NFC_CMD_RADIO_ON:
case SG_NFC_CMD_RADIO_OFF:
case SG_NFC_CMD_TO_UPDATE_MODE:
return sg_nfc_cmd_dummy(nfc, &req->simple, &res->simple);
default:
sg_nfc_dprintf(nfc, "Unimpl command %02x\n", req->simple.hdr.cmd);
return E_NOTIMPL;
}
}
static HRESULT sg_nfc_cmd_reset(
struct sg_nfc *nfc,
const struct sg_req_header *req,
struct sg_res_header *res)
{
sg_nfc_dprintf(nfc, "Reset\n");
sg_res_init(res, req, 0);
res->status = 3;
return S_OK;
}
static HRESULT sg_nfc_cmd_get_fw_version(
struct sg_nfc *nfc,
const struct sg_req_header *req,
struct sg_nfc_res_get_fw_version *res)
{
const struct version_info *fw = &fw_version[nfc->gen - 1];
/* Dest version is not NUL terminated, this is intentional */
sg_res_init(&res->res, req, fw->length);
memcpy(res->version, fw->version, fw->length);
return S_OK;
}
static HRESULT sg_nfc_cmd_get_hw_version(
struct sg_nfc *nfc,
const struct sg_req_header *req,
struct sg_nfc_res_get_hw_version *res)
{
const struct version_info *hw = &hw_version[nfc->gen - 1];
/* Dest version is not NUL terminated, this is intentional */
sg_res_init(&res->res, req, hw->length);
memcpy(res->version, hw->version, hw->length);
return S_OK;
}
static HRESULT sg_nfc_cmd_poll(
struct sg_nfc *nfc,
const struct sg_req_header *req,
struct sg_nfc_res_poll *res)
{
struct sg_nfc_poll_mifare mifare;
struct sg_nfc_poll_felica felica;
HRESULT hr;
hr = nfc->ops->poll(nfc->ops_ctx);
if (FAILED(hr)) {
return hr;
}
hr = sg_nfc_poll_felica(nfc, &felica);
if (SUCCEEDED(hr) && hr != S_FALSE) {
sg_res_init(&res->res, req, 1 + sizeof(felica));
memcpy(res->payload, &felica, sizeof(felica));
res->count = 1;
return S_OK;
}
hr = sg_nfc_poll_aime(nfc, &mifare);
if (SUCCEEDED(hr) && hr != S_FALSE) {
sg_res_init(&res->res, req, 1 + sizeof(mifare));
memcpy(res->payload, &mifare, sizeof(mifare));
res->count = 1;
return S_OK;
}
sg_res_init(&res->res, req, 1);
res->count = 0;
return S_OK;
}
static HRESULT sg_nfc_poll_aime(
struct sg_nfc *nfc,
struct sg_nfc_poll_mifare *mifare)
{
uint8_t luid[10];
HRESULT hr;
/* Call backend */
if (nfc->ops->get_aime_id != NULL) {
hr = nfc->ops->get_aime_id(nfc->ops_ctx, luid, sizeof(luid));
} else {
hr = S_FALSE;
}
if (FAILED(hr) || hr == S_FALSE) {
return hr;
}
sg_nfc_dprintf(nfc, "AiMe card is present\n");
/* Construct response (use an arbitrary UID) */
mifare->type = 0x10;
mifare->id_len = sizeof(mifare->uid);
// mifare->uid = _byteswap_ulong(0x8FBECBFF);
mifare->uid = _byteswap_ulong(0x01020304);
/* Initialize MIFARE IC emulator */
hr = aime_card_populate(&nfc->mifare, luid, sizeof(luid));
if (FAILED(hr)) {
return hr;
}
return S_OK;
}
static HRESULT sg_nfc_poll_felica(
struct sg_nfc *nfc,
struct sg_nfc_poll_felica *felica)
{
uint64_t IDm;
HRESULT hr;
/* Call backend */
if (nfc->ops->get_felica_id != NULL) {
hr = nfc->ops->get_felica_id(nfc->ops_ctx, &IDm);
} else {
hr = S_FALSE;
}
if (FAILED(hr) || hr == S_FALSE) {
return hr;
}
sg_nfc_dprintf(nfc, "FeliCa card is present\n");
/* Construct poll response */
felica->type = 0x20;
felica->id_len = sizeof(felica->IDm) + sizeof(felica->PMm);
felica->IDm = _byteswap_uint64(IDm);
felica->PMm = _byteswap_uint64(felica_get_amusement_ic_PMm());
/* Initialize FeliCa IC emulator */
nfc->felica.IDm = IDm;
nfc->felica.PMm = felica_get_amusement_ic_PMm();
nfc->felica.system_code = 0x88b4;
return S_OK;
}
static HRESULT sg_nfc_cmd_mifare_read_block(
struct sg_nfc *nfc,
const struct sg_nfc_req_mifare_read_block *req,
struct sg_nfc_res_mifare_read_block *res)
{
uint32_t uid;
if (req->req.payload_len != sizeof(req->payload)) {
sg_nfc_dprintf(nfc, "%s: Payload size is incorrect\n", __func__);
return E_FAIL;
}
uid = _byteswap_ulong(req->payload.uid);
sg_nfc_dprintf(nfc, "Read uid %08x block %i\n", uid, req->payload.block_no);
if (req->payload.block_no > 14) {
sg_nfc_dprintf(nfc, "MIFARE block number out of range\n");
return E_FAIL;
} else if (req->payload.block_no >= 5){ // emoney auth encrypted
sg_res_init(&res->res, &req->req, sizeof(res->block));
char* auth;
long size = wslurp(nfc->authdata_path, &auth, false);
if (size < 0){
sg_nfc_dprintf(nfc, "Failed to read %ls: %lx!\n", nfc->authdata_path, GetLastError());
return E_FAIL;
}
int offset = 0;
if (req->payload.block_no == 6){
offset = 16;
} else if (req->payload.block_no == 8){
offset = 32;
} else if (req->payload.block_no == 9){
offset = 48;
} else if (req->payload.block_no == 10){
offset = 64;
} else if (req->payload.block_no == 12){
offset = 82;
} else if (req->payload.block_no == 13){
offset = 98;
} else if (req->payload.block_no == 14){
offset = 114;
}
for (int i = 0; i < 16 && offset + i < size; i++){
res->block[i] = auth[offset + i];
}
free(auth);
} else if (req->payload.block_no == 4){ // emoney auth plain
sg_res_init(&res->res, &req->req, sizeof(res->block));
res->block[0] = 0x54; // header
res->block[1] = 0x43;
res->block[2] = nfc->proxy_flag; // 2 or 3 depending on game (useProxy in env.json)
res->block[3] = 0x01; // unknown flag
} else { // read all other blocks normally
sg_res_init(&res->res, &req->req, sizeof(res->block));
memcpy( res->block,
nfc->mifare.sectors[0].blocks[req->payload.block_no].bytes,
sizeof(res->block));
}
return S_OK;
}
static HRESULT sg_nfc_cmd_felica_encap(
struct sg_nfc *nfc,
const struct sg_nfc_req_felica_encap *req,
struct sg_nfc_res_felica_encap *res)
{
struct const_iobuf f_req;
struct iobuf f_res;
HRESULT hr;
/* First byte of encapsulated request and response is a length byte
(inclusive of itself). The FeliCa emulator expects its caller to handle
that length byte on its behalf (we adopt the convention that the length
byte is part of the FeliCa protocol's framing layer). */
if (req->req.payload_len != 8 + req->payload[0]) {
sg_nfc_dprintf(
nfc,
"FeliCa encap payload length mismatch: sg %i != felica %i + 8",
req->req.payload_len,
req->payload[0]);
return E_FAIL;
}
f_req.bytes = req->payload;
f_req.nbytes = req->payload[0];
f_req.pos = 1;
f_res.bytes = res->payload;
f_res.nbytes = sizeof(res->payload);
f_res.pos = 1;
#if defined(LOG_NFC)
dprintf("FELICA OUTBOUND:\n");
dump_const_iobuf(&f_req);
#endif
hr = felica_transact(&nfc->felica, &f_req, &f_res);
if (FAILED(hr)) {
return hr;
}
sg_res_init(&res->res, &req->req, f_res.pos);
res->payload[0] = f_res.pos;
#if defined(LOG_NFC)
dprintf("FELICA INBOUND:\n");
dump_iobuf(&f_res);
#endif
return S_OK;
}
static HRESULT sg_nfc_cmd_send_hex_data(
struct sg_nfc *nfc,
const struct sg_req_header *req,
struct sg_res_header *res)
{
sg_res_init(res, req, 0);
/* Firmware checksum length? */
if (req->payload_len == 0x2b) {
/* The firmware is identical flag? */
res->status = 0x20;
}
return S_OK;
}
static HRESULT sg_nfc_cmd_dummy(
struct sg_nfc *nfc,
const struct sg_req_header *req,
struct sg_res_header *res)
{
sg_res_init(res, req, 0);
return S_OK;
}
+45
View File
@@ -0,0 +1,45 @@
#pragma once
#include <windows.h>
#include <stddef.h>
#include <stdint.h>
#include "hook/iobuf.h"
#include "iccard/felica.h"
#include "iccard/mifare.h"
struct sg_nfc_ops {
HRESULT (*poll)(void *ctx);
HRESULT (*get_aime_id)(void *ctx, uint8_t *luid, size_t nbytes);
HRESULT (*get_felica_id)(void *ctx, uint64_t *IDm);
// TODO Banapass, AmuseIC
};
struct sg_nfc {
const struct sg_nfc_ops *ops;
void *ops_ctx;
uint8_t addr;
unsigned int gen;
unsigned int proxy_flag;
struct felica felica;
struct mifare mifare;
const wchar_t* authdata_path;
};
void sg_nfc_init(
struct sg_nfc *nfc,
uint8_t addr,
const struct sg_nfc_ops *ops,
unsigned int gen,
unsigned int proxy_flag,
const wchar_t* authdata_path,
void *ops_ctx);
void sg_nfc_transact(
struct sg_nfc *nfc,
struct iobuf *res_frame,
const void *req_bytes,
size_t req_nbytes);
+207
View File
@@ -0,0 +1,207 @@
#include <windows.h>
#include <assert.h>
#include <stdbool.h>
#include <stdint.h>
#include "board/aime-dll.h"
#include "board/sg-led.h"
#include "board/sg-nfc.h"
#include "board/sg-reader.h"
#include "hook/iohook.h"
#include "hooklib/uart.h"
#include "util/dprintf.h"
#include "util/dump.h"
static HRESULT sg_reader_handle_irp(struct irp *irp);
static HRESULT sg_reader_handle_irp_locked(struct irp *irp);
static HRESULT sg_reader_nfc_poll(void *ctx);
static HRESULT sg_reader_nfc_get_aime_id(
void *ctx,
uint8_t *luid,
size_t luid_size);
static HRESULT sg_reader_nfc_get_felica_id(void *ctx, uint64_t *IDm);
static void sg_reader_led_set_color(void *ctx, uint8_t r, uint8_t g, uint8_t b);
static const struct sg_nfc_ops sg_reader_nfc_ops = {
.poll = sg_reader_nfc_poll,
.get_aime_id = sg_reader_nfc_get_aime_id,
.get_felica_id = sg_reader_nfc_get_felica_id,
};
static const struct sg_led_ops sg_reader_led_ops = {
.set_color = sg_reader_led_set_color,
};
static CRITICAL_SECTION sg_reader_lock;
static bool sg_reader_started;
static HRESULT sg_reader_start_hr;
static struct uart sg_reader_uart;
static uint8_t sg_reader_written_bytes[520];
static uint8_t sg_reader_readable_bytes[520];
static struct sg_nfc sg_reader_nfc;
static struct sg_led sg_reader_led;
HRESULT sg_reader_hook_init(
const struct aime_config *cfg,
unsigned int default_port_no,
unsigned int gen,
HINSTANCE self)
{
HRESULT hr;
assert(cfg != NULL);
assert(self != NULL);
if (!cfg->enable) {
return S_FALSE;
}
hr = aime_dll_init(&cfg->dll, self);
if (FAILED(hr)) {
return hr;
}
unsigned int port_no = cfg->port_no;
if (port_no == 0){
port_no = default_port_no;
}
if (cfg->gen != 0) {
gen = cfg->gen;
}
if (gen < 1 || gen > 3) {
dprintf("NFC Assembly: Invalid reader generation: %u\n", gen);
return E_INVALIDARG;
}
sg_nfc_init(&sg_reader_nfc, 0x00, &sg_reader_nfc_ops, gen, cfg->proxy_flag, cfg->authdata_path, NULL);
sg_led_init(&sg_reader_led, 0x08, &sg_reader_led_ops, gen, NULL);
InitializeCriticalSection(&sg_reader_lock);
if (!cfg->high_baudrate) {
sg_reader_uart.baud.BaudRate = 38400;
}
dprintf("NFC Assembly: enabling (port=%d)\n", port_no);
uart_init(&sg_reader_uart, port_no);
sg_reader_uart.written.bytes = sg_reader_written_bytes;
sg_reader_uart.written.nbytes = sizeof(sg_reader_written_bytes);
sg_reader_uart.readable.bytes = sg_reader_readable_bytes;
sg_reader_uart.readable.nbytes = sizeof(sg_reader_readable_bytes);
return iohook_push_handler(sg_reader_handle_irp);
}
static HRESULT sg_reader_handle_irp(struct irp *irp)
{
HRESULT hr;
assert(irp != NULL);
if (!uart_match_irp(&sg_reader_uart, irp)) {
return iohook_invoke_next(irp);
}
EnterCriticalSection(&sg_reader_lock);
hr = sg_reader_handle_irp_locked(irp);
LeaveCriticalSection(&sg_reader_lock);
return hr;
}
static HRESULT sg_reader_handle_irp_locked(struct irp *irp)
{
HRESULT hr;
#if defined(LOG_NFC)
if (irp->op == IRP_OP_WRITE) {
dprintf("WRITE:\n");
dump_const_iobuf(&irp->write);
}
#endif
#if defined(LOG_NFC)
if (irp->op == IRP_OP_READ) {
dprintf("READ:\n");
dump_iobuf(&sg_reader_uart.readable);
}
#endif
if (irp->op == IRP_OP_OPEN) {
/* Unfortunately the card reader UART gets opened and closed
repeatedly */
if (!sg_reader_started) {
dprintf("NFC Assembly: Starting backend DLL\n");
hr = aime_dll.init();
sg_reader_started = true;
sg_reader_start_hr = hr;
if (FAILED(hr)) {
dprintf("NFC Assembly: Backend error: %x\n", (int) hr);
return hr;
}
} else {
hr = sg_reader_start_hr;
if (FAILED(hr)) {
return hr;
}
}
}
hr = uart_handle_irp(&sg_reader_uart, irp);
if (FAILED(hr) || irp->op != IRP_OP_WRITE) {
return hr;
}
sg_nfc_transact(
&sg_reader_nfc,
&sg_reader_uart.readable,
sg_reader_uart.written.bytes,
sg_reader_uart.written.pos);
sg_led_transact(
&sg_reader_led,
&sg_reader_uart.readable,
sg_reader_uart.written.bytes,
sg_reader_uart.written.pos);
sg_reader_uart.written.pos = 0;
return hr;
}
static HRESULT sg_reader_nfc_poll(void *ctx)
{
return aime_dll.nfc_poll(0);
}
static HRESULT sg_reader_nfc_get_aime_id(
void *ctx,
uint8_t *luid,
size_t luid_size)
{
return aime_dll.nfc_get_aime_id(0, luid, luid_size);
}
static HRESULT sg_reader_nfc_get_felica_id(void *ctx, uint64_t *IDm)
{
return aime_dll.nfc_get_felica_id(0, IDm);
}
static void sg_reader_led_set_color(void *ctx, uint8_t r, uint8_t g, uint8_t b)
{
aime_dll.led_set_color(0, r, g, b);
}
+23
View File
@@ -0,0 +1,23 @@
#pragma once
#include <windows.h>
#include <stdbool.h>
#include "board/aime-dll.h"
struct aime_config {
struct aime_dll_config dll;
bool enable;
unsigned int port_no;
bool high_baudrate;
unsigned int gen;
unsigned int proxy_flag;
wchar_t authdata_path[MAX_PATH];
};
HRESULT sg_reader_hook_init(
const struct aime_config *cfg,
unsigned int default_port_no,
unsigned int gen,
HINSTANCE self);
+38
View File
@@ -0,0 +1,38 @@
#pragma once
#include "board/slider-frame.h"
enum {
SLIDER_CMD_AUTO_SCAN = 0x01,
SLIDER_CMD_SET_LED = 0x02,
SLIDER_CMD_AUTO_SCAN_START = 0x03,
SLIDER_CMD_AUTO_SCAN_STOP = 0x04,
SLIDER_CMD_DIVA_UNK_09 = 0x09,
SLIDER_CMD_DIVA_UNK_0A = 0x0A,
SLIDER_CMD_RESET = 0x10,
SLIDER_CMD_GET_BOARD_INFO = 0xF0,
};
struct slider_req_set_led {
struct slider_hdr hdr;
struct {
uint8_t unk; /* 0x28, decimal 40. meaning unknown. */
uint8_t rgb[96];
} payload;
};
union slider_req_any {
struct slider_hdr hdr;
struct slider_req_set_led set_led;
uint8_t bytes[260];
};
struct slider_resp_get_board_info {
struct slider_hdr hdr;
char version[32];
};
struct slider_resp_auto_scan {
struct slider_hdr hdr;
uint8_t pressure[32];
};
+180
View File
@@ -0,0 +1,180 @@
#include <windows.h>
#include <assert.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include "board/slider-frame.h"
#include "hook/iobuf.h"
static void slider_frame_sync(struct iobuf *src);
static HRESULT slider_frame_accept(const struct iobuf *dest);
static HRESULT slider_frame_encode_byte(struct iobuf *dest, uint8_t byte);
/* Frame structure:
[0] Sync byte (0xFF)
[1] Command
[2] Payload size
... Payload
[n] Checksum: Negate the sum of all prior bytes (including sync byte!)
Byte stuffing:
0xFD is an escape byte. Un-escape the subsequent byte by adding 1. */
static void slider_frame_sync(struct iobuf *src)
{
size_t i;
for (i = 0 ; i < src->pos && src->bytes[i] != 0xFF ; i++);
src->pos -= i;
memmove(&src->bytes[0], &src->bytes[i], i);
}
static HRESULT slider_frame_accept(const struct iobuf *dest)
{
uint8_t checksum;
size_t i;
if (dest->pos < 2 || dest->pos != dest->bytes[2] + 4) {
return S_FALSE;
}
checksum = 0;
for (i = 0 ; i < dest->pos ; i++) {
checksum += dest->bytes[i];
}
if (checksum != 0) {
return HRESULT_FROM_WIN32(ERROR_CRC);
}
return S_OK;
}
HRESULT slider_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);
slider_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 == 0xFF) {
hr = E_FAIL;
} else if (byte == 0xFD) {
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 = slider_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 slider_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 >= 2 && src[0] == 0xFF && src[2] + 3 == nbytes);
if (dest->pos >= dest->nbytes) {
return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
}
dest->bytes[dest->pos++] = 0xFF;
checksum = 0xFF;
for (i = 1 ; i < nbytes ; i++) {
byte = src[i];
checksum += byte;
hr = slider_frame_encode_byte(dest, byte);
if (FAILED(hr)) {
return hr;
}
}
return slider_frame_encode_byte(dest, -checksum);
}
static HRESULT slider_frame_encode_byte(struct iobuf *dest, uint8_t byte)
{
if (byte == 0xFF || byte == 0xFD) {
if (dest->pos + 2 > dest->nbytes) {
return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
}
dest->bytes[dest->pos++] = 0xFD;
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;
}
+25
View File
@@ -0,0 +1,25 @@
#pragma once
#include <windows.h>
#include <stddef.h>
#include <stdint.h>
#include "hook/iobuf.h"
enum {
SLIDER_FRAME_SYNC = 0xFF,
};
struct slider_hdr {
uint8_t sync;
uint8_t cmd;
uint8_t nbytes;
};
HRESULT slider_frame_decode(struct iobuf *dest, struct iobuf *src);
HRESULT slider_frame_encode(
struct iobuf *dest,
const void *ptr,
size_t nbytes);
+123
View File
@@ -0,0 +1,123 @@
#pragma once
#include "board/vfd-frame.h"
enum {
VFD_CMD_GET_VERSION = 0x5B,
VFD_CMD_RESET = 0x0B,
VFD_CMD_CLEAR_SCREEN = 0x0C,
VFD_CMD_SET_BRIGHTNESS = 0x20,
VFD_CMD_SET_SCREEN_ON = 0x21,
VFD_CMD_SET_H_SCROLL = 0x22,
VFD_CMD_DRAW_IMAGE = 0x2E,
VFD_CMD_SET_CURSOR = 0x30,
VFD_CMD_SET_ENCODING = 0x32,
VFD_CMD_SET_TEXT_WND = 0x40,
VFD_CMD_SET_TEXT_SPEED = 0x41,
VFD_CMD_WRITE_TEXT = 0x50,
VFD_CMD_ENABLE_SCROLL = 0x51,
VFD_CMD_DISABLE_SCROLL = 0x52,
VFD_CMD_ROTATE = 0x5D,
VFD_CMD_CREATE_CHAR = 0xA3,
VFD_CMD_CREATE_CHAR2 = 0xA4,
};
enum {
VFD_ENC_GB2312 = 0,
VFD_ENC_BIG5 = 1,
VFD_ENC_SHIFT_JIS = 2,
VFD_ENC_KSC5601 = 3,
VFD_ENC_MAX = 3,
};
struct vfd_req_hdr {
uint8_t sync;
uint8_t cmd;
};
struct vfd_req_any {
struct vfd_req_hdr hdr;
uint8_t payload[2054];
};
struct vfd_req_board_info {
struct vfd_req_hdr hdr;
uint8_t unk1;
};
struct vfd_resp_board_info { // \x0201.20\x03
uint8_t unk1;
char version[5];
uint8_t unk2;
};
struct vfd_req_reset {
struct vfd_req_hdr hdr;
};
struct vfd_req_cls {
struct vfd_req_hdr hdr;
};
struct vfd_req_brightness {
struct vfd_req_hdr hdr;
uint8_t brightness;
};
struct vfd_req_power {
struct vfd_req_hdr hdr;
uint8_t power_state;
};
struct vfd_req_hscroll {
struct vfd_req_hdr hdr;
uint8_t x_pos;
};
struct vfd_req_draw {
struct vfd_req_hdr hdr;
uint16_t x0;
uint8_t y0;
uint16_t x1;
uint8_t y1;
uint8_t image[2048];
};
struct vfd_req_cursor {
struct vfd_req_hdr hdr;
uint16_t x;
uint8_t y;
};
struct vfd_req_encoding {
struct vfd_req_hdr hdr;
uint8_t encoding;
};
struct vfd_req_wnd {
struct vfd_req_hdr hdr;
uint16_t x0;
uint8_t y0;
uint16_t x1;
uint8_t y1;
};
struct vfd_req_speed {
struct vfd_req_hdr hdr;
uint8_t encoding;
};
struct vfd_req_scroll {
struct vfd_req_hdr hdr;
};
struct vfd_req_rotate {
struct vfd_req_hdr hdr;
uint8_t unk1;
};
struct vfd_req_create_char {
struct vfd_req_hdr hdr;
uint8_t type;
uint8_t pixels[32];
};
+88
View File
@@ -0,0 +1,88 @@
#include <windows.h>
#include <assert.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#define SUPER_VERBOSE 1
#include "board/vfd-frame.h"
#include "hook/iobuf.h"
#include "util/dprintf.h"
static HRESULT vfd_frame_encode_byte(struct iobuf *dest, uint8_t byte);
/* Frame structure:
REQUEST:
[0] Sync byte (0x1A or 0x1B)
[1] Packet ID
[2...n-1] Data/payload
--- OR ---
if no sync byte is given, plain static text in the currently configured encoding is expected.
RESPONSE:
This thing never responds, unless it's VFD_CMD_GET_VERSION
*/
bool vfd_frame_sync(struct const_iobuf *src) {
return src->bytes[src->pos] == VFD_SYNC_BYTE || src->bytes[src->pos] == VFD_SYNC_BYTE2;
}
HRESULT vfd_frame_encode(
struct iobuf *dest,
const void *ptr,
size_t nbytes) {
const uint8_t *src;
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;
if (dest->pos >= dest->nbytes) {
return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
}
#if SUPER_VERBOSE
dprintf("VFD: RX Buffer:\n");
#endif
for (i = 1; i < nbytes; i++) {
byte = src[i];
#if SUPER_VERBOSE
dprintf("%02x ", byte);
#endif
hr = vfd_frame_encode_byte(dest, byte);
if (FAILED(hr)) {
return hr;
}
}
#if SUPER_VERBOSE
dprintf("\n");
#endif
return hr;
}
static HRESULT vfd_frame_encode_byte(struct iobuf *dest, uint8_t byte) {
if (dest->pos + 1 > dest->nbytes) {
return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
}
dest->bytes[dest->pos++] = byte;
return S_OK;
}
+20
View File
@@ -0,0 +1,20 @@
#pragma once
#include <windows.h>
#include <stddef.h>
#include <stdint.h>
#include "hook/iobuf.h"
enum {
VFD_SYNC_BYTE = 0x1B,
VFD_SYNC_BYTE2 = 0x1A,
};
bool vfd_frame_sync(struct const_iobuf *src);
HRESULT vfd_frame_encode(
struct iobuf *dest,
const void *ptr,
size_t nbytes);
+399
View File
@@ -0,0 +1,399 @@
/* This is some sort of LCD display found on various cabinets. It is driven
directly by amdaemon, and it has something to do with displaying the status
of electronic payments.
Part number in schematics is "VFD GP1232A02A FUTABA". */
#include <windows.h>
#include <assert.h>
#include <stdint.h>
#include <stdlib.h>
#include "board/config.h"
#include "board/vfd.h"
#include "board/vfd-cmd.h"
#include "hook/iohook.h"
#include "hooklib/uart.h"
#include "util/dprintf.h"
#include "util/dump.h"
#define SUPER_VERBOSE 0
static HRESULT vfd_handle_irp(struct irp *irp);
static struct uart vfd_uart;
static uint8_t vfd_written[4096];
static uint8_t vfd_readable[4096];
static int encoding = VFD_ENC_SHIFT_JIS;
HRESULT vfd_handle_get_version(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart);
HRESULT vfd_handle_reset(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart);
HRESULT vfd_handle_clear_screen(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart);
HRESULT vfd_handle_set_brightness(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart);
HRESULT vfd_handle_set_screen_on(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart);
HRESULT vfd_handle_set_h_scroll(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart);
HRESULT vfd_handle_draw_image(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart);
HRESULT vfd_handle_set_cursor(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart);
HRESULT vfd_handle_set_encoding(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart);
HRESULT vfd_handle_set_text_wnd(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart);
HRESULT vfd_handle_set_text_speed(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart);
HRESULT vfd_handle_write_text(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart);
HRESULT vfd_handle_enable_scroll(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart);
HRESULT vfd_handle_disable_scroll(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart);
HRESULT vfd_handle_rotate(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart);
HRESULT vfd_handle_create_char(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart);
HRESULT vfd_handle_create_char2(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart);
static bool utf_enabled;
HRESULT vfd_hook_init(struct vfd_config *cfg, unsigned int default_port_no)
{
if (!cfg->enable){
return S_FALSE;
}
utf_enabled = cfg->utf_conversion;
unsigned int port_no = cfg->port_no;
if (port_no == 0){
port_no = default_port_no;
}
dprintf("VFD: enabling (port=%d)\n", port_no);
uart_init(&vfd_uart, port_no);
vfd_uart.written.bytes = vfd_written;
vfd_uart.written.nbytes = sizeof(vfd_written);
vfd_uart.readable.bytes = vfd_readable;
vfd_uart.readable.nbytes = sizeof(vfd_readable);
return iohook_push_handler(vfd_handle_irp);
}
const char* get_encoding_name(int b){
switch (b){
case 0: return "gb2312";
case 1: return "big5";
case 2: return "shift-jis";
case 3: return "ks_c_5601-1987";
default: return "unknown";
}
}
void print_vfd_text(const char* str, int len){
if (utf_enabled){
wchar_t encoded[1024];
memset(encoded, 0, 1024 * sizeof(wchar_t));
int codepage = 0;
if (encoding == VFD_ENC_GB2312){
codepage = 936;
} else if (encoding == VFD_ENC_BIG5){
codepage = 950;
} else if (encoding == VFD_ENC_SHIFT_JIS){
codepage = 932;
} else if (encoding == VFD_ENC_KSC5601) {
codepage = 949;
}
if (!MultiByteToWideChar(codepage, MB_USEGLYPHCHARS, str, len, encoded, 1024)){
dprintf("VFD: Text conversion failed: %ld", GetLastError());
return;
}
dprintf("VFD: Text: %ls\n", encoded);
} else {
dprintf("VFD: Text: %s\n", str);
}
}
static HRESULT vfd_handle_irp(struct irp *irp)
{
HRESULT hr;
assert(irp != NULL);
if (!uart_match_irp(&vfd_uart, irp)) {
return iohook_invoke_next(irp);
}
if (irp->op == IRP_OP_OPEN){
dprintf("VFD: Open\n");
} else if (irp->op == IRP_OP_CLOSE){
dprintf("VFD: Close\n");
}
hr = uart_handle_irp(&vfd_uart, irp);
if (FAILED(hr) || irp->op != IRP_OP_WRITE) {
return hr;
}
#if SUPER_VERBOSE
dprintf("VFD TX:\n");
dump_iobuf(&vfd_uart.written);
#endif
struct const_iobuf reader;
iobuf_flip(&reader, &vfd_uart.written);
struct iobuf* writer = &vfd_uart.readable;
for (; reader.pos < reader.nbytes ; ){
if (vfd_frame_sync(&reader)) {
reader.pos++; // get the sync byte out of the way
uint8_t cmd;
iobuf_read_8(&reader, &cmd);
if (cmd == VFD_CMD_GET_VERSION) {
hr = vfd_handle_get_version(&reader, writer, &vfd_uart);
} else if (cmd == VFD_CMD_RESET) {
hr = vfd_handle_reset(&reader, writer, &vfd_uart);
} else if (cmd == VFD_CMD_CLEAR_SCREEN) {
hr = vfd_handle_clear_screen(&reader, writer, &vfd_uart);
} else if (cmd == VFD_CMD_SET_BRIGHTNESS) {
hr = vfd_handle_set_brightness(&reader, writer, &vfd_uart);
} else if (cmd == VFD_CMD_SET_SCREEN_ON) {
hr = vfd_handle_set_screen_on(&reader, writer, &vfd_uart);
} else if (cmd == VFD_CMD_SET_H_SCROLL) {
hr = vfd_handle_set_h_scroll(&reader, writer, &vfd_uart);
} else if (cmd == VFD_CMD_DRAW_IMAGE) {
hr = vfd_handle_draw_image(&reader, writer, &vfd_uart);
} else if (cmd == VFD_CMD_SET_CURSOR) {
hr = vfd_handle_set_cursor(&reader, writer, &vfd_uart);
} else if (cmd == VFD_CMD_SET_ENCODING) {
hr = vfd_handle_set_encoding(&reader, writer, &vfd_uart);
} else if (cmd == VFD_CMD_SET_TEXT_WND) {
hr = vfd_handle_set_text_wnd(&reader, writer, &vfd_uart);
} else if (cmd == VFD_CMD_SET_TEXT_SPEED) {
hr = vfd_handle_set_text_speed(&reader, writer, &vfd_uart);
} else if (cmd == VFD_CMD_WRITE_TEXT) {
hr = vfd_handle_write_text(&reader, writer, &vfd_uart);
} else if (cmd == VFD_CMD_ENABLE_SCROLL) {
hr = vfd_handle_enable_scroll(&reader, writer, &vfd_uart);
} else if (cmd == VFD_CMD_DISABLE_SCROLL) {
hr = vfd_handle_disable_scroll(&reader, writer, &vfd_uart);
} else if (cmd == VFD_CMD_ROTATE) {
hr = vfd_handle_rotate(&reader, writer, &vfd_uart);
} else if (cmd == VFD_CMD_CREATE_CHAR) {
hr = vfd_handle_create_char(&reader, writer, &vfd_uart);
} else if (cmd == VFD_CMD_CREATE_CHAR2) {
hr = vfd_handle_create_char2(&reader, writer, &vfd_uart);
} else {
dprintf("VFD: Unknown command 0x%x\n", cmd);
dump_const_iobuf(&reader);
hr = S_FALSE;
}
} else {
// if no sync byte is sent, we are just getting plain text...
if (reader.pos < reader.nbytes){
int len = 0;
// read chars until we hit a new sync byte or the data ends
while (reader.pos + len + 1 < reader.nbytes && reader.bytes[reader.pos + len] != VFD_SYNC_BYTE && reader.bytes[reader.pos + len] != VFD_SYNC_BYTE2){
len++;
}
char* str = malloc(len);
memset(str, 0, len);
iobuf_read(&reader, str, len);
print_vfd_text(str, len);
free(str);
reader.pos += len;
}
}
if (!SUCCEEDED(hr)){
return hr;
}
}
vfd_uart.written.pos = 0;
return hr;
}
HRESULT vfd_handle_get_version(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart){
dprintf("VFD: Get Version\n");
struct vfd_resp_board_info resp;
memset(&resp, 0, sizeof(resp));
resp.unk1 = 2;
strcpy(resp.version, "01.20");
resp.unk2 = 1;
return vfd_frame_encode(writer, &resp, sizeof(resp));
}
HRESULT vfd_handle_reset(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart){
dprintf("VFD: Reset\n");
encoding = VFD_ENC_SHIFT_JIS;
return S_FALSE;
}
HRESULT vfd_handle_clear_screen(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart){
dprintf("VFD: Clear Screen\n");
return S_FALSE;
}
HRESULT vfd_handle_set_brightness(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart){
uint8_t b;
iobuf_read_8(reader, &b);
if (b > 4){
dprintf("VFD: Brightness, invalid argument\n");
return E_FAIL;
}
dprintf("VFD: Brightness, %d\n", b);
return S_FALSE;
}
HRESULT vfd_handle_set_screen_on(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart){
uint8_t b;
iobuf_read_8(reader, &b);
if (b > 1){
dprintf("VFD: Screen Power, invalid argument\n");
return E_FAIL;
}
dprintf("VFD: Screen Power, %d\n", b);
return S_FALSE;
}
HRESULT vfd_handle_set_h_scroll(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart){
uint8_t x;
iobuf_read_8(reader, &x);
dprintf("VFD: Horizontal Scroll, X=%d\n", x);
return S_FALSE;
}
HRESULT vfd_handle_draw_image(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart){
int w, h;
uint16_t x0, x1;
uint8_t y0, y1;
uint8_t image[2048];
iobuf_read_be16(reader, &x0);
iobuf_read_8(reader, &y0);
iobuf_read_be16(reader, &x1);
iobuf_read_8(reader, &y1);
w = x1 - x0;
h = y1 - y0;
iobuf_read(reader, image, w*h);
dprintf("VFD: Draw image, %dx%d\n", w, h);
return S_FALSE;
}
HRESULT vfd_handle_set_cursor(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart){
uint16_t x;
uint8_t y;
iobuf_read_be16(reader, &x);
iobuf_read_8(reader, &y);
dprintf("VFD: Set Cursor, x=%d,y=%d\n", x, y);
return S_FALSE;
}
HRESULT vfd_handle_set_encoding(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart){
uint8_t b;
iobuf_read_8(reader, &b);
dprintf("VFD: Set Encoding, %d (%s)\n", b, get_encoding_name(b));
if (b < 0 || b > VFD_ENC_MAX){
dprintf("Invalid encoding specified\n");
return E_FAIL;
}
encoding = b;
return S_FALSE;
}
HRESULT vfd_handle_set_text_wnd(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart){
uint16_t x0, x1;
uint8_t y0, y1;
iobuf_read_be16(reader, &x0);
iobuf_read_8(reader, &y0);
iobuf_read_be16(reader, &x1);
iobuf_read_8(reader, &y1);
dprintf("VFD: Set Text Window, p0:%d,%d, p1:%d,%d\n", x0, y0, x1, y1);
return S_FALSE;
}
HRESULT vfd_handle_set_text_speed(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart){
uint8_t b;
iobuf_read_8(reader, &b);
dprintf("VFD: Set Text Speed, %d\n", b);
return S_FALSE;
}
HRESULT vfd_handle_write_text(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart){
uint8_t len;
iobuf_read_8(reader, &len);
char* str = malloc(len);
iobuf_read(reader, str, len);
print_vfd_text(str, len);
free(str);
return S_FALSE;
}
HRESULT vfd_handle_enable_scroll(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart){
dprintf("VFD: Enable Scrolling\n");
return S_FALSE;
}
HRESULT vfd_handle_disable_scroll(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart){
dprintf("VFD: Disable Scrolling\n");
return S_FALSE;
}
HRESULT vfd_handle_rotate(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart){
uint8_t b;
iobuf_read_8(reader, &b);
dprintf("VFD: Rotate, %d\n", b);
return S_FALSE;
}
HRESULT vfd_handle_create_char(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart){
uint8_t b;
iobuf_read_8(reader, &b);
char buf[32];
iobuf_read(reader, buf, 32);
dprintf("VFD: Create character, %d\n", b);
return S_FALSE;
}
HRESULT vfd_handle_create_char2(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart){
uint8_t b, b2;
iobuf_read_8(reader, &b);
iobuf_read_8(reader, &b2);
char buf[16];
iobuf_read(reader, buf, 16);
dprintf("VFD: Create character, %d, %d\n", b, b2);
return S_FALSE;
}
+13
View File
@@ -0,0 +1,13 @@
#pragma once
#include <windows.h>
struct vfd_config {
bool enable;
unsigned int port_no;
bool utf_conversion;
};
HRESULT vfd_hook_init(struct vfd_config *cfg, unsigned int default_port_no);
+18
View File
@@ -0,0 +1,18 @@
#include <windows.h>
#include <assert.h>
#include <stddef.h>
#include "gfxhook/config.h"
void gfx_config_load(struct gfx_config *cfg, const wchar_t *filename)
{
assert(cfg != NULL);
assert(filename != NULL);
cfg->enable = GetPrivateProfileIntW(L"gfx", L"enable", 1, filename);
cfg->windowed = GetPrivateProfileIntW(L"gfx", L"windowed", 0, filename);
cfg->framed = GetPrivateProfileIntW(L"gfx", L"framed", 1, filename);
cfg->monitor = GetPrivateProfileIntW(L"gfx", L"monitor", 0, filename);
cfg->dpiAware = GetPrivateProfileIntW(L"gfx", L"dpiAware", 1, filename);
}
+7
View File
@@ -0,0 +1,7 @@
#pragma once
#include <stddef.h>
#include "gfxhook/gfx.h"
void gfx_config_load(struct gfx_config *cfg, const wchar_t *filename);
+195
View File
@@ -0,0 +1,195 @@
#include <windows.h>
#include <dxgi.h>
#include <d3d11.h>
#include <assert.h>
#include <stdlib.h>
#include "gfxhook/d3d11.h"
#include "gfxhook/gfx.h"
#include "gfxhook/util.h"
#include "hook/table.h"
#include "hooklib/dll.h"
#include "util/dprintf.h"
typedef HRESULT (WINAPI *D3D11CreateDevice_t)(
IDXGIAdapter *pAdapter,
D3D_DRIVER_TYPE DriverType,
HMODULE Software,
UINT Flags,
const D3D_FEATURE_LEVEL *ppFeatureLevels,
UINT FeatureLevels,
UINT SDKVersion,
ID3D11Device **ppDevice,
D3D_FEATURE_LEVEL *pFeatureLevel,
ID3D11DeviceContext **ppImmediateContext);
typedef HRESULT (WINAPI *D3D11CreateDeviceAndSwapChain_t)(
IDXGIAdapter *pAdapter,
D3D_DRIVER_TYPE DriverType,
HMODULE Software,
UINT Flags,
const D3D_FEATURE_LEVEL *ppFeatureLevels,
UINT FeatureLevels,
UINT SDKVersion,
const DXGI_SWAP_CHAIN_DESC *pSwapChainDesc,
IDXGISwapChain **ppSwapChain,
ID3D11Device **ppDevice,
D3D_FEATURE_LEVEL *pFeatureLevel,
ID3D11DeviceContext **ppImmediateContext);
static struct gfx_config gfx_config;
static D3D11CreateDevice_t next_D3D11CreateDevice;
static D3D11CreateDeviceAndSwapChain_t next_D3D11CreateDeviceAndSwapChain;
static const struct hook_symbol d3d11_hooks[] = {
{
.name = "D3D11CreateDevice",
.patch = D3D11CreateDevice,
.link = (void **) &next_D3D11CreateDevice,
}, {
.name = "D3D11CreateDeviceAndSwapChain",
.patch = D3D11CreateDeviceAndSwapChain,
.link = (void **) &next_D3D11CreateDeviceAndSwapChain,
},
};
void gfx_d3d11_hook_init(const struct gfx_config *cfg, HINSTANCE self)
{
HMODULE d3d11;
assert(cfg != NULL);
if (!cfg->enable) {
return;
}
memcpy(&gfx_config, cfg, sizeof(*cfg));
hook_table_apply(NULL, "d3d11.dll", d3d11_hooks, _countof(d3d11_hooks));
if (next_D3D11CreateDevice == NULL || next_D3D11CreateDeviceAndSwapChain == NULL) {
d3d11 = LoadLibraryW(L"d3d11.dll");
if (d3d11 == NULL) {
dprintf("D3D11: d3d11.dll not found or failed initialization\n");
goto fail;
}
if (next_D3D11CreateDevice == NULL) {
next_D3D11CreateDevice = (D3D11CreateDevice_t) GetProcAddress(
d3d11,
"D3D11CreateDevice");
}
if (next_D3D11CreateDeviceAndSwapChain == NULL) {
next_D3D11CreateDeviceAndSwapChain = (D3D11CreateDeviceAndSwapChain_t) GetProcAddress(
d3d11,
"D3D11CreateDeviceAndSwapChain");
}
if (next_D3D11CreateDevice == NULL) {
dprintf("D3D11: D3D11CreateDevice not found in loaded d3d11.dll\n");
goto fail;
}
if (next_D3D11CreateDeviceAndSwapChain == NULL) {
dprintf("D3D11: D3D11CreateDeviceAndSwapChain not found in loaded d3d11.dll\n");
goto fail;
}
}
if (self != NULL) {
dll_hook_push(self, L"d3d11.dll");
}
return;
fail:
if (d3d11 != NULL) {
FreeLibrary(d3d11);
}
}
HRESULT WINAPI D3D11CreateDevice(
IDXGIAdapter *pAdapter,
D3D_DRIVER_TYPE DriverType,
HMODULE Software,
UINT Flags,
const D3D_FEATURE_LEVEL *ppFeatureLevels,
UINT FeatureLevels,
UINT SDKVersion,
ID3D11Device **ppDevice,
D3D_FEATURE_LEVEL *pFeatureLevel,
ID3D11DeviceContext **ppImmediateContext)
{
dprintf("D3D11: D3D11CreateDevice hook hit\n");
return next_D3D11CreateDevice(
pAdapter,
DriverType,
Software,
Flags,
ppFeatureLevels,
FeatureLevels,
SDKVersion,
ppDevice,
pFeatureLevel,
ppImmediateContext);
}
HRESULT WINAPI D3D11CreateDeviceAndSwapChain(
IDXGIAdapter *pAdapter,
D3D_DRIVER_TYPE DriverType,
HMODULE Software,
UINT Flags,
const D3D_FEATURE_LEVEL *ppFeatureLevels,
UINT FeatureLevels,
UINT SDKVersion,
const DXGI_SWAP_CHAIN_DESC *pSwapChainDesc,
IDXGISwapChain **ppSwapChain,
ID3D11Device **ppDevice,
D3D_FEATURE_LEVEL *pFeatureLevel,
ID3D11DeviceContext **ppImmediateContext)
{
DXGI_SWAP_CHAIN_DESC *desc;
HWND hwnd;
UINT width;
UINT height;
dprintf("D3D11: D3D11CreateDeviceAndSwapChain hook hit\n");
desc = (DXGI_SWAP_CHAIN_DESC *) pSwapChainDesc;
if (desc != NULL) {
desc->Windowed = gfx_config.windowed;
hwnd = desc->OutputWindow;
width = desc->BufferDesc.Width;
height = desc->BufferDesc.Height;
} else {
hwnd = NULL;
}
if (hwnd != NULL) {
gfx_util_ensure_win_visible(hwnd);
gfx_util_borderless_fullscreen_windowed(hwnd, width, height);
}
return next_D3D11CreateDeviceAndSwapChain(
pAdapter,
DriverType,
Software,
Flags,
ppFeatureLevels,
FeatureLevels,
SDKVersion,
pSwapChainDesc,
ppSwapChain,
ppDevice,
pFeatureLevel,
ppImmediateContext);
}
+7
View File
@@ -0,0 +1,7 @@
#pragma once
#include <windows.h>
#include "gfxhook/gfx.h"
void gfx_d3d11_hook_init(const struct gfx_config *cfg, HINSTANCE self);
+261
View File
@@ -0,0 +1,261 @@
#include <windows.h>
#include <d3d9.h>
#include <assert.h>
#include <stdlib.h>
#include "hook/com-proxy.h"
#include "hook/table.h"
#include "hooklib/dll.h"
#include "gfxhook/gfx.h"
#include "gfxhook/util.h"
#include "util/dprintf.h"
typedef IDirect3D9 * (WINAPI *Direct3DCreate9_t)(UINT sdk_ver);
typedef HRESULT (WINAPI *Direct3DCreate9Ex_t)(UINT sdk_ver, IDirect3D9Ex **d3d9ex);
static HRESULT STDMETHODCALLTYPE my_IDirect3D9_CreateDevice(
IDirect3D9 *self,
UINT adapter,
D3DDEVTYPE type,
HWND hwnd,
DWORD flags,
D3DPRESENT_PARAMETERS *pp,
IDirect3DDevice9 **pdev);
static HRESULT STDMETHODCALLTYPE my_IDirect3D9Ex_CreateDevice(
IDirect3D9Ex *self,
UINT adapter,
D3DDEVTYPE type,
HWND hwnd,
DWORD flags,
D3DPRESENT_PARAMETERS *pp,
IDirect3DDevice9 **pdev);
static struct gfx_config gfx_config;
static Direct3DCreate9_t next_Direct3DCreate9;
static Direct3DCreate9Ex_t next_Direct3DCreate9Ex;
static const struct hook_symbol gfx_hooks[] = {
{
.name = "Direct3DCreate9",
.patch = Direct3DCreate9,
.link = (void **) &next_Direct3DCreate9,
}, {
.name = "Direct3DCreate9Ex",
.patch = Direct3DCreate9Ex,
.link = (void **) &next_Direct3DCreate9Ex,
},
};
void gfx_d3d9_hook_init(const struct gfx_config *cfg, HINSTANCE self)
{
HMODULE d3d9;
assert(cfg != NULL);
if (!cfg->enable) {
return;
}
memcpy(&gfx_config, cfg, sizeof(*cfg));
hook_table_apply(NULL, "d3d9.dll", gfx_hooks, _countof(gfx_hooks));
if (next_Direct3DCreate9 == NULL || next_Direct3DCreate9Ex == NULL) {
d3d9 = LoadLibraryW(L"d3d9.dll");
if (d3d9 == NULL) {
dprintf("Gfx: d3d9.dll not found or failed initialization\n");
goto fail;
}
if (next_Direct3DCreate9 == NULL) {
next_Direct3DCreate9 = (Direct3DCreate9_t) GetProcAddress(d3d9, "Direct3DCreate9");
}
if (next_Direct3DCreate9Ex == NULL) {
next_Direct3DCreate9Ex = (Direct3DCreate9Ex_t) GetProcAddress(d3d9, "Direct3DCreate9Ex");
}
if (next_Direct3DCreate9 == NULL) {
dprintf("Gfx: Direct3DCreate9 not found in loaded d3d9.dll\n");
goto fail;
}
if (next_Direct3DCreate9Ex == NULL) {
dprintf("Gfx: Direct3DCreate9Ex not found in loaded d3d9.dll\n");
goto fail;
}
}
if (self != NULL) {
dll_hook_push(self, L"d3d9.dll");
}
return;
fail:
if (d3d9 != NULL) {
FreeLibrary(d3d9);
}
}
IDirect3D9 * WINAPI Direct3DCreate9(UINT sdk_ver)
{
struct com_proxy *proxy;
IDirect3D9Vtbl *vtbl;
IDirect3D9 *api;
HRESULT hr;
dprintf("Gfx: Direct3DCreate9 hook hit\n");
api = NULL;
if (next_Direct3DCreate9 == NULL) {
dprintf("Gfx: next_Direct3DCreate9 == NULL\n");
goto fail;
}
api = next_Direct3DCreate9(sdk_ver);
if (api == NULL) {
dprintf("Gfx: next_Direct3DCreate9 returned NULL\n");
goto fail;
}
hr = com_proxy_wrap(&proxy, api, sizeof(*api->lpVtbl));
if (FAILED(hr)) {
dprintf("Gfx: com_proxy_wrap returned %x\n", (int) hr);
goto fail;
}
vtbl = proxy->vptr;
vtbl->CreateDevice = my_IDirect3D9_CreateDevice;
return (IDirect3D9 *) proxy;
fail:
if (api != NULL) {
IDirect3D9_Release(api);
}
return NULL;
}
HRESULT WINAPI Direct3DCreate9Ex(UINT sdk_ver, IDirect3D9Ex **d3d9ex)
{
struct com_proxy *proxy;
IDirect3D9ExVtbl *vtbl;
IDirect3D9Ex *api;
HRESULT hr;
dprintf("Gfx: Direct3DCreate9Ex hook hit\n");
api = NULL;
if (next_Direct3DCreate9Ex == NULL) {
dprintf("Gfx: next_Direct3DCreate9Ex == NULL\n");
goto fail;
}
hr = next_Direct3DCreate9Ex(sdk_ver, d3d9ex);
if (FAILED(hr)) {
dprintf("Gfx: next_Direct3DCreate9Ex returned %x\n", (int) hr);
goto fail;
}
api = *d3d9ex;
hr = com_proxy_wrap(&proxy, api, sizeof(*api->lpVtbl));
if (FAILED(hr)) {
dprintf("Gfx: com_proxy_wrap returned %x\n", (int) hr);
goto fail;
}
vtbl = proxy->vptr;
vtbl->CreateDevice = my_IDirect3D9Ex_CreateDevice;
*d3d9ex = (IDirect3D9Ex *) proxy;
return S_OK;
fail:
if (api != NULL) {
IDirect3D9Ex_Release(api);
}
return hr;
}
static HRESULT STDMETHODCALLTYPE my_IDirect3D9_CreateDevice(
IDirect3D9 *self,
UINT adapter,
D3DDEVTYPE type,
HWND hwnd,
DWORD flags,
D3DPRESENT_PARAMETERS *pp,
IDirect3DDevice9 **pdev)
{
struct com_proxy *proxy;
IDirect3D9 *real;
dprintf("Gfx: IDirect3D9::CreateDevice hook hit\n");
proxy = com_proxy_downcast(self);
real = proxy->real;
if (gfx_config.windowed) {
pp->Windowed = TRUE;
pp->FullScreen_RefreshRateInHz = 0;
}
if (gfx_config.framed) {
gfx_util_frame_window(hwnd);
}
UINT max_adapter = IDirect3D9_GetAdapterCount(real);
adapter = gfx_config.monitor;
if (adapter >= max_adapter) {
dprintf(
"Gfx: Requested adapter %d but maximum is %d. Using primary monitor\n",
gfx_config.monitor, max_adapter - 1
);
adapter = D3DADAPTER_DEFAULT;
} else {
dprintf("Gfx: Using adapter %d\n", gfx_config.monitor);
}
return IDirect3D9_CreateDevice(real, adapter, type, hwnd, flags, pp, pdev);
}
static HRESULT STDMETHODCALLTYPE my_IDirect3D9Ex_CreateDevice(
IDirect3D9Ex *self,
UINT adapter,
D3DDEVTYPE type,
HWND hwnd,
DWORD flags,
D3DPRESENT_PARAMETERS *pp,
IDirect3DDevice9 **pdev)
{
dprintf("Gfx: IDirect3D9Ex::CreateDevice hook forwarding to my_IDirect3D9_CreateDevice\n");
return my_IDirect3D9_CreateDevice(
(IDirect3D9 *) self,
adapter,
type,
hwnd,
flags,
pp,
pdev);
}
+7
View File
@@ -0,0 +1,7 @@
#pragma once
#include <windows.h>
#include "gfxhook/gfx.h"
void gfx_d3d9_hook_init(const struct gfx_config *cfg, HINSTANCE self);
+364
View File
@@ -0,0 +1,364 @@
#include <windows.h>
#include <dxgi.h>
#include <dxgi1_3.h>
#include <assert.h>
#include <stdlib.h>
#include "gfxhook/dxgi.h"
#include "gfxhook/gfx.h"
#include "hook/com-proxy.h"
#include "hook/table.h"
#include "hooklib/dll.h"
#include "util/dprintf.h"
typedef HRESULT (WINAPI *CreateDXGIFactory_t)(REFIID riid, void **factory);
typedef HRESULT (WINAPI *CreateDXGIFactory1_t)(REFIID riid, void **factory);
typedef HRESULT (WINAPI *CreateDXGIFactory2_t)(
UINT flags,
REFIID riid,
void **factory);
static HRESULT hook_factory(REFIID riid, void **factory);
static HRESULT STDMETHODCALLTYPE my_IDXGIFactory_CreateSwapChain(
IDXGIFactory *self,
IUnknown *device,
DXGI_SWAP_CHAIN_DESC *desc,
IDXGISwapChain **swapchain);
static HRESULT STDMETHODCALLTYPE my_IDXGIFactory1_CreateSwapChain(
IDXGIFactory1 *self,
IUnknown *device,
DXGI_SWAP_CHAIN_DESC *desc,
IDXGISwapChain **swapchain);
static HRESULT STDMETHODCALLTYPE my_IDXGIFactory2_CreateSwapChain(
IDXGIFactory2 *self,
IUnknown *device,
DXGI_SWAP_CHAIN_DESC *desc,
IDXGISwapChain **swapchain);
static struct gfx_config gfx_config;
static CreateDXGIFactory_t next_CreateDXGIFactory;
static CreateDXGIFactory1_t next_CreateDXGIFactory1;
static CreateDXGIFactory2_t next_CreateDXGIFactory2;
static const struct hook_symbol dxgi_hooks[] = {
{
.name = "CreateDXGIFactory",
.patch = CreateDXGIFactory,
.link = (void **) &next_CreateDXGIFactory,
}, {
.name = "CreateDXGIFactory1",
.patch = CreateDXGIFactory1,
.link = (void **) &next_CreateDXGIFactory1,
}, {
.name = "CreateDXGIFactory2",
.patch = CreateDXGIFactory2,
.link = (void **) &next_CreateDXGIFactory2,
},
};
void gfx_dxgi_hook_init(const struct gfx_config *cfg, HINSTANCE self)
{
HMODULE dxgi;
assert(cfg != NULL);
if (!cfg->enable) {
return;
}
memcpy(&gfx_config, cfg, sizeof(*cfg));
hook_table_apply(NULL, "dxgi.dll", dxgi_hooks, _countof(dxgi_hooks));
if (next_CreateDXGIFactory == NULL || next_CreateDXGIFactory1 == NULL) {
dxgi = LoadLibraryW(L"dxgi.dll");
if (dxgi == NULL) {
dprintf("DXGI: dxgi.dll not found or failed initialization\n");
goto fail;
}
if (next_CreateDXGIFactory == NULL) {
next_CreateDXGIFactory = (CreateDXGIFactory_t) GetProcAddress(
dxgi,
"CreateDXGIFactory");
}
if (next_CreateDXGIFactory1 == NULL) {
next_CreateDXGIFactory1 = (CreateDXGIFactory1_t) GetProcAddress(
dxgi,
"CreateDXGIFactory1");
}
if (next_CreateDXGIFactory2 == NULL) {
next_CreateDXGIFactory2 = (CreateDXGIFactory2_t) GetProcAddress(
dxgi,
"CreateDXGIFactory2");
}
if (next_CreateDXGIFactory == NULL) {
dprintf("DXGI: CreateDXGIFactory not found in loaded dxgi.dll\n");
goto fail;
}
if (next_CreateDXGIFactory1 == NULL) {
dprintf("DXGI: CreateDXGIFactory1 not found in loaded dxgi.dll\n");
goto fail;
}
/* `CreateDXGIFactory2` was introduced in Windows 8.1 and the original
* Nu runs Windows 8, so do not require it to exist */
}
if (self != NULL) {
dll_hook_push(self, L"dxgi.dll");
}
return;
fail:
if (dxgi != NULL) {
FreeLibrary(dxgi);
}
}
HRESULT WINAPI CreateDXGIFactory(REFIID riid, void **factory)
{
HRESULT hr;
dprintf("DXGI: CreateDXGIFactory hook hit\n");
hr = next_CreateDXGIFactory(riid, factory);
if (FAILED(hr)) {
dprintf("DXGI: CreateDXGIFactory returned %x\n", (int) hr);
return hr;
}
hr = hook_factory(riid, factory);
if (FAILED(hr)) {
return hr;
}
return hr;
}
HRESULT WINAPI CreateDXGIFactory1(REFIID riid, void **factory)
{
HRESULT hr;
dprintf("DXGI: CreateDXGIFactory1 hook hit\n");
hr = next_CreateDXGIFactory1(riid, factory);
if (FAILED(hr)) {
dprintf("DXGI: CreateDXGIFactory1 returned %x\n", (int) hr);
return hr;
}
hr = hook_factory(riid, factory);
if (FAILED(hr)) {
return hr;
}
return hr;
}
HRESULT WINAPI CreateDXGIFactory2(UINT flags, REFIID riid, void **factory)
{
HRESULT hr;
dprintf("DXGI: CreateDXGIFactory2 hook hit\n");
if (next_CreateDXGIFactory2 == NULL) {
dprintf("DXGI: CreateDXGIFactory2 not available, forwarding to CreateDXGIFactory1\n");
return CreateDXGIFactory1(riid, factory);
}
hr = next_CreateDXGIFactory2(flags, riid, factory);
if (FAILED(hr)) {
dprintf("DXGI: CreateDXGIFactory2 returned %x\n", (int) hr);
return hr;
}
hr = hook_factory(riid, factory);
if (FAILED(hr)) {
return hr;
}
return hr;
}
static HRESULT hook_factory(REFIID riid, void **factory)
{
struct com_proxy *proxy;
IDXGIFactory *api_0;
IDXGIFactory1 *api_1;
IDXGIFactory2 *api_2;
IDXGIFactoryVtbl *vtbl_0;
IDXGIFactory1Vtbl *vtbl_1;
IDXGIFactory2Vtbl *vtbl_2;
HRESULT hr;
api_0 = NULL;
api_1 = NULL;
api_2 = NULL;
if (memcmp(riid, &IID_IDXGIFactory, sizeof(*riid)) == 0) {
api_0 = *factory;
hr = com_proxy_wrap(&proxy, api_0, sizeof(*api_0->lpVtbl));
if (FAILED(hr)) {
dprintf("DXGI: com_proxy_wrap returned %x\n", (int) hr);
goto fail;
}
vtbl_0 = proxy->vptr;
vtbl_0->CreateSwapChain = my_IDXGIFactory_CreateSwapChain;
*factory = proxy;
} else if (memcmp(riid, &IID_IDXGIFactory1, sizeof(*riid)) == 0) {
api_1 = *factory;
hr = com_proxy_wrap(&proxy, api_1, sizeof(*api_1->lpVtbl));
if (FAILED(hr)) {
dprintf("DXGI: com_proxy_wrap returned %x\n", (int) hr);
goto fail;
}
vtbl_1 = proxy->vptr;
vtbl_1->CreateSwapChain = my_IDXGIFactory1_CreateSwapChain;
*factory = proxy;
} else if (memcmp(riid, &IID_IDXGIFactory2, sizeof(*riid)) == 0) {
api_2 = *factory;
hr = com_proxy_wrap(&proxy, api_2, sizeof(*api_2->lpVtbl));
if (FAILED(hr)) {
dprintf("DXGI: com_proxy_wrap returned %x\n", (int) hr);
goto fail;
}
vtbl_2 = proxy->vptr;
vtbl_2->CreateSwapChain = my_IDXGIFactory2_CreateSwapChain;
*factory = proxy;
}
return S_OK;
fail:
if (api_0 != NULL) {
IDXGIFactory_Release(api_0);
}
if (api_1 != NULL) {
IDXGIFactory1_Release(api_1);
}
if (api_2 != NULL) {
IDXGIFactory2_Release(api_2);
}
return hr;
}
static HRESULT STDMETHODCALLTYPE my_IDXGIFactory_CreateSwapChain(
IDXGIFactory *self,
IUnknown *device,
DXGI_SWAP_CHAIN_DESC *desc,
IDXGISwapChain **swapchain)
{
struct com_proxy *proxy;
IDXGIFactory *real;
HWND hwnd;
UINT width;
UINT height;
dprintf("DXGI: IDXGIFactory::CreateSwapChain hook hit\n");
proxy = com_proxy_downcast(self);
real = proxy->real;
if (desc != NULL) {
desc->Windowed = gfx_config.windowed;
hwnd = desc->OutputWindow;
width = desc->BufferDesc.Width;
height = desc->BufferDesc.Height;
} else {
hwnd = NULL;
}
if (hwnd != NULL) {
/*
* Ensure window is maximized to avoid a Windows 10 issue where a
* fullscreen swap chain is not created because the window is minimized
* at the time of creation.
*/
ShowWindow(hwnd, SW_RESTORE);
if (!gfx_config.framed && width > 0 && height > 0) {
dprintf("DXGI: Resizing window to %ux%u\n", width, height);
SetWindowLongPtrW(hwnd, GWL_STYLE, WS_POPUP);
SetWindowLongPtrW(hwnd, GWL_EXSTYLE, WS_EX_TOPMOST);
SetWindowPos(
hwnd,
HWND_TOP,
0,
0,
(int) width,
(int) height,
SWP_FRAMECHANGED | SWP_NOSENDCHANGING);
ShowWindow(hwnd, SW_SHOWMAXIMIZED);
}
}
return IDXGIFactory_CreateSwapChain(real, device, desc, swapchain);
}
static HRESULT STDMETHODCALLTYPE my_IDXGIFactory1_CreateSwapChain(
IDXGIFactory1 *self,
IUnknown *device,
DXGI_SWAP_CHAIN_DESC *desc,
IDXGISwapChain **swapchain)
{
dprintf("DXGI: IDXGIFactory1::CreateSwapChain hook forwarding to my_IDXGIFactory_CreateSwapChain\n");
return my_IDXGIFactory_CreateSwapChain(
(IDXGIFactory *) self,
device,
desc,
swapchain);
}
static HRESULT STDMETHODCALLTYPE my_IDXGIFactory2_CreateSwapChain(
IDXGIFactory2 *self,
IUnknown *device,
DXGI_SWAP_CHAIN_DESC *desc,
IDXGISwapChain **swapchain)
{
dprintf("DXGI: IDXGIFactory2::CreateSwapChain hook forwarding to my_IDXGIFactory_CreateSwapChain\n");
return my_IDXGIFactory_CreateSwapChain(
(IDXGIFactory *) self,
device,
desc,
swapchain);
}
+7
View File
@@ -0,0 +1,7 @@
#pragma once
#include <windows.h>
#include "gfxhook/gfx.h"
void gfx_dxgi_hook_init(const struct gfx_config *cfg, HINSTANCE self);
+147
View File
@@ -0,0 +1,147 @@
#include <windows.h>
#include <assert.h>
#include <stdlib.h>
#include "gfxhook/gfx.h"
#include "hook/table.h"
#include "util/dprintf.h"
/* Hook functions */
static BOOL WINAPI hook_ShowWindow(HWND hWnd, int nCmdShow);
static HWND WINAPI hook_CreateWindowExA(
DWORD dwExStyle,
LPCSTR lpClassName,
LPCSTR lpWindowName,
DWORD dwStyle,
int X,
int Y,
int nWidth,
int nHeight,
HWND hWndParent,
HMENU hMenu,
HINSTANCE hInstance,
LPVOID lpParam
);
/* Link pointers */
static BOOL (WINAPI *next_ShowWindow)(HWND hWnd, int nCmdShow);
static HWND (WINAPI *next_CreateWindowExA)(
DWORD dwExStyle,
LPCSTR lpClassName,
LPCSTR lpWindowName,
DWORD dwStyle,
int X,
int Y,
int nWidth,
int nHeight,
HWND hWndParent,
HMENU hMenu,
HINSTANCE hInstance,
LPVOID lpParam
);
static struct gfx_config gfx_config;
static const struct hook_symbol gfx_hooks[] = {
{
.name = "ShowWindow",
.patch = hook_ShowWindow,
.link = (void **) &next_ShowWindow,
}, {
.name = "CreateWindowExA",
.patch = hook_CreateWindowExA,
.link = (void **) &next_CreateWindowExA,
},
};
void gfx_hook_init(const struct gfx_config *cfg)
{
assert(cfg != NULL);
if (!cfg->enable) {
return;
}
if (cfg->dpiAware) {
if (SetProcessDPIAware()) {
dprintf("Gfx: Game process set to DPI aware.\n");
} else {
dprintf("Gfx: Failed to set process DPI aware\n");
}
}
memcpy(&gfx_config, cfg, sizeof(*cfg));
hook_table_apply(NULL, "user32.dll", gfx_hooks, _countof(gfx_hooks));
}
static BOOL WINAPI hook_ShowWindow(HWND hWnd, int nCmdShow)
{
dprintf("Gfx: ShowWindow hook hit\n");
if (!gfx_config.framed && nCmdShow == SW_RESTORE) {
nCmdShow = SW_SHOW;
}
return next_ShowWindow(hWnd, nCmdShow);
}
static HWND WINAPI hook_CreateWindowExA(
DWORD dwExStyle,
LPCSTR lpClassName,
LPCSTR lpWindowName,
DWORD dwStyle,
int X,
int Y,
int nWidth,
int nHeight,
HWND hWndParent,
HMENU hMenu,
HINSTANCE hInstance,
LPVOID lpParam
)
{
RECT rect;
dprintf("Gfx: CreateWindowExA hook hit\n");
if (gfx_config.windowed)
{
if (gfx_config.framed)
dwStyle |= WS_BORDER | WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU;
else
dwStyle = WS_POPUP;
rect.left = ((X == CW_USEDEFAULT) ? 0 : X);
rect.top = ((Y == CW_USEDEFAULT) ? 0 : Y);
rect.right = rect.left + nWidth;
rect.bottom = rect.top + nHeight;
// Don't care if it's ok or not, since we are creating window and we can't just return a NULL
AdjustWindowRect(&rect, dwStyle, !!hMenu);
X = ((X == CW_USEDEFAULT) ? X : rect.left);
Y = ((Y == CW_USEDEFAULT) ? Y : rect.top);
nWidth = rect.right - rect.left;
nHeight = rect.bottom - rect.top;
}
return next_CreateWindowExA(
dwExStyle,
lpClassName,
lpWindowName,
dwStyle,
X,
Y,
nWidth,
nHeight,
hWndParent,
hMenu,
hInstance,
lpParam
);
}
+13
View File
@@ -0,0 +1,13 @@
#pragma once
#include <stdbool.h>
struct gfx_config {
bool enable;
bool windowed;
bool framed;
int monitor;
bool dpiAware;
};
void gfx_hook_init(const struct gfx_config *cfg);
+77
View File
@@ -0,0 +1,77 @@
#include <windows.h>
#include <assert.h>
#include <stdlib.h>
#include "gfxhook/gfx.h"
#include "gfxhook/gl.h"
#include "hook/table.h"
#include "hooklib/dll.h"
#include "util/dprintf.h"
/* Hook functions */
static void WINAPI hook_glutFullScreen(void);
static void WINAPI hook_glutInitDisplayMode(unsigned int mode);
/* Link pointers */
static void (WINAPI *next_glutFullScreen)(void);
static void (WINAPI *next_glutInitDisplayMode)(unsigned int mode);
static struct gfx_config gfx_config;
static const struct hook_symbol glut_hooks[] = {
{
.name = "glutFullScreen",
.patch = hook_glutFullScreen,
.link = (void **) &next_glutFullScreen,
}, {
.name = "glutInitDisplayMode",
.patch = hook_glutInitDisplayMode,
.link = (void **) &next_glutInitDisplayMode,
},
};
void gfx_gl_hook_init(const struct gfx_config *cfg, HINSTANCE self)
{
assert(cfg != NULL);
if (!cfg->enable) {
return;
}
memcpy(&gfx_config, cfg, sizeof(*cfg));
hook_table_apply(NULL, "glut32.dll", glut_hooks, _countof(glut_hooks));
if (self != NULL) {
dll_hook_push(self, L"glut32.dll");
}
}
static void WINAPI hook_glutFullScreen(void)
{
dprintf("Gfx: glutFullScreen hook hit\n");
if (gfx_config.windowed) {
return;
}
next_glutFullScreen();
}
static void WINAPI hook_glutInitDisplayMode(unsigned int mode)
{
dprintf("Gfx: glutInitDisplayMode hook hit\n");
// GLUT adds a frame when going windowed
if (gfx_config.windowed && !gfx_config.framed) {
// GLUT_BORDERLESS
mode |= 0x0800;
}
next_glutInitDisplayMode(mode);
}
+3
View File
@@ -0,0 +1,3 @@
#pragma once
void gfx_gl_hook_init(const struct gfx_config *cfg, HINSTANCE self);
+29
View File
@@ -0,0 +1,29 @@
gfxhook_lib = static_library(
'gfxhook',
include_directories : inc,
implicit_include_directories : false,
dependencies : [
capnhook.get_variable('hook_dep'),
dxguid_lib,
],
link_with : [
hooklib_lib,
util_lib,
],
sources : [
'config.c',
'config.h',
'd3d9.c',
'd3d9.h',
'd3d11.c',
'd3d11.h',
'dxgi.c',
'dxgi.h',
'gfx.c',
'gfx.h',
'gl.c',
'gl.h',
'util.c',
'util.h',
],
)
+116
View File
@@ -0,0 +1,116 @@
#include <windows.h>
#include "gfxhook/util.h"
#include "util/dprintf.h"
void gfx_util_ensure_win_visible(HWND hwnd)
{
/*
* Ensure window is maximized to avoid a Windows 10 issue where a
* fullscreen swap chain is not created because the window is minimized
* at the time of creation.
*/
ShowWindow(hwnd, SW_RESTORE);
}
void gfx_util_borderless_fullscreen_windowed(HWND hwnd, UINT width, UINT height)
{
BOOL ok;
HRESULT hr;
dprintf("Gfx: Resizing window to %ux%u\n", width, height);
SetWindowLongPtrW(hwnd, GWL_STYLE, WS_POPUP);
SetWindowLongPtrW(hwnd, GWL_EXSTYLE, WS_EX_TOPMOST);
ok = SetWindowPos(
hwnd,
HWND_TOP,
0,
0,
(int) width,
(int) height,
SWP_FRAMECHANGED | SWP_NOSENDCHANGING);
if (!ok) {
/* come on... */
hr = HRESULT_FROM_WIN32(GetLastError());
dprintf("Gfx: SetWindowPos failed: %x\n", (int) hr);
return;
}
ok = ShowWindow(hwnd, SW_SHOWMAXIMIZED);
if (!ok) {
/* come on... */
hr = HRESULT_FROM_WIN32(GetLastError());
dprintf("Gfx: ShowWindow failed: %x\n", (int) hr);
return;
}
}
HRESULT gfx_util_frame_window(HWND hwnd)
{
HRESULT hr;
DWORD error;
LONG style;
RECT rect;
BOOL ok;
SetLastError(ERROR_SUCCESS);
style = GetWindowLongW(hwnd, GWL_STYLE);
error = GetLastError();
if (error != ERROR_SUCCESS) {
hr = HRESULT_FROM_WIN32(error);
dprintf("Gfx: GetWindowLongPtrW(%p, GWL_STYLE) failed: %x\n",
hwnd,
(int) hr);
return hr;
}
ok = GetClientRect(hwnd, &rect);
if (!ok) {
hr = HRESULT_FROM_WIN32(GetLastError());
dprintf("Gfx: GetClientRect(%p) failed: %x\n", hwnd, (int) hr);
return hr;
}
style |= WS_BORDER | WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU;
ok = AdjustWindowRect(&rect, style, FALSE);
if (!ok) {
/* come on... */
hr = HRESULT_FROM_WIN32(GetLastError());
dprintf("Gfx: AdjustWindowRect failed: %x\n", (int) hr);
return hr;
}
/* This... always seems to set an error, even though it works? idk */
SetWindowLongW(hwnd, GWL_STYLE, style);
ok = SetWindowPos(
hwnd,
HWND_TOP,
rect.left,
rect.top,
rect.right - rect.left,
rect.bottom - rect.top,
SWP_FRAMECHANGED | SWP_NOMOVE);
if (!ok) {
hr = HRESULT_FROM_WIN32(GetLastError());
dprintf("Gfx: SetWindowPos(%p) failed: %x\n", hwnd, (int) hr);
return hr;
}
return S_OK;
}
+7
View File
@@ -0,0 +1,7 @@
#pragma once
#include <windows.h>
void gfx_util_ensure_win_visible(HWND hwnd);
void gfx_util_borderless_fullscreen_windowed(HWND hwnd, UINT width, UINT height);
HRESULT gfx_util_frame_window(HWND hwnd);
+86
View File
@@ -0,0 +1,86 @@
#include <windows.h>
#include <assert.h>
#include <stdbool.h>
#include <stdlib.h>
#include <stddef.h>
#include "hooklib/config.h"
#include "hooklib/dvd.h"
void dvd_config_load(struct dvd_config *cfg, const wchar_t *filename)
{
assert(cfg != NULL);
assert(filename != NULL);
cfg->enable = GetPrivateProfileIntW(L"dvd", L"enable", 1, filename);
}
void touch_screen_config_load(struct touch_screen_config *cfg, const wchar_t *filename)
{
assert(cfg != NULL);
assert(filename != NULL);
cfg->enable = GetPrivateProfileIntW(L"touch", L"enable", 1, filename);
cfg->remap = GetPrivateProfileIntW(L"touch", L"remap", 1, filename);
cfg->cursor = GetPrivateProfileIntW(L"touch", L"cursor", 1, filename);
}
void printer_config_load(struct printer_config *cfg, const wchar_t *filename)
{
assert(cfg != NULL);
assert(filename != NULL);
wchar_t tmpstr[16];
cfg->enable = GetPrivateProfileIntW(L"printer", L"enable", 0, filename);
cfg->rotate_180 = GetPrivateProfileIntW(L"printer", L"rotate180", 0, filename);
GetPrivateProfileStringW(
L"printer",
L"serial_no",
L"5A-A123",
tmpstr,
_countof(tmpstr),
filename);
size_t n = wcstombs(cfg->serial_no, tmpstr, sizeof(cfg->serial_no));
for (int i = n; i < sizeof(cfg->serial_no); i++)
{
cfg->serial_no[i] = '\0';
}
GetPrivateProfileStringW(
L"printer",
L"mainFwPath",
L"DEVICE\\printer_main_fw.bin",
cfg->main_fw_path,
_countof(cfg->main_fw_path),
filename);
GetPrivateProfileStringW(
L"printer",
L"dspFwPath",
L"DEVICE\\printer_dsp_fw.bin",
cfg->dsp_fw_path,
_countof(cfg->dsp_fw_path),
filename);
GetPrivateProfileStringW(
L"printer",
L"paramFwPath",
L"DEVICE\\printer_param_fw.bin",
cfg->param_fw_path,
_countof(cfg->param_fw_path),
filename);
GetPrivateProfileStringW(
L"printer",
L"printerOutPath",
L"DEVICE\\print",
cfg->printer_out_path,
_countof(cfg->printer_out_path),
filename);
cfg->wait_time = GetPrivateProfileIntW(L"printer", L"waitTime", 0, filename);
}
+11
View File
@@ -0,0 +1,11 @@
#pragma once
#include <stddef.h>
#include "hooklib/dvd.h"
#include "hooklib/touch.h"
#include "hooklib/printer.h"
void dvd_config_load(struct dvd_config *cfg, const wchar_t *filename);
void touch_screen_config_load(struct touch_screen_config *cfg, const wchar_t *filename);
void printer_config_load(struct printer_config *cfg, const wchar_t *filename);
+258
View File
@@ -0,0 +1,258 @@
#include <windows.h>
#include <assert.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include "hook/table.h"
#include "hooklib/createprocess.h"
#include "util/dprintf.h"
void createprocess_hook_init();
static BOOL WINAPI my_CreateProcessA(
LPCSTR lpApplicationName,
LPSTR lpCommandLine,
LPSECURITY_ATTRIBUTES lpProcessAttributes,
LPSECURITY_ATTRIBUTES lpThreadAttributes,
BOOL bInheritHandles,
DWORD dwCreationFlags,
LPVOID lpEnvironment,
LPCSTR lpCurrentDirectory,
LPSTARTUPINFOA lpStartupInfo,
LPPROCESS_INFORMATION lpProcessInformation
);
BOOL my_CreateProcessW(
LPCWSTR lpApplicationName,
LPWSTR lpCommandLine,
LPSECURITY_ATTRIBUTES lpProcessAttributes,
LPSECURITY_ATTRIBUTES lpThreadAttributes,
BOOL bInheritHandles,
DWORD dwCreationFlags,
LPVOID lpEnvironment,
LPCWSTR lpCurrentDirectory,
LPSTARTUPINFOW lpStartupInfo,
LPPROCESS_INFORMATION lpProcessInformation
);
static BOOL (WINAPI *next_CreateProcessA)(
LPCSTR lpApplicationName,
LPSTR lpCommandLine,
LPSECURITY_ATTRIBUTES lpProcessAttributes,
LPSECURITY_ATTRIBUTES lpThreadAttributes,
BOOL bInheritHandles,
DWORD dwCreationFlags,
LPVOID lpEnvironment,
LPCSTR lpCurrentDirectory,
LPSTARTUPINFOA lpStartupInfo,
LPPROCESS_INFORMATION lpProcessInformation
);
static BOOL (WINAPI *next_CreateProcessW)(
LPCWSTR lpApplicationName,
LPWSTR lpCommandLine,
LPSECURITY_ATTRIBUTES lpProcessAttributes,
LPSECURITY_ATTRIBUTES lpThreadAttributes,
BOOL bInheritHandles,
DWORD dwCreationFlags,
LPVOID lpEnvironment,
LPCWSTR lpCurrentDirectory,
LPSTARTUPINFOW lpStartupInfo,
LPPROCESS_INFORMATION lpProcessInformation
);
static const struct hook_symbol win32_hooks[] = {
{
.name = "CreateProcessA",
.patch = my_CreateProcessA,
.link = (void **) &next_CreateProcessA
},
{
.name = "CreateProcessW",
.patch = my_CreateProcessW,
.link = (void **) &next_CreateProcessW
},
};
static bool did_init = false;
static struct process_hook_sym_w *process_syms_w;
static struct process_hook_sym_a *process_syms_a;
static size_t process_nsyms_a = 0;
static size_t process_nsyms_w = 0;
static CRITICAL_SECTION createproc_lock;
HRESULT createprocess_push_hook_w(const wchar_t *name, const wchar_t *head, const wchar_t *tail, bool replace_all) {
struct process_hook_sym_w *new_mem;
struct process_hook_sym_w *new_proc;
HRESULT hr;
assert(name != NULL);
assert(head != NULL);
createprocess_hook_init();
EnterCriticalSection(&createproc_lock);
new_mem = realloc(
process_syms_w,
(process_nsyms_w + 1) * sizeof(struct process_hook_sym_w));
if (new_mem == NULL) {
LeaveCriticalSection(&createproc_lock);
return E_OUTOFMEMORY;
}
new_proc = &new_mem[process_nsyms_w];
memset(new_proc, 0, sizeof(*new_proc));
new_proc->name = name;
new_proc->head = head;
new_proc->tail = tail;
new_proc->replace_all = replace_all;
process_syms_w = new_mem;
process_nsyms_w++;
LeaveCriticalSection(&createproc_lock);
return S_OK;
}
HRESULT createprocess_push_hook_a(const char *name, const char *head, const char *tail, bool replace_all) {
struct process_hook_sym_a *new_mem;
struct process_hook_sym_a *new_proc;
assert(name != NULL);
assert(head != NULL);
createprocess_hook_init();
EnterCriticalSection(&createproc_lock);
new_mem = realloc(
process_syms_a,
(process_nsyms_a + 1) * sizeof(struct process_hook_sym_a));
if (new_mem == NULL) {
LeaveCriticalSection(&createproc_lock);
return E_OUTOFMEMORY;
}
new_proc = &new_mem[process_nsyms_a];
memset(new_proc, 0, sizeof(*new_proc));
new_proc->name = name;
new_proc->head = head;
new_proc->tail = tail;
new_proc->replace_all = replace_all;
process_syms_a = new_mem;
process_nsyms_a++;
LeaveCriticalSection(&createproc_lock);
return S_OK;
}
void createprocess_hook_init() {
if (did_init) {
return;
}
did_init = true;
hook_table_apply(
NULL,
"kernel32.dll",
win32_hooks,
_countof(win32_hooks));
InitializeCriticalSection(&createproc_lock);
dprintf("CreateProcess: Init\n");
}
static BOOL WINAPI my_CreateProcessA(
LPCSTR lpApplicationName,
LPSTR lpCommandLine,
LPSECURITY_ATTRIBUTES lpProcessAttributes,
LPSECURITY_ATTRIBUTES lpThreadAttributes,
BOOL bInheritHandles,
DWORD dwCreationFlags,
LPVOID lpEnvironment,
LPCSTR lpCurrentDirectory,
LPSTARTUPINFOA lpStartupInfo,
LPPROCESS_INFORMATION lpProcessInformation
)
{
for (int i = 0; i < process_nsyms_a; i++) {
if (strncmp(process_syms_a[i].name, lpCommandLine, strlen(process_syms_a[i].name))) {
continue;
}
dprintf("CreateProcess: Hooking child process %s %s\n", lpApplicationName, lpCommandLine);
char new_cmd[MAX_PATH] = {0};
strcat_s(new_cmd, MAX_PATH, process_syms_a[i].head);
if (!process_syms_a[i].replace_all) {
strcat_s(new_cmd, MAX_PATH, lpCommandLine);
}
if (process_syms_a[i].tail != NULL) {
strcat_s(new_cmd, MAX_PATH, process_syms_a[i].tail);
}
dprintf("CreateProcess: Replaced CreateProcessA %s\n", new_cmd);
return next_CreateProcessA(
lpApplicationName,
new_cmd,
lpProcessAttributes,
lpThreadAttributes,
bInheritHandles,
dwCreationFlags,
lpEnvironment,
lpCurrentDirectory,
lpStartupInfo,
lpProcessInformation
);
}
return next_CreateProcessA(
lpApplicationName,
lpCommandLine,
lpProcessAttributes,
lpThreadAttributes,
bInheritHandles,
dwCreationFlags,
lpEnvironment,
lpCurrentDirectory,
lpStartupInfo,
lpProcessInformation
);
}
BOOL my_CreateProcessW(
LPCWSTR lpApplicationName,
LPWSTR lpCommandLine,
LPSECURITY_ATTRIBUTES lpProcessAttributes,
LPSECURITY_ATTRIBUTES lpThreadAttributes,
BOOL bInheritHandles,
DWORD dwCreationFlags,
LPVOID lpEnvironment,
LPCWSTR lpCurrentDirectory,
LPSTARTUPINFOW lpStartupInfo,
LPPROCESS_INFORMATION lpProcessInformation)
{
return next_CreateProcessW(
lpApplicationName,
lpCommandLine,
lpProcessAttributes,
lpThreadAttributes,
bInheritHandles,
dwCreationFlags,
lpEnvironment,
lpCurrentDirectory,
lpStartupInfo,
lpProcessInformation
);
}
+21
View File
@@ -0,0 +1,21 @@
#pragma once
#include <windows.h>
#include <stdbool.h>
HRESULT createprocess_push_hook_w(const wchar_t *name, const wchar_t *head, const wchar_t *tail, bool replace_all);
HRESULT createprocess_push_hook_a(const char *name, const char *head, const char *tail, bool replace_all);
struct process_hook_sym_w {
const wchar_t *name;
const wchar_t *head;
const wchar_t *tail;
bool replace_all;
};
struct process_hook_sym_a {
const char *name;
const char *head;
const char *tail;
bool replace_all;
};
+80
View File
@@ -0,0 +1,80 @@
#include <windows.h>
#include <assert.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include "hook/table.h"
#include "util/dprintf.h"
static HCURSOR my_SetCursor(HCURSOR hCursor);
static HCURSOR (*next_SetCursor)(HCURSOR hCursor);
static BOOL my_SetCursorPos(int x, int y);
static BOOL my_SetPhysicalCursorPos(int x, int y);
static int my_ShowCursor(BOOL bShow);
static int cursor_track = -1; // If no mouse is connected, this starts as -1
static const struct hook_symbol cursor_syms[] = {
{
.name = "SetCursor",
.patch = my_SetCursor,
.link = (void **) &next_SetCursor
},/*{
.name = "SetCursorPos",
.patch = my_SetCursorPos,
},*/ {
.name = "SetPhysicalCursorPos",
.patch = my_SetPhysicalCursorPos
}, /*{
.name = "ShowCursor",
.patch = my_ShowCursor
}*/
};
void cursor_hook_init()
{
hook_table_apply(
NULL,
"user32.dll",
cursor_syms,
_countof(cursor_syms));
dprintf("Cursor: Init\n");
}
static BOOL my_SetCursorPos(int x, int y)
{
// dprintf("my_SetCursorPos Hit! x %d y %d\n", x, y);
return true;
}
static BOOL my_SetPhysicalCursorPos(int x, int y)
{
dprintf("my_SetPhysicalCursorPos Hit! x %d y %d\n", x, y);
return true;
}
static int my_ShowCursor(BOOL bShow)
{
dprintf("my_ShowCursor Hit!\n");
if (bShow) {
cursor_track++;
} else {
cursor_track--;
}
return cursor_track;
}
static HCURSOR my_SetCursor(HCURSOR hCursor)
{
dprintf("my_SetCursor Hit!\n");
HCURSOR fake_cursor;
if ( hCursor )
return next_SetCursor(hCursor);
fake_cursor = LoadCursorA(0, (LPCSTR)0x7F00);
next_SetCursor(fake_cursor);
return 0;
}
+3
View File
@@ -0,0 +1,3 @@
#pragma once
void cursor_hook_init();
+351
View File
@@ -0,0 +1,351 @@
/* This is general enough to break out into capnhook eventually.
Don't introduce util/ dependencies here. */
#include <windows.h>
#include <assert.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdlib.h>
#include "hook/table.h"
#include "hooklib/dll.h"
struct dll_hook_reg {
const wchar_t *name;
HMODULE redir_mod;
};
/* Helper functions */
static void dll_hook_init(void);
static HMODULE dll_hook_search_dll(const wchar_t *name);
/* Hook functions */
static BOOL WINAPI hook_FreeLibrary(HMODULE mod);
static HMODULE WINAPI hook_GetModuleHandleA(const char *name);
static HMODULE WINAPI hook_GetModuleHandleW(const wchar_t *name);
static HMODULE WINAPI hook_LoadLibraryA(const char *name);
static HMODULE WINAPI hook_LoadLibraryW(const wchar_t *name);
static HMODULE WINAPI hook_LoadLibraryExA(const char *name, HANDLE file, DWORD flags);
static HMODULE WINAPI hook_LoadLibraryExW(const wchar_t *name, HANDLE file, DWORD flags);
/* Link pointers */
static BOOL (WINAPI *next_FreeLibrary)(HMODULE mod);
static HMODULE (WINAPI *next_GetModuleHandleA)(const char *name);
static HMODULE (WINAPI *next_GetModuleHandleW)(const wchar_t *name);
static HMODULE (WINAPI *next_LoadLibraryA)(const char *name);
static HMODULE (WINAPI *next_LoadLibraryW)(const wchar_t *name);
static HMODULE (WINAPI *next_LoadLibraryExA)(const char *name, HANDLE file, DWORD flags);
static HMODULE (WINAPI *next_LoadLibraryExW)(const wchar_t *name, HANDLE file, DWORD flags);
static const struct hook_symbol dll_loader_syms[] = {
{
.name = "FreeLibrary",
.patch = hook_FreeLibrary,
.link = (void **) &next_FreeLibrary,
}, {
.name = "GetModuleHandleA",
.patch = hook_GetModuleHandleA,
.link = (void **) &next_GetModuleHandleA,
}, {
.name = "GetModuleHandleW",
.patch = hook_GetModuleHandleW,
.link = (void **) &next_GetModuleHandleW,
}, {
.name = "LoadLibraryA",
.patch = hook_LoadLibraryA,
.link = (void **) &next_LoadLibraryA,
}, {
.name = "LoadLibraryW",
.patch = hook_LoadLibraryW,
.link = (void **) &next_LoadLibraryW,
}, {
.name = "LoadLibraryExA",
.patch = hook_LoadLibraryExA,
.link = (void **) &next_LoadLibraryExA,
}, {
.name = "LoadLibraryExW",
.patch = hook_LoadLibraryExW,
.link = (void **) &next_LoadLibraryExW,
}
};
static bool dll_hook_initted;
static CRITICAL_SECTION dll_hook_lock;
static struct dll_hook_reg *dll_hook_list;
static size_t dll_hook_count;
HRESULT dll_hook_push(
HMODULE redir_mod,
const wchar_t *name)
{
struct dll_hook_reg *new_item;
struct dll_hook_reg *new_mem;
HRESULT hr;
assert(name != NULL);
dll_hook_init();
EnterCriticalSection(&dll_hook_lock);
new_mem = realloc(
dll_hook_list,
(dll_hook_count + 1) * sizeof(struct dll_hook_reg));
if (new_mem == NULL) {
hr = E_OUTOFMEMORY;
goto end;
}
new_item = &new_mem[dll_hook_count];
new_item->name = name;
new_item->redir_mod = redir_mod;
dll_hook_list = new_mem;
dll_hook_count++;
hr = S_OK;
end:
LeaveCriticalSection(&dll_hook_lock);
return hr;
}
static void dll_hook_init(void)
{
HMODULE kernel32;
/* Init is not thread safe, because API hooking is not thread safe. */
if (dll_hook_initted) {
return;
}
dll_hook_initted = true;
InitializeCriticalSection(&dll_hook_lock);
/* Protect against the (probably impossible) scenario where nothing in the
process imports LoadLibraryW but something imports LoadLibraryA. Also
do the same with LoadLibraryExW.
We know something imports GetModuleHandleW because we do, right here.
(we're about to hook these APIs of course, so we have to set this up
before the hooks go in) */
kernel32 = GetModuleHandleW(L"kernel32.dll");
next_LoadLibraryW = (void *) GetProcAddress(kernel32, "LoadLibraryW");
next_LoadLibraryExW = (void *) GetProcAddress(kernel32, "LoadLibraryExW");
/* Now we can apply the hook table */
hook_table_apply(
NULL,
"kernel32.dll",
dll_loader_syms,
_countof(dll_loader_syms));
}
static HMODULE dll_hook_search_dll(const wchar_t *name)
{
HMODULE result;
size_t i;
result = NULL;
EnterCriticalSection(&dll_hook_lock);
for (i = 0 ; i < dll_hook_count ; i++) {
if (wcsicmp(name, dll_hook_list[i].name) == 0) {
result = dll_hook_list[i].redir_mod;
break;
}
}
LeaveCriticalSection(&dll_hook_lock);
return result;
}
static BOOL WINAPI hook_FreeLibrary(HMODULE mod)
{
bool match;
size_t i;
match = false;
EnterCriticalSection(&dll_hook_lock);
for (i = 0 ; i < dll_hook_count ; i++) {
if (mod == dll_hook_list[i].redir_mod) {
match = true;
break;
}
}
LeaveCriticalSection(&dll_hook_lock);
if (match) {
/* Block attempts to unload redirected modules, since this could cause
a hook DLL to unexpectedly vanish and crash the whole application.
Reference counting might be another solution, although it is
possible that a buggy application might cause a hook DLL unload in
that case. */
SetLastError(ERROR_SUCCESS);
return TRUE;
}
return next_FreeLibrary(mod);
}
static HMODULE WINAPI hook_GetModuleHandleA(const char *name)
{
HMODULE result;
wchar_t *name_w;
size_t name_c;
if (name == NULL) {
return next_GetModuleHandleA(NULL);
}
mbstowcs_s(&name_c, NULL, 0, name, 0);
name_w = malloc(name_c * sizeof(wchar_t));
if (name_w == NULL) {
SetLastError(ERROR_OUTOFMEMORY);
return NULL;
}
mbstowcs_s(NULL, name_w, name_c, name, name_c - 1);
result = hook_GetModuleHandleW(name_w);
free(name_w);
return result;
}
static HMODULE WINAPI hook_GetModuleHandleW(const wchar_t *name)
{
HMODULE result;
if (name == NULL) {
return next_GetModuleHandleW(NULL);
}
result = dll_hook_search_dll(name);
if (result != NULL) {
SetLastError(ERROR_SUCCESS);
} else {
result = next_GetModuleHandleW(name);
}
return result;
}
static HMODULE WINAPI hook_LoadLibraryA(const char *name)
{
HMODULE result;
wchar_t *name_w;
size_t name_c;
if (name == NULL) {
SetLastError(ERROR_INVALID_PARAMETER);
return NULL;
}
mbstowcs_s(&name_c, NULL, 0, name, 0);
name_w = malloc(name_c * sizeof(wchar_t));
if (name_w == NULL) {
SetLastError(ERROR_OUTOFMEMORY);
return NULL;
}
mbstowcs_s(NULL, name_w, name_c, name, name_c - 1);
result = hook_LoadLibraryW(name_w);
free(name_w);
return result;
}
static HMODULE WINAPI hook_LoadLibraryW(const wchar_t *name)
{
HMODULE result;
if (name == NULL) {
SetLastError(ERROR_INVALID_PARAMETER);
return NULL;
}
result = dll_hook_search_dll(name);
if (result != NULL) {
SetLastError(ERROR_SUCCESS);
} else {
result = next_LoadLibraryW(name);
}
return result;
}
static HMODULE WINAPI hook_LoadLibraryExA(const char *name, HANDLE file, DWORD flags)
{
HMODULE result;
wchar_t *name_w;
size_t name_c;
if (name == NULL) {
SetLastError(ERROR_INVALID_PARAMETER);
return NULL;
}
mbstowcs_s(&name_c, NULL, 0, name, 0);
name_w = malloc(name_c * sizeof(wchar_t));
if (name_w == NULL) {
SetLastError(ERROR_OUTOFMEMORY);
return NULL;
}
mbstowcs_s(NULL, name_w, name_c, name, name_c - 1);
result = hook_LoadLibraryExW(name_w, file, flags);
free(name_w);
return result;
}
static HMODULE WINAPI hook_LoadLibraryExW(const wchar_t *name, HANDLE file, DWORD flags)
{
HMODULE result;
if (name == NULL) {
SetLastError(ERROR_INVALID_PARAMETER);
return NULL;
}
result = dll_hook_search_dll(name);
if (result != NULL) {
SetLastError(ERROR_SUCCESS);
} else {
result = next_LoadLibraryExW(name, file, flags);
}
return result;
}
+10
View File
@@ -0,0 +1,10 @@
#pragma once
#include <windows.h>
#include <stddef.h>
#include <stdint.h>
HRESULT dll_hook_push(
HMODULE redir_mod,
const wchar_t *name);
+783
View File
@@ -0,0 +1,783 @@
/* Might push this to capnhook, don't add any util dependencies. */
#include <windows.h>
#include <windns.h>
#include <ws2tcpip.h>
#include <winhttp.h>
#include <assert.h>
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "hook/hr.h"
#include "hook/table.h"
#include "util/dprintf.h"
#include "util/get_function_ordinal.h"
#include "hooklib/dns.h"
/* Latest w32headers does not include DnsQueryEx, so we'll have to "polyfill"
its associated data types here for the time being.
Results and cancel handle are passed through, so we'll just use void
pointers for those args. So are most of the fields in this structure, for
that matter. */
typedef struct POLYFILL_DNS_QUERY_REQUEST {
ULONG Version;
PCWSTR QueryName;
WORD QueryType;
ULONG64 QueryOptions;
void* pDnsServerList;
ULONG InterfaceIndex;
void* pQueryCompletionCallback;
PVOID pQueryContext;
} POLYFILL_DNS_QUERY_REQUEST;
struct dns_hook_entry {
wchar_t *from;
wchar_t *to;
};
/* Hook funcs */
static DNS_STATUS WINAPI hook_DnsQuery_A(
const char *pszName,
WORD wType,
DWORD Options,
void *pExtra,
DNS_RECORD **ppQueryResults,
void *pReserved);
static DNS_STATUS WINAPI hook_DnsQuery_W(
const wchar_t *pszName,
WORD wType,
DWORD Options,
void *pExtra,
DNS_RECORD **ppQueryResults,
void *pReserved);
static DNS_STATUS WINAPI hook_DnsQueryEx(
POLYFILL_DNS_QUERY_REQUEST *pRequest,
void *pQueryResults,
void *pCancelHandle);
static int WSAAPI hook_getaddrinfo(
const char *pNodeName,
const char *pServiceName,
const ADDRINFOA *pHints,
ADDRINFOA **ppResult);
static HINTERNET WINAPI hook_WinHttpConnect(
HINTERNET hSession,
const wchar_t *pwszServerName,
INTERNET_PORT nServerPort,
DWORD dwReserved);
static bool WINAPI hook_WinHttpCrackUrl(
const wchar_t *pwszUrl,
DWORD dwUrlLength,
DWORD dwFlags,
LPURL_COMPONENTS lpUrlComponents);
static DWORD WINAPI hook_send(
SOCKET s,
const char* buf,
int len,
int flags);
static int WINAPI hook_connect(
SOCKET s,
const struct sockaddr *name,
int namelen);
/* Link pointers */
static DNS_STATUS (WINAPI *next_DnsQuery_A)(
const char *pszName,
WORD wType,
DWORD Options,
void *pExtra,
DNS_RECORD **ppQueryResults,
void *pReserved);
static DNS_STATUS (WINAPI *next_DnsQuery_W)(
const wchar_t *pszName,
WORD wType,
DWORD Options,
void *pExtra,
DNS_RECORD **ppQueryResults,
void *pReserved);
static DNS_STATUS (WINAPI *next_DnsQueryEx)(
POLYFILL_DNS_QUERY_REQUEST *pRequest,
void *pQueryResults,
void *pCancelHandle);
static int (WSAAPI *next_getaddrinfo)(
const char *pNodeName,
const char *pServiceName,
const ADDRINFOA *pHints,
ADDRINFOA **ppResult);
static HINTERNET (WINAPI *next_WinHttpConnect)(
HINTERNET hSession,
const wchar_t *pwszServerName,
INTERNET_PORT nServerPort,
DWORD dwReserved);
static bool (WINAPI *next_WinHttpCrackUrl)(
const wchar_t *pwszUrl,
DWORD dwUrlLength,
DWORD dwFlags,
LPURL_COMPONENTS lpUrlComponents);
static DWORD (WINAPI *next_send)(
SOCKET s,
const char* buf,
int len,
int flags);
static int (__stdcall *next_connect)(
SOCKET s,
const struct sockaddr *name,
int namelen);
static const struct hook_symbol dns_hook_syms_dnsapi[] = {
{
.name = "DnsQuery_A",
.patch = hook_DnsQuery_A,
.link = (void **) &next_DnsQuery_A,
}, {
.name = "DnsQuery_W",
.patch = hook_DnsQuery_W,
.link = (void **) &next_DnsQuery_W,
}, {
.name = "DnsQueryEx",
.patch = hook_DnsQueryEx,
.link = (void **) &next_DnsQueryEx,
}
};
static const struct hook_symbol dns_hook_syms_ws2[] = {
{
.name = "getaddrinfo",
.ordinal = 176,
.patch = hook_getaddrinfo,
.link = (void **) &next_getaddrinfo,
},
};
static const struct hook_symbol dns_hook_syms_winhttp[] = {
{
.name = "WinHttpConnect",
.patch = hook_WinHttpConnect,
.link = (void **) &next_WinHttpConnect,
}, {
.name = "WinHttpCrackUrl",
.patch = hook_WinHttpCrackUrl,
.link = (void **) &next_WinHttpCrackUrl,
}
};
static struct hook_symbol http_hook_syms_ws2[] = {
{
.name = "send",
.patch = hook_send,
.link = (void **) &next_send
},
};
static struct hook_symbol port_hook_syms_ws2[] = {
{
.name = "connect",
.patch = hook_connect,
.link = (void **) &next_connect
},
};
static bool dns_hook_initted;
static CRITICAL_SECTION dns_hook_lock;
static struct dns_hook_entry *dns_hook_entries;
static size_t dns_hook_nentries;
static char received_title_url[255];
static unsigned short startup_port;
static unsigned short billing_port;
static unsigned short aimedb_port;
static void dns_hook_init(void)
{
if (dns_hook_initted) {
return;
}
dns_hook_initted = true;
InitializeCriticalSection(&dns_hook_lock);
dns_hook_apply_hooks(NULL);
}
void dns_hook_apply_hooks(HMODULE mod){
hook_table_apply(
mod,
"dnsapi.dll",
dns_hook_syms_dnsapi,
_countof(dns_hook_syms_dnsapi));
hook_table_apply(
mod,
"ws2_32.dll",
dns_hook_syms_ws2,
_countof(dns_hook_syms_ws2));
hook_table_apply(
mod,
"winhttp.dll",
dns_hook_syms_winhttp,
_countof(dns_hook_syms_winhttp));
}
void http_hook_init(){
for (size_t i = 0; i < _countof(http_hook_syms_ws2); ++i) {
http_hook_syms_ws2[i].ordinal = get_function_ordinal("ws2_32.dll", http_hook_syms_ws2[i].name);
}
hook_table_apply(
NULL,
"ws2_32.dll",
http_hook_syms_ws2,
_countof(http_hook_syms_ws2));
}
void port_hook_init(unsigned short _startup_port, unsigned short _billing_port, unsigned short _aimedb_port){
startup_port = _startup_port;
billing_port = _billing_port;
aimedb_port = _aimedb_port;
for (size_t i = 0; i < _countof(port_hook_syms_ws2); ++i) {
port_hook_syms_ws2[i].ordinal = get_function_ordinal("ws2_32.dll", port_hook_syms_ws2[i].name);
}
hook_table_apply(
NULL,
"ws2_32.dll",
port_hook_syms_ws2,
_countof(port_hook_syms_ws2));
}
// This function match domain and subdomains like *.naominet.jp.
bool match_domain(const wchar_t* target, const wchar_t* pattern) {
if (_wcsicmp(pattern, target) == 0) {
return true;
}
int pattern_ptr_index = 0;
int target_ptr_index = 0;
while (pattern[pattern_ptr_index] != '\0' && target[target_ptr_index] != '\0') {
if (pattern[pattern_ptr_index] == '*') {
pattern_ptr_index++; // Check next character for wildcard match.
while (pattern[pattern_ptr_index] != target[target_ptr_index]) {
target_ptr_index++;
if (target[target_ptr_index] == '\0') return false;
}
}
else if (pattern[pattern_ptr_index] != target[target_ptr_index]) {
return false;
}
else {
pattern_ptr_index++;
target_ptr_index++;
}
}
return pattern[pattern_ptr_index] == '\0' && target[target_ptr_index] == '\0';
}
HRESULT dns_hook_push(const wchar_t *from_src, const wchar_t *to_src)
{
HRESULT hr;
struct dns_hook_entry *newmem;
struct dns_hook_entry *newitem;
wchar_t *from;
wchar_t *to;
assert(from_src != NULL);
to = NULL;
from = NULL;
dns_hook_init();
EnterCriticalSection(&dns_hook_lock);
from = _wcsdup(from_src);
if (from == NULL) {
hr = E_OUTOFMEMORY;
goto end;
}
if (to_src != NULL) {
to = _wcsdup(to_src);
if (to == NULL) {
hr = E_OUTOFMEMORY;
goto end;
}
}
newmem = realloc(
dns_hook_entries,
(dns_hook_nentries + 1) * sizeof(struct dns_hook_entry));
if (newmem == NULL) {
hr = E_OUTOFMEMORY;
goto end;
}
dns_hook_entries = newmem;
newitem = &newmem[dns_hook_nentries++];
newitem->from = from;
newitem->to = to;
from = NULL;
to = NULL;
hr = S_OK;
end:
LeaveCriticalSection(&dns_hook_lock);
free(to);
free(from);
return hr;
}
static DNS_STATUS WINAPI hook_DnsQuery_A(
const char *pszName,
WORD wType,
DWORD Options,
void *pExtra,
DNS_RECORD **ppQueryResults,
void *pReserved)
{
const struct dns_hook_entry *pos;
size_t i;
size_t wstr_c;
wchar_t *wstr;
size_t str_c;
char *str;
DNS_STATUS code;
HRESULT hr;
wstr = NULL;
str = NULL;
if (pszName == NULL) {
hr = HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
goto end;
}
mbstowcs_s(&wstr_c, NULL, 0, pszName, 0);
wstr = malloc(wstr_c * sizeof(wchar_t));
if (wstr == NULL) {
hr = HRESULT_FROM_WIN32(ERROR_OUTOFMEMORY);
goto end;
}
mbstowcs_s(NULL, wstr, wstr_c, pszName, wstr_c - 1);
EnterCriticalSection(&dns_hook_lock);
for (i = 0 ; i < dns_hook_nentries ; i++) {
pos = &dns_hook_entries[i];
if (match_domain(wstr, pos->from)) {
if (pos->to == NULL) {
LeaveCriticalSection(&dns_hook_lock);
hr = HRESULT_FROM_WIN32(DNS_ERROR_RCODE_NAME_ERROR);
goto end;
}
wcstombs_s(&str_c, NULL, 0, pos->to, 0);
str = malloc(str_c * sizeof(char));
if (str == NULL) {
LeaveCriticalSection(&dns_hook_lock);
hr = HRESULT_FROM_WIN32(ERROR_OUTOFMEMORY);
goto end;
}
wcstombs_s(NULL, str, str_c, pos->to, str_c - 1);
pszName = str;
break;
}
}
LeaveCriticalSection(&dns_hook_lock);
code = next_DnsQuery_A(
pszName,
wType,
Options,
pExtra,
ppQueryResults,
pReserved);
hr = HRESULT_FROM_WIN32(code);
end:
free(str);
free(wstr);
return hr_to_win32_error(hr);
}
static DNS_STATUS WINAPI hook_DnsQuery_W(
const wchar_t *pszName,
WORD wType,
DWORD Options,
void *pExtra,
DNS_RECORD **ppQueryResults,
void *pReserved)
{
const struct dns_hook_entry *pos;
size_t i;
if (pszName == NULL) {
return ERROR_INVALID_PARAMETER;
}
EnterCriticalSection(&dns_hook_lock);
for (i = 0 ; i < dns_hook_nentries ; i++) {
pos = &dns_hook_entries[i];
if (match_domain(pszName, pos->from)) {
if (pos->to == NULL) {
LeaveCriticalSection(&dns_hook_lock);
return HRESULT_FROM_WIN32(DNS_ERROR_RCODE_NAME_ERROR);
}
pszName = pos->to;
break;
}
}
LeaveCriticalSection(&dns_hook_lock);
return next_DnsQuery_W(
pszName,
wType,
Options,
pExtra,
ppQueryResults,
pReserved);
}
static DNS_STATUS WINAPI hook_DnsQueryEx(
POLYFILL_DNS_QUERY_REQUEST *pRequest,
void *pQueryResults,
void *pCancelHandle)
{
const wchar_t *orig;
const struct dns_hook_entry *pos;
DNS_STATUS code;
size_t i;
if (pRequest == NULL) {
return ERROR_INVALID_PARAMETER;
}
orig = pRequest->QueryName;
EnterCriticalSection(&dns_hook_lock);
for (i = 0 ; i < dns_hook_nentries ; i++) {
pos = &dns_hook_entries[i];
if (match_domain(pRequest->QueryName, pos->from)) {
if (pos->to == NULL) {
LeaveCriticalSection(&dns_hook_lock);
return HRESULT_FROM_WIN32(DNS_ERROR_RCODE_NAME_ERROR);
}
pRequest->QueryName = pos->to;
break;
}
}
LeaveCriticalSection(&dns_hook_lock);
code = next_DnsQueryEx(pRequest, pQueryResults, pCancelHandle);
/* Caller might not appreciate QueryName changing under its feet. It is
strongly implied by MSDN that a copy of *pRequest is taken by WINAPI,
so we can change it back after the call has been issued with no ill
effect... we hope.
Hopefully the completion callback is issued from an APC or something
(or otherwise happens after this returns) or we're in trouble. */
pRequest->QueryName = orig;
return code;
}
static int WSAAPI hook_getaddrinfo(
const char *pNodeName,
const char *pServiceName,
const ADDRINFOA *pHints,
ADDRINFOA **ppResult)
{
const struct dns_hook_entry *pos;
char *str;
size_t str_c;
wchar_t *wstr;
size_t wstr_c;
int result;
size_t i;
str = NULL;
wstr = NULL;
if (pNodeName == NULL) {
result = WSA_INVALID_PARAMETER;
goto end;
}
mbstowcs_s(&wstr_c, NULL, 0, pNodeName, 0);
wstr = malloc(wstr_c * sizeof(wchar_t));
if (wstr == NULL) {
result = WSA_NOT_ENOUGH_MEMORY;
goto end;
}
mbstowcs_s(NULL, wstr, wstr_c, pNodeName, wstr_c - 1);
EnterCriticalSection(&dns_hook_lock);
for (i = 0 ; i < dns_hook_nentries ; i++) {
pos = &dns_hook_entries[i];
if (match_domain(wstr, pos->from)) {
if (pos->to == NULL) {
LeaveCriticalSection(&dns_hook_lock);
result = EAI_NONAME;
goto end;
}
wcstombs_s(&str_c, NULL, 0, pos->to, 0);
str = malloc(str_c * sizeof(char));
if (str == NULL) {
LeaveCriticalSection(&dns_hook_lock);
result = WSA_NOT_ENOUGH_MEMORY;
goto end;
}
wcstombs_s(NULL, str, str_c, pos->to, str_c - 1);
pNodeName = str;
break;
}
}
LeaveCriticalSection(&dns_hook_lock);
result = next_getaddrinfo(pNodeName, pServiceName, pHints, ppResult);
end:
free(wstr);
free(str);
return result;
}
static HINTERNET WINAPI hook_WinHttpConnect(
HINTERNET hSession,
const wchar_t *pwszServerName,
INTERNET_PORT nServerPort,
DWORD dwReserved)
{
const struct dns_hook_entry *pos;
size_t i;
if (pwszServerName == NULL) {
return NULL;
}
EnterCriticalSection(&dns_hook_lock);
for (i = 0 ; i < dns_hook_nentries ; i++) {
pos = &dns_hook_entries[i];
if (match_domain(pwszServerName, pos->from)) {
if (pos->to == NULL) {
LeaveCriticalSection(&dns_hook_lock);
return NULL;
}
pwszServerName = pos->to;
break;
}
}
LeaveCriticalSection(&dns_hook_lock);
return next_WinHttpConnect(hSession, pwszServerName, nServerPort, dwReserved);
}
// Hook to replace CXB title url
static bool WINAPI hook_WinHttpCrackUrl(
const wchar_t *pwszUrl,
DWORD dwUrlLength,
DWORD dwFlags,
LPURL_COMPONENTS lpUrlComponents)
{
const struct dns_hook_entry *pos;
size_t i;
EnterCriticalSection(&dns_hook_lock);
for (i = 0 ; i < dns_hook_nentries ; i++) {
pos = &dns_hook_entries[i];
if (match_domain(pwszUrl, pos->from)) {
wchar_t* toAddr = pos->to;
wchar_t titleBuffer[255];
if (wcscmp(toAddr, L"title") == 0) {
size_t wstr_c;
mbstowcs_s(&wstr_c, titleBuffer, 255, received_title_url, strlen(received_title_url));
toAddr = titleBuffer;
}
bool result = next_WinHttpCrackUrl(
toAddr,
wcslen(toAddr),
dwFlags,
lpUrlComponents
);
LeaveCriticalSection(&dns_hook_lock);
return result;
}
}
LeaveCriticalSection(&dns_hook_lock);
return next_WinHttpCrackUrl(
pwszUrl,
dwUrlLength,
dwFlags,
lpUrlComponents
);
}
int WINAPI hook_connect(SOCKET s, const struct sockaddr *name, int namelen) {
const struct sockaddr_in *n;
struct sockaddr_in new_name;
unsigned ip;
unsigned short port, new_port;
EnterCriticalSection(&dns_hook_lock);
n = (const struct sockaddr_in *)name;
ip = n->sin_addr.S_un.S_addr;
if (WSANtohs(s, n->sin_port, &port)) return SOCKET_ERROR;
if (port == 80 && startup_port) {
new_port = startup_port;
} else if (port == 8443 && billing_port) {
new_port = billing_port;
} else if (port == 22345 && aimedb_port) {
new_port = aimedb_port;
} else { // No match
dprintf("TCP Connect: %u.%u.%u.%u:%hu\n", ip & 0xff, (ip >> 8) & 0xff, (ip >> 16) & 0xff, (ip >> 24) & 0xff, port);
LeaveCriticalSection(&dns_hook_lock);
return next_connect(
s,
name,
namelen
);
}
// matched
new_name = *n;
if (WSAHtons(s, new_port, &new_name.sin_port)) return SOCKET_ERROR;
dprintf("TCP Connect: %u.%u.%u.%u:%hu, mapped to port %hu\n", ip & 0xff, (ip >> 8) & 0xff, (ip >> 16) & 0xff, (ip >> 24) & 0xff, port, new_port);
LeaveCriticalSection(&dns_hook_lock);
return next_connect(
s,
(const struct sockaddr *)&new_name,
sizeof(new_name)
);
}
DWORD WINAPI hook_send(SOCKET s, const char* buf, int len, int flags) {
if (strstr(buf, "HTTP/") != NULL) {
char *new_buf = malloc(len + 1);
if (new_buf == NULL) return SOCKET_ERROR;
memcpy(new_buf, buf, len);
new_buf[len] = '\0';
char *host_start = strstr(new_buf, "Host: ");
if (host_start != NULL) {
char *host_end = strstr(host_start, "\r\n");
if (host_end != NULL) {
host_end += 2;
int host_len = host_end - host_start;
char *host_value_start = host_start + 6;
char *host_value_end = strstr(host_value_start, "\r\n");
if (host_value_end != NULL) {
int value_len = host_value_end - host_value_start;
char* host_value = (char*)malloc(value_len + 1);
strncpy(host_value, host_value_start, value_len);
host_value[value_len] = '\0';
for (struct dns_hook_entry *entry = dns_hook_entries; entry && entry->from; entry++) {
char from_value[256];
wcstombs(from_value, entry->from, sizeof(from_value));
if (strcmp(host_value, from_value) == 0) {
char to_value[256];
wcstombs(to_value, entry->to, sizeof(to_value));
snprintf(host_start, len - (host_start - new_buf), "Host: %s\r\n", to_value);
break;
}
}
free(host_value);
}
len = (int)strlen(new_buf);
}
}
DWORD result = next_send(s, new_buf, len, flags);
free(new_buf);
return result;
}
return next_send(s, buf, len, flags);
}
+11
View File
@@ -0,0 +1,11 @@
#pragma once
#include <windows.h>
#include <stddef.h>
void http_hook_init();
void port_hook_init(unsigned short _startup_port, unsigned short _billing_port, unsigned short _aimedb_port);
// if to_src is NULL, all lookups for from_src will fail
HRESULT dns_hook_push(const wchar_t *from_src, const wchar_t *to_src);
void dns_hook_apply_hooks(HMODULE mod);
+82
View File
@@ -0,0 +1,82 @@
#include <windows.h>
#include <assert.h>
#include <stdbool.h>
#include <stdlib.h>
#include "hook/com-proxy.h"
#include "hook/table.h"
#include "hooklib/config.h"
#include "hooklib/dll.h"
#include "hooklib/dvd.h"
#include "util/dprintf.h"
/* API hooks */
static DWORD WINAPI hook_QueryDosDeviceW(
const wchar_t *lpDeviceName,
wchar_t *lpTargetPath,
DWORD ucchMax);
/* Link pointers */
static DWORD (WINAPI *next_QueryDosDeviceW)(
const wchar_t *lpDeviceName,
wchar_t *lpTargetPath,
DWORD ucchMax);
static bool dvd_hook_initted;
static struct dvd_config dvd_config;
static const struct hook_symbol dvd_hooks[] = {
{
.name = "QueryDosDeviceW",
.patch = hook_QueryDosDeviceW,
.link = (void **) &next_QueryDosDeviceW
},
};
void dvd_hook_init(const struct dvd_config *cfg, HINSTANCE self)
{
assert(cfg != NULL);
if (!cfg->enable) {
return;
}
if (dvd_hook_initted) {
return;
}
dvd_hook_initted = true;
memcpy(&dvd_config, cfg, sizeof(*cfg));
hook_table_apply(NULL, "kernel32.dll", dvd_hooks, _countof(dvd_hooks));
dprintf("DVD: hook enabled.\n");
}
DWORD WINAPI hook_QueryDosDeviceW(
const wchar_t *lpDeviceName,
wchar_t *lpTargetPath,
DWORD ucchMax)
{
DWORD ok;
wchar_t *p_dest;
wchar_t *dvd_string = L"CdRom";
ok = next_QueryDosDeviceW(
lpDeviceName,
lpTargetPath,
ucchMax);
p_dest = wcsstr (lpTargetPath, dvd_string);
if ( p_dest != NULL ) {
dprintf("DVD: Hiding DVD drive.\n");
return 0;
}
return ok;
}
+14
View File
@@ -0,0 +1,14 @@
#pragma once
#include <windows.h>
#include <stdbool.h>
struct dvd_config {
bool enable;
};
/* Init is not thread safe because API hook init is not thread safe blah
blah blah you know the drill by now. */
void dvd_hook_init(const struct dvd_config *cfg, HINSTANCE self);
+218
View File
@@ -0,0 +1,218 @@
#include <windows.h>
#include <assert.h>
#include <stdbool.h>
#include <stddef.h>
#include <string.h>
#include "hook/iobuf.h"
#include "hook/iohook.h"
#include "hooklib/fdshark.h"
#include "util/dprintf.h"
#include "util/dump.h"
static const wchar_t *fdshark_path;
static HANDLE fdshark_target_fd;
static int fdshark_flags;
static HRESULT fdshark_handle_irp(struct irp *irp);
static HRESULT fdshark_handle_open(struct irp *irp);
static HRESULT fdshark_handle_close(struct irp *irp);
static HRESULT fdshark_handle_read(struct irp *irp);
static HRESULT fdshark_handle_write(struct irp *irp);
static HRESULT fdshark_handle_ioctl(struct irp *irp);
static bool fdshark_force_sync(struct irp *irp, HRESULT hr);
HRESULT fdshark_hook_init(const wchar_t *path, int flags)
{
assert(path != NULL);
assert(!(flags & ~FDSHARK_ALL_FLAGS_));
fdshark_path = path;
fdshark_flags = flags;
return iohook_push_handler(fdshark_handle_irp);
}
static HRESULT fdshark_handle_irp(struct irp *irp)
{
assert(irp != NULL);
if (irp->op != IRP_OP_OPEN && irp->fd != fdshark_target_fd) {
return iohook_invoke_next(irp);
}
switch (irp->op) {
case IRP_OP_OPEN: return fdshark_handle_open(irp);
case IRP_OP_CLOSE: return fdshark_handle_close(irp);
case IRP_OP_READ: return fdshark_handle_read(irp);
case IRP_OP_WRITE: return fdshark_handle_write(irp);
case IRP_OP_IOCTL: return fdshark_handle_ioctl(irp);
default: return iohook_invoke_next(irp);
}
}
static HRESULT fdshark_handle_open(struct irp *irp)
{
HRESULT hr;
if (_wcsicmp(irp->open_filename, fdshark_path) != 0) {
return iohook_invoke_next(irp);
}
hr = iohook_invoke_next(irp);
if (FAILED(hr)) {
return hr;
}
dprintf("FdShark: Opened %S\n", fdshark_path);
fdshark_target_fd = irp->fd;
return hr;
}
static HRESULT fdshark_handle_close(struct irp *irp)
{
dprintf("FdShark: Closed %S\n", fdshark_path);
fdshark_target_fd = NULL;
return iohook_invoke_next(irp);
}
static HRESULT fdshark_handle_read(struct irp *irp)
{
HRESULT hr;
if (!(fdshark_flags & FDSHARK_TRACE_READ)) {
return iohook_invoke_next(irp);
}
dprintf("FdShark: Read %p:%i/%i\n",
irp->read.bytes,
(int) irp->read.pos,
(int) irp->read.nbytes);
hr = iohook_invoke_next(irp);
if (FAILED(hr) && !fdshark_force_sync(irp, hr)) {
dprintf("FdShark: FAILED: %x\n", (int) hr);
} else {
dprintf("FdShark: Read %p:%i/%i OK\n",
irp->read.bytes,
(int) irp->read.pos,
(int) irp->read.nbytes);
dump_iobuf(&irp->read);
}
return S_OK;
}
static HRESULT fdshark_handle_write(struct irp *irp)
{
HRESULT hr;
if (!(fdshark_flags & FDSHARK_TRACE_WRITE)) {
return iohook_invoke_next(irp);
}
dprintf("FdShark: Write %p:%i/%i\n",
irp->write.bytes,
(int) irp->write.pos,
(int) irp->write.nbytes);
dump_const_iobuf(&irp->write);
hr = iohook_invoke_next(irp);
if (FAILED(hr) && !fdshark_force_sync(irp, hr)) {
dprintf("FdShark: FAILED: %x\n", (int) hr);
} else {
dprintf("FdShark: Write %p:%i/%i OK\n",
irp->write.bytes,
(int) irp->write.pos,
(int) irp->write.nbytes);
}
return S_OK;
}
static HRESULT fdshark_handle_ioctl(struct irp *irp)
{
HRESULT hr;
if (!(fdshark_flags & FDSHARK_TRACE_IOCTL)) {
return iohook_invoke_next(irp);
}
dprintf("FdShark: Ioctl %08x w:%p:%i/%i r:%p:%i/%i\n",
irp->ioctl,
irp->write.bytes,
(int) irp->write.pos,
(int) irp->write.nbytes,
irp->read.bytes,
(int) irp->read.pos,
(int) irp->read.nbytes);
dump_const_iobuf(&irp->write);
hr = iohook_invoke_next(irp);
if (FAILED(hr) && !fdshark_force_sync(irp, hr)) {
dprintf("FdShark: FAILED: %x\n", (int) hr);
} else {
dprintf("FdShark: Ioctl %08x w:%p:%i/%i r:%p:%i/%i OK\n",
irp->ioctl,
irp->write.bytes,
(int) irp->write.pos,
(int) irp->write.nbytes,
irp->read.bytes,
(int) irp->read.pos,
(int) irp->read.nbytes);
dump_iobuf(&irp->read);
}
return S_OK;
}
static bool fdshark_force_sync(struct irp *irp, HRESULT hr)
{
DWORD xferred;
BOOL ok;
if (!(fdshark_flags & FDSHARK_FORCE_SYNC)) {
return false;
}
if ( hr != HRESULT_FROM_WIN32(ERROR_IO_PENDING) &&
hr != HRESULT_FROM_NT(STATUS_PENDING)) {
return false;
}
ok = GetOverlappedResult(irp->fd, irp->ovl, &xferred, TRUE);
if (!ok) {
hr = HRESULT_FROM_WIN32(GetLastError());
dprintf("FdShark: Synchronous block failed: %x\n", (int) hr);
return false;
}
switch (irp->op) {
case IRP_OP_READ:
case IRP_OP_IOCTL:
irp->read.pos += xferred;
break;
case IRP_OP_WRITE:
irp->write.pos += xferred;
break;
default:
break;
}
return true;
}
+16
View File
@@ -0,0 +1,16 @@
#pragma once
#include <windows.h>
#include <stdbool.h>
#include <stddef.h>
enum {
FDSHARK_FORCE_SYNC = 0x1,
FDSHARK_TRACE_READ = 0x2,
FDSHARK_TRACE_WRITE = 0x4,
FDSHARK_TRACE_IOCTL = 0x8,
FDSHARK_ALL_FLAGS_ = 0xF,
};
HRESULT fdshark_hook_init(const wchar_t *filename, int flags);
+37
View File
@@ -0,0 +1,37 @@
hooklib_lib = static_library(
'hooklib',
include_directories : inc,
implicit_include_directories : false,
dependencies : [
capnhook.get_variable('hook_dep'),
ws2_32_lib
],
sources : [
'cursor.c',
'cursor.h',
'config.c',
'config.h',
'createprocess.c',
'createprocess.h',
'dll.c',
'dll.h',
'dns.c',
'dns.h',
'dvd.c',
'dvd.h',
'fdshark.c',
'fdshark.h',
'path.c',
'path.h',
'reg.c',
'reg.h',
'setupapi.c',
'setupapi.h',
'spike.c',
'spike.h',
'touch.c',
'touch.h',
'printer.c',
'printer.h',
],
)
File diff suppressed because it is too large Load Diff
+20
View File
@@ -0,0 +1,20 @@
#pragma once
#include <windows.h>
#include <stdbool.h>
#include <stddef.h>
typedef HRESULT (*path_hook_t)(
const wchar_t *src,
wchar_t *dest,
size_t *count);
HRESULT path_hook_push(path_hook_t hook);
void path_hook_insert_hooks(HMODULE target);
int path_compare_w(const wchar_t *string1, const wchar_t *string2, size_t count);
static inline bool path_is_separator_w(wchar_t c)
{
return c == L'\\' || c == L'/';
}
File diff suppressed because it is too large Load Diff
+24
View File
@@ -0,0 +1,24 @@
#pragma once
#include <windows.h>
#include <stdbool.h>
#include <stdint.h>
struct printer_config {
bool enable;
bool rotate_180;
char serial_no[8];
wchar_t main_fw_path[MAX_PATH];
wchar_t dsp_fw_path[MAX_PATH];
wchar_t param_fw_path[MAX_PATH];
wchar_t printer_out_path[MAX_PATH];
uint32_t wait_time;
};
void printer_hook_init(const struct printer_config *cfg, int rfid_port_no, HINSTANCE self);
void printer_hook_insert_hooks(HMODULE target);
void printer_set_dimensions(int width, int height);
int WINAPI fwdlusb_updateFirmware_main(uint8_t update, LPCSTR filename, uint16_t *rResult);
int WINAPI fwdlusb_updateFirmware_dsp(uint8_t update, LPCSTR filename, uint16_t *rResult);
int WINAPI fwdlusb_updateFirmware_param(uint8_t update, LPCSTR filename, uint16_t *rResult);
+1054
View File
File diff suppressed because it is too large Load Diff
+37
View File
@@ -0,0 +1,37 @@
#pragma once
#include <windows.h>
#include <stddef.h>
#include <stdint.h>
struct reg_hook_val {
const wchar_t *name;
HRESULT (*read)(void *bytes, uint32_t *nbytes);
HRESULT (*write)(const void *bytes, uint32_t nbytes);
uint32_t type;
};
void reg_hook_insert_hooks(HMODULE target);
HRESULT reg_hook_push_key(
HKEY root,
const wchar_t *name,
const struct reg_hook_val *vals,
size_t nvals);
HRESULT reg_hook_read_bin(
void *bytes,
uint32_t *nbytes,
const void *src_bytes,
size_t src_nbytes);
HRESULT reg_hook_read_u32(
void *bytes,
uint32_t *nbytes,
uint32_t src);
HRESULT reg_hook_read_wstr(
void *bytes,
uint32_t *nbytes,
const wchar_t *src);

Some files were not shown because too many files have changed in this diff Show More