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:
parent
6ce4cce500
commit
2a03690772
12
Module.mk
12
Module.mk
@ -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
15
doc/jbhook/jbio-p4io.md
Normal 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
|
@ -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;
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
42
src/main/aciodrv/h44b.c
Normal 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
32
src/main/aciodrv/h44b.h
Normal 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
|
@ -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);
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
16
src/main/jbio-p4io/Module.mk
Normal file
16
src/main/jbio-p4io/Module.mk
Normal 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 \
|
55
src/main/jbio-p4io/config-h44b.c
Normal file
55
src/main/jbio-p4io/config-h44b.c
Normal 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);
|
||||
}
|
||||
}
|
18
src/main/jbio-p4io/config-h44b.h
Normal file
18
src/main/jbio-p4io/config-h44b.h
Normal 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
99
src/main/jbio-p4io/h44b.c
Normal 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;
|
||||
}
|
||||
|
7
src/main/jbio-p4io/h44b.h
Normal file
7
src/main/jbio-p4io/h44b.h
Normal 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);
|
13
src/main/jbio-p4io/jbio-p4io.def
Normal file
13
src/main/jbio-p4io/jbio-p4io.def
Normal 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
206
src/main/jbio-p4io/jbio.c
Normal 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);
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
60
src/main/p4io/cmd.h
Normal 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
13
src/main/p4io/guid.h
Normal 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
42
src/main/p4io/ioctl.h
Normal 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
|
6
src/main/p4iodrv/Module.mk
Normal file
6
src/main/p4iodrv/Module.mk
Normal file
@ -0,0 +1,6 @@
|
||||
libs += p4iodrv
|
||||
|
||||
src_p4iodrv := \
|
||||
device.c \
|
||||
usb.c \
|
||||
|
122
src/main/p4iodrv/device.c
Normal file
122
src/main/p4iodrv/device.c
Normal 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
18
src/main/p4iodrv/device.h
Normal 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
173
src/main/p4iodrv/usb.c
Normal 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
22
src/main/p4iodrv/usb.h
Normal 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
|
@ -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;
|
||||
|
@ -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",
|
||||
};
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user