1
0
mirror of https://github.com/djhackersdev/bemanitools.git synced 2025-02-17 11:18:31 +01:00

Update jbio for testmenu support and add jbio-p4io

This commit is contained in:
Will Toohey 2021-04-04 16:41:45 +10:00
parent 6ce4cce500
commit 2a03690772
34 changed files with 1214 additions and 172 deletions

View File

@ -137,6 +137,7 @@ include src/main/inject/Module.mk
include src/main/jbhook/Module.mk
include src/main/jbhook1/Module.mk
include src/main/jbio-magicbox/Module.mk
include src/main/jbio-p4io/Module.mk
include src/main/jbio/Module.mk
include src/main/jbiotest/Module.mk
include src/main/launcher/Module.mk
@ -144,6 +145,7 @@ include src/main/mempatch-hook/Module.mk
include src/main/mm/Module.mk
include src/main/p3io/Module.mk
include src/main/p3ioemu/Module.mk
include src/main/p4iodrv/Module.mk
include src/main/p4ioemu/Module.mk
include src/main/pcbidgen/Module.mk
include src/main/sdvxhook/Module.mk
@ -444,6 +446,15 @@ $(zipdir)/jb-08.zip: \
$(V)echo ... $@
$(V)zip -j $@ $^
$(zipdir)/jb-hwio.zip: \
build/bin/indep-32/aciomgr.dll \
build/bin/indep-32/eamio-icca.dll \
build/bin/indep-32/jbio-magicbox.dll \
build/bin/indep-32/jbio-p4io.dll \
| $(zipdir)/
$(V)echo ... $@
$(V)zip -j $@ $^
$(zipdir)/sdvx-01-to-04.zip: \
build/bin/avs2_1508-32/launcher.exe \
build/bin/avs2_1508-32/sdvxhook.dll \
@ -609,6 +620,7 @@ $(BUILDDIR)/bemanitools.zip: \
$(zipdir)/jb-01.zip \
$(zipdir)/jb-05-to-07.zip \
$(zipdir)/jb-08.zip \
$(zipdir)/jb-hwio.zip \
$(zipdir)/sdvx-01-to-04.zip \
$(zipdir)/sdvx-05.zip \
$(zipdir)/sdvx-05-cn.zip \

15
doc/jbhook/jbio-p4io.md Normal file
View File

@ -0,0 +1,15 @@
This library talks to a P4IO (panel) and H44B through ACIO (lights) of a jubeat cab and implements the jbio API of BT5.
Thus, it allows you to use a modern jubeat cab with *any* version of jubeat that is supported by BT5.
# Setup
* Rename `jbio-p4io.dll` to `jbio.dll`.
* Make sure `jbio.dll` is in the same folder as both `jbhook.dll`, `aciomgr.dll` and `jubeat.dll`
* Ensure that your `gamestart.bat` actually injects the appropriate jbhook dll
for example:
```
launcher -K jbhook.dll jubeat.dll ...*
```
or that the application otherwise uses `jbio.dll`
* If you have P4IO but no H44B, lights will be disabled
* You can change the port and baudrate of the H44B node by editing the jbio-h44b.conf that should be created by default

View File

@ -5,6 +5,7 @@
#include <stdint.h>
#include <stdlib.h>
#include "acio/h44b.h"
#include "acio/hdxs.h"
#include "acio/icca.h"
#include "acio/kfca.h"
@ -69,6 +70,8 @@ struct ac_io_message {
uint8_t param;
struct ac_io_version version;
struct ac_io_h44b_output h44b_output;
struct ac_io_icca_misc icca_misc;
struct ac_io_icca_state icca_state;

View File

@ -14,6 +14,6 @@ struct ac_io_h44b_output {
uint8_t right_rgb[3];
uint8_t title_rgb[3];
uint8_t woofer_rgb[3];
};
} __attribute__((__packed__));
#endif
#endif

View File

@ -1,9 +1,10 @@
libs += aciodrv
libs_aciodrv := \
src_aciodrv := \
device.c \
h44b.c \
icca.c \
kfca.c \
port.c \

42
src/main/aciodrv/h44b.c Normal file
View File

@ -0,0 +1,42 @@
#define LOG_MODULE "aciodrv-h44b"
#include <stdio.h>
#include <string.h>
#include "acio/h44b.h"
#include "aciodrv/device.h"
#include "util/log.h"
bool aciodrv_h44b_init(
struct aciodrv_device_ctx *device,
uint8_t node_id)
{
return true;
}
bool aciodrv_h44b_lights(
struct aciodrv_device_ctx *device,
uint8_t node_id,
const struct ac_io_h44b_output *lights)
{
struct ac_io_message msg;
log_assert(device);
msg.addr = node_id + 1;
msg.cmd.code = ac_io_u16(AC_IO_H44B_CMD_SET_OUTPUTS);
msg.cmd.nbytes = sizeof(*lights);
msg.cmd.h44b_output = *lights;
if (!aciodrv_send_and_recv(
device,
&msg,
offsetof(struct ac_io_message, cmd.raw) + 1)) {
log_warning("Polling of node %d failed", node_id + 1);
return false;
}
return true;
}

32
src/main/aciodrv/h44b.h Normal file
View File

@ -0,0 +1,32 @@
#ifndef ACIODRV_H44B_H
#define ACIODRV_H44B_H
#include "aciodrv/device.h"
#include "acio/h44b.h"
/**
* Initialize an H44B node.
*
* @param device Context of opened device
* @param node_id Id of the node to initialize (0 based).
* @return True if successful, false on error.
* @note This module is supposed to be used in combination with the common
* device driver foundation.
* @see driver.h
*/
bool aciodrv_h44b_init(struct aciodrv_device_ctx *device, uint8_t node_id);
/**
* Set the H44B LEDs
*
* @param device Context of opened device
* @param node_id Id of the node to query (0 based).
* @param lights Packed lights struct to send
* @return True on success, false on error.
*/
bool aciodrv_h44b_lights(
struct aciodrv_device_ctx *device,
uint8_t node_id,
const struct ac_io_h44b_output *lights);
#endif

View File

@ -61,7 +61,7 @@ void ac_io_emu_h44b_dispatch_request(
req->cmd.raw[i * 3 + 2]);
}
jb_io_write_outputs();
jb_io_write_lights();
ac_io_emu_h44b_send_status(h44b, req, 0x00);

View File

