Move p3io-specific jbhook-util funcs to their own static lib
This commit is contained in:
@@ -6,8 +6,5 @@ libs_jbhook-util := \
|
||||
src_jbhook-util := \
|
||||
acio.c \
|
||||
eamuse.c \
|
||||
gfx.c \
|
||||
mixer.c \
|
||||
locale.c \
|
||||
p3io.c \
|
||||
p4io.c \
|
||||
|
||||
@@ -1,219 +0,0 @@
|
||||
#define LOG_MODULE "jbhook-gfx"
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include <math.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <GL/gl.h>
|
||||
#include <GL/glext.h>
|
||||
|
||||
#include "hook/com-proxy.h"
|
||||
#include "hook/table.h"
|
||||
|
||||
#include "imports/glhelper.h"
|
||||
|
||||
#include "jbhook-util/gfx.h"
|
||||
|
||||
#include "util/defs.h"
|
||||
#include "util/log.h"
|
||||
#include "util/str.h"
|
||||
#include "util/time.h"
|
||||
|
||||
static void __stdcall hook_glFlush(void);
|
||||
static void (__stdcall *real_glFlush)(void);
|
||||
|
||||
static void hook_glBindFramebufferEXT(GLenum target, GLuint framebuffer);
|
||||
static void (*real_glBindFramebufferEXT)(GLenum target, GLuint framebuffer);
|
||||
|
||||
static void hook_infodispcore_set_angle(void* this, int angle);
|
||||
|
||||
static const struct hook_symbol jbhook1_opengl_hook_syms[] = {
|
||||
{.name = "glFlush",
|
||||
.patch = hook_glFlush,
|
||||
.link = (void **) &real_glFlush},
|
||||
};
|
||||
|
||||
static const struct hook_symbol jbhook1_glhelper_hook_syms[] = {
|
||||
{.name = "glBindFramebufferEXT",
|
||||
.patch = hook_glBindFramebufferEXT,
|
||||
.link = (void **) &real_glBindFramebufferEXT},
|
||||
};
|
||||
|
||||
// on knit/copious, this gives us right-side-up errors, too!
|
||||
static const struct hook_symbol jbhook_infodisp_hook_syms[] = {
|
||||
{.name = "?set_angle@infodispcore@@QAEXH@Z",
|
||||
.patch = hook_infodispcore_set_angle},
|
||||
};
|
||||
|
||||
static DWORD STDCALL my_GetGlyphOutline(
|
||||
HDC hdc,
|
||||
UINT uChar,
|
||||
UINT uFormat,
|
||||
LPGLYPHMETRICS lpgm,
|
||||
DWORD cbBuffer,
|
||||
LPVOID lpvBuffer,
|
||||
const MAT2 *lpmat2);
|
||||
|
||||
static DWORD(STDCALL *real_GetGlyphOutline)(
|
||||
HDC hdc,
|
||||
UINT uChar,
|
||||
UINT uFormat,
|
||||
LPGLYPHMETRICS lpgm,
|
||||
DWORD cbBuffer,
|
||||
LPVOID lpvBuffer,
|
||||
const MAT2 *lpmat2);
|
||||
|
||||
static const struct hook_symbol gfx_hook_syms[] = {
|
||||
{.name = "GetGlyphOutlineA",
|
||||
.patch = my_GetGlyphOutline,
|
||||
.link = (void **) &real_GetGlyphOutline},
|
||||
{
|
||||
.name = "IsDBCSLeadByteEx",
|
||||
.patch = my_GetGlyphOutline, // !??
|
||||
.link = (void **) &real_GetGlyphOutline // !??
|
||||
},
|
||||
};
|
||||
|
||||
static DWORD STDCALL my_GetGlyphOutline(
|
||||
HDC hdc,
|
||||
UINT uChar,
|
||||
UINT uFormat,
|
||||
LPGLYPHMETRICS lpgm,
|
||||
DWORD cbBuffer,
|
||||
LPVOID lpvBuffer,
|
||||
const MAT2 *lpmat2)
|
||||
{
|
||||
if (IsDBCSLeadByteEx(CP_ACP, uChar & 0xFF)) {
|
||||
log_warning("!!!!!!!!");
|
||||
|
||||
char tmp[2];
|
||||
|
||||
tmp[0] = uChar & 0xFF;
|
||||
tmp[1] = (uChar >> 8) & 0xFF;
|
||||
|
||||
MultiByteToWideChar(
|
||||
CP_ACP, MB_USEGLYPHCHARS, tmp, 2, lpvBuffer, cbBuffer);
|
||||
}
|
||||
|
||||
return real_GetGlyphOutline(
|
||||
hdc, uChar, uFormat, lpgm, cbBuffer, lpvBuffer, lpmat2);
|
||||
}
|
||||
|
||||
void jbhook_util_gfx_hook_init(void)
|
||||
{
|
||||
hook_table_apply(NULL, "gdi32.dll", gfx_hook_syms, lengthof(gfx_hook_syms));
|
||||
|
||||
log_info("Inserted gfx hooks");
|
||||
}
|
||||
|
||||
void jbhook_util_gfx_set_windowed(bool framed)
|
||||
{
|
||||
}
|
||||
|
||||
void jbhook_util_gfx_install_vertical_hooks(void) {
|
||||
hook_table_apply(
|
||||
NULL,
|
||||
"opengl32.dll",
|
||||
jbhook1_opengl_hook_syms,
|
||||
lengthof(jbhook1_opengl_hook_syms));
|
||||
|
||||
hook_table_apply(
|
||||
NULL,
|
||||
"glhelper.dll",
|
||||
jbhook1_glhelper_hook_syms,
|
||||
lengthof(jbhook1_glhelper_hook_syms));
|
||||
|
||||
hook_table_apply(
|
||||
NULL,
|
||||
"infodisp.dll",
|
||||
jbhook_infodisp_hook_syms,
|
||||
lengthof(jbhook_infodisp_hook_syms));
|
||||
|
||||
log_info("Inserted vertical display hooks");
|
||||
}
|
||||
|
||||
static void hook_infodispcore_set_angle(void* this, int angle) {
|
||||
// ignore
|
||||
}
|
||||
|
||||
// Welcome to OpenGL land! There is a ton of boilerplate needed here "just" to
|
||||
// rotate the render output
|
||||
|
||||
// only jubeat uses openGL, let alone needs rotation at all, so hardcode for now
|
||||
#define W 768
|
||||
#define H 1360
|
||||
|
||||
// the framebuffer we redirect renders to instead of rendering to the screen
|
||||
static GLuint fb;
|
||||
static GLuint color;
|
||||
|
||||
static void fb_init(void) {
|
||||
static bool init_done = false;
|
||||
|
||||
if(init_done) {
|
||||
return;
|
||||
}
|
||||
|
||||
init_done = true;
|
||||
|
||||
glGenFramebuffersEXT(1, &fb);
|
||||
glGenTextures(1, &color);
|
||||
}
|
||||
|
||||
static void __stdcall hook_glFlush(void) {
|
||||
// 3 bytes per RGB pixel
|
||||
// these could really be stack variables but they are too big for gcc's
|
||||
// default stack size, and it's no problem for 6MiB of data to hang around
|
||||
static uint8_t pixels_raw[W*H*3];
|
||||
static uint8_t pixels_rot[W*H*3];
|
||||
|
||||
glReadPixels(0, 0, H, W, GL_RGB, GL_UNSIGNED_BYTE, pixels_raw);
|
||||
|
||||
// CPU copies may seem slow here, but this runs fine on my jubeat cab, so
|
||||
// speed is not a huge concern.
|
||||
for(size_t x = 0; x < W; x++) {
|
||||
for(size_t y = 0; y < H; y++) {
|
||||
memcpy(&pixels_rot[3*(y*W + x)], &pixels_raw[3*((W-x)*H + y)], 3);
|
||||
}
|
||||
}
|
||||
|
||||
// now *we* get to draw to the main display
|
||||
real_glBindFramebufferEXT(GL_FRAMEBUFFER, 0);
|
||||
|
||||
// the scissor test clips pixels to the game window - must be disabled or
|
||||
// the draw area is cut off vertically
|
||||
glDisable(GL_SCISSOR_TEST);
|
||||
glDrawPixels(W, H, GL_RGB, GL_UNSIGNED_BYTE, pixels_rot);
|
||||
|
||||
real_glFlush();
|
||||
|
||||
// reset the framebuffer for the next draw - must be after flush (i.e. when
|
||||
// all state is reset) and before the game tries to draw anything
|
||||
fb_init();
|
||||
real_glBindFramebufferEXT(GL_FRAMEBUFFER, fb);
|
||||
glBindTexture(GL_TEXTURE_2D, color);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, H, W, 0, GL_RGBA,GL_UNSIGNED_BYTE, NULL);
|
||||
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, color, 0);
|
||||
}
|
||||
|
||||
// hooking something in glhelper.dll (a jubeat supplied DLL) might seem
|
||||
// insufficiently generic compared to something in opengl32.dll, but the render
|
||||
// loop of the game makes it very difficult to "catch" the rendering at the
|
||||
// right place otherwise. This works with all horizontal jubeats, and they
|
||||
// stopped needing rotation fixes starting with saucer.
|
||||
static void hook_glBindFramebufferEXT(GLenum target, GLuint framebuffer) {
|
||||
fb_init();
|
||||
|
||||
// check this is actually the screen - the game also uses internal
|
||||
// framebuffers for some parts of the display
|
||||
if(target == GL_FRAMEBUFFER && framebuffer == 0) {
|
||||
framebuffer = fb;
|
||||
}
|
||||
|
||||
return real_glBindFramebufferEXT(target, framebuffer);
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
#ifndef JBHOOK_D3D8_H
|
||||
#define JBHOOK_D3D8_H
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
/**
|
||||
* Hook some gfx related functions to patch gfx related stuff
|
||||
* like enabling window mode.
|
||||
*/
|
||||
void jbhook_util_gfx_hook_init(void);
|
||||
|
||||
/**
|
||||
* Set the game to window mode.
|
||||
*
|
||||
* @param framed True to add a window frame and make the window
|
||||
* movable, resizable, minizable. False for no frame.
|
||||
*/
|
||||
void jbhook_util_gfx_set_windowed(bool framed);
|
||||
|
||||
/**
|
||||
* Rotate a horizontal-by-default jubeat window to vertical
|
||||
*/
|
||||
void jbhook_util_gfx_install_vertical_hooks(void);
|
||||
|
||||
#endif
|
||||
@@ -1,79 +0,0 @@
|
||||
#define LOG_MODULE "jbhook-mixer"
|
||||
|
||||
#include <windows.h>
|
||||
#include <mmsystem.h>
|
||||
|
||||
#include "hook/table.h"
|
||||
|
||||
#include "util/defs.h"
|
||||
#include "util/log.h"
|
||||
|
||||
MMRESULT STDCALL hook_mixerGetLineControlsA(HMIXEROBJ hmxobj, LPMIXERLINECONTROLSA pmxlc, DWORD fdwControls);
|
||||
MMRESULT STDCALL hook_mixerGetDevCapsA(UINT_PTR uMxId, LPMIXERCAPSA pmxcaps, UINT cbmxcaps);
|
||||
MMRESULT STDCALL hook_mixerOpen(LPHMIXER phmx, UINT uMxId, DWORD_PTR dwCallback, DWORD_PTR dwInstance, DWORD fdwOpen);
|
||||
MMRESULT STDCALL hook_mixerSetControlDetails(HMIXEROBJ hmxobj, LPMIXERCONTROLDETAILS pmxcd, DWORD fdwDetails);
|
||||
MMRESULT STDCALL hook_mixerGetControlDetailsA(HMIXEROBJ hmxobj, LPMIXERCONTROLDETAILS pmxcd, DWORD fdwDetails);
|
||||
MMRESULT STDCALL hook_mixerClose(HMIXER hmx);
|
||||
MMRESULT STDCALL hook_mixerGetLineInfoA(HMIXEROBJ hmxobj, LPMIXERLINEA pmxl, DWORD fdwInfo);
|
||||
|
||||
static const struct hook_symbol mixer_hook_syms[] = {
|
||||
{.name = "mixerGetLineControlsA",
|
||||
.patch = hook_mixerGetLineControlsA},
|
||||
{.name = "mixerGetDevCapsA",
|
||||
.patch = hook_mixerGetDevCapsA},
|
||||
{.name = "mixerOpen",
|
||||
.patch = hook_mixerOpen},
|
||||
{.name = "mixerSetControlDetails",
|
||||
.patch = hook_mixerSetControlDetails},
|
||||
{.name = "mixerGetControlDetailsA",
|
||||
.patch = hook_mixerGetControlDetailsA},
|
||||
{.name = "mixerClose",
|
||||
.patch = hook_mixerClose},
|
||||
{.name = "mixerGetLineInfoA",
|
||||
.patch = hook_mixerGetLineInfoA},
|
||||
};
|
||||
|
||||
/*
|
||||
Some of these functions return values which are used as pointer offsets into
|
||||
memory, but that doesn't matter because the game never *modifies* the
|
||||
pointed-to value, only passes it to the other mixer functions. So it's safe
|
||||
to not set any of the returning data.
|
||||
*/
|
||||
|
||||
MMRESULT STDCALL hook_mixerOpen(LPHMIXER phmx, UINT uMxId, DWORD_PTR dwCallback, DWORD_PTR dwInstance, DWORD fdwOpen) {
|
||||
*(DWORD*)phmx = 1234; // any non-zero value is fine
|
||||
|
||||
return MMSYSERR_NOERROR;
|
||||
}
|
||||
|
||||
MMRESULT STDCALL hook_mixerClose(HMIXER hmx) {
|
||||
return MMSYSERR_NOERROR;
|
||||
}
|
||||
|
||||
MMRESULT STDCALL hook_mixerGetLineControlsA(HMIXEROBJ hmxobj, LPMIXERLINECONTROLSA pmxlc, DWORD fdwControls) {
|
||||
return MMSYSERR_NOERROR;
|
||||
}
|
||||
|
||||
MMRESULT STDCALL hook_mixerGetDevCapsA(UINT_PTR uMxId, LPMIXERCAPSA pmxcaps, UINT cbmxcaps) {
|
||||
return MMSYSERR_NOERROR;
|
||||
}
|
||||
|
||||
MMRESULT STDCALL hook_mixerGetControlDetailsA(HMIXEROBJ hmxobj, LPMIXERCONTROLDETAILS pmxcd, DWORD fdwDetails) {
|
||||
return MMSYSERR_NOERROR;
|
||||
}
|
||||
|
||||
MMRESULT STDCALL hook_mixerGetLineInfoA(HMIXEROBJ hmxobj, LPMIXERLINEA pmxl, DWORD fdwInfo) {
|
||||
return MMSYSERR_NOERROR;
|
||||
}
|
||||
|
||||
MMRESULT STDCALL hook_mixerSetControlDetails(HMIXEROBJ hmxobj, LPMIXERCONTROLDETAILS pmxcd, DWORD fdwDetails) {
|
||||
return MMSYSERR_NOERROR;
|
||||
}
|
||||
|
||||
|
||||
void jbhook_util_mixer_hook_init(void)
|
||||
{
|
||||
hook_table_apply(NULL, "winmm.dll", mixer_hook_syms, lengthof(mixer_hook_syms));
|
||||
|
||||
log_info("Inserted mixer hooks");
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
#ifndef JBHOOK_MIXER_H
|
||||
#define JBHOOK_MIXER_H
|
||||
|
||||
/**
|
||||
* Hook some mixer related functions and stub out attempts to change the volume.
|
||||
* In addition to being annoying, this can fail on Vista+ on some outputs,
|
||||
* despite not actually preventing sound from playing.
|
||||
*/
|
||||
void jbhook_util_mixer_hook_init(void);
|
||||
|
||||
#endif
|
||||
@@ -1,206 +0,0 @@
|
||||
#include <windows.h>
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "bemanitools/jbio.h"
|
||||
|
||||
#include "jbhook-util/p3io.h"
|
||||
|
||||
#include "p3ioemu/emu.h"
|
||||
#include "p3ioemu/uart.h"
|
||||
|
||||
#include "security/rp-sign-key.h"
|
||||
#include "security/rp3.h"
|
||||
|
||||
#include "util/log.h"
|
||||
|
||||
static HRESULT jbhook_p3io_read_jamma(void *ctx, uint32_t *state);
|
||||
static HRESULT jbhook_p3io_get_roundplug(
|
||||
void *ctx, uint8_t plug_id, uint8_t *rom, uint8_t *eeprom);
|
||||
static HRESULT jbhook_p3io_set_outputs(void *ctx, uint32_t state);
|
||||
|
||||
/*
|
||||
0:0 b13
|
||||
0:1 -
|
||||
0:2 b15
|
||||
0:3 -
|
||||
0:4 test
|
||||
0:5 coin
|
||||
0:6 service
|
||||
0:7 -
|
||||
|
||||
1:0 -
|
||||
1:1 b4
|
||||
1:2 b8
|
||||
1:3 b12
|
||||
1:4 b16
|
||||
1:5 b3
|
||||
1:6 b7
|
||||
1:7 b11
|
||||
|
||||
2:0 -
|
||||
2:1 b2
|
||||
2:2 b6
|
||||
2:3 b10
|
||||
2:4 b14
|
||||
2:5 b1
|
||||
2:6 b5
|
||||
2:7 b9
|
||||
|
||||
3:0 -
|
||||
3:1 -
|
||||
3:2 -
|
||||
3:3 -
|
||||
3:4 -
|
||||
3:5 -
|
||||
3:6 -
|
||||
3:7 -
|
||||
*/
|
||||
static const uint32_t jbhook_p3io_panel_mappings[] = {
|
||||
(1 << 21),
|
||||
(1 << 17),
|
||||
(1 << 13),
|
||||
(1 << 9),
|
||||
(1 << 22),
|
||||
(1 << 18),
|
||||
(1 << 14),
|
||||
(1 << 10),
|
||||
(1 << 23),
|
||||
(1 << 19),
|
||||
(1 << 15),
|
||||
(1 << 11),
|
||||
(1 << 0),
|
||||
(1 << 20),
|
||||
(1 << 2),
|
||||
(1 << 12),
|
||||
};
|
||||
|
||||
static const uint32_t jbhook_p3io_sys_button_mappings[] = {
|
||||
(1 << 4),
|
||||
(1 << 6),
|
||||
(1 << 5),
|
||||
};
|
||||
|
||||
static struct security_mcode jbhook_p3io_mcode;
|
||||
static struct security_id jbhook_p3io_pcbid;
|
||||
static struct security_id jbhook_p3io_eamid;
|
||||
|
||||
static const struct p3io_ops p3io_ddr_ops = {
|
||||
.read_jamma = jbhook_p3io_read_jamma,
|
||||
.get_roundplug = jbhook_p3io_get_roundplug,
|
||||
.set_outputs = jbhook_p3io_set_outputs,
|
||||
};
|
||||
|
||||
void jbhook_util_p3io_init(
|
||||
const struct security_mcode *mcode,
|
||||
const struct security_id *pcbid,
|
||||
const struct security_id *eamid)
|
||||
{
|
||||
memcpy(&jbhook_p3io_mcode, mcode, sizeof(struct security_mcode));
|
||||
memcpy(&jbhook_p3io_pcbid, pcbid, sizeof(struct security_id));
|
||||
memcpy(&jbhook_p3io_eamid, eamid, sizeof(struct security_id));
|
||||
|
||||
p3io_emu_init(&p3io_ddr_ops, NULL);
|
||||
}
|
||||
|
||||
void jbhook_util_p3io_fini(void)
|
||||
{
|
||||
p3io_emu_fini();
|
||||
}
|
||||
|
||||
static HRESULT jbhook_p3io_read_jamma(void *ctx, uint32_t *state)
|
||||
{
|
||||
uint16_t panels;
|
||||
uint8_t buttons;
|
||||
|
||||
log_assert(state != NULL);
|
||||
|
||||
*state = 0;
|
||||
|
||||
if (!jb_io_read_inputs()) {
|
||||
log_warning("Reading inputs from jbio failed");
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
panels = jb_io_get_panel_inputs();
|
||||
buttons = jb_io_get_sys_inputs();
|
||||
|
||||
for (uint8_t i = 0; i < 16; i++) {
|
||||
// panels are active-low
|
||||
if ((panels & (1 << i)) == 0) {
|
||||
*state |= jbhook_p3io_panel_mappings[i];
|
||||
}
|
||||
}
|
||||
|
||||
for (uint8_t i = 0; i < 2; i++) {
|
||||
// sys buttons are active-high
|
||||
if (buttons & (1 << i)) {
|
||||
*state |= jbhook_p3io_sys_button_mappings[i];
|
||||
}
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static HRESULT jbhook_p3io_get_roundplug(
|
||||
void *ctx, uint8_t plug_id, uint8_t *rom, uint8_t *eeprom)
|
||||
{
|
||||
struct security_rp3_eeprom eeprom_out;
|
||||
|
||||
if (plug_id == 0) {
|
||||
/* black */
|
||||
memcpy(rom, jbhook_p3io_pcbid.id, sizeof(jbhook_p3io_pcbid.id));
|
||||
security_rp3_generate_signed_eeprom_data(
|
||||
SECURITY_RP_UTIL_RP_TYPE_BLACK,
|
||||
&security_rp_sign_key_black_gfdmv4,
|
||||
&jbhook_p3io_mcode,
|
||||
&jbhook_p3io_pcbid,
|
||||
&eeprom_out);
|
||||
} else {
|
||||
/* white */
|
||||
memcpy(rom, jbhook_p3io_eamid.id, sizeof(jbhook_p3io_eamid.id));
|
||||
security_rp3_generate_signed_eeprom_data(
|
||||
SECURITY_RP_UTIL_RP_TYPE_WHITE,
|
||||
&security_rp_sign_key_white_eamuse,
|
||||
&security_mcode_eamuse,
|
||||
&jbhook_p3io_eamid,
|
||||
&eeprom_out);
|
||||
}
|
||||
|
||||
memcpy(eeprom, &eeprom_out, sizeof(struct security_rp3_eeprom));
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static HRESULT jbhook_p3io_set_outputs(void *ctx, uint32_t state) {
|
||||
uint8_t p3io_panel = (state & 0x00FF00) >> 8;
|
||||
uint8_t p3io_coinblocker = (state & 0xFF0000) >> 16;
|
||||
|
||||
enum jb_io_panel_mode panel_mode;
|
||||
|
||||
switch(p3io_panel) {
|
||||
case 5:
|
||||
panel_mode = JB_IO_PANEL_MODE_TOP_LEFT;
|
||||
break;
|
||||
case 4:
|
||||
panel_mode = JB_IO_PANEL_MODE_TOP_RIGHT;
|
||||
break;
|
||||
case 6:
|
||||
panel_mode = JB_IO_PANEL_MODE_BOTTOM_RIGHT;
|
||||
break;
|
||||
case 7:
|
||||
panel_mode = JB_IO_PANEL_MODE_BOTTOM_LEFT;
|
||||
break;
|
||||
default:
|
||||
panel_mode = JB_IO_PANEL_MODE_ALL;
|
||||
break;
|
||||
}
|
||||
|
||||
jb_io_set_panel_mode(panel_mode);
|
||||
|
||||
// 0x40 has been seen to unblock, no other values observed
|
||||
jb_io_set_coin_blocker(p3io_coinblocker == 0x00);
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
#ifndef JBHOOK1_P3IO_H
|
||||
#define JBHOOK1_P3IO_H
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include "hook/iohook.h"
|
||||
|
||||
#include "security/id.h"
|
||||
#include "security/mcode.h"
|
||||
|
||||
/**
|
||||
* Initialize the jb01-04 specific p3io emulation backend.
|
||||
*
|
||||
* @param mcode Mcode of the target game to run. Required for dongle emulation.
|
||||
* @param pcbid PCBDID
|
||||
* @param eamid EAMID
|
||||
*/
|
||||
void jbhook_util_p3io_init(
|
||||
const struct security_mcode *mcode,
|
||||
const struct security_id *pcbid,
|
||||
const struct security_id *eamid);
|
||||
|
||||
/**
|
||||
* Shutdown the p3io emulation backend.
|
||||
*/
|
||||
void jbhook_util_p3io_fini(void);
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user