@ -169,6 +169,10 @@ static void ac_io_emu_iccb_send_state(
/* state update */
if (!eam_io_poll(iccb->unit_no)) {
log_warning("Polling eamio failed");
}
sensor = eam_io_get_sensor_state(iccb->unit_no);
if (sensor != iccb->last_sensor) {

View File

@ -29,6 +29,17 @@ enum jb_io_panel_bit {
JB_IO_PANEL_16 = 0x0F,
};
/* input "single button mode" mappings. Allows you to check each corner of each
button to determine any flaky inputs
*/
enum jb_io_panel_mode {
JB_IO_PANEL_MODE_ALL = 0, // any of the four corners will trigger a panel
JB_IO_PANEL_MODE_TOP_LEFT = 1,
JB_IO_PANEL_MODE_TOP_RIGHT = 2,
JB_IO_PANEL_MODE_BOTTOM_RIGHT = 3,
JB_IO_PANEL_MODE_BOTTOM_LEFT = 4,
};
/* Bit mappings for "system" inputs */
enum jb_io_sys_bit {
JB_IO_SYS_TEST = 0x00,
@ -73,17 +84,36 @@ bool jb_io_init(
void jb_io_fini(void);
/* TODO doc */
/* Read input state */
bool jb_io_read_inputs(void);
bool jb_io_write_outputs(void);
/* Get state of coin, test, service inputs */
uint8_t jb_io_get_sys_inputs(void);
/* Get panel button state. Will return either any button being pressed, or a
particular panel corner depending on previous call to jb_io_set_panel_mode */
uint16_t jb_io_get_panel_inputs(void);
/* Set state of a PWM (dimmable) light */
void jb_io_set_rgb_led(
enum jb_io_rgb_led unit, uint8_t r, uint8_t g, uint8_t b);
/* Transmit the light state to the IOPCB */
bool jb_io_write_lights(void);
/* Select operating mode for the panel. Should be immediately sent to the IOPCB */
bool jb_io_set_panel_mode(enum jb_io_panel_mode mode);
/* Open or close the coin chute - true will redirect all coins to the return
slot. Required for jb_io_set_panel_mode to operate correctly on p4io.
Should be immediately sent to the IOPCB */
bool jb_io_set_coin_blocker(bool blocked);
#endif

View File

@ -42,9 +42,10 @@ static bool my_dll_entry_init(char *sidcode, struct property_node *param)
log_info("--- Begin jbhook dll_entry_init ---");
if (!options.disable_p4ioemu) {
p4ioemu_init(jbhook_io_init());
iohook_push_handler(p4ioemu_dispatch_irp);
iohook_push_handler(ac_io_port_dispatch_irp);
if (!options.disable_p4ioemu) {
log_info("Starting up jubeat IO backend");
jb_io_set_loggers(
@ -56,11 +57,12 @@ static bool my_dll_entry_init(char *sidcode, struct property_node *param)
if (!jb_io_ok) {
goto fail;
}
hook_setupapi_init(&p4ioemu_setupapi_data);
p4ioemu_init(jbhook_io_init());
}
if (!options.disable_cardemu) {
ac_io_port_init();
log_info("Starting up card reader backend");
eam_io_set_loggers(
@ -72,6 +74,9 @@ static bool my_dll_entry_init(char *sidcode, struct property_node *param)
if (!eam_io_ok) {
goto fail;
}
rs232_hook_init();
ac_io_port_init();
}
log_info("--- End jbhook dll_entry_init ---");
@ -128,21 +133,10 @@ BOOL WINAPI DllMain(HMODULE mod, DWORD reason, void *ctx)
app_hook_init(my_dll_entry_init, my_dll_entry_main);
iohook_push_handler(p4ioemu_dispatch_irp);
iohook_push_handler(ac_io_port_dispatch_irp);
if (!options.disable_adapteremu) {
adapter_hook_init();
}
if (!options.disable_cardemu) {
rs232_hook_init();
}
if (!options.disable_p4ioemu) {
hook_setupapi_init(&p4ioemu_setupapi_data);
}
gfx_hook_init();
jbhook_eamuse_hook_init();

View File

@ -8,16 +8,10 @@
#include "jbhook/io.h"
#include "p4io/cmd.h"
#include "util/log.h"
enum jbhook_io_p4io_command {
JUHOOK_IO_P4IO_CMD_OUTPUTS = 0x18,
};
struct jbhook_io_p4io_outputs {
uint32_t outputs;
};
static void jbhook_io_jamma2_read(void *resp, uint32_t nbytes);
static uint32_t jbhook_command_handle(
uint8_t cmd,
@ -91,6 +85,7 @@ static const uint32_t jbhook_io_panel_mappings[] = {
static const uint32_t jbhook_io_sys_button_mappings[] = {
(1 << 28),
(1 << 25),
(1 << 24),
};
static void jbhook_io_jamma2_read(void *resp, uint32_t nbytes)
@ -116,7 +111,7 @@ static void jbhook_io_jamma2_read(void *resp, uint32_t nbytes)
}
}
for (uint8_t i = 0; i < 2; i++) {
for (uint8_t i = 0; i < 3; i++) {
if (buttons & (1 << i)) {
*inputs |= jbhook_io_sys_button_mappings[i];
}
@ -131,19 +126,56 @@ static uint32_t jbhook_command_handle(
uint32_t resp_max_len)
{
switch (cmd) {
case JUHOOK_IO_P4IO_CMD_OUTPUTS: {
// const struct jbhook_io_p4io_outputs* req =
// (const struct jbhook_io_p4io_outputs*) payload;
// log_misc("JUHOOK_IO_P4IO_CMD_OUTPUTS: 0x%X", req->outputs);
/* coin blocker: off 0x20, on 0x00 */
case P4IO_CMD_COINSTOCK: {
// on is 0x00, off is either 0x10 or 0x20 depending on whether it's
// during gameplay (0x10) or test menu (0x20). Both seem to have the
// same effect
jb_io_set_coin_blocker(*(uint8_t*)payload == 0x00);
// this actually returns the coinstock, don't care for it
memset(resp, 0, 4);
return 4;
}
case P4IO_CMD_SET_PORTOUT: {
const struct p4io_req_panel_mode *req =
(const struct p4io_req_panel_mode *) payload;
// always fallback to ALL if input is unknown
enum jb_io_panel_mode mode = JB_IO_PANEL_MODE_ALL;
if(req->is_single) {
switch(req->mode) {
case 0x0001:
mode = JB_IO_PANEL_MODE_TOP_LEFT;
break;
case 0x0000:
mode = JB_IO_PANEL_MODE_TOP_RIGHT;
break;
case 0x0101:
mode = JB_IO_PANEL_MODE_BOTTOM_LEFT;
break;
case 0x0100:
mode = JB_IO_PANEL_MODE_BOTTOM_RIGHT;
break;
default:
mode = JB_IO_PANEL_MODE_ALL;
break;
}
}
jb_io_set_panel_mode(mode);
memset(resp, 0, 1);
return 1;
}
default:
return 0xFFFFFFFF;
}

View File

@ -8,4 +8,6 @@ EXPORTS
jb_io_read_inputs
jb_io_set_loggers
jb_io_set_rgb_led
jb_io_write_outputs
jb_io_set_coin_blocker
jb_io_set_panel_mode
jb_io_write_lights

View File

@ -119,7 +119,7 @@ bool jb_io_read_inputs(void)
return true;
}
bool jb_io_write_outputs(void)
bool jb_io_write_lights(void)
{
return true;
}
@ -139,3 +139,13 @@ void jb_io_set_rgb_led(enum jb_io_rgb_led unit, uint8_t r, uint8_t g, uint8_t b)
// I mean I guess there's reactive LEDs on the sides? I'm not going to the
// effort to work out if they're controllable or not
}
bool jb_io_set_panel_mode(enum jb_io_panel_mode mode)
{
return true;
}
bool jb_io_set_coin_blocker(bool blocked)
{
return true;
}

View File

@ -0,0 +1,16 @@
dlls += jbio-p4io
ldflags_jbio-p4io := \
-lsetupapi
src_jbio-p4io := \
config-h44b.c \
h44b.c \
jbio.c \
libs_jbio-p4io := \
aciodrv \
aciomgr \
cconfig \
p4iodrv \
util \

View File

@ -0,0 +1,55 @@
#include "cconfig/cconfig-util.h"
#include "jbio-p4io/config-h44b.h"
#include "util/log.h"
#define JBIO_CONFIG_H44B_PORT_KEY "h44b.port"
#define JBIO_CONFIG_H44B_BAUD_KEY "h44b.baud"
#define JBIO_CONFIG_H44B_DEFAULT_PORT_VALUE "COM2"
#define JBIO_CONFIG_H44B_DEFAULT_BAUD_VALUE 57600
void jbio_config_h44b_init(struct cconfig *config)
{
cconfig_util_set_str(
config,
JBIO_CONFIG_H44B_PORT_KEY,
JBIO_CONFIG_H44B_DEFAULT_PORT_VALUE,
"H44B serial port");
cconfig_util_set_int(
config,
JBIO_CONFIG_H44B_BAUD_KEY,
JBIO_CONFIG_H44B_DEFAULT_BAUD_VALUE,
"H44B bus baudrate (real devices expect 57600)");
}
void jbio_config_h44b_get(
struct h44b_config *config_h44b, struct cconfig *config)
{
if (!cconfig_util_get_str(
config,
JBIO_CONFIG_H44B_PORT_KEY,
config_h44b->port,
sizeof(config_h44b->port) - 1,
JBIO_CONFIG_H44B_DEFAULT_PORT_VALUE)) {
log_warning(
"Invalid value for key '%s' specified, fallback "
"to default '%s'",
JBIO_CONFIG_H44B_PORT_KEY,
JBIO_CONFIG_H44B_DEFAULT_PORT_VALUE);
}
if (!cconfig_util_get_int(
config,
JBIO_CONFIG_H44B_BAUD_KEY,
&config_h44b->baud,
JBIO_CONFIG_H44B_DEFAULT_BAUD_VALUE)) {
log_warning(
"Invalid value for key '%s' specified, fallback "
"to default '%d'",
JBIO_CONFIG_H44B_BAUD_KEY,
JBIO_CONFIG_H44B_DEFAULT_BAUD_VALUE);
}
}

View File

@ -0,0 +1,18 @@
#ifndef JBIO_CONFIG_H44B_H
#define JBIO_CONFIG_H44B_H
#include <windows.h>
#include "cconfig/cconfig.h"
struct h44b_config {
char port[64];
int32_t baud;
};
void jbio_config_h44b_init(struct cconfig *config);
void jbio_config_h44b_get(
struct h44b_config *config_h44b, struct cconfig *config);
#endif

99
src/main/jbio-p4io/h44b.c Normal file
View File

@ -0,0 +1,99 @@
#define LOG_MODULE "jbio-h44b"
#include <stdatomic.h>
#include <stdint.h>
#include <stdbool.h>
#include <stddef.h>
#include <string.h>
#include "aciodrv/h44b.h"
#include "aciomgr/manager.h"
#include "util/log.h"
static int16_t h44b_node_id;
static atomic_bool running;
static struct aciomgr_port_dispatcher *acio_manager_ctx;
bool jb_io_h44b_init(const char *port, int32_t baud) {
acio_manager_ctx = aciomgr_port_init(port, baud);
if (acio_manager_ctx == NULL) {
log_info("Opening acio device on [%s] failed", port);
return false;
}
log_info("Opening acio device successful");
uint8_t node_count = aciomgr_get_node_count(acio_manager_ctx);
log_info("Enumerated %d nodes", node_count);
h44b_node_id = -1;
for (uint8_t i = 0; i < node_count; i++) {
char product[4];
aciomgr_get_node_product_ident(acio_manager_ctx, i, product);
log_info(
"> %d: %c%c%c%c",
i,
product[0],
product[1],
product[2],
product[3]);
if (!memcmp(product, "H44B", 4)) {
if (h44b_node_id != -1) {
log_warning("Multiple H44B found! Using highest node id.");
}
h44b_node_id = i;
}
}
if (h44b_node_id != -1) {
log_warning("Using H44B on node: %d", h44b_node_id);
bool init_result = aciodrv_h44b_init(
aciomgr_port_checkout(acio_manager_ctx),
h44b_node_id);
aciomgr_port_checkin(acio_manager_ctx);
if (!init_result) {
log_warning("Unable to start H44B on node: %d", h44b_node_id);
return false;
}
running = true;
log_warning("jbio-h44b now running");
} else {
log_warning("No H44B device found");
}
return running;
}
bool jb_io_h44b_fini(void) {
return true;
}
bool jb_io_h44b_write_lights(struct ac_io_h44b_output *lights) {
if (!running) {
return false;
}
bool amp_result = aciodrv_h44b_lights(
aciomgr_port_checkout(acio_manager_ctx),
h44b_node_id,
lights);
aciomgr_port_checkin(acio_manager_ctx);
if (!amp_result) {
return false;
}
return true;
}

View File

@ -0,0 +1,7 @@
#include <stdbool.h>
#include "acio/h44b.h"
bool jb_io_h44b_init(const char *port, int32_t baud);
bool jb_io_h44b_fini(void);
bool jb_io_h44b_write_lights(struct ac_io_h44b_output *lights);

View File

@ -0,0 +1,13 @@
LIBRARY jbio
EXPORTS
jb_io_fini
jb_io_get_panel_inputs
jb_io_get_sys_inputs
jb_io_init
jb_io_read_inputs
jb_io_set_loggers
jb_io_set_rgb_led
jb_io_set_panel_mode
jb_io_set_coin_blocker
jb_io_write_lights

206
src/main/jbio-p4io/jbio.c Normal file
View File

@ -0,0 +1,206 @@
// clang-format off
// Don't format because the order is important here
#include <windows.h>
#include <setupapi.h>
#include <stdlib.h>
// clang-format on
#include "aciomgr/manager.h"
#include "cconfig/cconfig-main.h"
#include "bemanitools/jbio.h"
#include "jbio-p4io/config-h44b.h"
#include "jbio-p4io/h44b.h"
#include "p4iodrv/device.h"
#include "util/log.h"
static struct p4iodrv_ctx *p4io_ctx;
static uint16_t jb_io_panels;
static uint8_t jb_io_sys_buttons;
static bool lights_present;
static struct ac_io_h44b_output jb_io_lights;
static struct ac_io_h44b_output jb_io_new_lights;
static bool coin_blocked;
void jb_io_set_loggers(
log_formatter_t misc,
log_formatter_t info,
log_formatter_t warning,
log_formatter_t fatal)
{
aciomgr_set_loggers(misc, info, warning, fatal);
log_to_external(misc, info, warning, fatal);
}
bool jb_io_init(
thread_create_t thread_create,
thread_join_t thread_join,
thread_destroy_t thread_destroy)
{
struct cconfig *config;
struct h44b_config config_h44b;
config = cconfig_init();
jbio_config_h44b_init(config);
if (!cconfig_main_config_init(
config,
"--h44b-config",
"jbio-h44b.conf",
"--help",
"-h",
"jbio-h44b",
CCONFIG_CMD_USAGE_OUT_STDOUT)) {
cconfig_finit(config);
exit(EXIT_FAILURE);
}
jbio_config_h44b_get(&config_h44b, config);
cconfig_finit(config);
p4io_ctx = p4iodrv_open();
if(!p4io_ctx) {
return false;
}
// some people use p4io just for inputs and have no lights. Soft fail when
// h44b is not able to be connected instead of returning false
lights_present = jb_io_h44b_init(config_h44b.port, config_h44b.baud);
if(!lights_present) {
log_warning("Could not connect to H44B, lights disabled");
}
return true;
}
void jb_io_fini(void)
{
p4iodrv_close(p4io_ctx);
}
static const uint32_t jb_io_panel_mappings[] = {
(1 << 5),
(1 << 1),
(1 << 13),
(1 << 9),
(1 << 6),
(1 << 2),
(1 << 14),
(1 << 10),
(1 << 7),
(1 << 3),
(1 << 15),
(1 << 11),
(1 << 16),
(1 << 4),
(1 << 20),
(1 << 12),
};
static const uint32_t jb_io_sys_button_mappings[] = {
(1 << 28),
(1 << 25),
};
bool jb_io_read_inputs(void)
{
uint32_t jamma[4];
if(!p4iodrv_read_jamma(p4io_ctx, jamma)) {
return false;
}
jb_io_panels = 0;
jb_io_sys_buttons = 0;
// panel is active low
uint32_t panel_in = ~jamma[0];
for (uint8_t i = 0; i < 16; i++) {
if (panel_in & jb_io_panel_mappings[i]) {
jb_io_panels |= 1 << i;
}
}
// sys is active high
for (uint8_t i = 0; i < 2; i++) {
if (jamma[0] & jb_io_sys_button_mappings[i]) {
jb_io_sys_buttons |= 1 << i;
}
}
return true;
}
bool jb_io_write_lights(void)
{
if(lights_present && memcmp(&jb_io_lights, &jb_io_new_lights, sizeof(jb_io_lights))) {
memcpy(&jb_io_lights, &jb_io_new_lights, sizeof(jb_io_lights));
return jb_io_h44b_write_lights(&jb_io_lights);
}
return true;
}
uint8_t jb_io_get_sys_inputs(void)
{
return jb_io_sys_buttons;
}
uint16_t jb_io_get_panel_inputs(void)
{
return jb_io_panels;
}
bool jb_io_set_panel_mode(enum jb_io_panel_mode mode)
{
struct p4io_req_panel_mode panel_mode = {0};
panel_mode.is_single = 1;
switch(mode) {
case JB_IO_PANEL_MODE_ALL:
panel_mode.is_single = 0;
panel_mode.mode = 0;
break;
case JB_IO_PANEL_MODE_TOP_LEFT:
panel_mode.mode = 0x0001;
break;
case JB_IO_PANEL_MODE_TOP_RIGHT:
panel_mode.mode = 0x0000;
break;
case JB_IO_PANEL_MODE_BOTTOM_LEFT:
panel_mode.mode = 0x0101;
break;
case JB_IO_PANEL_MODE_BOTTOM_RIGHT:
panel_mode.mode = 0x0100;
break;
}
return p4iodrv_cmd_portout(p4io_ctx, (uint8_t*)&panel_mode);
}
void jb_io_set_rgb_led(enum jb_io_rgb_led unit, uint8_t r, uint8_t g, uint8_t b)
{
// enum jb_io_rgb_led matches the ACIO message order
uint8_t *raw_lights = (uint8_t*)&jb_io_new_lights;
raw_lights[unit * 3] = r;
raw_lights[unit * 3 + 1] = g;
raw_lights[unit * 3 + 2] = b;
}
bool jb_io_set_coin_blocker(bool blocked) {
coin_blocked = blocked;
uint8_t coin[4] = {0};
coin[0] = coin_blocked ? 0x00 : 0x20;
return p4iodrv_cmd_coinstock(p4io_ctx, coin);
}

View File

@ -102,7 +102,7 @@ bool jb_io_read_inputs(void)
return true;
}
bool jb_io_write_outputs(void)
bool jb_io_write_lights(void)
{
/* The generic input stack currently initiates lighting sends and input
reads simultaneously, though this might change later. Perform all of our
@ -122,9 +122,20 @@ uint16_t jb_io_get_panel_inputs(void)
return jb_io_panels;
}
bool jb_io_set_panel_mode(enum jb_io_panel_mode mode)
{
// geninput only uses 1 switch per panel, so ignore alternate modes
return true;
}
bool jb_io_set_coin_blocker(bool blocked)
{
return true;
}
void jb_io_set_rgb_led(enum jb_io_rgb_led unit, uint8_t r, uint8_t g, uint8_t b)
{
mapper_write_light(unit * 3, r);
mapper_write_light(unit * 3 + 1, g);
mapper_write_light(unit * 3 + 2, b);
}
}

View File

@ -7,5 +7,7 @@ EXPORTS
jb_io_init
jb_io_read_inputs
jb_io_set_loggers
jb_io_set_panel_mode
jb_io_set_rgb_led
jb_io_write_outputs
jb_io_set_coin_blocker
jb_io_write_lights

View File

@ -51,8 +51,13 @@ int main(int argc, char **argv)
rgb_t lights[6] = {0};
bool loop = true;
uint8_t cnt = 0;
uint16_t cnt = 0;
enum jbio_light_mode light_mode = LIGHTS_OFF;
enum jb_io_panel_mode panel_mode = JB_IO_PANEL_MODE_ALL;
bool panel_corners_animate = false;
char *all_text;
char top_left, top_right, bottom_left, bottom_right;
while (loop) {
if (!jb_io_read_inputs()) {
@ -60,6 +65,39 @@ int main(int argc, char **argv)
return -2;
}
if(panel_corners_animate && (cnt % 50) == 0) {
panel_mode++;
panel_mode %= 5;
// skip the all state
if(panel_mode == JB_IO_PANEL_MODE_ALL) {
panel_mode++;
}
jb_io_set_panel_mode(panel_mode);
}
all_text = " ";
top_left = top_right = bottom_left = bottom_right = ' ';
switch(panel_mode) {
case JB_IO_PANEL_MODE_ALL:
all_text = "ALL";
top_left = top_right = bottom_left = bottom_right = '*';
break;
case JB_IO_PANEL_MODE_TOP_LEFT:
top_left = '*';
break;
case JB_IO_PANEL_MODE_TOP_RIGHT:
top_right = '*';
break;
case JB_IO_PANEL_MODE_BOTTOM_LEFT:
bottom_left = '*';
break;
case JB_IO_PANEL_MODE_BOTTOM_RIGHT:
bottom_right = '*';
break;
}
/* get inputs */
input_sys = jb_io_get_sys_inputs();
input_panel = jb_io_get_panel_inputs();
@ -85,12 +123,12 @@ int main(int argc, char **argv)
"\n"
" Test: %d Service: %d Coin: %d\n"
" .___.___.___.___.\n"
" | %d | %d | %d | %d |\n"
" |---|---|---|---|\n"
" | %d | %d | %d | %d |\n"
" |---|---|---|---|\n"
" | %d | %d | %d | %d |\n"
" |---|---|---|---|\n"
" | %d | %d | %d | %d | Corner\n"
" |---|---|---|---| .___.\n"
" | %d | %d | %d | %d | |%c %c|\n"
" |---|---|---|---| |%s|\n"
" | %d | %d | %d | %d | |%c %c|\n"
" |---|---|---|---| `---`\n"
" | %d | %d | %d | %d |\n"
" `---`---`---`---`\n",
cnt,
@ -126,10 +164,19 @@ int main(int argc, char **argv)
IS_BIT_SET(input_panel, JB_IO_PANEL_06),
IS_BIT_SET(input_panel, JB_IO_PANEL_07),
IS_BIT_SET(input_panel, JB_IO_PANEL_08),
top_left,
top_right,
all_text,
IS_BIT_SET(input_panel, JB_IO_PANEL_09),
IS_BIT_SET(input_panel, JB_IO_PANEL_10),
IS_BIT_SET(input_panel, JB_IO_PANEL_11),
IS_BIT_SET(input_panel, JB_IO_PANEL_12),
bottom_left,
bottom_right,
IS_BIT_SET(input_panel, JB_IO_PANEL_13),
IS_BIT_SET(input_panel, JB_IO_PANEL_14),
IS_BIT_SET(input_panel, JB_IO_PANEL_15),
@ -165,7 +212,7 @@ int main(int argc, char **argv)
jb_io_set_rgb_led(i, lights[i].r, lights[i].g, lights[i].b);
}
if (!jb_io_write_outputs()) {
if (!jb_io_write_lights()) {
printf("ERROR: Writing outputs failed\n");
return -4;
}
@ -185,6 +232,7 @@ int main(int argc, char **argv)
" 2: Set all lights on (cleared by pressing any panel)\n"
" 3: Tie each R/G/B to inputs (panels + test + service)\n"
" 4: Set all lights off\n"
" 5: Toggle switch corner test mode\n"
"Waiting for input: ");
char c = getchar();
@ -195,7 +243,7 @@ int main(int argc, char **argv)
jb_io_set_rgb_led(i, 0, 0, 0);
}
if (!jb_io_write_outputs()) {
if (!jb_io_write_lights()) {
printf("ERROR: Writing outputs failed\n");
return -4;
}
@ -219,6 +267,15 @@ int main(int argc, char **argv)
break;
}
case '5': {
panel_corners_animate = !panel_corners_animate;
if(!panel_corners_animate) {
panel_mode = JB_IO_PANEL_MODE_ALL;
jb_io_set_panel_mode(panel_mode);
}
break;
}
case '0':
default:
break;

60
src/main/p4io/cmd.h Normal file
View File

@ -0,0 +1,60 @@
#ifndef P4IO_CMD_H
#define P4IO_CMD_H
#include <stdint.h>
enum p4ioemu_p4io_command {
P4IO_CMD_INIT = 0x00,
P4IO_CMD_GET_DEVICE_INFO = 0x01,
P4IO_CMD_SET_PORTOUT = 0x12,
P4IO_CMD_COINSTOCK = 0x18,
P4IO_CMD_RESET_WTD = 0x1C,
P4IO_CMD_SCI_MNG_OPEN = 0x20,
P4IO_CMD_SCI_UPDATE = 0x21,
/* SCI = serial communication interface */
P4IO_CMD_SCI_MNG_BREAK = 0x24,
/* Read round plug id over one-wire */
P4IO_CMD_DALLAS_READ_ID = 0x40,
/* Read round plug mem over one-wire */
P4IO_CMD_DALLAS_READ_MEM = 0x41
};
#define P4IO_CMD_HEADER_LEN 4
#define P4IO_MAX_PAYLOAD 60
struct p4io_cmd_header {
uint8_t AA;
uint8_t cmd;
uint8_t seq_num;
uint8_t payload_len;
};
struct p4io_cmd_package {
struct p4io_cmd_header header;
uint8_t payload[P4IO_MAX_PAYLOAD];
};
struct p4io_req_read_roundplug {
/* 0 = black, 1 = white */
uint8_t type;
};
struct p4io_req_panel_mode {
uint16_t mode;
uint8_t is_single;
uint8_t padding[13];
} __attribute__((__packed__));
struct p4io_resp_device_info {
uint32_t type;
uint8_t padding;
uint8_t version_major;
uint8_t version_minor;
uint8_t version_revision;
char product_code[4];
char build_date[16];
char build_time[16];
};
#endif

13
src/main/p4io/guid.h Normal file
View File

@ -0,0 +1,13 @@
#ifndef P4IO_GUID_H
#define P4IO_GUID_H
#include <windows.h>
static const GUID p4io_guid = {
0x8B7250A5,
0x4F61,
0x46C9,
{0x84, 0x3A, 0xE6, 0x68, 0x06, 0x47, 0x6A, 0x20}
};
#endif

42
src/main/p4io/ioctl.h Normal file
View File

@ -0,0 +1,42 @@
#ifndef P4IO_IOCTL_H
#define P4IO_IOCTL_H
/* can't seem to #include the requisite DDK headers from usermode code,
so we have to redefine these macros here */
#ifndef CTL_CODE
#define CTL_CODE(DeviceType, Function, Method, Access) \
(((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method))
#endif
#ifndef METHOD_BUFFERED
#define METHOD_BUFFERED 0
#endif
#ifndef FILE_ANY_ACCESS
#define FILE_ANY_ACCESS 0x00
#endif
#ifndef FILE_DEVICE_UNKNOWN
#define FILE_DEVICE_UNKNOWN 0x22
#endif
#define P4IO_FUNCTION_READ_JAMMA_2 0x801
#define P4IO_FUNCTION_GET_DEVICE_NAME 0x803
// 0x22200Cu sent to bulk handle
#define P4IO_IOCTL_GET_DEVICE_NAME \
CTL_CODE( \
FILE_DEVICE_UNKNOWN, \
P4IO_FUNCTION_GET_DEVICE_NAME, \
METHOD_BUFFERED, \
FILE_ANY_ACCESS)
// 0x222004 sent to int handle
#define P4IO_IOCTL_READ_JAMMA_2 \
CTL_CODE( \
FILE_DEVICE_UNKNOWN, \
P4IO_FUNCTION_READ_JAMMA_2, \
METHOD_BUFFERED, \
FILE_ANY_ACCESS)
#endif

View File

@ -0,0 +1,6 @@
libs += p4iodrv
src_p4iodrv := \
device.c \
usb.c \

122
src/main/p4iodrv/device.c Normal file
View File

@ -0,0 +1,122 @@
#define LOG_MODULE "p4iodrv-device"
#include <windows.h>
#include "p4io/cmd.h"
#include "p4iodrv/device.h"
#include "p4iodrv/usb.h"
#include "util/log.h"
#include "util/mem.h"
struct p4iodrv_ctx {
HANDLE jamma_handle;
HANDLE bulk_handle;
uint8_t seq_no;
};
static void p4io_cmd_init(struct p4iodrv_ctx *ctx);
static bool p4io_print_version(struct p4iodrv_ctx *ctx);
static bool p4io_transfer(
struct p4iodrv_ctx *ctx,
uint8_t cmd,
const void *req_payload,
size_t req_payload_len,
void *resp_payload,
size_t resp_payload_len
) {
bool ret = p4io_usb_transfer(ctx->bulk_handle, cmd, ctx->seq_no,
req_payload, req_payload_len,
resp_payload, &resp_payload_len);
ctx->seq_no++;
return ret;
}
struct p4iodrv_ctx *p4iodrv_open(void) {
struct p4iodrv_ctx *ctx = xcalloc(sizeof(struct p4iodrv_ctx));
// jamma is read as fast as possible in its own thread, so having them be
// separate files is absolutely essential to avoid the bulk handle being
// starved
ctx->jamma_handle = p4io_usb_open();
ctx->bulk_handle = p4io_usb_open();
ctx->seq_no = 0;
if(ctx->jamma_handle == INVALID_HANDLE_VALUE || ctx->bulk_handle == INVALID_HANDLE_VALUE) {
free(ctx);
return NULL;
}
p4io_cmd_init(ctx);
if(!p4io_print_version(ctx)) {
free(ctx);
return NULL;
}
return ctx;
}
void p4iodrv_close(struct p4iodrv_ctx *ctx) {
p4io_usb_close(ctx->jamma_handle);
p4io_usb_close(ctx->bulk_handle);
free(ctx);
}
bool p4iodrv_read_jamma(struct p4iodrv_ctx *ctx, uint32_t jamma[4]) {
return p4io_usb_read_jamma(ctx->jamma_handle, jamma);
}
// send something you don't expect a response for
static bool p4io_send(struct p4iodrv_ctx *ctx, uint8_t cmd) {
uint8_t dummy[P4IO_MAX_PAYLOAD];
return p4io_transfer(ctx, cmd, NULL, 0, dummy, sizeof(dummy));
}
// real IO does not check the return value, so neither do we
static void p4io_cmd_init(struct p4iodrv_ctx *ctx) {
p4io_send(ctx, P4IO_CMD_INIT);
}
static bool p4io_print_version(struct p4iodrv_ctx *ctx) {
char p4io_name[128];
if(!p4io_usb_read_device_name(ctx->bulk_handle, p4io_name)) {
return false;
}
struct p4io_resp_device_info dev_info;
if(!p4iodrv_cmd_device_info(ctx, &dev_info)) {
log_warning("p4io get_device_info failed");
return false;
}
dev_info.build_date[15] = '\0';
dev_info.build_time[15] = '\0';
log_info("p4io name: %s", p4io_name);
log_info("p4io type: %08X", dev_info.type);
log_info("p4io version: %d.%d.%d", dev_info.version_major, dev_info.version_minor, dev_info.version_revision);
log_info("p4io product: %.4s", dev_info.product_code);
log_info("p4io build date: %.16s", dev_info.build_date);
log_info("p4io build time: %.16s", dev_info.build_time);
return true;
}
bool p4iodrv_cmd_device_info(struct p4iodrv_ctx *ctx, struct p4io_resp_device_info *info) {
return p4io_transfer(ctx, P4IO_CMD_GET_DEVICE_INFO, NULL, 0, info, sizeof(*info));
}
bool p4iodrv_cmd_portout(struct p4iodrv_ctx *ctx, const uint8_t buffer[16]) {
uint8_t dummy[P4IO_MAX_PAYLOAD];
return p4io_transfer(ctx, P4IO_CMD_SET_PORTOUT, buffer, 16, dummy, sizeof(dummy));
}
bool p4iodrv_cmd_coinstock(struct p4iodrv_ctx *ctx, const uint8_t buffer[4]) {
uint8_t dummy[P4IO_MAX_PAYLOAD];
return p4io_transfer(ctx, P4IO_CMD_COINSTOCK, buffer, 4, dummy, sizeof(dummy));
}

18
src/main/p4iodrv/device.h Normal file
View File

@ -0,0 +1,18 @@
#ifndef P4IODRV_DEVICE_H
#define P4IODRV_DEVICE_H
#include <stdbool.h>
#include <stdint.h>
#include "p4io/cmd.h"
struct p4iodrv_ctx;
struct p4iodrv_ctx *p4iodrv_open(void);
void p4iodrv_close(struct p4iodrv_ctx *ctx);
bool p4iodrv_cmd_device_info(struct p4iodrv_ctx *ctx, struct p4io_resp_device_info *info);
bool p4iodrv_cmd_portout(struct p4iodrv_ctx *ctx, const uint8_t buffer[16]);
bool p4iodrv_cmd_coinstock(struct p4iodrv_ctx *ctx, const uint8_t buffer[4]);
bool p4iodrv_read_jamma(struct p4iodrv_ctx *ctx, uint32_t jamma[4]);
#endif

173
src/main/p4iodrv/usb.c Normal file
View File

@ -0,0 +1,173 @@
#define LOG_MODULE "p4iodrv-usb"
#include <stdlib.h>
#include <stdint.h>
#include <inttypes.h>
// clang-format off
// Don't format because the order is important here
#include <windows.h>
#include <setupapi.h>
// clang-format on
#include "p4io/cmd.h"
#include "p4io/guid.h"
#include "p4io/ioctl.h"
#include "p4iodrv/usb.h"
#include "util/log.h"
#include "util/str.h"
HANDLE p4io_usb_open(void) {
HANDLE handle = INVALID_HANDLE_VALUE;
wchar_t p4io_filename[MAX_PATH]; // game uses 1024, but it shouldn't be that long
PSP_DEVICE_INTERFACE_DETAIL_DATA_W detail_data = NULL;
HDEVINFO dev_info_set;
dev_info_set = SetupDiGetClassDevsW(&p4io_guid, NULL, NULL, DIGCF_DEVICEINTERFACE | DIGCF_PRESENT);
if(dev_info_set == INVALID_HANDLE_VALUE) {
log_warning("SetupDiGetClassDevs fail, is p4io device connected and driver installed?");
return INVALID_HANDLE_VALUE;
}
SP_DEVICE_INTERFACE_DATA interface_data;
interface_data.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
if(!SetupDiEnumDeviceInterfaces(dev_info_set, NULL, &p4io_guid, 0, &interface_data)) {
log_warning("SetupDiEnumDeviceInterfaces fail");
goto CLEANUP;
}
DWORD required_size;
SetupDiGetDeviceInterfaceDetailW(dev_info_set, &interface_data, NULL, 0, &required_size, NULL);
detail_data = malloc(required_size);
detail_data->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W);
if(!SetupDiGetDeviceInterfaceDetailW(dev_info_set, &interface_data, detail_data, required_size, NULL, NULL)) {
log_warning("SetupDiGetDeviceInterfaceDetailW fail");
goto CLEANUP;
}
wstr_cpy(p4io_filename, MAX_PATH, detail_data->DevicePath);
wstr_cat(p4io_filename, MAX_PATH, L"\\p4io");
log_info("p4io found at path %ls", p4io_filename);
handle = CreateFileW(p4io_filename, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
if(handle == INVALID_HANDLE_VALUE) {
log_warning("CreateFileW fail");
goto CLEANUP;
}
CLEANUP:
free(detail_data);
SetupDiDestroyDeviceInfoList(dev_info_set);
return handle;
}
void p4io_usb_close(HANDLE p4io_handle) {
if(p4io_handle != INVALID_HANDLE_VALUE) {
CloseHandle(p4io_handle);
}
p4io_handle = INVALID_HANDLE_VALUE;
}
bool p4io_usb_read_jamma(HANDLE jamma_handle, uint32_t jamma[4]) {
DWORD bytes_returned;
if(!DeviceIoControl(jamma_handle, P4IO_IOCTL_READ_JAMMA_2, NULL, 0, jamma, sizeof(uint32_t[4]), &bytes_returned, NULL)) {
log_warning("jamma read failed");
return false;
}
return true;
}
bool p4io_usb_read_device_name(HANDLE bulk_handle, char name[128]) {
DWORD bytes_returned;
if(!DeviceIoControl(bulk_handle, P4IO_IOCTL_GET_DEVICE_NAME, NULL, 0, name, 128, &bytes_returned, NULL)) {
log_warning("p4io does not support get_name cmd");
return false;
}
return true;
}
bool p4io_usb_transfer(
HANDLE bulk_handle,
uint8_t cmd,
uint8_t seq_no,
const void *req_payload,
size_t req_payload_len,
void *resp_payload,
size_t *resp_payload_len
) {
DWORD bytes_requested;
DWORD bytes_xferred;
struct p4io_cmd_package cmd_buf;
if(bulk_handle == INVALID_HANDLE_VALUE) {
log_warning("p4io not open");
return false;
}
if(req_payload_len > sizeof(cmd_buf.payload)) {
log_warning("request too big");
return false;
}
cmd_buf.header.AA = 0xAA;
cmd_buf.header.cmd = cmd;
cmd_buf.header.seq_num = seq_no;
cmd_buf.header.payload_len = req_payload_len;
memcpy(cmd_buf.payload, req_payload, req_payload_len);
bytes_requested = P4IO_CMD_HEADER_LEN + req_payload_len;
if(!WriteFile(bulk_handle, &cmd_buf, bytes_requested, &bytes_xferred, 0)) {
log_warning("WriteFile failed");
return false;
}
if(bytes_xferred != bytes_requested) {
log_warning("WriteFile didn't finish");
return false;
}
bytes_requested = P4IO_CMD_HEADER_LEN + *resp_payload_len;
// must do this or requests can stall
if(bytes_requested == 64) {
bytes_requested = 65;
}
if(!ReadFile(bulk_handle, &cmd_buf, bytes_requested, &bytes_xferred, 0)) {
log_warning("ReadFile failed");
return false;
}
if(bytes_xferred > 0) {
if(resp_payload_len) {
if(*resp_payload_len < cmd_buf.header.payload_len) {
log_warning("Response buffer too short");
return false;
}
memcpy(resp_payload, cmd_buf.payload, *resp_payload_len);
*resp_payload_len = cmd_buf.header.payload_len;
}
if(cmd_buf.header.AA != 0xAA) {
log_warning("Response bad header");
return false;
}
if(seq_no != cmd_buf.header.seq_num) {
log_warning("seq_num mismatch (ours %d != theirs %d)", seq_no, cmd_buf.header.seq_num);
return false;
}
} else if(resp_payload_len) {
*resp_payload_len = 0;
}
return true;
}

22
src/main/p4iodrv/usb.h Normal file
View File

@ -0,0 +1,22 @@
#ifndef P4IODRV_USB_H
#define P4IODRV_USB_H
#include <stdbool.h>
#include <stddef.h>
#include <windows.h>
HANDLE p4io_usb_open(void);
void p4io_usb_close(HANDLE p4io_handle);
bool p4io_usb_read_jamma(HANDLE jamma_handle, uint32_t jamma[4]);
bool p4io_usb_read_device_name(HANDLE bulk_handle, char name[128]);
bool p4io_usb_transfer(
HANDLE bulk_handle,
uint8_t cmd,
uint8_t seq_no,
const void *req_payload,
size_t req_payload_len,
void *resp_payload,
size_t *resp_payload_len
);
#endif

View File

@ -7,78 +7,14 @@
#include <windows.h>
#include "hook/iohook.h"
#include "p4io/cmd.h"
#include "p4io/ioctl.h"
#include "util/hex.h"
#include "util/log.h"
#include "util/str.h"
//#define P4IOEMU_DEBUG_DUMP
/* can't seem to #include the requisite DDK headers from usermode code,
so we have to redefine these macros here */
#define CTL_CODE(DeviceType, Function, Method, Access) \
(((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method))
#define METHOD_BUFFERED 0
#define FILE_ANY_ACCESS 0x00
#define FILE_DEVICE_UNKNOWN 0x22
#define P4IO_FUNCTION_READ_JAMMA_2 0x801
#define P4IO_FUNCTION_GET_DEVICE_NAME 0x803
#define IOCTL_P4IO_GET_DEVICE_NAME \
CTL_CODE( \
FILE_DEVICE_UNKNOWN, \
P4IO_FUNCTION_GET_DEVICE_NAME, \
METHOD_BUFFERED, \
FILE_ANY_ACCESS)
#define IOCTL_P4IO_READ_JAMMA_2 \
CTL_CODE( \
FILE_DEVICE_UNKNOWN, \
P4IO_FUNCTION_READ_JAMMA_2, \
METHOD_BUFFERED, \
FILE_ANY_ACCESS)
enum p4ioemu_p4io_command {
P4IOEMU_P4IO_CMD_INIT = 0x00,
P4IOEMU_P4IO_CMD_GET_DEVICE_INFO = 0x01,
P4IOEMU_P4IO_CMD_UNKNOWN = 0x12,
P4IOEMU_P4IO_CMD_RESET_WTD = 0x1C,
P4IOEMU_P4IO_CMD_SCI_MNG_OPEN = 0x20,
P4IOEMU_P4IO_CMD_SCI_UPDATE = 0x21,
/* SCI = serial communication interface */
P4IOEMU_P4IO_CMD_SCI_MNG_BREAK = 0x24,
/* Read round plug id over one-wire */
P4IOEMU_P4IO_CMD_DALLAS_READ_ID = 0x40,
/* Read round plug mem over one-wire */
P4IOEMU_P4IO_CMD_DALLAS_READ_MEM = 0x41
};
struct p4ioemu_p4io_cmd_package {
uint8_t header_AA;
uint8_t cmd;
uint8_t seq_num;
uint8_t payload_len;
};
struct p4ioemu_p4io_device_info_resp {
uint32_t type;
uint8_t padding;
uint8_t version_major;
uint8_t version_minor;
uint8_t version_revision;
char product_code[4];
char build_date[16];
char build_time[16];
};
struct p4ioemu_p4io_read_roundplug_req {
/* 0 = black, 1 = white */
uint8_t type;
};
static const struct p4ioemu_device_msg_hook *p4ioemu_device_msg_hook;
static HANDLE p4ioemu_p4io_fd;
@ -95,7 +31,7 @@ static uint32_t p4ioemu_p4io_command_handle(
uint32_t resp_max_len)
{
switch (cmd) {
case P4IOEMU_P4IO_CMD_INIT: {
case P4IO_CMD_INIT: {
log_misc("P4IOEMU_P4IO_CMD_INIT");
/* no data to send to host */
@ -104,11 +40,11 @@ static uint32_t p4ioemu_p4io_command_handle(
return 0;
}
case P4IOEMU_P4IO_CMD_GET_DEVICE_INFO: {
case P4IO_CMD_GET_DEVICE_INFO: {
log_misc("P4IOEMU_P4IO_CMD_GET_DEVICE_INFO");
struct p4ioemu_p4io_device_info_resp *info =
(struct p4ioemu_p4io_device_info_resp *) resp;
struct p4io_resp_device_info *info =
(struct p4io_resp_device_info *) resp;
info->type = 0x37133713;
info->version_major = 5;
@ -118,12 +54,12 @@ static uint32_t p4ioemu_p4io_command_handle(
memcpy(info->build_date, "build_date", 11);
memcpy(info->build_time, "build_time", 11);
return sizeof(struct p4ioemu_p4io_device_info_resp);
return sizeof(struct p4io_resp_device_info);
}
case P4IOEMU_P4IO_CMD_DALLAS_READ_ID: {
const struct p4ioemu_p4io_read_roundplug_req *req =
(const struct p4ioemu_p4io_read_roundplug_req *) payload;
case P4IO_CMD_DALLAS_READ_ID: {
const struct p4io_req_read_roundplug *req =
(const struct p4io_req_read_roundplug *) payload;
log_misc("P4IOEMU_P4IO_CMD_DALLAS_READ_ID: %d", req->type);
@ -136,9 +72,9 @@ static uint32_t p4ioemu_p4io_command_handle(
return 8;
}
case P4IOEMU_P4IO_CMD_DALLAS_READ_MEM: {
const struct p4ioemu_p4io_read_roundplug_req *req =
(const struct p4ioemu_p4io_read_roundplug_req *) payload;
case P4IO_CMD_DALLAS_READ_MEM: {
const struct p4io_req_read_roundplug *req =
(const struct p4io_req_read_roundplug *) payload;
log_misc("P4IOEMU_P4IO_CMD_DALLAS_READ_MEM: %d", req->type);
@ -152,13 +88,7 @@ static uint32_t p4ioemu_p4io_command_handle(
return 32;
}
case P4IOEMU_P4IO_CMD_UNKNOWN: {
log_misc("P4IOEMU_P4IO_CMD_UNKNOWN: %d", payload_len);
return 0;
}
case P4IOEMU_P4IO_CMD_SCI_UPDATE: {
case P4IO_CMD_SCI_UPDATE: {
// log_misc("P4IOEMU_P4IO_CMD_SCI_UPDATE");
// TODO we need a game which uses it
@ -167,7 +97,7 @@ static uint32_t p4ioemu_p4io_command_handle(
return 0;
}
case P4IOEMU_P4IO_CMD_RESET_WTD: {
case P4IO_CMD_RESET_WTD: {
// log_misc("P4IOEMU_P4IO_CMD_RESET_WTD");
return 0;
@ -188,20 +118,18 @@ static void p4ioemu_p4io_dump_buffer(const void *buffer, uint32_t len)
static HRESULT p4ioemu_p4io_bulk_read(void *resp, uint32_t nbytes)
{
struct p4ioemu_p4io_cmd_package *package;
void *payload;
struct p4io_cmd_package *package;
uint32_t max_payload_len;
uint32_t payload_len;
if (nbytes < sizeof(struct p4ioemu_p4io_cmd_package)) {
log_warning("Buffer for bulk read endpoint to short: %d", nbytes);
if (nbytes < sizeof(struct p4io_cmd_header)) {
log_warning("Buffer for bulk read endpoint too short: %d", nbytes);
return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
}
package = (struct p4ioemu_p4io_cmd_package *) resp;
payload = resp + sizeof(struct p4ioemu_p4io_cmd_package);
max_payload_len = nbytes - sizeof(struct p4ioemu_p4io_cmd_package);
package = (struct p4io_cmd_package *) resp;
max_payload_len = nbytes - sizeof(struct p4io_cmd_header);
if (max_payload_len < p4ioemu_p4io_cmd_buffer_resp_len) {
log_warning(
@ -213,46 +141,44 @@ static HRESULT p4ioemu_p4io_bulk_read(void *resp, uint32_t nbytes)
payload_len = p4ioemu_p4io_cmd_buffer_resp_len;
}
package->header_AA = 0xAA;
package->cmd = p4ioemu_p4io_last_cmd;
package->seq_num = p4ioemu_p4io_last_seq_num;
package->payload_len = payload_len;
package->header.AA = 0xAA;
package->header.cmd = p4ioemu_p4io_last_cmd;
package->header.seq_num = p4ioemu_p4io_last_seq_num;
package->header.payload_len = payload_len;
memcpy(payload, p4ioemu_p4io_cmd_read_buffer, payload_len);
memcpy(package->payload, p4ioemu_p4io_cmd_read_buffer, payload_len);
return S_OK;
}
static HRESULT p4ioemu_p4io_bulk_write(const void *req, uint32_t nbytes)
{
const struct p4ioemu_p4io_cmd_package *package;
const void *payload;
const struct p4io_cmd_package *package;
if (nbytes < sizeof(struct p4ioemu_p4io_cmd_package)) {
log_warning("Command on bulk write endpoint to short: %d", nbytes);
if (nbytes < sizeof(struct p4io_cmd_header)) {
log_warning("Command on bulk write endpoint too short: %d", nbytes);
p4ioemu_p4io_dump_buffer(req, nbytes);
return E_INVALIDARG;
}
package = (struct p4ioemu_p4io_cmd_package *) req;
payload = req + sizeof(struct p4ioemu_p4io_cmd_package);
package = (struct p4io_cmd_package *) req;
if (package->header_AA != 0xAA) {
log_warning("Command on bulk endpoint to short: %d", nbytes);
if (package->header.AA != 0xAA) {
log_warning("Command on bulk endpoint too short: %d", nbytes);
p4ioemu_p4io_dump_buffer(req, nbytes);
return E_INVALIDARG;
}
p4ioemu_p4io_last_cmd = package->cmd;
p4ioemu_p4io_last_seq_num = package->seq_num;
p4ioemu_p4io_last_cmd = package->header.cmd;
p4ioemu_p4io_last_seq_num = package->header.seq_num;
/* handle commands that are common p4io ones first */
p4ioemu_p4io_cmd_buffer_resp_len = p4ioemu_p4io_command_handle(
package->cmd,
payload,
package->payload_len,
package->header.cmd,
package->payload,
package->header.payload_len,
p4ioemu_p4io_cmd_read_buffer,
sizeof(p4ioemu_p4io_cmd_read_buffer));
@ -261,16 +187,16 @@ static HRESULT p4ioemu_p4io_bulk_write(const void *req, uint32_t nbytes)
if (p4ioemu_device_msg_hook->command_handle) {
p4ioemu_p4io_cmd_buffer_resp_len =
p4ioemu_device_msg_hook->command_handle(
package->cmd,
payload,
package->payload_len,
package->header.cmd,
package->payload,
package->header.payload_len,
p4ioemu_p4io_cmd_read_buffer,
sizeof(p4ioemu_p4io_cmd_read_buffer));
}
}
if (p4ioemu_p4io_cmd_buffer_resp_len == 0xFFFFFFFF) {
log_warning("Unhandled cmd 0x%X", package->cmd);
log_warning("Unhandled cmd 0x%X", package->header.cmd);
return E_NOTIMPL;
}
@ -413,7 +339,7 @@ static HRESULT p4ioemu_device_ioctl(struct irp *irp)
/* Cases are listed in order of first receipt */
switch (irp->ioctl) {
case IOCTL_P4IO_GET_DEVICE_NAME: {
case P4IO_IOCTL_GET_DEVICE_NAME: {
const char dev_name[] = "kactools p4ioemu";
if (irp->read.nbytes < strlen(dev_name)) {
@ -427,7 +353,7 @@ static HRESULT p4ioemu_device_ioctl(struct irp *irp)
return S_OK;
}
case IOCTL_P4IO_READ_JAMMA_2: {
case P4IO_IOCTL_READ_JAMMA_2: {
p4ioemu_device_msg_hook->jamma2_read(
irp->read.bytes, irp->read.nbytes);
irp->read.pos = irp->read.nbytes;

View File

@ -2,11 +2,10 @@
#include "p4ioemu/setupapi.h"
#include "p4io/guid.h"
const struct hook_setupapi_data p4ioemu_setupapi_data = {
.device_guid = {0x8B7250A5,
0x4F61,
0x46C9,
{0x84, 0x3A, 0xE6, 0x68, 0x06, 0x47, 0x6A, 0x20}},
.device_guid = p4io_guid,
.device_desc = NULL,
.device_path = "\\p4io",
};
};